1 /*
2  #
3  #  File            : CImg.h
4  #                    ( C++ header file )
5  #
6  #  Description     : The C++ Template Image Processing Library.
7  #                    This file is the main part of the CImg Library project.
8  #                    ( http://cimg.sourceforge.net )
9  #
10  #  Project manager : David Tschumperle.
11  #                    ( http://www.greyc.ensicaen.fr/~dtschump/ )
12  #
13  #                    The complete contributor list can be seen in the 'README.txt' file.
14  #
15  #  Licenses        : This file is "dual-licensed", you have to choose one
16  #                    of the two licenses below to apply on this file.
17  #
18  #                    CeCILL-C
19  #                    The CeCILL-C license is close to the GNU LGPL.
20  #                    ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
21  #
22  #                or  CeCILL v2.0
23  #                    The CeCILL license is compatible with the GNU GPL.
24  #                    ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
25  #
26  #  This software is governed either by the CeCILL or the CeCILL-C license
27  #  under French law and abiding by the rules of distribution of free software.
28  #  You can  use, modify and or redistribute the software under the terms of
29  #  the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA
30  #  at the following URL : "http://www.cecill.info".
31  #
32  #  As a counterpart to the access to the source code and  rights to copy,
33  #  modify and redistribute granted by the license, users are provided only
34  #  with a limited warranty  and the software's author,  the holder of the
35  #  economic rights,  and the successive licensors  have only  limited
36  #  liability.
37  #
38  #  In this respect, the user's attention is drawn to the risks associated
39  #  with loading,  using,  modifying and/or developing or reproducing the
40  #  software by the user in light of its specific status of free software,
41  #  that may mean  that it is complicated to manipulate,  and  that  also
42  #  therefore means  that it is reserved for developers  and  experienced
43  #  professionals having in-depth computer knowledge. Users are therefore
44  #  encouraged to load and test the software's suitability as regards their
45  #  requirements in conditions enabling the security of their systems and/or
46  #  data to be ensured and,  more generally, to use and operate it in the
47  #  same conditions as regards security.
48  #
49  #  The fact that you are presently reading this means that you have had
50  #  knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms.
51  #
52 */
53 
54 // Define version number of the current file.
55 //
56 #ifndef cimg_version
57 #define cimg_version 130
58 
59 /*-----------------------------------------------------------
60  #
61  # Test/auto-set CImg configuration variables
62  # and include required headers.
63  #
64  # If you find that default configuration variables are
65  # not adapted, you can override their values before including
66  # the header file "CImg.h" (using the #define directive).
67  #
68  ------------------------------------------------------------*/
69 
70 // Include required standard C++ headers.
71 //
72 #include <cstdio>
73 #include <cstdlib>
74 #include <cstdarg>
75 #include <cstring>
76 #include <cmath>
77 #include <ctime>
78 
79 // Operating system configuration.
80 //
81 // Define 'cimg_OS' to : 0 for an unknown OS (will try to minimize library dependencies).
82 //                       1 for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...).
83 //                       2 for Microsoft Windows.
84 //
85 #ifndef cimg_OS
86 #if defined(unix)        || defined(__unix)      || defined(__unix__) \
87  || defined(linux)       || defined(__linux)     || defined(__linux__) \
88  || defined(sun)         || defined(__sun) \
89  || defined(BSD)         || defined(__OpenBSD__) || defined(__NetBSD__) \
90  || defined(__FreeBSD__) || defined __DragonFly__ \
91  || defined(sgi)         || defined(__sgi) \
92  || defined(__MACOSX__)  || defined(__APPLE__) \
93  || defined(__CYGWIN__)
94 #define cimg_OS 1
95 #elif defined(_MSC_VER) || defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) \
96    || defined(WIN64)    || defined(_WIN64) || defined(__WIN64__)
97 #define cimg_OS 2
98 #else
99 #define cimg_OS 0
100 #endif
101 #elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2)
102 #error CImg Library : Configuration variable 'cimg_OS' is badly defined.
103 #error (valid values are '0=unknown OS', '1=Unix-like OS', '2=Microsoft Windows').
104 #endif
105 
106 // Compiler configuration.
107 //
108 // Try to detect Microsoft VC++ compilers.
109 // (lot of workarounds are needed afterwards to
110 // make CImg working, particularly with VC++ 6.0).
111 //
112 #ifdef _MSC_VER
113 #pragma warning(push)
114 #pragma warning(disable:4311)
115 #pragma warning(disable:4312)
116 #pragma warning(disable:4800)
117 #pragma warning(disable:4804)
118 #pragma warning(disable:4996)
119 #ifndef _CRT_SECURE_NO_DEPRECATE
120 #   define _CRT_SECURE_NO_DEPRECATE 1
121 #endif
122 #ifndef _CRT_NONSTDC_NO_DEPRECATE
123 #   define _CRT_NONSTDC_NO_DEPRECATE 1
124 #endif
125 #if _MSC_VER<1300
126 #define cimg_use_visualcpp6
127 #define cimg_std
128 #define _WIN32_WINNT 0x0500
129 #endif
130 #endif
131 
132 // Include OS-specific headers.
133 //
134 #if cimg_OS==1
135 #include <sys/time.h>
136 #include <unistd.h>
137 #elif cimg_OS==2
138 #include <windows.h>
139 #ifndef _WIN32_IE
140 #define _WIN32_IE 0x0400
141 #endif
142 #include <shlobj.h>
143 #endif
144 
145 // Define default pipe for output messages
146 //
147 // Define 'cimg_stdout' to : stdout to print CImg messages on the standard output.
148 //                           stderr to print CImg messages on the standart error output (default behavior).
149 //
150 #ifndef cimg_std
151 #define cimg_std std
152 #endif
153 #ifndef cimg_stdout
154 #define cimg_stdout stderr
155 #endif
156 
157 // Output messages configuration.
158 //
159 // Define 'cimg_debug' to : 0 to hide debug messages (quiet mode, but exceptions are still thrown).
160 //                          1 to display debug messages on the console.
161 //                          2 to display debug messages with dialog windows (default behavior).
162 //                          3 to do as 1 + add extra warnings (may slow down the code !).
163 //                          4 to do as 2 + add extra warnings (may slow down the code !).
164 //
165 // Define 'cimg_strict_warnings' to replace warning messages by exception throwns.
166 //
167 // Define 'cimg_use_vt100' to allow output of color messages (require VT100-compatible terminal).
168 //
169 #ifndef cimg_debug
170 #define cimg_debug 2
171 #elif !(cimg_debug==0 || cimg_debug==1 || cimg_debug==2 || cimg_debug==3 || cimg_debug==4)
172 #error CImg Library : Configuration variable 'cimg_debug' is badly defined.
173 #error (valid values are '0=quiet', '1=console', '2=dialog', '3=console+warnings', '4=dialog+warnings').
174 #endif
175 
176 // Display framework configuration.
177 //
178 // Define 'cimg_display' to : 0 to disable display capabilities.
179 //                            1 to use X-Window framework (X11).
180 //                            2 to use Microsoft GDI32 framework.
181 //                            3 to use Apple Carbon framework.
182 //
183 #ifndef cimg_display
184 #if cimg_OS==0
185 #define cimg_display 0
186 #elif cimg_OS==1
187 #if defined(__MACOSX__) || defined(__APPLE__)
188 #define cimg_display 1
189 #else
190 #define cimg_display 1
191 #endif
192 #elif cimg_OS==2
193 #define cimg_display 2
194 #endif
195 #elif !(cimg_display==0 || cimg_display==1 || cimg_display==2 || cimg_display==3)
196 #error CImg Library : Configuration variable 'cimg_display' is badly defined.
197 #error (valid values are '0=disable', '1=X-Window (X11)', '2=Microsoft GDI32', '3=Apple Carbon').
198 #endif
199 
200 // Include display-specific headers.
201 //
202 #if cimg_display==1
203 #include <X11/Xlib.h>
204 #include <X11/Xutil.h>
205 #include <X11/keysym.h>
206 #include <pthread.h>
207 #ifdef cimg_use_xshm
208 #include <sys/ipc.h>
209 #include <sys/shm.h>
210 #include <X11/extensions/XShm.h>
211 #endif
212 #ifdef cimg_use_xrandr
213 #include <X11/extensions/Xrandr.h>
214 #endif
215 #elif cimg_display==3
216 #include <Carbon/Carbon.h>
217 #include <pthread.h>
218 #endif
219 
220 // OpenMP configuration.
221 // (http://www.openmp.org)
222 //
223 // Define 'cimg_use_openmp' to enable OpenMP support.
224 //
225 // OpenMP directives can be used in few CImg functions to get
226 // advantages of multi-core CPUs. Using OpenMP is not mandatory.
227 //
228 #ifdef cimg_use_openmp
229 #include "omp.h"
230 #endif
231 
232 // LibPNG configuration.
233 // (http://www.libpng.org)
234 //
235 // Define 'cimg_use_png' to enable LibPNG support.
236 //
237 // LibPNG can be used in functions 'CImg<T>::{load,save}_png()'
238 // to get a builtin support of PNG files. Using LibPNG is not mandatory.
239 //
240 #ifdef cimg_use_png
241 extern "C" {
242 #include "png.h"
243 }
244 #endif
245 
246 // LibJPEG configuration.
247 // (https://en.wikipedia.org/wiki/Libjpeg)
248 //
249 // Define 'cimg_use_jpeg' to enable LibJPEG support.
250 //
251 // LibJPEG can be used in functions 'CImg<T>::{load,save}_jpeg()'
252 // to get a builtin support of JPEG files. Using LibJPEG is not mandatory.
253 //
254 #ifdef cimg_use_jpeg
255 extern "C" {
256 #include "jpeglib.h"
257 }
258 #endif
259 
260 // LibTIFF configuration.
261 // (http://www.libtiff.org)
262 //
263 // Define 'cimg_use_tiff' to enable LibTIFF support.
264 //
265 // LibTIFF can be used in functions 'CImg[List]<T>::{load,save}_tiff()'
266 // to get a builtin support of TIFF files. Using LibTIFF is not mandatory.
267 //
268 #ifdef cimg_use_tiff
269 extern "C" {
270 #include "tiffio.h"
271 }
272 #endif
273 
274 // FFMPEG Avcodec and Avformat libraries configuration.
275 // (http://www.ffmpeg.org)
276 //
277 // Define 'cimg_use_ffmpeg' to enable FFMPEG lib support.
278 //
279 // Avcodec and Avformat libraries can be used in functions
280 // 'CImg[List]<T>::load_ffmpeg()' to get a builtin
281 // support of various image sequences files.
282 // Using FFMPEG libraries is not mandatory.
283 //
284 #ifdef cimg_use_ffmpeg
285 extern "C" {
286 #include "avformat.h"
287 #include "avcodec.h"
288 #include "swscale.h"
289 }
290 #endif
291 
292 // Zlib configuration
293 // (http://www.zlib.net)
294 //
295 // Define 'cimg_use_zlib' to enable Zlib support.
296 //
297 // Zlib can be used in functions 'CImg[List]<T>::{load,save}_cimg()'
298 // to allow compressed data in '.cimg' files. Using Zlib is not mandatory.
299 //
300 #ifdef cimg_use_zlib
301 extern "C" {
302 #include "zlib.h"
303 }
304 #endif
305 
306 // Magick++ configuration.
307 // (http://www.imagemagick.org/Magick++)
308 //
309 // Define 'cimg_use_magick' to enable Magick++ support.
310 //
311 // Magick++ library can be used in functions 'CImg<T>::{load,save}()'
312 // to get a builtin support of various image formats (PNG,JPEG,TIFF,...).
313 // Using Magick++ is not mandatory.
314 //
315 #ifdef cimg_use_magick
316 #include "Magick++.h"
317 #endif
318 
319 // FFTW3 configuration.
320 // (http://www.fftw.org)
321 //
322 // Define 'cimg_use_fftw3' to enable libFFTW3 support.
323 //
324 // FFTW3 library can be used in functions 'CImg[List]<T>::FFT()' to
325 // efficiently compile the Fast Fourier Transform of image data.
326 //
327 #ifdef cimg_use_fftw3
328 extern "C" {
329 #include "fftw3.h"
330 }
331 #endif
332 
333 // Board configuration.
334 // (http://libboard.sourceforge.net/)
335 //
336 // Define 'cimg_use_board' to enable Board support.
337 //
338 // Board library can be used in functions 'CImg<T>::draw_object3d()'
339 // to draw objects 3D in vector-graphics canvas that can be saved
340 // as .PS or .SVG files afterwards.
341 //
342 #ifdef cimg_use_board
343 #include "Board.h"
344 #endif
345 
346 // Lapack configuration.
347 // (http://www.netlib.org/lapack)
348 //
349 // Define 'cimg_use_lapack' to enable LAPACK support.
350 //
351 // Lapack can be used in various CImg functions dealing with
352 // matrix computation and algorithms (eigenvalues, inverse, ...).
353 // Using Lapack is not mandatory.
354 //
355 #ifdef cimg_use_lapack
356 extern "C" {
357   extern void sgetrf_(int*, int*, float*, int*, int*, int*);
358   extern void sgetri_(int*, float*, int*, int*, float*, int*, int*);
359   extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*);
360   extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*);
361   extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*);
362   extern void dgetrf_(int*, int*, double*, int*, int*, int*);
363   extern void dgetri_(int*, double*, int*, int*, double*, int*, int*);
364   extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*);
365   extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*, int*, double*, int*, double*, int*, int*);
366   extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*);
367 }
368 #endif
369 
370 // Check if min/max macros are defined.
371 //
372 // CImg does not compile if macros 'min' or 'max' are defined,
373 // because min() and max() functions are also defined in the cimg:: namespace.
374 // so it '#undef' these macros if necessary, and restore them to reasonable
375 // values at the end of the file.
376 //
377 #ifdef min
378 #undef min
379 #define _cimg_redefine_min
380 #endif
381 #ifdef max
382 #undef max
383 #define _cimg_redefine_max
384 #endif
385 
386 // Set the current working directory for native MacOSX bundled applications.
387 //
388 // By default, MacOS bundled applications set the cwd at the root directory '/',
389 // the code below allows to set it to the current exec directory instead when
390 // a CImg-based program is executed.
391 //
392 #if cimg_OS==1 && cimg_display==3
393 static struct _cimg_macosx_setcwd {
_cimg_macosx_setcwd_cimg_macosx_setcwd394   _cimg_macosx_setcwd() {
395     FSRef location;
396     ProcessSerialNumber psn;
397     char filePath[512];
398     if (GetCurrentProcess(&psn)!=noErr) return;
399     if (GetProcessBundleLocation(&psn,&location)!=noErr) return;
400     FSRefMakePath(&location,(UInt8*)filePath,sizeof(filePath)-1);
401     int p = cimg_std::strlen(filePath);
402     while (filePath[p] != '/') --p;
403     filePath[p] = 0;
404     chdir(filePath);
405   }
406 } cimg_macosx_setcwd;
407 #endif
408 
409 /*------------------------------------------------------------------------------
410   #
411   # Define user-friendly macros.
412   #
413   # User macros are prefixed by 'cimg_' and can be used in your own code.
414   # They are particularly useful for option parsing, and image loops creation.
415   #
416   ------------------------------------------------------------------------------*/
417 
418 // Define the program usage, and retrieve command line arguments.
419 //
420 #define cimg_usage(usage) cimg_library::cimg::option((char*)0,argc,argv,(char*)0,usage)
421 #define cimg_help(str)    cimg_library::cimg::option((char*)0,argc,argv,str,(char*)0)
422 #define cimg_option(name,defaut,usage) cimg_library::cimg::option(name,argc,argv,defaut,usage)
423 #define cimg_argument(pos) cimg_library::cimg::argument(pos,argc,argv)
424 #define cimg_argument1(pos,s0) cimg_library::cimg::argument(pos,argc,argv,1,s0)
425 #define cimg_argument2(pos,s0,s1) cimg_library::cimg::argument(pos,argc,argv,2,s0,s1)
426 #define cimg_argument3(pos,s0,s1,s2) cimg_library::cimg::argument(pos,argc,argv,3,s0,s1,s2)
427 #define cimg_argument4(pos,s0,s1,s2,s3) cimg_library::cimg::argument(pos,argc,argv,4,s0,s1,s2,s3)
428 #define cimg_argument5(pos,s0,s1,s2,s3,s4) cimg_library::cimg::argument(pos,argc,argv,5,s0,s1,s2,s3,s4)
429 #define cimg_argument6(pos,s0,s1,s2,s3,s4,s5) cimg_library::cimg::argument(pos,argc,argv,6,s0,s1,s2,s3,s4,s5)
430 #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)
431 #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)
432 #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)
433 
434 // Define and manipulate local neighborhoods.
435 //
436 #define CImg_2x2(I,T) T I[4]; \
437                       T& I##cc = I[0]; T& I##nc = I[1]; \
438                       T& I##cn = I[2]; T& I##nn = I[3]; \
439                       I##cc = I##nc = \
440                       I##cn = I##nn = 0
441 
442 #define CImg_3x3(I,T) T I[9]; \
443                       T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \
444                       T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \
445                       T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \
446                       I##pp = I##cp = I##np = \
447                       I##pc = I##cc = I##nc = \
448                       I##pn = I##cn = I##nn = 0
449 
450 #define CImg_4x4(I,T) T I[16]; \
451                       T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \
452                       T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \
453                       T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \
454                       T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \
455                       I##pp = I##cp = I##np = I##ap = \
456                       I##pc = I##cc = I##nc = I##ac = \
457                       I##pn = I##cn = I##nn = I##an = \
458                       I##pa = I##ca = I##na = I##aa = 0
459 
460 #define CImg_5x5(I,T) T I[25]; \
461                       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]; \
462                       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]; \
463                       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]; \
464                       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]; \
465                       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]; \
466                       I##bb = I##pb = I##cb = I##nb = I##ab = \
467                       I##bp = I##pp = I##cp = I##np = I##ap = \
468                       I##bc = I##pc = I##cc = I##nc = I##ac = \
469                       I##bn = I##pn = I##cn = I##nn = I##an = \
470                       I##ba = I##pa = I##ca = I##na = I##aa = 0
471 
472 #define CImg_2x2x2(I,T) T I[8]; \
473                       T& I##ccc = I[0]; T& I##ncc = I[1]; \
474                       T& I##cnc = I[2]; T& I##nnc = I[3]; \
475                       T& I##ccn = I[4]; T& I##ncn = I[5]; \
476                       T& I##cnn = I[6]; T& I##nnn = I[7]; \
477                       I##ccc = I##ncc = \
478                       I##cnc = I##nnc = \
479                       I##ccn = I##ncn = \
480                       I##cnn = I##nnn = 0
481 
482 #define CImg_3x3x3(I,T) T I[27]; \
483                       T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \
484                       T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \
485                       T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \
486                       T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \
487                       T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \
488                       T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \
489                       T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \
490                       T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \
491                       T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \
492                       I##ppp = I##cpp = I##npp = \
493                       I##pcp = I##ccp = I##ncp = \
494                       I##pnp = I##cnp = I##nnp = \
495                       I##ppc = I##cpc = I##npc = \
496                       I##pcc = I##ccc = I##ncc = \
497                       I##pnc = I##cnc = I##nnc = \
498                       I##ppn = I##cpn = I##npn = \
499                       I##pcn = I##ccn = I##ncn = \
500                       I##pnn = I##cnn = I##nnn = 0
501 
502 #define cimg_get2x2(img,x,y,z,v,I) \
503   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)
504 
505 #define cimg_get3x3(img,x,y,z,v,I) \
506   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), \
507   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), \
508   I[8] = (img)(_n1##x,_n1##y,z,v)
509 
510 #define cimg_get4x4(img,x,y,z,v,I) \
511   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), \
512   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), \
513   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), \
514   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)
515 
516 #define cimg_get5x5(img,x,y,z,v,I) \
517   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), \
518   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), \
519   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), \
520   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), \
521   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), \
522   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), \
523   I[24] = (img)(_n2##x,_n2##y,z,v)
524 
525 #define cimg_get6x6(img,x,y,z,v,I) \
526  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), \
527  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), \
528  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), \
529  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), \
530  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), \
531  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), \
532  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), \
533  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), \
534  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)
535 
536 #define cimg_get7x7(img,x,y,z,v,I) \
537  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), \
538  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), \
539  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), \
540  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), \
541  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), \
542  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), \
543  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), \
544  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), \
545  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), \
546  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), \
547  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), \
548  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), \
549  I[48] = (img)(_n3##x,_n3##y,z,v)
550 
551 #define cimg_get8x8(img,x,y,z,v,I) \
552  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), \
553  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), \
554  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), \
555  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), \
556  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), \
557  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), \
558  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), \
559  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), \
560  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), \
561  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), \
562  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), \
563  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), \
564  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), \
565  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), \
566  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), \
567  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);
568 
569 #define cimg_get9x9(img,x,y,z,v,I) \
570  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), \
571  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), \
572  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), \
573  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), \
574  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), \
575  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), \
576  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), \
577  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), \
578  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), \
579  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), \
580  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), \
581  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), \
582  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), \
583  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), \
584  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), \
585  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), \
586  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), \
587  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), \
588  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), \
589  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), \
590  I[80] = (img)(_n4##x,_n4##y,z,v)
591 
592 #define cimg_get2x2x2(img,x,y,z,v,I) \
593   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), \
594   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)
595 
596 #define cimg_get3x3x3(img,x,y,z,v,I) \
597   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), \
598   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), \
599   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), \
600   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), \
601   I[12] = (img)(_p1##x,y,z,v), I[13] = (img)(x,y,z,v), I[14] = (img)(_n1##x,y,z,v), \
602   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), \
603   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), \
604   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), \
605   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)
606 
607 // Define various image loops.
608 //
609 // These macros generally avoid the use of iterators, but you are not forced to used them !
610 //
611 #define cimg_for(img,ptr,T_ptr) for (T_ptr *ptr = (img).data + (img).size(); (ptr--)>(img).data; )
612 #define cimg_foroff(img,off) for (unsigned int off = 0, _max##off = (unsigned int)(img).size(); off<_max##off; ++off)
613 #define cimglist_for(list,l) for (unsigned int l=0; l<(list).size; ++l)
614 #define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn
615 
616 #define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i)
617 #define cimg_forX(img,x) cimg_for1((img).width,x)
618 #define cimg_forY(img,y) cimg_for1((img).height,y)
619 #define cimg_forZ(img,z) cimg_for1((img).depth,z)
620 #define cimg_forV(img,v) cimg_for1((img).dim,v)
621 #define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x)
622 #define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x)
623 #define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y)
624 #define cimg_forXV(img,x,v) cimg_forV(img,v) cimg_forX(img,x)
625 #define cimg_forYV(img,y,v) cimg_forV(img,v) cimg_forY(img,y)
626 #define cimg_forZV(img,z,v) cimg_forV(img,v) cimg_forZ(img,z)
627 #define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y)
628 #define cimg_forXYV(img,x,y,v) cimg_forV(img,v) cimg_forXY(img,x,y)
629 #define cimg_forXZV(img,x,z,v) cimg_forV(img,v) cimg_forXZ(img,x,z)
630 #define cimg_forYZV(img,y,z,v) cimg_forV(img,v) cimg_forYZ(img,y,z)
631 #define cimg_forXYZV(img,x,y,z,v) cimg_forV(img,v) cimg_forXYZ(img,x,y,z)
632 
633 #define cimg_for_in1(bound,i0,i1,i) \
634  for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound)-1; i<=_max##i; ++i)
635 #define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img).width,x0,x1,x)
636 #define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img).height,y0,y1,y)
637 #define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img).depth,z0,z1,z)
638 #define cimg_for_inV(img,v0,v1,v) cimg_for_in1((img).dim,v0,v1,v)
639 #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)
640 #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)
641 #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)
642 #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)
643 #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)
644 #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)
645 #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)
646 #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)
647 #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)
648 #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)
649 #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)
650 #define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img).width-1-(n),x)
651 #define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img).height-1-(n),y)
652 #define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img).depth-1-(n),z)
653 #define cimg_for_insideV(img,v,n) cimg_for_inV(img,n,(img).dim-1-(n),v)
654 #define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
655 #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)
656 #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)
657 
658 #define cimg_for_out1(boundi,i0,i1,i) \
659  for (int i = (int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1)+1:i)
660 #define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \
661  for (int j = 0; j<(int)(boundj); ++j) \
662  for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
663   ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1)+1:i))
664 #define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \
665  for (int k = 0; k<(int)(boundk); ++k) \
666  for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
667  for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
668   ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1)+1:i))
669 #define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \
670  for (int l = 0; l<(int)(boundl); ++l) \
671  for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \
672  for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
673  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); \
674   ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1)+1:i))
675 #define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img).width,x0,x1,x)
676 #define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img).height,y0,y1,y)
677 #define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img).depth,z0,z1,z)
678 #define cimg_for_outV(img,v0,v1,v) cimg_for_out1((img).dim,v0,v1,v)
679 #define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img).width,(img).height,x0,y0,x1,y1,x,y)
680 #define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img).width,(img).depth,x0,z0,x1,z1,x,z)
681 #define cimg_for_outXV(img,x0,v0,x1,v1,x,v) cimg_for_out2((img).width,(img).dim,x0,v0,x1,v1,x,v)
682 #define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img).height,(img).depth,y0,z0,y1,z1,y,z)
683 #define cimg_for_outYV(img,y0,v0,y1,v1,y,v) cimg_for_out2((img).height,(img).dim,y0,v0,y1,v1,y,v)
684 #define cimg_for_outZV(img,z0,v0,z1,v1,z,v) cimg_for_out2((img).depth,(img).dim,z0,v0,z1,v1,z,v)
685 #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)
686 #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)
687 #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)
688 #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)
689 #define cimg_for_outXYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) \
690  cimg_for_out4((img).width,(img).height,(img).depth,(img).dim,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v)
691 #define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img).width-1-(n),x)
692 #define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img).height-1-(n),y)
693 #define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img).depth-1-(n),z)
694 #define cimg_for_borderV(img,v,n) cimg_for_outV(img,n,(img).dim-1-(n),v)
695 #define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
696 #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)
697 #define cimg_for_borderXYZV(img,x,y,z,v,n) \
698  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)
699 
700 #define cimg_for_spiralXY(img,x,y) \
701  for (int x = 0, y = 0, _n1##x = 1, _n1##y = (int)((img).width*(img).height); _n1##y; \
702       --_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)
703 
704 #define cimg_for_lineXY(x,y,x0,y0,x1,y1) \
705  for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \
706       _dx=(x1)>(x0)?(int)(x1)-(int)(x0):(_sx=-1,(int)(x0)-(int)(x1)), \
707       _dy=(y1)>(y0)?(int)(y1)-(int)(y0):(_sy=-1,(int)(y0)-(int)(y1)), \
708       _counter = _dx, \
709       _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \
710       _counter>=0; \
711       --_counter, x+=_steep? \
712       (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \
713       (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx))
714 
715 #define cimg_for2(bound,i) \
716  for (int i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1; \
717       _n1##i<(int)(bound) || i==--_n1##i; \
718       ++i, ++_n1##i)
719 #define cimg_for2X(img,x) cimg_for2((img).width,x)
720 #define cimg_for2Y(img,y) cimg_for2((img).height,y)
721 #define cimg_for2Z(img,z) cimg_for2((img).depth,z)
722 #define cimg_for2V(img,v) cimg_for2((img).dim,v)
723 #define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x)
724 #define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x)
725 #define cimg_for2XV(img,x,v) cimg_for2V(img,v) cimg_for2X(img,x)
726 #define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y)
727 #define cimg_for2YV(img,y,v) cimg_for2V(img,v) cimg_for2Y(img,y)
728 #define cimg_for2ZV(img,z,v) cimg_for2V(img,v) cimg_for2Z(img,z)
729 #define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y)
730 #define cimg_for2XZV(img,x,z,v) cimg_for2V(img,v) cimg_for2XZ(img,x,z)
731 #define cimg_for2YZV(img,y,z,v) cimg_for2V(img,v) cimg_for2YZ(img,y,z)
732 #define cimg_for2XYZV(img,x,y,z,v) cimg_for2V(img,v) cimg_for2XYZ(img,x,y,z)
733 
734 #define cimg_for_in2(bound,i0,i1,i) \
735  for (int i = (int)(i0)<0?0:(int)(i0), \
736       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
737       i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
738       ++i, ++_n1##i)
739 #define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img).width,x0,x1,x)
740 #define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img).height,y0,y1,y)
741 #define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img).depth,z0,z1,z)
742 #define cimg_for_in2V(img,v0,v1,v) cimg_for_in2((img).dim,v0,v1,v)
743 #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)
744 #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)
745 #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)
746 #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)
747 #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)
748 #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)
749 #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)
750 #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)
751 #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)
752 #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)
753 
754 #define cimg_for3(bound,i) \
755  for (int i = 0, _p1##i = 0, \
756       _n1##i = 1>=(bound)?(int)(bound)-1:1; \
757       _n1##i<(int)(bound) || i==--_n1##i; \
758       _p1##i = i++, ++_n1##i)
759 #define cimg_for3X(img,x) cimg_for3((img).width,x)
760 #define cimg_for3Y(img,y) cimg_for3((img).height,y)
761 #define cimg_for3Z(img,z) cimg_for3((img).depth,z)
762 #define cimg_for3V(img,v) cimg_for3((img).dim,v)
763 #define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x)
764 #define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x)
765 #define cimg_for3XV(img,x,v) cimg_for3V(img,v) cimg_for3X(img,x)
766 #define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y)
767 #define cimg_for3YV(img,y,v) cimg_for3V(img,v) cimg_for3Y(img,y)
768 #define cimg_for3ZV(img,z,v) cimg_for3V(img,v) cimg_for3Z(img,z)
769 #define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y)
770 #define cimg_for3XZV(img,x,z,v) cimg_for3V(img,v) cimg_for3XZ(img,x,z)
771 #define cimg_for3YZV(img,y,z,v) cimg_for3V(img,v) cimg_for3YZ(img,y,z)
772 #define cimg_for3XYZV(img,x,y,z,v) cimg_for3V(img,v) cimg_for3XYZ(img,x,y,z)
773 
774 #define cimg_for_in3(bound,i0,i1,i) \
775  for (int i = (int)(i0)<0?0:(int)(i0), \
776       _p1##i = i-1<0?0:i-1, \
777       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
778       i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
779       _p1##i = i++, ++_n1##i)
780 #define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img).width,x0,x1,x)
781 #define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img).height,y0,y1,y)
782 #define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img).depth,z0,z1,z)
783 #define cimg_for_in3V(img,v0,v1,v) cimg_for_in3((img).dim,v0,v1,v)
784 #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)
785 #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)
786 #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)
787 #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)
788 #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)
789 #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)
790 #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)
791 #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)
792 #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)
793 #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)
794 
795 #define cimg_for4(bound,i) \
796  for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1, \
797       _n2##i = 2>=(bound)?(int)(bound)-1:2; \
798       _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
799       _p1##i = i++, ++_n1##i, ++_n2##i)
800 #define cimg_for4X(img,x) cimg_for4((img).width,x)
801 #define cimg_for4Y(img,y) cimg_for4((img).height,y)
802 #define cimg_for4Z(img,z) cimg_for4((img).depth,z)
803 #define cimg_for4V(img,v) cimg_for4((img).dim,v)
804 #define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x)
805 #define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x)
806 #define cimg_for4XV(img,x,v) cimg_for4V(img,v) cimg_for4X(img,x)
807 #define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y)
808 #define cimg_for4YV(img,y,v) cimg_for4V(img,v) cimg_for4Y(img,y)
809 #define cimg_for4ZV(img,z,v) cimg_for4V(img,v) cimg_for4Z(img,z)
810 #define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y)
811 #define cimg_for4XZV(img,x,z,v) cimg_for4V(img,v) cimg_for4XZ(img,x,z)
812 #define cimg_for4YZV(img,y,z,v) cimg_for4V(img,v) cimg_for4YZ(img,y,z)
813 #define cimg_for4XYZV(img,x,y,z,v) cimg_for4V(img,v) cimg_for4XYZ(img,x,y,z)
814 
815 #define cimg_for_in4(bound,i0,i1,i) \
816  for (int i = (int)(i0)<0?0:(int)(i0), \
817       _p1##i = i-1<0?0:i-1, \
818       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
819       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
820       i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
821       _p1##i = i++, ++_n1##i, ++_n2##i)
822 #define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img).width,x0,x1,x)
823 #define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img).height,y0,y1,y)
824 #define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img).depth,z0,z1,z)
825 #define cimg_for_in4V(img,v0,v1,v) cimg_for_in4((img).dim,v0,v1,v)
826 #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)
827 #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)
828 #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)
829 #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)
830 #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)
831 #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)
832 #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)
833 #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)
834 #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)
835 #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)
836 
837 #define cimg_for5(bound,i) \
838  for (int i = 0, _p2##i = 0, _p1##i = 0, \
839       _n1##i = 1>=(bound)?(int)(bound)-1:1, \
840       _n2##i = 2>=(bound)?(int)(bound)-1:2; \
841       _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
842       _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
843 #define cimg_for5X(img,x) cimg_for5((img).width,x)
844 #define cimg_for5Y(img,y) cimg_for5((img).height,y)
845 #define cimg_for5Z(img,z) cimg_for5((img).depth,z)
846 #define cimg_for5V(img,v) cimg_for5((img).dim,v)
847 #define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x)
848 #define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x)
849 #define cimg_for5XV(img,x,v) cimg_for5V(img,v) cimg_for5X(img,x)
850 #define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y)
851 #define cimg_for5YV(img,y,v) cimg_for5V(img,v) cimg_for5Y(img,y)
852 #define cimg_for5ZV(img,z,v) cimg_for5V(img,v) cimg_for5Z(img,z)
853 #define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y)
854 #define cimg_for5XZV(img,x,z,v) cimg_for5V(img,v) cimg_for5XZ(img,x,z)
855 #define cimg_for5YZV(img,y,z,v) cimg_for5V(img,v) cimg_for5YZ(img,y,z)
856 #define cimg_for5XYZV(img,x,y,z,v) cimg_for5V(img,v) cimg_for5XYZ(img,x,y,z)
857 
858 #define cimg_for_in5(bound,i0,i1,i) \
859  for (int i = (int)(i0)<0?0:(int)(i0), \
860       _p2##i = i-2<0?0:i-2, \
861       _p1##i = i-1<0?0:i-1, \
862       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
863       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
864       i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
865       _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
866 #define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img).width,x0,x1,x)
867 #define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img).height,y0,y1,y)
868 #define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img).depth,z0,z1,z)
869 #define cimg_for_in5V(img,v0,v1,v) cimg_for_in5((img).dim,v0,v1,v)
870 #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)
871 #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)
872 #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)
873 #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)
874 #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)
875 #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)
876 #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)
877 #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)
878 #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)
879 #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)
880 
881 #define cimg_for6(bound,i) \
882  for (int i = 0, _p2##i = 0, _p1##i = 0, \
883       _n1##i = 1>=(bound)?(int)(bound)-1:1, \
884       _n2##i = 2>=(bound)?(int)(bound)-1:2, \
885       _n3##i = 3>=(bound)?(int)(bound)-1:3; \
886       _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
887       _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
888 #define cimg_for6X(img,x) cimg_for6((img).width,x)
889 #define cimg_for6Y(img,y) cimg_for6((img).height,y)
890 #define cimg_for6Z(img,z) cimg_for6((img).depth,z)
891 #define cimg_for6V(img,v) cimg_for6((img).dim,v)
892 #define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x)
893 #define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x)
894 #define cimg_for6XV(img,x,v) cimg_for6V(img,v) cimg_for6X(img,x)
895 #define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y)
896 #define cimg_for6YV(img,y,v) cimg_for6V(img,v) cimg_for6Y(img,y)
897 #define cimg_for6ZV(img,z,v) cimg_for6V(img,v) cimg_for6Z(img,z)
898 #define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y)
899 #define cimg_for6XZV(img,x,z,v) cimg_for6V(img,v) cimg_for6XZ(img,x,z)
900 #define cimg_for6YZV(img,y,z,v) cimg_for6V(img,v) cimg_for6YZ(img,y,z)
901 #define cimg_for6XYZV(img,x,y,z,v) cimg_for6V(img,v) cimg_for6XYZ(img,x,y,z)
902 
903 #define cimg_for_in6(bound,i0,i1,i) \
904  for (int i = (int)(i0)<0?0:(int)(i0), \
905       _p2##i = i-2<0?0:i-2, \
906       _p1##i = i-1<0?0:i-1, \
907       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
908       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
909       _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
910       i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
911       _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
912 #define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img).width,x0,x1,x)
913 #define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img).height,y0,y1,y)
914 #define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img).depth,z0,z1,z)
915 #define cimg_for_in6V(img,v0,v1,v) cimg_for_in6((img).dim,v0,v1,v)
916 #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)
917 #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)
918 #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)
919 #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)
920 #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)
921 #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)
922 #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)
923 #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)
924 #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)
925 #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)
926 
927 #define cimg_for7(bound,i) \
928  for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
929       _n1##i = 1>=(bound)?(int)(bound)-1:1, \
930       _n2##i = 2>=(bound)?(int)(bound)-1:2, \
931       _n3##i = 3>=(bound)?(int)(bound)-1:3; \
932       _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
933       _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
934 #define cimg_for7X(img,x) cimg_for7((img).width,x)
935 #define cimg_for7Y(img,y) cimg_for7((img).height,y)
936 #define cimg_for7Z(img,z) cimg_for7((img).depth,z)
937 #define cimg_for7V(img,v) cimg_for7((img).dim,v)
938 #define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x)
939 #define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x)
940 #define cimg_for7XV(img,x,v) cimg_for7V(img,v) cimg_for7X(img,x)
941 #define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y)
942 #define cimg_for7YV(img,y,v) cimg_for7V(img,v) cimg_for7Y(img,y)
943 #define cimg_for7ZV(img,z,v) cimg_for7V(img,v) cimg_for7Z(img,z)
944 #define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y)
945 #define cimg_for7XZV(img,x,z,v) cimg_for7V(img,v) cimg_for7XZ(img,x,z)
946 #define cimg_for7YZV(img,y,z,v) cimg_for7V(img,v) cimg_for7YZ(img,y,z)
947 #define cimg_for7XYZV(img,x,y,z,v) cimg_for7V(img,v) cimg_for7XYZ(img,x,y,z)
948 
949 #define cimg_for_in7(bound,i0,i1,i) \
950  for (int i = (int)(i0)<0?0:(int)(i0), \
951       _p3##i = i-3<0?0:i-3, \
952       _p2##i = i-2<0?0:i-2, \
953       _p1##i = i-1<0?0:i-1, \
954       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
955       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
956       _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
957       i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
958       _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
959 #define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img).width,x0,x1,x)
960 #define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img).height,y0,y1,y)
961 #define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img).depth,z0,z1,z)
962 #define cimg_for_in7V(img,v0,v1,v) cimg_for_in7((img).dim,v0,v1,v)
963 #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)
964 #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)
965 #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)
966 #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)
967 #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)
968 #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)
969 #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)
970 #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)
971 #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)
972 #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)
973 
974 #define cimg_for8(bound,i) \
975  for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
976       _n1##i = 1>=(bound)?(int)(bound)-1:1, \
977       _n2##i = 2>=(bound)?(int)(bound)-1:2, \
978       _n3##i = 3>=(bound)?(int)(bound)-1:3, \
979       _n4##i = 4>=(bound)?(int)(bound)-1:4; \
980       _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
981       i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
982       _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
983 #define cimg_for8X(img,x) cimg_for8((img).width,x)
984 #define cimg_for8Y(img,y) cimg_for8((img).height,y)
985 #define cimg_for8Z(img,z) cimg_for8((img).depth,z)
986 #define cimg_for8V(img,v) cimg_for8((img).dim,v)
987 #define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x)
988 #define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x)
989 #define cimg_for8XV(img,x,v) cimg_for8V(img,v) cimg_for8X(img,x)
990 #define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y)
991 #define cimg_for8YV(img,y,v) cimg_for8V(img,v) cimg_for8Y(img,y)
992 #define cimg_for8ZV(img,z,v) cimg_for8V(img,v) cimg_for8Z(img,z)
993 #define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y)
994 #define cimg_for8XZV(img,x,z,v) cimg_for8V(img,v) cimg_for8XZ(img,x,z)
995 #define cimg_for8YZV(img,y,z,v) cimg_for8V(img,v) cimg_for8YZ(img,y,z)
996 #define cimg_for8XYZV(img,x,y,z,v) cimg_for8V(img,v) cimg_for8XYZ(img,x,y,z)
997 
998 #define cimg_for_in8(bound,i0,i1,i) \
999  for (int i = (int)(i0)<0?0:(int)(i0), \
1000       _p3##i = i-3<0?0:i-3, \
1001       _p2##i = i-2<0?0:i-2, \
1002       _p1##i = i-1<0?0:i-1, \
1003       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
1004       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
1005       _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
1006       _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
1007       i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
1008       i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
1009       _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1010 #define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img).width,x0,x1,x)
1011 #define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img).height,y0,y1,y)
1012 #define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img).depth,z0,z1,z)
1013 #define cimg_for_in8V(img,v0,v1,v) cimg_for_in8((img).dim,v0,v1,v)
1014 #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)
1015 #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)
1016 #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)
1017 #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)
1018 #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)
1019 #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)
1020 #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)
1021 #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)
1022 #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)
1023 #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)
1024 
1025 #define cimg_for9(bound,i) \
1026   for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
1027        _n1##i = 1>=(int)(bound)?(int)(bound)-1:1, \
1028        _n2##i = 2>=(int)(bound)?(int)(bound)-1:2, \
1029        _n3##i = 3>=(int)(bound)?(int)(bound)-1:3, \
1030        _n4##i = 4>=(int)(bound)?(int)(bound)-1:4; \
1031        _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
1032        i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
1033        _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1034 #define cimg_for9X(img,x) cimg_for9((img).width,x)
1035 #define cimg_for9Y(img,y) cimg_for9((img).height,y)
1036 #define cimg_for9Z(img,z) cimg_for9((img).depth,z)
1037 #define cimg_for9V(img,v) cimg_for9((img).dim,v)
1038 #define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x)
1039 #define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x)
1040 #define cimg_for9XV(img,x,v) cimg_for9V(img,v) cimg_for9X(img,x)
1041 #define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y)
1042 #define cimg_for9YV(img,y,v) cimg_for9V(img,v) cimg_for9Y(img,y)
1043 #define cimg_for9ZV(img,z,v) cimg_for9V(img,v) cimg_for9Z(img,z)
1044 #define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y)
1045 #define cimg_for9XZV(img,x,z,v) cimg_for9V(img,v) cimg_for9XZ(img,x,z)
1046 #define cimg_for9YZV(img,y,z,v) cimg_for9V(img,v) cimg_for9YZ(img,y,z)
1047 #define cimg_for9XYZV(img,x,y,z,v) cimg_for9V(img,v) cimg_for9XYZ(img,x,y,z)
1048 
1049 #define cimg_for_in9(bound,i0,i1,i) \
1050   for (int i = (int)(i0)<0?0:(int)(i0), \
1051        _p4##i = i-4<0?0:i-4, \
1052        _p3##i = i-3<0?0:i-3, \
1053        _p2##i = i-2<0?0:i-2, \
1054        _p1##i = i-1<0?0:i-1, \
1055        _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
1056        _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
1057        _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
1058        _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
1059        i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
1060        i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
1061        _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1062 #define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img).width,x0,x1,x)
1063 #define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img).height,y0,y1,y)
1064 #define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img).depth,z0,z1,z)
1065 #define cimg_for_in9V(img,v0,v1,v) cimg_for_in9((img).dim,v0,v1,v)
1066 #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)
1067 #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)
1068 #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)
1069 #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)
1070 #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)
1071 #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)
1072 #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)
1073 #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)
1074 #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)
1075 #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)
1076 
1077 #define cimg_for2x2(img,x,y,z,v,I) \
1078   cimg_for2((img).height,y) for (int x = 0, \
1079    _n1##x = (int)( \
1080    (I[0] = (img)(0,y,z,v)), \
1081    (I[2] = (img)(0,_n1##y,z,v)), \
1082    1>=(img).width?(int)((img).width)-1:1);  \
1083    (_n1##x<(int)((img).width) && ( \
1084    (I[1] = (img)(_n1##x,y,z,v)), \
1085    (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1086    x==--_n1##x; \
1087    I[0] = I[1], \
1088    I[2] = I[3], \
1089    ++x, ++_n1##x)
1090 
1091 #define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,v,I) \
1092   cimg_for_in2((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1093    _n1##x = (int)( \
1094    (I[0] = (img)(x,y,z,v)), \
1095    (I[2] = (img)(x,_n1##y,z,v)), \
1096    x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1097    x<=(int)(x1) && ((_n1##x<(int)((img).width) && (  \
1098    (I[1] = (img)(_n1##x,y,z,v)), \
1099    (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1100    x==--_n1##x); \
1101    I[0] = I[1], \
1102    I[2] = I[3], \
1103    ++x, ++_n1##x)
1104 
1105 #define cimg_for3x3(img,x,y,z,v,I) \
1106   cimg_for3((img).height,y) for (int x = 0, \
1107    _p1##x = 0, \
1108    _n1##x = (int)( \
1109    (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
1110    (I[3] = I[4] = (img)(0,y,z,v)), \
1111    (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
1112    1>=(img).width?(int)((img).width)-1:1); \
1113    (_n1##x<(int)((img).width) && ( \
1114    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1115    (I[5] = (img)(_n1##x,y,z,v)), \
1116    (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1117    x==--_n1##x; \
1118    I[0] = I[1], I[1] = I[2], \
1119    I[3] = I[4], I[4] = I[5], \
1120    I[6] = I[7], I[7] = I[8], \
1121    _p1##x = x++, ++_n1##x)
1122 
1123 #define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,v,I) \
1124   cimg_for_in3((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1125    _p1##x = x-1<0?0:x-1, \
1126    _n1##x = (int)( \
1127    (I[0] = (img)(_p1##x,_p1##y,z,v)), \
1128    (I[3] = (img)(_p1##x,y,z,v)), \
1129    (I[6] = (img)(_p1##x,_n1##y,z,v)), \
1130    (I[1] = (img)(x,_p1##y,z,v)), \
1131    (I[4] = (img)(x,y,z,v)), \
1132    (I[7] = (img)(x,_n1##y,z,v)), \
1133    x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1134    x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
1135    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1136    (I[5] = (img)(_n1##x,y,z,v)), \
1137    (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1138    x==--_n1##x);            \
1139    I[0] = I[1], I[1] = I[2], \
1140    I[3] = I[4], I[4] = I[5], \
1141    I[6] = I[7], I[7] = I[8], \
1142    _p1##x = x++, ++_n1##x)
1143 
1144 #define cimg_for4x4(img,x,y,z,v,I) \
1145   cimg_for4((img).height,y) for (int x = 0, \
1146    _p1##x = 0, \
1147    _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1148    _n2##x = (int)( \
1149    (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
1150    (I[4] = I[5] = (img)(0,y,z,v)), \
1151    (I[8] = I[9] = (img)(0,_n1##y,z,v)), \
1152    (I[12] = I[13] = (img)(0,_n2##y,z,v)), \
1153    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1154    (I[6] = (img)(_n1##x,y,z,v)), \
1155    (I[10] = (img)(_n1##x,_n1##y,z,v)), \
1156    (I[14] = (img)(_n1##x,_n2##y,z,v)), \
1157    2>=(img).width?(int)((img).width)-1:2); \
1158    (_n2##x<(int)((img).width) && ( \
1159    (I[3] = (img)(_n2##x,_p1##y,z,v)), \
1160    (I[7] = (img)(_n2##x,y,z,v)), \
1161    (I[11] = (img)(_n2##x,_n1##y,z,v)), \
1162    (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1163    _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
1164    I[0] = I[1], I[1] = I[2], I[2] = I[3], \
1165    I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1166    I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1167    I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1168    _p1##x = x++, ++_n1##x, ++_n2##x)
1169 
1170 #define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,v,I) \
1171   cimg_for_in4((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1172    _p1##x = x-1<0?0:x-1, \
1173    _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1174    _n2##x = (int)( \
1175    (I[0] = (img)(_p1##x,_p1##y,z,v)), \
1176    (I[4] = (img)(_p1##x,y,z,v)), \
1177    (I[8] = (img)(_p1##x,_n1##y,z,v)), \
1178    (I[12] = (img)(_p1##x,_n2##y,z,v)), \
1179    (I[1] = (img)(x,_p1##y,z,v)), \
1180    (I[5] = (img)(x,y,z,v)), \
1181    (I[9] = (img)(x,_n1##y,z,v)), \
1182    (I[13] = (img)(x,_n2##y,z,v)), \
1183    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1184    (I[6] = (img)(_n1##x,y,z,v)), \
1185    (I[10] = (img)(_n1##x,_n1##y,z,v)), \
1186    (I[14] = (img)(_n1##x,_n2##y,z,v)), \
1187    x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
1188    x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
1189    (I[3] = (img)(_n2##x,_p1##y,z,v)), \
1190    (I[7] = (img)(_n2##x,y,z,v)), \
1191    (I[11] = (img)(_n2##x,_n1##y,z,v)), \
1192    (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1193    _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
1194    I[0] = I[1], I[1] = I[2], I[2] = I[3], \
1195    I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1196    I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1197    I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1198    _p1##x = x++, ++_n1##x, ++_n2##x)
1199 
1200 #define cimg_for5x5(img,x,y,z,v,I) \
1201  cimg_for5((img).height,y) for (int x = 0, \
1202    _p2##x = 0, _p1##x = 0, \
1203    _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1204    _n2##x = (int)( \
1205    (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
1206    (I[5] = I[6] = I[7] = (img)(0,_p1##y,z,v)), \
1207    (I[10] = I[11] = I[12] = (img)(0,y,z,v)), \
1208    (I[15] = I[16] = I[17] = (img)(0,_n1##y,z,v)), \
1209    (I[20] = I[21] = I[22] = (img)(0,_n2##y,z,v)), \
1210    (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1211    (I[8] = (img)(_n1##x,_p1##y,z,v)), \
1212    (I[13] = (img)(_n1##x,y,z,v)), \
1213    (I[18] = (img)(_n1##x,_n1##y,z,v)), \
1214    (I[23] = (img)(_n1##x,_n2##y,z,v)),     \
1215    2>=(img).width?(int)((img).width)-1:2); \
1216    (_n2##x<(int)((img).width) && ( \
1217    (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1218    (I[9] = (img)(_n2##x,_p1##y,z,v)), \
1219    (I[14] = (img)(_n2##x,y,z,v)), \
1220    (I[19] = (img)(_n2##x,_n1##y,z,v)), \
1221    (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1222    _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
1223    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
1224    I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
1225    I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
1226    I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
1227    I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
1228    _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
1229 
1230 #define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,v,I) \
1231  cimg_for_in5((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1232    _p2##x = x-2<0?0:x-2, \
1233    _p1##x = x-1<0?0:x-1, \
1234    _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1235    _n2##x = (int)( \
1236    (I[0] = (img)(_p2##x,_p2##y,z,v)), \
1237    (I[5] = (img)(_p2##x,_p1##y,z,v)), \
1238    (I[10] = (img)(_p2##x,y,z,v)), \
1239    (I[15] = (img)(_p2##x,_n1##y,z,v)), \
1240    (I[20] = (img)(_p2##x,_n2##y,z,v)), \
1241    (I[1] = (img)(_p1##x,_p2##y,z,v)), \
1242    (I[6] = (img)(_p1##x,_p1##y,z,v)), \
1243    (I[11] = (img)(_p1##x,y,z,v)), \
1244    (I[16] = (img)(_p1##x,_n1##y,z,v)), \
1245    (I[21] = (img)(_p1##x,_n2##y,z,v)), \
1246    (I[2] = (img)(x,_p2##y,z,v)), \
1247    (I[7] = (img)(x,_p1##y,z,v)), \
1248    (I[12] = (img)(x,y,z,v)), \
1249    (I[17] = (img)(x,_n1##y,z,v)), \
1250    (I[22] = (img)(x,_n2##y,z,v)), \
1251    (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1252    (I[8] = (img)(_n1##x,_p1##y,z,v)), \
1253    (I[13] = (img)(_n1##x,y,z,v)), \
1254    (I[18] = (img)(_n1##x,_n1##y,z,v)), \
1255    (I[23] = (img)(_n1##x,_n2##y,z,v)), \
1256    x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
1257    x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
1258    (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1259    (I[9] = (img)(_n2##x,_p1##y,z,v)), \
1260    (I[14] = (img)(_n2##x,y,z,v)), \
1261    (I[19] = (img)(_n2##x,_n1##y,z,v)), \
1262    (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1263    _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
1264    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
1265    I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
1266    I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
1267    I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
1268    I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
1269    _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
1270 
1271 #define cimg_for6x6(img,x,y,z,v,I) \
1272  cimg_for6((img).height,y) for (int x = 0, \
1273    _p2##x = 0, _p1##x = 0, \
1274    _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1275    _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
1276    _n3##x = (int)( \
1277    (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
1278    (I[6] = I[7] = I[8] = (img)(0,_p1##y,z,v)), \
1279    (I[12] = I[13] = I[14] = (img)(0,y,z,v)), \
1280    (I[18] = I[19] = I[20] = (img)(0,_n1##y,z,v)), \
1281    (I[24] = I[25] = I[26] = (img)(0,_n2##y,z,v)), \
1282    (I[30] = I[31] = I[32] = (img)(0,_n3##y,z,v)), \
1283    (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1284    (I[9] = (img)(_n1##x,_p1##y,z,v)), \
1285    (I[15] = (img)(_n1##x,y,z,v)), \
1286    (I[21] = (img)(_n1##x,_n1##y,z,v)), \
1287    (I[27] = (img)(_n1##x,_n2##y,z,v)), \
1288    (I[33] = (img)(_n1##x,_n3##y,z,v)), \
1289    (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1290    (I[10] = (img)(_n2##x,_p1##y,z,v)), \
1291    (I[16] = (img)(_n2##x,y,z,v)), \
1292    (I[22] = (img)(_n2##x,_n1##y,z,v)), \
1293    (I[28] = (img)(_n2##x,_n2##y,z,v)), \
1294    (I[34] = (img)(_n2##x,_n3##y,z,v)), \
1295    3>=(img).width?(int)((img).width)-1:3); \
1296    (_n3##x<(int)((img).width) && ( \
1297    (I[5] = (img)(_n3##x,_p2##y,z,v)), \
1298    (I[11] = (img)(_n3##x,_p1##y,z,v)), \
1299    (I[17] = (img)(_n3##x,y,z,v)), \
1300    (I[23] = (img)(_n3##x,_n1##y,z,v)), \
1301    (I[29] = (img)(_n3##x,_n2##y,z,v)), \
1302    (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1303    _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \
1304    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
1305    I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1306    I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
1307    I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1308    I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
1309    I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
1310    _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1311 
1312 #define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,v,I) \
1313   cimg_for_in6((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \
1314    _p2##x = x-2<0?0:x-2, \
1315    _p1##x = x-1<0?0:x-1, \
1316    _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1317    _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
1318    _n3##x = (int)( \
1319    (I[0] = (img)(_p2##x,_p2##y,z,v)), \
1320    (I[6] = (img)(_p2##x,_p1##y,z,v)), \
1321    (I[12] = (img)(_p2##x,y,z,v)), \
1322    (I[18] = (img)(_p2##x,_n1##y,z,v)), \
1323    (I[24] = (img)(_p2##x,_n2##y,z,v)), \
1324    (I[30] = (img)(_p2##x,_n3##y,z,v)), \
1325    (I[1] = (img)(_p1##x,_p2##y,z,v)), \
1326    (I[7] = (img)(_p1##x,_p1##y,z,v)), \
1327    (I[13] = (img)(_p1##x,y,z,v)), \
1328    (I[19] = (img)(_p1##x,_n1##y,z,v)), \
1329    (I[25] = (img)(_p1##x,_n2##y,z,v)), \
1330    (I[31] = (img)(_p1##x,_n3##y,z,v)), \
1331    (I[2] = (img)(x,_p2##y,z,v)), \
1332    (I[8] = (img)(x,_p1##y,z,v)), \
1333    (I[14] = (img)(x,y,z,v)), \
1334    (I[20] = (img)(x,_n1##y,z,v)), \
1335    (I[26] = (img)(x,_n2##y,z,v)), \
1336    (I[32] = (img)(x,_n3##y,z,v)), \
1337    (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1338    (I[9] = (img)(_n1##x,_p1##y,z,v)), \
1339    (I[15] = (img)(_n1##x,y,z,v)), \
1340    (I[21] = (img)(_n1##x,_n1##y,z,v)), \
1341    (I[27] = (img)(_n1##x,_n2##y,z,v)), \
1342    (I[33] = (img)(_n1##x,_n3##y,z,v)), \
1343    (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1344    (I[10] = (img)(_n2##x,_p1##y,z,v)), \
1345    (I[16] = (img)(_n2##x,y,z,v)), \
1346    (I[22] = (img)(_n2##x,_n1##y,z,v)), \
1347    (I[28] = (img)(_n2##x,_n2##y,z,v)), \
1348    (I[34] = (img)(_n2##x,_n3##y,z,v)), \
1349    x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
1350    x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
1351    (I[5] = (img)(_n3##x,_p2##y,z,v)), \
1352    (I[11] = (img)(_n3##x,_p1##y,z,v)), \
1353    (I[17] = (img)(_n3##x,y,z,v)), \
1354    (I[23] = (img)(_n3##x,_n1##y,z,v)), \
1355    (I[29] = (img)(_n3##x,_n2##y,z,v)), \
1356    (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1357    _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \
1358    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
1359    I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1360    I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
1361    I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1362    I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
1363    I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
1364    _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1365 
1366 #define cimg_for7x7(img,x,y,z,v,I) \
1367   cimg_for7((img).height,y) for (int x = 0, \
1368    _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1369    _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1370    _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
1371    _n3##x = (int)( \
1372    (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
1373    (I[7] = I[8] = I[9] = I[10] = (img)(0,_p2##y,z,v)), \
1374    (I[14] = I[15] = I[16] = I[17] = (img)(0,_p1##y,z,v)), \
1375    (I[21] = I[22] = I[23] = I[24] = (img)(0,y,z,v)), \
1376    (I[28] = I[29] = I[30] = I[31] = (img)(0,_n1##y,z,v)), \
1377    (I[35] = I[36] = I[37] = I[38] = (img)(0,_n2##y,z,v)), \
1378    (I[42] = I[43] = I[44] = I[45] = (img)(0,_n3##y,z,v)), \
1379    (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1380    (I[11] = (img)(_n1##x,_p2##y,z,v)), \
1381    (I[18] = (img)(_n1##x,_p1##y,z,v)), \
1382    (I[25] = (img)(_n1##x,y,z,v)), \
1383    (I[32] = (img)(_n1##x,_n1##y,z,v)), \
1384    (I[39] = (img)(_n1##x,_n2##y,z,v)), \
1385    (I[46] = (img)(_n1##x,_n3##y,z,v)), \
1386    (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1387    (I[12] = (img)(_n2##x,_p2##y,z,v)), \
1388    (I[19] = (img)(_n2##x,_p1##y,z,v)), \
1389    (I[26] = (img)(_n2##x,y,z,v)), \
1390    (I[33] = (img)(_n2##x,_n1##y,z,v)), \
1391    (I[40] = (img)(_n2##x,_n2##y,z,v)), \
1392    (I[47] = (img)(_n2##x,_n3##y,z,v)), \
1393    3>=(img).width?(int)((img).width)-1:3); \
1394    (_n3##x<(int)((img).width) && ( \
1395    (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1396    (I[13] = (img)(_n3##x,_p2##y,z,v)), \
1397    (I[20] = (img)(_n3##x,_p1##y,z,v)), \
1398    (I[27] = (img)(_n3##x,y,z,v)), \
1399    (I[34] = (img)(_n3##x,_n1##y,z,v)), \
1400    (I[41] = (img)(_n3##x,_n2##y,z,v)), \
1401    (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1402    _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \
1403    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
1404    I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
1405    I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
1406    I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
1407    I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
1408    I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
1409    I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
1410    _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1411 
1412 #define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,v,I) \
1413   cimg_for_in7((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1414    _p3##x = x-3<0?0:x-3, \
1415    _p2##x = x-2<0?0:x-2, \
1416    _p1##x = x-1<0?0:x-1, \
1417    _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1418    _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
1419    _n3##x = (int)( \
1420    (I[0] = (img)(_p3##x,_p3##y,z,v)), \
1421    (I[7] = (img)(_p3##x,_p2##y,z,v)), \
1422    (I[14] = (img)(_p3##x,_p1##y,z,v)), \
1423    (I[21] = (img)(_p3##x,y,z,v)), \
1424    (I[28] = (img)(_p3##x,_n1##y,z,v)), \
1425    (I[35] = (img)(_p3##x,_n2##y,z,v)), \
1426    (I[42] = (img)(_p3##x,_n3##y,z,v)), \
1427    (I[1] = (img)(_p2##x,_p3##y,z,v)), \
1428    (I[8] = (img)(_p2##x,_p2##y,z,v)), \
1429    (I[15] = (img)(_p2##x,_p1##y,z,v)), \
1430    (I[22] = (img)(_p2##x,y,z,v)), \
1431    (I[29] = (img)(_p2##x,_n1##y,z,v)), \
1432    (I[36] = (img)(_p2##x,_n2##y,z,v)), \
1433    (I[43] = (img)(_p2##x,_n3##y,z,v)), \
1434    (I[2] = (img)(_p1##x,_p3##y,z,v)), \
1435    (I[9] = (img)(_p1##x,_p2##y,z,v)), \
1436    (I[16] = (img)(_p1##x,_p1##y,z,v)), \
1437    (I[23] = (img)(_p1##x,y,z,v)), \
1438    (I[30] = (img)(_p1##x,_n1##y,z,v)), \
1439    (I[37] = (img)(_p1##x,_n2##y,z,v)), \
1440    (I[44] = (img)(_p1##x,_n3##y,z,v)), \
1441    (I[3] = (img)(x,_p3##y,z,v)), \
1442    (I[10] = (img)(x,_p2##y,z,v)), \
1443    (I[17] = (img)(x,_p1##y,z,v)), \
1444    (I[24] = (img)(x,y,z,v)), \
1445    (I[31] = (img)(x,_n1##y,z,v)), \
1446    (I[38] = (img)(x,_n2##y,z,v)), \
1447    (I[45] = (img)(x,_n3##y,z,v)), \
1448    (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1449    (I[11] = (img)(_n1##x,_p2##y,z,v)), \
1450    (I[18] = (img)(_n1##x,_p1##y,z,v)), \
1451    (I[25] = (img)(_n1##x,y,z,v)), \
1452    (I[32] = (img)(_n1##x,_n1##y,z,v)), \
1453    (I[39] = (img)(_n1##x,_n2##y,z,v)), \
1454    (I[46] = (img)(_n1##x,_n3##y,z,v)), \
1455    (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1456    (I[12] = (img)(_n2##x,_p2##y,z,v)), \
1457    (I[19] = (img)(_n2##x,_p1##y,z,v)), \
1458    (I[26] = (img)(_n2##x,y,z,v)), \
1459    (I[33] = (img)(_n2##x,_n1##y,z,v)), \
1460    (I[40] = (img)(_n2##x,_n2##y,z,v)), \
1461    (I[47] = (img)(_n2##x,_n3##y,z,v)), \
1462    x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
1463    x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
1464    (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1465    (I[13] = (img)(_n3##x,_p2##y,z,v)), \
1466    (I[20] = (img)(_n3##x,_p1##y,z,v)), \
1467    (I[27] = (img)(_n3##x,y,z,v)), \
1468    (I[34] = (img)(_n3##x,_n1##y,z,v)), \
1469    (I[41] = (img)(_n3##x,_n2##y,z,v)), \
1470    (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1471    _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \
1472    I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
1473    I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
1474    I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
1475    I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
1476    I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
1477    I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
1478    I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
1479    _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1480 
1481 #define cimg_for8x8(img,x,y,z,v,I) \
1482   cimg_for8((img).height,y) for (int x = 0, \
1483    _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1484    _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
1485    _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
1486    _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
1487    _n4##x = (int)( \
1488    (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
1489    (I[8] = I[9] = I[10] = I[11] = (img)(0,_p2##y,z,v)), \
1490    (I[16] = I[17] = I[18] = I[19] = (img)(0,_p1##y,z,v)), \
1491    (I[24] = I[25] = I[26] = I[27] = (img)(0,y,z,v)), \
1492    (I[32] = I[33] = I[34] = I[35] = (img)(0,_n1##y,z,v)), \
1493    (I[40] = I[41] = I[42] = I[43] = (img)(0,_n2##y,z,v)), \
1494    (I[48] = I[49] = I[50] = I[51] = (img)(0,_n3##y,z,v)), \
1495    (I[56] = I[57] = I[58] = I[59] = (img)(0,_n4##y,z,v)), \
1496    (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1497    (I[12] = (img)(_n1##x,_p2##y,z,v)), \
1498    (I[20] = (img)(_n1##x,_p1##y,z,v)), \
1499    (I[28] = (img)(_n1##x,y,z,v)), \
1500    (I[36] = (img)(_n1##x,_n1##y,z,v)), \
1501    (I[44] = (img)(_n1##x,_n2##y,z,v)), \
1502    (I[52] = (img)(_n1##x,_n3##y,z,v)), \
1503    (I[60] = (img)(_n1##x,_n4##y,z,v)), \
1504    (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1505    (I[13] = (img)(_n2##x,_p2##y,z,v)), \
1506    (I[21] = (img)(_n2##x,_p1##y,z,v)), \
1507    (I[29] = (img)(_n2##x,y,z,v)), \
1508    (I[37] = (img)(_n2##x,_n1##y,z,v)), \
1509    (I[45] = (img)(_n2##x,_n2##y,z,v)), \
1510    (I[53] = (img)(_n2##x,_n3##y,z,v)), \
1511    (I[61] = (img)(_n2##x,_n4##y,z,v)), \
1512    (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1513    (I[14] = (img)(_n3##x,_p2##y,z,v)), \
1514    (I[22] = (img)(_n3##x,_p1##y,z,v)), \
1515    (I[30] = (img)(_n3##x,y,z,v)), \
1516    (I[38] = (img)(_n3##x,_n1##y,z,v)), \
1517    (I[46] = (img)(_n3##x,_n2##y,z,v)), \
1518    (I[54] = (img)(_n3##x,_n3##y,z,v)), \
1519    (I[62] = (img)(_n3##x,_n4##y,z,v)), \
1520    4>=((img).width)?(int)((img).width)-1:4); \
1521    (_n4##x<(int)((img).width) && ( \
1522    (I[7] = (img)(_n4##x,_p3##y,z,v)), \
1523    (I[15] = (img)(_n4##x,_p2##y,z,v)), \
1524    (I[23] = (img)(_n4##x,_p1##y,z,v)), \
1525    (I[31] = (img)(_n4##x,y,z,v)), \
1526    (I[39] = (img)(_n4##x,_n1##y,z,v)), \
1527    (I[47] = (img)(_n4##x,_n2##y,z,v)), \
1528    (I[55] = (img)(_n4##x,_n3##y,z,v)), \
1529    (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1530    _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
1531    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], \
1532    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], \
1533    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], \
1534    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], \
1535    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], \
1536    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], \
1537    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], \
1538    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], \
1539    _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1540 
1541 #define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,v,I) \
1542   cimg_for_in8((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1543    _p3##x = x-3<0?0:x-3, \
1544    _p2##x = x-2<0?0:x-2, \
1545    _p1##x = x-1<0?0:x-1, \
1546    _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
1547    _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
1548    _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
1549    _n4##x = (int)( \
1550    (I[0] = (img)(_p3##x,_p3##y,z,v)), \
1551    (I[8] = (img)(_p3##x,_p2##y,z,v)), \
1552    (I[16] = (img)(_p3##x,_p1##y,z,v)), \
1553    (I[24] = (img)(_p3##x,y,z,v)), \
1554    (I[32] = (img)(_p3##x,_n1##y,z,v)), \
1555    (I[40] = (img)(_p3##x,_n2##y,z,v)), \
1556    (I[48] = (img)(_p3##x,_n3##y,z,v)), \
1557    (I[56] = (img)(_p3##x,_n4##y,z,v)), \
1558    (I[1] = (img)(_p2##x,_p3##y,z,v)), \
1559    (I[9] = (img)(_p2##x,_p2##y,z,v)), \
1560    (I[17] = (img)(_p2##x,_p1##y,z,v)), \
1561    (I[25] = (img)(_p2##x,y,z,v)), \
1562    (I[33] = (img)(_p2##x,_n1##y,z,v)), \
1563    (I[41] = (img)(_p2##x,_n2##y,z,v)), \
1564    (I[49] = (img)(_p2##x,_n3##y,z,v)), \
1565    (I[57] = (img)(_p2##x,_n4##y,z,v)), \
1566    (I[2] = (img)(_p1##x,_p3##y,z,v)), \
1567    (I[10] = (img)(_p1##x,_p2##y,z,v)), \
1568    (I[18] = (img)(_p1##x,_p1##y,z,v)), \
1569    (I[26] = (img)(_p1##x,y,z,v)), \
1570    (I[34] = (img)(_p1##x,_n1##y,z,v)), \
1571    (I[42] = (img)(_p1##x,_n2##y,z,v)), \
1572    (I[50] = (img)(_p1##x,_n3##y,z,v)), \
1573    (I[58] = (img)(_p1##x,_n4##y,z,v)), \
1574    (I[3] = (img)(x,_p3##y,z,v)), \
1575    (I[11] = (img)(x,_p2##y,z,v)), \
1576    (I[19] = (img)(x,_p1##y,z,v)), \
1577    (I[27] = (img)(x,y,z,v)), \
1578    (I[35] = (img)(x,_n1##y,z,v)), \
1579    (I[43] = (img)(x,_n2##y,z,v)), \
1580    (I[51] = (img)(x,_n3##y,z,v)), \
1581    (I[59] = (img)(x,_n4##y,z,v)), \
1582    (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1583    (I[12] = (img)(_n1##x,_p2##y,z,v)), \
1584    (I[20] = (img)(_n1##x,_p1##y,z,v)), \
1585    (I[28] = (img)(_n1##x,y,z,v)), \
1586    (I[36] = (img)(_n1##x,_n1##y,z,v)), \
1587    (I[44] = (img)(_n1##x,_n2##y,z,v)), \
1588    (I[52] = (img)(_n1##x,_n3##y,z,v)), \
1589    (I[60] = (img)(_n1##x,_n4##y,z,v)), \
1590    (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1591    (I[13] = (img)(_n2##x,_p2##y,z,v)), \
1592    (I[21] = (img)(_n2##x,_p1##y,z,v)), \
1593    (I[29] = (img)(_n2##x,y,z,v)), \
1594    (I[37] = (img)(_n2##x,_n1##y,z,v)), \
1595    (I[45] = (img)(_n2##x,_n2##y,z,v)), \
1596    (I[53] = (img)(_n2##x,_n3##y,z,v)), \
1597    (I[61] = (img)(_n2##x,_n4##y,z,v)), \
1598    (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1599    (I[14] = (img)(_n3##x,_p2##y,z,v)), \
1600    (I[22] = (img)(_n3##x,_p1##y,z,v)), \
1601    (I[30] = (img)(_n3##x,y,z,v)), \
1602    (I[38] = (img)(_n3##x,_n1##y,z,v)), \
1603    (I[46] = (img)(_n3##x,_n2##y,z,v)), \
1604    (I[54] = (img)(_n3##x,_n3##y,z,v)), \
1605    (I[62] = (img)(_n3##x,_n4##y,z,v)), \
1606    x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
1607    x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
1608    (I[7] = (img)(_n4##x,_p3##y,z,v)), \
1609    (I[15] = (img)(_n4##x,_p2##y,z,v)), \
1610    (I[23] = (img)(_n4##x,_p1##y,z,v)), \
1611    (I[31] = (img)(_n4##x,y,z,v)), \
1612    (I[39] = (img)(_n4##x,_n1##y,z,v)), \
1613    (I[47] = (img)(_n4##x,_n2##y,z,v)), \
1614    (I[55] = (img)(_n4##x,_n3##y,z,v)), \
1615    (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1616    _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
1617    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], \
1618    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], \
1619    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], \
1620    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], \
1621    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], \
1622    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], \
1623    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], \
1624    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], \
1625    _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1626 
1627 #define cimg_for9x9(img,x,y,z,v,I) \
1628   cimg_for9((img).height,y) for (int x = 0, \
1629    _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1630    _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
1631    _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
1632    _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
1633    _n4##x = (int)( \
1634    (I[0] = I[1] = I[2] = I[3] = I[4] = (img)(0,_p4##y,z,v)), \
1635    (I[9] = I[10] = I[11] = I[12] = I[13] = (img)(0,_p3##y,z,v)), \
1636    (I[18] = I[19] = I[20] = I[21] = I[22] = (img)(0,_p2##y,z,v)), \
1637    (I[27] = I[28] = I[29] = I[30] = I[31] = (img)(0,_p1##y,z,v)), \
1638    (I[36] = I[37] = I[38] = I[39] = I[40] = (img)(0,y,z,v)), \
1639    (I[45] = I[46] = I[47] = I[48] = I[49] = (img)(0,_n1##y,z,v)), \
1640    (I[54] = I[55] = I[56] = I[57] = I[58] = (img)(0,_n2##y,z,v)), \
1641    (I[63] = I[64] = I[65] = I[66] = I[67] = (img)(0,_n3##y,z,v)), \
1642    (I[72] = I[73] = I[74] = I[75] = I[76] = (img)(0,_n4##y,z,v)), \
1643    (I[5] = (img)(_n1##x,_p4##y,z,v)), \
1644    (I[14] = (img)(_n1##x,_p3##y,z,v)), \
1645    (I[23] = (img)(_n1##x,_p2##y,z,v)), \
1646    (I[32] = (img)(_n1##x,_p1##y,z,v)), \
1647    (I[41] = (img)(_n1##x,y,z,v)), \
1648    (I[50] = (img)(_n1##x,_n1##y,z,v)), \
1649    (I[59] = (img)(_n1##x,_n2##y,z,v)), \
1650    (I[68] = (img)(_n1##x,_n3##y,z,v)), \
1651    (I[77] = (img)(_n1##x,_n4##y,z,v)), \
1652    (I[6] = (img)(_n2##x,_p4##y,z,v)), \
1653    (I[15] = (img)(_n2##x,_p3##y,z,v)), \
1654    (I[24] = (img)(_n2##x,_p2##y,z,v)), \
1655    (I[33] = (img)(_n2##x,_p1##y,z,v)), \
1656    (I[42] = (img)(_n2##x,y,z,v)), \
1657    (I[51] = (img)(_n2##x,_n1##y,z,v)), \
1658    (I[60] = (img)(_n2##x,_n2##y,z,v)), \
1659    (I[69] = (img)(_n2##x,_n3##y,z,v)), \
1660    (I[78] = (img)(_n2##x,_n4##y,z,v)), \
1661    (I[7] = (img)(_n3##x,_p4##y,z,v)), \
1662    (I[16] = (img)(_n3##x,_p3##y,z,v)), \
1663    (I[25] = (img)(_n3##x,_p2##y,z,v)), \
1664    (I[34] = (img)(_n3##x,_p1##y,z,v)), \
1665    (I[43] = (img)(_n3##x,y,z,v)), \
1666    (I[52] = (img)(_n3##x,_n1##y,z,v)), \
1667    (I[61] = (img)(_n3##x,_n2##y,z,v)), \
1668    (I[70] = (img)(_n3##x,_n3##y,z,v)), \
1669    (I[79] = (img)(_n3##x,_n4##y,z,v)), \
1670    4>=((img).width)?(int)((img).width)-1:4); \
1671    (_n4##x<(int)((img).width) && ( \
1672    (I[8] = (img)(_n4##x,_p4##y,z,v)), \
1673    (I[17] = (img)(_n4##x,_p3##y,z,v)), \
1674    (I[26] = (img)(_n4##x,_p2##y,z,v)), \
1675    (I[35] = (img)(_n4##x,_p1##y,z,v)), \
1676    (I[44] = (img)(_n4##x,y,z,v)), \
1677    (I[53] = (img)(_n4##x,_n1##y,z,v)), \
1678    (I[62] = (img)(_n4##x,_n2##y,z,v)), \
1679    (I[71] = (img)(_n4##x,_n3##y,z,v)), \
1680    (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1681    _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
1682    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], \
1683    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], \
1684    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], \
1685    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], \
1686    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], \
1687    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], \
1688    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], \
1689    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], \
1690    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], \
1691    _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1692 
1693 #define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,v,I) \
1694   cimg_for_in9((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1695    _p4##x = x-4<0?0:x-4, \
1696    _p3##x = x-3<0?0:x-3, \
1697    _p2##x = x-2<0?0:x-2, \
1698    _p1##x = x-1<0?0:x-1, \
1699    _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
1700    _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
1701    _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
1702    _n4##x = (int)( \
1703    (I[0] = (img)(_p4##x,_p4##y,z,v)), \
1704    (I[9] = (img)(_p4##x,_p3##y,z,v)), \
1705    (I[18] = (img)(_p4##x,_p2##y,z,v)), \
1706    (I[27] = (img)(_p4##x,_p1##y,z,v)), \
1707    (I[36] = (img)(_p4##x,y,z,v)), \
1708    (I[45] = (img)(_p4##x,_n1##y,z,v)), \
1709    (I[54] = (img)(_p4##x,_n2##y,z,v)), \
1710    (I[63] = (img)(_p4##x,_n3##y,z,v)), \
1711    (I[72] = (img)(_p4##x,_n4##y,z,v)), \
1712    (I[1] = (img)(_p3##x,_p4##y,z,v)), \
1713    (I[10] = (img)(_p3##x,_p3##y,z,v)), \
1714    (I[19] = (img)(_p3##x,_p2##y,z,v)), \
1715    (I[28] = (img)(_p3##x,_p1##y,z,v)), \
1716    (I[37] = (img)(_p3##x,y,z,v)), \
1717    (I[46] = (img)(_p3##x,_n1##y,z,v)), \
1718    (I[55] = (img)(_p3##x,_n2##y,z,v)), \
1719    (I[64] = (img)(_p3##x,_n3##y,z,v)), \
1720    (I[73] = (img)(_p3##x,_n4##y,z,v)), \
1721    (I[2] = (img)(_p2##x,_p4##y,z,v)), \
1722    (I[11] = (img)(_p2##x,_p3##y,z,v)), \
1723    (I[20] = (img)(_p2##x,_p2##y,z,v)), \
1724    (I[29] = (img)(_p2##x,_p1##y,z,v)), \
1725    (I[38] = (img)(_p2##x,y,z,v)), \
1726    (I[47] = (img)(_p2##x,_n1##y,z,v)), \
1727    (I[56] = (img)(_p2##x,_n2##y,z,v)), \
1728    (I[65] = (img)(_p2##x,_n3##y,z,v)), \
1729    (I[74] = (img)(_p2##x,_n4##y,z,v)), \
1730    (I[3] = (img)(_p1##x,_p4##y,z,v)), \
1731    (I[12] = (img)(_p1##x,_p3##y,z,v)), \
1732    (I[21] = (img)(_p1##x,_p2##y,z,v)), \
1733    (I[30] = (img)(_p1##x,_p1##y,z,v)), \
1734    (I[39] = (img)(_p1##x,y,z,v)), \
1735    (I[48] = (img)(_p1##x,_n1##y,z,v)), \
1736    (I[57] = (img)(_p1##x,_n2##y,z,v)), \
1737    (I[66] = (img)(_p1##x,_n3##y,z,v)), \
1738    (I[75] = (img)(_p1##x,_n4##y,z,v)), \
1739    (I[4] = (img)(x,_p4##y,z,v)), \
1740    (I[13] = (img)(x,_p3##y,z,v)), \
1741    (I[22] = (img)(x,_p2##y,z,v)), \
1742    (I[31] = (img)(x,_p1##y,z,v)), \
1743    (I[40] = (img)(x,y,z,v)), \
1744    (I[49] = (img)(x,_n1##y,z,v)), \
1745    (I[58] = (img)(x,_n2##y,z,v)), \
1746    (I[67] = (img)(x,_n3##y,z,v)), \
1747    (I[76] = (img)(x,_n4##y,z,v)), \
1748    (I[5] = (img)(_n1##x,_p4##y,z,v)), \
1749    (I[14] = (img)(_n1##x,_p3##y,z,v)), \
1750    (I[23] = (img)(_n1##x,_p2##y,z,v)), \
1751    (I[32] = (img)(_n1##x,_p1##y,z,v)), \
1752    (I[41] = (img)(_n1##x,y,z,v)), \
1753    (I[50] = (img)(_n1##x,_n1##y,z,v)), \
1754    (I[59] = (img)(_n1##x,_n2##y,z,v)), \
1755    (I[68] = (img)(_n1##x,_n3##y,z,v)), \
1756    (I[77] = (img)(_n1##x,_n4##y,z,v)), \
1757    (I[6] = (img)(_n2##x,_p4##y,z,v)), \
1758    (I[15] = (img)(_n2##x,_p3##y,z,v)), \
1759    (I[24] = (img)(_n2##x,_p2##y,z,v)), \
1760    (I[33] = (img)(_n2##x,_p1##y,z,v)), \
1761    (I[42] = (img)(_n2##x,y,z,v)), \
1762    (I[51] = (img)(_n2##x,_n1##y,z,v)), \
1763    (I[60] = (img)(_n2##x,_n2##y,z,v)), \
1764    (I[69] = (img)(_n2##x,_n3##y,z,v)), \
1765    (I[78] = (img)(_n2##x,_n4##y,z,v)), \
1766    (I[7] = (img)(_n3##x,_p4##y,z,v)), \
1767    (I[16] = (img)(_n3##x,_p3##y,z,v)), \
1768    (I[25] = (img)(_n3##x,_p2##y,z,v)), \
1769    (I[34] = (img)(_n3##x,_p1##y,z,v)), \
1770    (I[43] = (img)(_n3##x,y,z,v)), \
1771    (I[52] = (img)(_n3##x,_n1##y,z,v)), \
1772    (I[61] = (img)(_n3##x,_n2##y,z,v)), \
1773    (I[70] = (img)(_n3##x,_n3##y,z,v)), \
1774    (I[79] = (img)(_n3##x,_n4##y,z,v)), \
1775    x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
1776    x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
1777    (I[8] = (img)(_n4##x,_p4##y,z,v)), \
1778    (I[17] = (img)(_n4##x,_p3##y,z,v)), \
1779    (I[26] = (img)(_n4##x,_p2##y,z,v)), \
1780    (I[35] = (img)(_n4##x,_p1##y,z,v)), \
1781    (I[44] = (img)(_n4##x,y,z,v)), \
1782    (I[53] = (img)(_n4##x,_n1##y,z,v)), \
1783    (I[62] = (img)(_n4##x,_n2##y,z,v)), \
1784    (I[71] = (img)(_n4##x,_n3##y,z,v)), \
1785    (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1786    _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
1787    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], \
1788    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], \
1789    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], \
1790    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], \
1791    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], \
1792    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], \
1793    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], \
1794    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], \
1795    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], \
1796    _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1797 
1798 #define cimg_for2x2x2(img,x,y,z,v,I) \
1799  cimg_for2((img).depth,z) cimg_for2((img).height,y) for (int x = 0, \
1800    _n1##x = (int)( \
1801    (I[0] = (img)(0,y,z,v)), \
1802    (I[2] = (img)(0,_n1##y,z,v)), \
1803    (I[4] = (img)(0,y,_n1##z,v)), \
1804    (I[6] = (img)(0,_n1##y,_n1##z,v)), \
1805    1>=(img).width?(int)((img).width)-1:1); \
1806    (_n1##x<(int)((img).width) && ( \
1807    (I[1] = (img)(_n1##x,y,z,v)), \
1808    (I[3] = (img)(_n1##x,_n1##y,z,v)), \
1809    (I[5] = (img)(_n1##x,y,_n1##z,v)), \
1810    (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1811    x==--_n1##x; \
1812    I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
1813    ++x, ++_n1##x)
1814 
1815 #define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
1816  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), \
1817    _n1##x = (int)( \
1818    (I[0] = (img)(x,y,z,v)), \
1819    (I[2] = (img)(x,_n1##y,z,v)), \
1820    (I[4] = (img)(x,y,_n1##z,v)), \
1821    (I[6] = (img)(x,_n1##y,_n1##z,v)), \
1822    x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1823    x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
1824    (I[1] = (img)(_n1##x,y,z,v)), \
1825    (I[3] = (img)(_n1##x,_n1##y,z,v)), \
1826    (I[5] = (img)(_n1##x,y,_n1##z,v)), \
1827    (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1828    x==--_n1##x); \
1829    I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
1830    ++x, ++_n1##x)
1831 
1832 #define cimg_for3x3x3(img,x,y,z,v,I) \
1833  cimg_for3((img).depth,z) cimg_for3((img).height,y) for (int x = 0, \
1834    _p1##x = 0, \
1835    _n1##x = (int)( \
1836    (I[0] = I[1] = (img)(0,_p1##y,_p1##z,v)), \
1837    (I[3] = I[4] = (img)(0,y,_p1##z,v)),  \
1838    (I[6] = I[7] = (img)(0,_n1##y,_p1##z,v)), \
1839    (I[9] = I[10] = (img)(0,_p1##y,z,v)), \
1840    (I[12] = I[13] = (img)(0,y,z,v)), \
1841    (I[15] = I[16] = (img)(0,_n1##y,z,v)), \
1842    (I[18] = I[19] = (img)(0,_p1##y,_n1##z,v)), \
1843    (I[21] = I[22] = (img)(0,y,_n1##z,v)), \
1844    (I[24] = I[25] = (img)(0,_n1##y,_n1##z,v)), \
1845    1>=(img).width?(int)((img).width)-1:1); \
1846    (_n1##x<(int)((img).width) && ( \
1847    (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
1848    (I[5] = (img)(_n1##x,y,_p1##z,v)), \
1849    (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
1850    (I[11] = (img)(_n1##x,_p1##y,z,v)), \
1851    (I[14] = (img)(_n1##x,y,z,v)), \
1852    (I[17] = (img)(_n1##x,_n1##y,z,v)), \
1853    (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
1854    (I[23] = (img)(_n1##x,y,_n1##z,v)), \
1855    (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1856    x==--_n1##x; \
1857    I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
1858    I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
1859    I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
1860    _p1##x = x++, ++_n1##x)
1861 
1862 #define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
1863  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), \
1864    _p1##x = x-1<0?0:x-1, \
1865    _n1##x = (int)( \
1866    (I[0] = (img)(_p1##x,_p1##y,_p1##z,v)), \
1867    (I[3] = (img)(_p1##x,y,_p1##z,v)),  \
1868    (I[6] = (img)(_p1##x,_n1##y,_p1##z,v)), \
1869    (I[9] = (img)(_p1##x,_p1##y,z,v)), \
1870    (I[12] = (img)(_p1##x,y,z,v)), \
1871    (I[15] = (img)(_p1##x,_n1##y,z,v)), \
1872    (I[18] = (img)(_p1##x,_p1##y,_n1##z,v)), \
1873    (I[21] = (img)(_p1##x,y,_n1##z,v)), \
1874    (I[24] = (img)(_p1##x,_n1##y,_n1##z,v)), \
1875    (I[1] = (img)(x,_p1##y,_p1##z,v)), \
1876    (I[4] = (img)(x,y,_p1##z,v)),  \
1877    (I[7] = (img)(x,_n1##y,_p1##z,v)), \
1878    (I[10] = (img)(x,_p1##y,z,v)), \
1879    (I[13] = (img)(x,y,z,v)), \
1880    (I[16] = (img)(x,_n1##y,z,v)), \
1881    (I[19] = (img)(x,_p1##y,_n1##z,v)), \
1882    (I[22] = (img)(x,y,_n1##z,v)), \
1883    (I[25] = (img)(x,_n1##y,_n1##z,v)), \
1884    x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1885    x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
1886    (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
1887    (I[5] = (img)(_n1##x,y,_p1##z,v)), \
1888    (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
1889    (I[11] = (img)(_n1##x,_p1##y,z,v)), \
1890    (I[14] = (img)(_n1##x,y,z,v)), \
1891    (I[17] = (img)(_n1##x,_n1##y,z,v)), \
1892    (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
1893    (I[23] = (img)(_n1##x,y,_n1##z,v)), \
1894    (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1895    x==--_n1##x); \
1896    I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
1897    I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
1898    I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
1899    _p1##x = x++, ++_n1##x)
1900 
1901 namespace Digikam
1902 {
1903 
1904 /*------------------------------------------------
1905  #
1906  #
1907  #  Definition of the cimg_library:: namespace
1908  #
1909  #
1910  -------------------------------------------------*/
1911 //! This namespace encompasses all classes and functions of the %CImg library.
1912 /**
1913    This namespace is defined to avoid functions and class names collisions
1914    that could happen with the include of other C++ header files.
1915    Anyway, it should not happen often and you should reasonably start most of your
1916    %CImg-based programs with
1917    \code
1918    #include "CImg.h"
1919    using namespace cimg_library;
1920    \endcode
1921    to simplify the declaration of %CImg Library variables afterwards.
1922 **/
1923 namespace cimg_library {
1924 
1925   // Declare the only four classes of the CImg Library.
1926   //
1927   template<typename T=float> struct CImg;
1928   template<typename T=float> struct CImgList;
1929   struct CImgDisplay;
1930   struct CImgException;
1931 
1932   // (Pre)declare the cimg namespace.
1933   // This is not the complete namespace declaration. It only contains some
1934   // necessary stuffs to ensure a correct declaration order of classes and functions
1935   // defined afterwards.
1936   //
1937   namespace cimg {
1938 
1939 #ifdef cimg_use_vt100
1940     const char t_normal[] = { 0x1b,'[','0',';','0',';','0','m','\0' };
1941     const char t_red[] = { 0x1b,'[','4',';','3','1',';','5','9','m','\0' };
1942     const char t_bold[] = { 0x1b,'[','1','m','\0' };
1943     const char t_purple[] = { 0x1b,'[','0',';','3','5',';','5','9','m','\0' };
1944     const char t_green[] = { 0x1b,'[','0',';','3','2',';','5','9','m','\0' };
1945 #else
1946     const char t_normal[] = { '\0' };
1947     const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal,
1948       *const t_purple = cimg::t_normal, *const t_green = cimg::t_normal;
1949 #endif
1950 
1951     inline void info();
1952 
1953     //! Get/set the current CImg exception mode.
1954     /**
1955        The way error messages are handled by CImg can be changed dynamically, using this function.
1956        Possible values are :
1957        - 0 to hide debug messages (quiet mode, but exceptions are still thrown).
1958        - 1 to display debug messages on standard error (console).
1959        - 2 to display debug messages in modal windows (default behavior).
1960        - 3 to do as 1 + add extra warnings (may slow down the code !).
1961        - 4 to do as 2 + add extra warnings (may slow down the code !).
1962      **/
exception_mode()1963     inline unsigned int& exception_mode() { static unsigned int mode = cimg_debug; return mode; }
1964 
1965     inline int dialog(const char *title, const char *msg, const char *button1_txt="OK",
1966                       const char *button2_txt=0, const char *button3_txt=0,
1967                       const char *button4_txt=0, const char *button5_txt=0,
1968                       const char *button6_txt=0, const bool centering=false);
1969   }
1970 
1971   /*----------------------------------------------
1972    #
1973    # Definition of the CImgException structures
1974    #
1975    ----------------------------------------------*/
1976   //! Instances of this class are thrown when errors occur during a %CImg library function call.
1977   /**
1978      \section ex1 Overview
1979 
1980       CImgException is the base class of %CImg exceptions.
1981       Exceptions are thrown by the %CImg Library when an error occurred in a %CImg library function call.
1982       CImgException is seldom thrown itself. Children classes that specify the kind of error encountered
1983       are generally used instead. These sub-classes are :
1984 
1985       - \b CImgInstanceException : Thrown when the instance associated to the called %CImg function is not
1986       correctly defined. Generally, this exception is thrown when one tries to process \a empty images. The example
1987       below will throw a \a CImgInstanceException.
1988       \code
1989       CImg<float> img;        // Construct an empty image.
1990       img.blur(10);           // Try to blur the image.
1991       \endcode
1992 
1993       - \b CImgArgumentException : Thrown when one of the arguments given to the called %CImg function is not correct.
1994       Generally, this exception is thrown when arguments passed to the function are outside an admissible range of values.
1995       The example below will throw a \a CImgArgumentException.
1996       \code
1997       CImg<float> img(100,100,1,3);   // Define a 100x100 color image with float pixels.
1998       img = 0;                     // Try to fill pixels from the 0 pointer (invalid argument to operator=() ).
1999       \endcode
2000 
2001       - \b CImgIOException : Thrown when an error occurred when trying to load or save image files.
2002       The example below will throw a \a CImgIOException.
2003       \code
2004       CImg<float> img("file_doesnt_exist.jpg");    // Try to load a file that doesn't exist.
2005       \endcode
2006 
2007       - \b CImgDisplayException : Thrown when an error occurred when trying to display an image in a window.
2008       This exception is thrown when image display request cannot be satisfied.
2009 
2010       The parent class CImgException may be thrown itself when errors that cannot be classified in one of
2011       the above type occur. It is recommended not to throw CImgExceptions yourself, since there are normally
2012       reserved to %CImg Library functions.
2013       \b CImgInstanceException, \b CImgArgumentException, \b CImgIOException and \b CImgDisplayException are simple
2014       subclasses of CImgException and are thus not detailed more in this reference documentation.
2015 
2016       \section ex2 Exception handling
2017 
2018       When an error occurs, the %CImg Library first displays the error in a modal window.
2019       Then, it throws an instance of the corresponding exception class, generally leading the program to stop
2020       (this is the default behavior).
2021       You can bypass this default behavior by handling the exceptions yourself,
2022       using a code block <tt>try { ... } catch() { ... }</tt>.
2023       In this case, you can avoid the apparition of the modal window, by
2024       defining the environment variable <tt>cimg_debug</tt> to 0 before including the %CImg header file.
2025       The example below shows how to cleanly handle %CImg Library exceptions :
2026       \code
2027       #define cimg_debug 0     // Disable modal window in CImg exceptions.
2028       #define "CImg.h"
2029       int main() {
2030         try {
2031           ...; // Here, do what you want.
2032         }
2033         catch (CImgInstanceException &e) {
2034           std::fprintf(stderr,"CImg Library Error : %s",e.message);  // Display your own error message
2035           ...                                                        // Do what you want now.
2036         }
2037       }
2038       \endcode
2039   **/
2040   struct CImgException {
2041 #define _cimg_exception_err(etype,disp_flag) \
2042   cimg_std::va_list ap; va_start(ap,format); cimg_std::vsprintf(message,format,ap); va_end(ap); \
2043   switch (cimg::exception_mode()) { \
2044   case 0 : break; \
2045   case 2 : case 4 : try { cimg::dialog(etype,message,"Abort"); } catch (CImgException&) { \
2046     cimg_std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
2047   } break; \
2048   default : cimg_std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
2049   } \
2050   if (cimg::exception_mode()>=3) cimg_library::cimg::info();
2051 
2052     char message[1024]; //!< Message associated with the error that thrown the exception.
CImgExceptionCImgException2053     CImgException() { message[0]='\0'; }
CImgExceptionCImgException2054     CImgException(const char *format, ...) { _cimg_exception_err("CImgException",true); }
2055   };
2056 
2057   // The \ref CImgInstanceException class is used to throw an exception related
2058   // to a non suitable instance encountered in a library function call.
2059   struct CImgInstanceException: public CImgException {
CImgInstanceExceptionCImgInstanceException2060     CImgInstanceException(const char *format, ...) { _cimg_exception_err("CImgInstanceException",true); }
2061   };
2062 
2063   // The \ref CImgArgumentException class is used to throw an exception related
2064   // to invalid arguments encountered in a library function call.
2065   struct CImgArgumentException: public CImgException {
CImgArgumentExceptionCImgArgumentException2066     CImgArgumentException(const char *format, ...) { _cimg_exception_err("CImgArgumentException",true); }
2067   };
2068 
2069   // The \ref CImgIOException class is used to throw an exception related
2070   // to Input/Output file problems encountered in a library function call.
2071   struct CImgIOException: public CImgException {
CImgIOExceptionCImgIOException2072     CImgIOException(const char *format, ...) { _cimg_exception_err("CImgIOException",true); }
2073   };
2074 
2075   // The CImgDisplayException class is used to throw an exception related to display problems
2076   // encountered in a library function call.
2077   struct CImgDisplayException: public CImgException {
CImgDisplayExceptionCImgDisplayException2078     CImgDisplayException(const char *format, ...) { _cimg_exception_err("CImgDisplayException",false); }
2079   };
2080 
2081   // The CImgWarningException class is used to throw an exception for warnings
2082   // encountered in a library function call.
2083   struct CImgWarningException: public CImgException {
CImgWarningExceptionCImgWarningException2084     CImgWarningException(const char *format, ...) { _cimg_exception_err("CImgWarningException",false); }
2085   };
2086 
2087   /*-------------------------------------
2088    #
2089    # Definition of the namespace 'cimg'
2090    #
2091    --------------------------------------*/
2092   //! Namespace that encompasses \a low-level functions and variables of the %CImg Library.
2093   /**
2094      Most of the functions and variables within this namespace are used by the library for low-level processing.
2095      Nevertheless, documented variables and functions of this namespace may be used safely in your own source code.
2096 
2097      \warning Never write <tt>using namespace cimg_library::cimg;</tt> in your source code, since a lot of functions of the
2098      <tt>cimg::</tt> namespace have prototypes similar to standard C functions that could defined in the global namespace <tt>::</tt>.
2099   **/
2100   namespace cimg {
2101 
2102     // Define the traits that will be used to determine the best data type to work with.
2103     //
2104     template<typename T> struct type {
stringtype2105       static const char* string() {
2106         static const char* s[] = { "unknown",   "unknown8",   "unknown16",  "unknown24",
2107                                    "unknown32", "unknown40",  "unknown48",  "unknown56",
2108                                    "unknown64", "unknown72",  "unknown80",  "unknown88",
2109                                    "unknown96", "unknown104", "unknown112", "unknown120",
2110                                    "unknown128" };
2111         return s[(sizeof(T)<17)?sizeof(T):0];
2112       }
is_floattype2113       static bool is_float() { return false; }
mintype2114       static T min() { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); }
maxtype2115       static T max() { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); }
formattype2116       static const char* format() { return "%s"; }
formattype2117       static const char* format(const T val) { static const char *s = "unknown"; return s; }
2118     };
2119 
2120     template<> struct type<bool> {
2121       static const char* string() { static const char *const s = "bool"; return s; }
2122       static bool is_float() { return false; }
2123       static bool min() { return false; }
2124       static bool max() { return true; }
2125       static const char* format() { return "%s"; }
2126       static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; }
2127     };
2128 
2129     template<> struct type<unsigned char> {
2130       static const char* string() { static const char *const s = "unsigned char"; return s; }
2131       static bool is_float() { return false; }
2132       static unsigned char min() { return 0; }
2133       static unsigned char max() { return (unsigned char)~0U; }
2134       static const char* format() { return "%u"; }
2135       static unsigned int format(const unsigned char val) { return (unsigned int)val; }
2136     };
2137 
2138     template<> struct type<char> {
2139       static const char* string() { static const char *const s = "char"; return s; }
2140       static bool is_float() { return false; }
2141       static char min() { return (char)(-1L<<(8*sizeof(char)-1)); }
2142       static char max() { return ~((char)(-1L<<(8*sizeof(char)-1))); }
2143       static const char* format() { return "%d"; }
2144       static int format(const char val) { return (int)val; }
2145     };
2146 
2147     template<> struct type<signed char> {
2148       static const char* string() { static const char *const s = "signed char"; return s; }
2149       static bool is_float() { return false; }
2150       static signed char min() { return (signed char)(-1L<<(8*sizeof(signed char)-1)); }
2151       static signed char max() { return ~((signed char)(-1L<<(8*sizeof(signed char)-1))); }
2152       static const char* format() { return "%d"; }
2153       static unsigned int format(const signed char val) { return (int)val; }
2154     };
2155 
2156     template<> struct type<unsigned short> {
2157       static const char* string() { static const char *const s = "unsigned short"; return s; }
2158       static bool is_float() { return false; }
2159       static unsigned short min() { return 0; }
2160       static unsigned short max() { return (unsigned short)~0U; }
2161       static const char* format() { return "%u"; }
2162       static unsigned int format(const unsigned short val) { return (unsigned int)val; }
2163     };
2164 
2165     template<> struct type<short> {
2166       static const char* string() { static const char *const s = "short"; return s; }
2167       static bool is_float() { return false; }
2168       static short min() { return (short)(-1L<<(8*sizeof(short)-1)); }
2169       static short max() { return ~((short)(-1L<<(8*sizeof(short)-1))); }
2170       static const char* format() { return "%d"; }
2171       static int format(const short val) { return (int)val; }
2172     };
2173 
2174     template<> struct type<unsigned int> {
2175       static const char* string() { static const char *const s = "unsigned int"; return s; }
2176       static bool is_float() { return false; }
2177       static unsigned int min() { return 0; }
2178       static unsigned int max() { return (unsigned int)~0U; }
2179       static const char* format() { return "%u"; }
2180       static unsigned int format(const unsigned int val) { return val; }
2181     };
2182 
2183     template<> struct type<int> {
2184       static const char* string() { static const char *const s = "int"; return s; }
2185       static bool is_float() { return false; }
2186       static int min() { return (int)(-1L<<(8*sizeof(int)-1)); }
2187       static int max() { return ~((int)(-1L<<(8*sizeof(int)-1))); }
2188       static const char* format() { return "%d"; }
2189       static int format(const int val) { return val; }
2190     };
2191 
2192     template<> struct type<unsigned long> {
2193       static const char* string() { static const char *const s = "unsigned long"; return s; }
2194       static bool is_float() { return false; }
2195       static unsigned long min() { return 0; }
2196       static unsigned long max() { return (unsigned long)~0UL; }
2197       static const char* format() { return "%lu"; }
2198       static unsigned long format(const unsigned long val) { return val; }
2199     };
2200 
2201     template<> struct type<long> {
2202       static const char* string() { static const char *const s = "long"; return s; }
2203       static bool is_float() { return false; }
2204       static long min() { return (long)(-1L<<(8*sizeof(long)-1)); }
2205       static long max() { return ~((long)(-1L<<(8*sizeof(long)-1))); }
2206       static const char* format() { return "%ld"; }
2207       static long format(const long val) { return val; }
2208     };
2209 
2210     template<> struct type<float> {
2211       static const char* string() { static const char *const s = "float"; return s; }
2212       static bool is_float() { return true; }
2213       static float min() { return -3.4E38f; }
2214       static float max() { return  3.4E38f; }
2215       static const char* format() { return "%g"; }
2216       static double format(const float val) { return (double)val; }
2217     };
2218 
2219     template<> struct type<double> {
2220       static const char* string() { static const char *const s = "double"; return s; }
2221       static bool is_float() { return true; }
2222       static double min() { return -1.7E308; }
2223       static double max() { return  1.7E308; }
2224       static const char* format() { return "%g"; }
2225       static double format(const double val) { return val; }
2226     };
2227 
2228     template<typename T, typename t> struct superset { typedef T type; };
2229     template<> struct superset<bool,unsigned char> { typedef unsigned char type; };
2230     template<> struct superset<bool,char> { typedef char type; };
2231     template<> struct superset<bool,signed char> { typedef signed char type; };
2232     template<> struct superset<bool,unsigned short> { typedef unsigned short type; };
2233     template<> struct superset<bool,short> { typedef short type; };
2234     template<> struct superset<bool,unsigned int> { typedef unsigned int type; };
2235     template<> struct superset<bool,int> { typedef int type; };
2236     template<> struct superset<bool,unsigned long> { typedef unsigned long type; };
2237     template<> struct superset<bool,long> { typedef long type; };
2238     template<> struct superset<bool,float> { typedef float type; };
2239     template<> struct superset<bool,double> { typedef double type; };
2240     template<> struct superset<unsigned char,char> { typedef short type; };
2241     template<> struct superset<unsigned char,signed char> { typedef short type; };
2242     template<> struct superset<unsigned char,unsigned short> { typedef unsigned short type; };
2243     template<> struct superset<unsigned char,short> { typedef short type; };
2244     template<> struct superset<unsigned char,unsigned int> { typedef unsigned int type; };
2245     template<> struct superset<unsigned char,int> { typedef int type; };
2246     template<> struct superset<unsigned char,unsigned long> { typedef unsigned long type; };
2247     template<> struct superset<unsigned char,long> { typedef long type; };
2248     template<> struct superset<unsigned char,float> { typedef float type; };
2249     template<> struct superset<unsigned char,double> { typedef double type; };
2250     template<> struct superset<signed char,unsigned char> { typedef short type; };
2251     template<> struct superset<signed char,char> { typedef short type; };
2252     template<> struct superset<signed char,unsigned short> { typedef int type; };
2253     template<> struct superset<signed char,short> { typedef short type; };
2254     template<> struct superset<signed char,unsigned int> { typedef long type; };
2255     template<> struct superset<signed char,int> { typedef int type; };
2256     template<> struct superset<signed char,unsigned long> { typedef long type; };
2257     template<> struct superset<signed char,long> { typedef long type; };
2258     template<> struct superset<signed char,float> { typedef float type; };
2259     template<> struct superset<signed char,double> { typedef double type; };
2260     template<> struct superset<char,unsigned char> { typedef short type; };
2261     template<> struct superset<char,signed char> { typedef short type; };
2262     template<> struct superset<char,unsigned short> { typedef int type; };
2263     template<> struct superset<char,short> { typedef short type; };
2264     template<> struct superset<char,unsigned int> { typedef long type; };
2265     template<> struct superset<char,int> { typedef int type; };
2266     template<> struct superset<char,unsigned long> { typedef long type; };
2267     template<> struct superset<char,long> { typedef long type; };
2268     template<> struct superset<char,float> { typedef float type; };
2269     template<> struct superset<char,double> { typedef double type; };
2270     template<> struct superset<unsigned short,char> { typedef int type; };
2271     template<> struct superset<unsigned short,signed char> { typedef int type; };
2272     template<> struct superset<unsigned short,short> { typedef int type; };
2273     template<> struct superset<unsigned short,unsigned int> { typedef unsigned int type; };
2274     template<> struct superset<unsigned short,int> { typedef int type; };
2275     template<> struct superset<unsigned short,unsigned long> { typedef unsigned long type; };
2276     template<> struct superset<unsigned short,long> { typedef long type; };
2277     template<> struct superset<unsigned short,float> { typedef float type; };
2278     template<> struct superset<unsigned short,double> { typedef double type; };
2279     template<> struct superset<short,unsigned short> { typedef int type; };
2280     template<> struct superset<short,unsigned int> { typedef long type; };
2281     template<> struct superset<short,int> { typedef int type; };
2282     template<> struct superset<short,unsigned long> { typedef long type; };
2283     template<> struct superset<short,long> { typedef long type; };
2284     template<> struct superset<short,float> { typedef float type; };
2285     template<> struct superset<short,double> { typedef double type; };
2286     template<> struct superset<unsigned int,char> { typedef long type; };
2287     template<> struct superset<unsigned int,signed char> { typedef long type; };
2288     template<> struct superset<unsigned int,short> { typedef long type; };
2289     template<> struct superset<unsigned int,int> { typedef long type; };
2290     template<> struct superset<unsigned int,unsigned long> { typedef unsigned long type; };
2291     template<> struct superset<unsigned int,long> { typedef long type; };
2292     template<> struct superset<unsigned int,float> { typedef float type; };
2293     template<> struct superset<unsigned int,double> { typedef double type; };
2294     template<> struct superset<int,unsigned int> { typedef long type; };
2295     template<> struct superset<int,unsigned long> { typedef long type; };
2296     template<> struct superset<int,long> { typedef long type; };
2297     template<> struct superset<int,float> { typedef float type; };
2298     template<> struct superset<int,double> { typedef double type; };
2299     template<> struct superset<unsigned long,char> { typedef long type; };
2300     template<> struct superset<unsigned long,signed char> { typedef long type; };
2301     template<> struct superset<unsigned long,short> { typedef long type; };
2302     template<> struct superset<unsigned long,int> { typedef long type; };
2303     template<> struct superset<unsigned long,long> { typedef long type; };
2304     template<> struct superset<unsigned long,float> { typedef float type; };
2305     template<> struct superset<unsigned long,double> { typedef double type; };
2306     template<> struct superset<long,float> { typedef float type; };
2307     template<> struct superset<long,double> { typedef double type; };
2308     template<> struct superset<float,double> { typedef double type; };
2309 
2310     template<typename t1, typename t2, typename t3> struct superset2 {
2311       typedef typename superset<t1, typename superset<t2,t3>::type>::type type;
2312     };
2313 
2314     template<typename t1, typename t2, typename t3, typename t4> struct superset3 {
2315       typedef typename superset<t1, typename superset2<t2,t3,t4>::type>::type type;
2316     };
2317 
2318     template<typename t1, typename t2> struct last { typedef t2 type; };
2319 
2320 #define _cimg_Tuchar  typename cimg::superset<T,unsigned char>::type
2321 #define _cimg_Tint    typename cimg::superset<T,int>::type
2322 #define _cimg_Tfloat  typename cimg::superset<T,float>::type
2323 #define _cimg_Tdouble typename cimg::superset<T,double>::type
2324 #define _cimg_Tt      typename cimg::superset<T,t>::type
2325 
2326     // Define internal library variables.
2327     //
2328 #if cimg_display==1
2329     struct X11info {
2330       volatile unsigned int nb_wins;
2331       pthread_t*       event_thread;
2332       CImgDisplay*     wins[1024];
2333       Display*         display;
2334       unsigned int     nb_bits;
2335       GC*              gc;
2336       bool             blue_first;
2337       bool             byte_order;
2338       bool             shm_enabled;
2339 #ifdef cimg_use_xrandr
2340       XRRScreenSize *resolutions;
2341       Rotation curr_rotation;
2342       unsigned int curr_resolution;
2343       unsigned int nb_resolutions;
2344 #endif
2345       X11info():nb_wins(0),event_thread(0),display(0),
2346                 nb_bits(0),gc(0),blue_first(false),byte_order(false),shm_enabled(false) {
2347 #ifdef cimg_use_xrandr
2348         resolutions = 0;
2349         curr_rotation = 0;
2350         curr_resolution = nb_resolutions = 0;
2351 #endif
2352       }
2353     };
2354 #if defined(cimg_module)
2355     X11info& X11attr();
2356 #elif defined(cimg_main)
2357     X11info& X11attr() { static X11info val; return val; }
2358 #else
2359     inline X11info& X11attr() { static X11info val; return val; }
2360 #endif
2361 
2362 #elif cimg_display==2
2363     struct Win32info {
2364       HANDLE wait_event;
2365       Win32info() { wait_event = CreateEvent(0,FALSE,FALSE,0); }
2366     };
2367 #if defined(cimg_module)
2368     Win32info& Win32attr();
2369 #elif defined(cimg_main)
2370     Win32info& Win32attr() { static Win32info val; return val; }
2371 #else
2372     inline Win32info& Win32attr() { static Win32info val; return val; }
2373 #endif
2374 
2375 #elif cimg_display==3
2376     struct CarbonInfo {
2377       MPCriticalRegionID windowListCR; // Protects access to the list of windows
2378       int windowCount;                 // Count of displays used on the screen
2379       pthread_t event_thread;          // The background event thread
2380       MPSemaphoreID sync_event;        // Event used to perform tasks synchronizations
2381       MPSemaphoreID wait_event;        // Event used to notify that new events occurred on the display
2382       MPQueueID com_queue;             // The message queue
2383       CarbonInfo(): windowCount(0),event_thread(0),sync_event(0),com_queue(0) {
2384         if (MPCreateCriticalRegion(&windowListCR) != noErr) // Create the critical region
2385           throw CImgDisplayException("MPCreateCriticalRegion failed.");
2386         if (MPCreateSemaphore(1, 0, &sync_event) != noErr) // Create the inter-thread sync object
2387           throw CImgDisplayException("MPCreateSemaphore failed.");
2388         if (MPCreateSemaphore(1, 0, &wait_event) != noErr) // Create the event sync object
2389           throw CImgDisplayException("MPCreateSemaphore failed.");
2390         if (MPCreateQueue(&com_queue) != noErr) // Create the shared queue
2391           throw CImgDisplayException("MPCreateQueue failed.");
2392       }
2393       ~CarbonInfo() {
2394         if (event_thread != 0) { // Terminates the resident thread, if needed
2395           pthread_cancel(event_thread);
2396           pthread_join(event_thread, NULL);
2397           event_thread = 0;
2398         }
2399         if (MPDeleteCriticalRegion(windowListCR) != noErr) // Delete the critical region
2400           throw CImgDisplayException("MPDeleteCriticalRegion failed.");
2401         if (MPDeleteSemaphore(wait_event) != noErr) // Delete the event sync event
2402           throw CImgDisplayException("MPDeleteEvent failed.");
2403         if (MPDeleteSemaphore(sync_event) != noErr) // Delete the inter-thread sync event
2404           throw CImgDisplayException("MPDeleteEvent failed.");
2405         if (MPDeleteQueue(com_queue) != noErr) // Delete the shared queue
2406           throw CImgDisplayException("MPDeleteQueue failed.");
2407       }
2408     };
2409 #if defined(cimg_module)
2410     CarbonInfo& CarbonAttr();
2411 #elif defined(cimg_main)
2412     CarbonInfo CarbonAttr() { static CarbonInfo val; return val; }
2413 #else
2414     inline CarbonInfo& CarbonAttr() { static CarbonInfo val; return val; }
2415 #endif
2416 #endif
2417 
2418 #if cimg_display==1
2419     // Keycodes for X11-based graphical systems.
2420     //
2421     const unsigned int keyESC        = XK_Escape;
2422     const unsigned int keyF1         = XK_F1;
2423     const unsigned int keyF2         = XK_F2;
2424     const unsigned int keyF3         = XK_F3;
2425     const unsigned int keyF4         = XK_F4;
2426     const unsigned int keyF5         = XK_F5;
2427     const unsigned int keyF6         = XK_F6;
2428     const unsigned int keyF7         = XK_F7;
2429     const unsigned int keyF8         = XK_F8;
2430     const unsigned int keyF9         = XK_F9;
2431     const unsigned int keyF10        = XK_F10;
2432     const unsigned int keyF11        = XK_F11;
2433     const unsigned int keyF12        = XK_F12;
2434     const unsigned int keyPAUSE      = XK_Pause;
2435     const unsigned int key1          = XK_1;
2436     const unsigned int key2          = XK_2;
2437     const unsigned int key3          = XK_3;
2438     const unsigned int key4          = XK_4;
2439     const unsigned int key5          = XK_5;
2440     const unsigned int key6          = XK_6;
2441     const unsigned int key7          = XK_7;
2442     const unsigned int key8          = XK_8;
2443     const unsigned int key9          = XK_9;
2444     const unsigned int key0          = XK_0;
2445     const unsigned int keyBACKSPACE  = XK_BackSpace;
2446     const unsigned int keyINSERT     = XK_Insert;
2447     const unsigned int keyHOME       = XK_Home;
2448     const unsigned int keyPAGEUP     = XK_Page_Up;
2449     const unsigned int keyTAB        = XK_Tab;
2450     const unsigned int keyQ          = XK_q;
2451     const unsigned int keyW          = XK_w;
2452     const unsigned int keyE          = XK_e;
2453     const unsigned int keyR          = XK_r;
2454     const unsigned int keyT          = XK_t;
2455     const unsigned int keyY          = XK_y;
2456     const unsigned int keyU          = XK_u;
2457     const unsigned int keyI          = XK_i;
2458     const unsigned int keyO          = XK_o;
2459     const unsigned int keyP          = XK_p;
2460     const unsigned int keyDELETE     = XK_Delete;
2461     const unsigned int keyEND        = XK_End;
2462     const unsigned int keyPAGEDOWN   = XK_Page_Down;
2463     const unsigned int keyCAPSLOCK   = XK_Caps_Lock;
2464     const unsigned int keyA          = XK_a;
2465     const unsigned int keyS          = XK_s;
2466     const unsigned int keyD          = XK_d;
2467     const unsigned int keyF          = XK_f;
2468     const unsigned int keyG          = XK_g;
2469     const unsigned int keyH          = XK_h;
2470     const unsigned int keyJ          = XK_j;
2471     const unsigned int keyK          = XK_k;
2472     const unsigned int keyL          = XK_l;
2473     const unsigned int keyENTER      = XK_Return;
2474     const unsigned int keySHIFTLEFT  = XK_Shift_L;
2475     const unsigned int keyZ          = XK_z;
2476     const unsigned int keyX          = XK_x;
2477     const unsigned int keyC          = XK_c;
2478     const unsigned int keyV          = XK_v;
2479     const unsigned int keyB          = XK_b;
2480     const unsigned int keyN          = XK_n;
2481     const unsigned int keyM          = XK_m;
2482     const unsigned int keySHIFTRIGHT = XK_Shift_R;
2483     const unsigned int keyARROWUP    = XK_Up;
2484     const unsigned int keyCTRLLEFT   = XK_Control_L;
2485     const unsigned int keyAPPLEFT    = XK_Super_L;
2486     const unsigned int keyALT        = XK_Alt_L;
2487     const unsigned int keySPACE      = XK_space;
2488     const unsigned int keyALTGR      = XK_Alt_R;
2489     const unsigned int keyAPPRIGHT   = XK_Super_R;
2490     const unsigned int keyMENU       = XK_Menu;
2491     const unsigned int keyCTRLRIGHT  = XK_Control_R;
2492     const unsigned int keyARROWLEFT  = XK_Left;
2493     const unsigned int keyARROWDOWN  = XK_Down;
2494     const unsigned int keyARROWRIGHT = XK_Right;
2495     const unsigned int keyPAD0       = XK_KP_0;
2496     const unsigned int keyPAD1       = XK_KP_1;
2497     const unsigned int keyPAD2       = XK_KP_2;
2498     const unsigned int keyPAD3       = XK_KP_3;
2499     const unsigned int keyPAD4       = XK_KP_4;
2500     const unsigned int keyPAD5       = XK_KP_5;
2501     const unsigned int keyPAD6       = XK_KP_6;
2502     const unsigned int keyPAD7       = XK_KP_7;
2503     const unsigned int keyPAD8       = XK_KP_8;
2504     const unsigned int keyPAD9       = XK_KP_9;
2505     const unsigned int keyPADADD     = XK_KP_Add;
2506     const unsigned int keyPADSUB     = XK_KP_Subtract;
2507     const unsigned int keyPADMUL     = XK_KP_Multiply;
2508     const unsigned int keyPADDIV     = XK_KP_Divide;
2509 
2510 #elif cimg_display==2
2511     // Keycodes for Windows.
2512     //
2513     const unsigned int keyESC        = VK_ESCAPE;
2514     const unsigned int keyF1         = VK_F1;
2515     const unsigned int keyF2         = VK_F2;
2516     const unsigned int keyF3         = VK_F3;
2517     const unsigned int keyF4         = VK_F4;
2518     const unsigned int keyF5         = VK_F5;
2519     const unsigned int keyF6         = VK_F6;
2520     const unsigned int keyF7         = VK_F7;
2521     const unsigned int keyF8         = VK_F8;
2522     const unsigned int keyF9         = VK_F9;
2523     const unsigned int keyF10        = VK_F10;
2524     const unsigned int keyF11        = VK_F11;
2525     const unsigned int keyF12        = VK_F12;
2526     const unsigned int keyPAUSE      = VK_PAUSE;
2527     const unsigned int key1          = '1';
2528     const unsigned int key2          = '2';
2529     const unsigned int key3          = '3';
2530     const unsigned int key4          = '4';
2531     const unsigned int key5          = '5';
2532     const unsigned int key6          = '6';
2533     const unsigned int key7          = '7';
2534     const unsigned int key8          = '8';
2535     const unsigned int key9          = '9';
2536     const unsigned int key0          = '0';
2537     const unsigned int keyBACKSPACE  = VK_BACK;
2538     const unsigned int keyINSERT     = VK_INSERT;
2539     const unsigned int keyHOME       = VK_HOME;
2540     const unsigned int keyPAGEUP     = VK_PRIOR;
2541     const unsigned int keyTAB        = VK_TAB;
2542     const unsigned int keyQ          = 'Q';
2543     const unsigned int keyW          = 'W';
2544     const unsigned int keyE          = 'E';
2545     const unsigned int keyR          = 'R';
2546     const unsigned int keyT          = 'T';
2547     const unsigned int keyY          = 'Y';
2548     const unsigned int keyU          = 'U';
2549     const unsigned int keyI          = 'I';
2550     const unsigned int keyO          = 'O';
2551     const unsigned int keyP          = 'P';
2552     const unsigned int keyDELETE     = VK_DELETE;
2553     const unsigned int keyEND        = VK_END;
2554     const unsigned int keyPAGEDOWN   = VK_NEXT;
2555     const unsigned int keyCAPSLOCK   = VK_CAPITAL;
2556     const unsigned int keyA          = 'A';
2557     const unsigned int keyS          = 'S';
2558     const unsigned int keyD          = 'D';
2559     const unsigned int keyF          = 'F';
2560     const unsigned int keyG          = 'G';
2561     const unsigned int keyH          = 'H';
2562     const unsigned int keyJ          = 'J';
2563     const unsigned int keyK          = 'K';
2564     const unsigned int keyL          = 'L';
2565     const unsigned int keyENTER      = VK_RETURN;
2566     const unsigned int keySHIFTLEFT  = VK_SHIFT;
2567     const unsigned int keyZ          = 'Z';
2568     const unsigned int keyX          = 'X';
2569     const unsigned int keyC          = 'C';
2570     const unsigned int keyV          = 'V';
2571     const unsigned int keyB          = 'B';
2572     const unsigned int keyN          = 'N';
2573     const unsigned int keyM          = 'M';
2574     const unsigned int keySHIFTRIGHT = VK_SHIFT;
2575     const unsigned int keyARROWUP    = VK_UP;
2576     const unsigned int keyCTRLLEFT   = VK_CONTROL;
2577     const unsigned int keyAPPLEFT    = VK_LWIN;
2578     const unsigned int keyALT        = VK_LMENU;
2579     const unsigned int keySPACE      = VK_SPACE;
2580     const unsigned int keyALTGR      = VK_CONTROL;
2581     const unsigned int keyAPPRIGHT   = VK_RWIN;
2582     const unsigned int keyMENU       = VK_APPS;
2583     const unsigned int keyCTRLRIGHT  = VK_CONTROL;
2584     const unsigned int keyARROWLEFT  = VK_LEFT;
2585     const unsigned int keyARROWDOWN  = VK_DOWN;
2586     const unsigned int keyARROWRIGHT = VK_RIGHT;
2587     const unsigned int keyPAD0       = 0x60;
2588     const unsigned int keyPAD1       = 0x61;
2589     const unsigned int keyPAD2       = 0x62;
2590     const unsigned int keyPAD3       = 0x63;
2591     const unsigned int keyPAD4       = 0x64;
2592     const unsigned int keyPAD5       = 0x65;
2593     const unsigned int keyPAD6       = 0x66;
2594     const unsigned int keyPAD7       = 0x67;
2595     const unsigned int keyPAD8       = 0x68;
2596     const unsigned int keyPAD9       = 0x69;
2597     const unsigned int keyPADADD     = VK_ADD;
2598     const unsigned int keyPADSUB     = VK_SUBTRACT;
2599     const unsigned int keyPADMUL     = VK_MULTIPLY;
2600     const unsigned int keyPADDIV     = VK_DIVIDE;
2601 
2602 #elif cimg_display==3
2603     // Keycodes for MacOSX, when using the Carbon framework.
2604     //
2605     const unsigned int keyESC        = kEscapeCharCode;
2606     const unsigned int keyF1         = 2U;
2607     const unsigned int keyF2         = 3U;
2608     const unsigned int keyF3         = 4U;
2609     const unsigned int keyF4         = 5U;
2610     const unsigned int keyF5         = 6U;
2611     const unsigned int keyF6         = 7U;
2612     const unsigned int keyF7         = 8U;
2613     const unsigned int keyF8         = 9U;
2614     const unsigned int keyF9         = 10U;
2615     const unsigned int keyF10        = 11U;
2616     const unsigned int keyF11        = 12U;
2617     const unsigned int keyF12        = 13U;
2618     const unsigned int keyPAUSE      = 14U;
2619     const unsigned int key1          = '1';
2620     const unsigned int key2          = '2';
2621     const unsigned int key3          = '3';
2622     const unsigned int key4          = '4';
2623     const unsigned int key5          = '5';
2624     const unsigned int key6          = '6';
2625     const unsigned int key7          = '7';
2626     const unsigned int key8          = '8';
2627     const unsigned int key9          = '9';
2628     const unsigned int key0          = '0';
2629     const unsigned int keyBACKSPACE  = kBackspaceCharCode;
2630     const unsigned int keyINSERT     = 26U;
2631     const unsigned int keyHOME       = kHomeCharCode;
2632     const unsigned int keyPAGEUP     = kPageUpCharCode;
2633     const unsigned int keyTAB        = kTabCharCode;
2634     const unsigned int keyQ          = 'q';
2635     const unsigned int keyW          = 'w';
2636     const unsigned int keyE          = 'e';
2637     const unsigned int keyR          = 'r';
2638     const unsigned int keyT          = 't';
2639     const unsigned int keyY          = 'y';
2640     const unsigned int keyU          = 'u';
2641     const unsigned int keyI          = 'i';
2642     const unsigned int keyO          = 'o';
2643     const unsigned int keyP          = 'p';
2644     const unsigned int keyDELETE     = kDeleteCharCode;
2645     const unsigned int keyEND        = kEndCharCode;
2646     const unsigned int keyPAGEDOWN   = kPageDownCharCode;
2647     const unsigned int keyCAPSLOCK   = 43U;
2648     const unsigned int keyA          = 'a';
2649     const unsigned int keyS          = 's';
2650     const unsigned int keyD          = 'd';
2651     const unsigned int keyF          = 'f';
2652     const unsigned int keyG          = 'g';
2653     const unsigned int keyH          = 'h';
2654     const unsigned int keyJ          = 'j';
2655     const unsigned int keyK          = 'k';
2656     const unsigned int keyL          = 'l';
2657     const unsigned int keyENTER      = kEnterCharCode;
2658     const unsigned int keySHIFTLEFT  = 54U; //Macintosh modifier key, emulated
2659     const unsigned int keyZ          = 'z';
2660     const unsigned int keyX          = 'x';
2661     const unsigned int keyC          = 'c';
2662     const unsigned int keyV          = 'v';
2663     const unsigned int keyB          = 'b';
2664     const unsigned int keyN          = 'n';
2665     const unsigned int keyM          = 'm';
2666     const unsigned int keySHIFTRIGHT = 62U; //Macintosh modifier key, emulated
2667     const unsigned int keyARROWUP    = kUpArrowCharCode;
2668     const unsigned int keyCTRLLEFT   = 64U; //Macintosh modifier key, emulated
2669     const unsigned int keyAPPLEFT    = 65U; //Macintosh modifier key, emulated
2670     const unsigned int keyALT        = 66U;
2671     const unsigned int keySPACE      = kSpaceCharCode;
2672     const unsigned int keyALTGR      = 67U; //Macintosh modifier key, emulated
2673     const unsigned int keyAPPRIGHT   = 68U; //Aliased on keyAPPLEFT
2674     const unsigned int keyMENU       = 69U;
2675     const unsigned int keyCTRLRIGHT  = 70U; //Macintosh modifier key, emulated
2676     const unsigned int keyARROWLEFT  = kLeftArrowCharCode;
2677     const unsigned int keyARROWDOWN  = kDownArrowCharCode;
2678     const unsigned int keyARROWRIGHT = kRightArrowCharCode;
2679     const unsigned int keyPAD0       = 74U;
2680     const unsigned int keyPAD1       = 75U;
2681     const unsigned int keyPAD2       = 76U;
2682     const unsigned int keyPAD3       = 77U;
2683     const unsigned int keyPAD4       = 78U;
2684     const unsigned int keyPAD5       = 79U;
2685     const unsigned int keyPAD6       = 80U;
2686     const unsigned int keyPAD7       = 81U;
2687     const unsigned int keyPAD8       = 82U;
2688     const unsigned int keyPAD9       = 83U;
2689     const unsigned int keyPADADD     = 84U;
2690     const unsigned int keyPADSUB     = 85U;
2691     const unsigned int keyPADMUL     = 86U;
2692     const unsigned int keyPADDIV     = 87U;
2693 
2694 #else
2695     // Define unknow keycodes when no display are available.
2696     // (should rarely be used then !).
2697     //
2698     const unsigned int keyESC        = 1U;
2699     const unsigned int keyF1         = 2U;
2700     const unsigned int keyF2         = 3U;
2701     const unsigned int keyF3         = 4U;
2702     const unsigned int keyF4         = 5U;
2703     const unsigned int keyF5         = 6U;
2704     const unsigned int keyF6         = 7U;
2705     const unsigned int keyF7         = 8U;
2706     const unsigned int keyF8         = 9U;
2707     const unsigned int keyF9         = 10U;
2708     const unsigned int keyF10        = 11U;
2709     const unsigned int keyF11        = 12U;
2710     const unsigned int keyF12        = 13U;
2711     const unsigned int keyPAUSE      = 14U;
2712     const unsigned int key1          = 15U;
2713     const unsigned int key2          = 16U;
2714     const unsigned int key3          = 17U;
2715     const unsigned int key4          = 18U;
2716     const unsigned int key5          = 19U;
2717     const unsigned int key6          = 20U;
2718     const unsigned int key7          = 21U;
2719     const unsigned int key8          = 22U;
2720     const unsigned int key9          = 23U;
2721     const unsigned int key0          = 24U;
2722     const unsigned int keyBACKSPACE  = 25U;
2723     const unsigned int keyINSERT     = 26U;
2724     const unsigned int keyHOME       = 27U;
2725     const unsigned int keyPAGEUP     = 28U;
2726     const unsigned int keyTAB        = 29U;
2727     const unsigned int keyQ          = 30U;
2728     const unsigned int keyW          = 31U;
2729     const unsigned int keyE          = 32U;
2730     const unsigned int keyR          = 33U;
2731     const unsigned int keyT          = 34U;
2732     const unsigned int keyY          = 35U;
2733     const unsigned int keyU          = 36U;
2734     const unsigned int keyI          = 37U;
2735     const unsigned int keyO          = 38U;
2736     const unsigned int keyP          = 39U;
2737     const unsigned int keyDELETE     = 40U;
2738     const unsigned int keyEND        = 41U;
2739     const unsigned int keyPAGEDOWN   = 42U;
2740     const unsigned int keyCAPSLOCK   = 43U;
2741     const unsigned int keyA          = 44U;
2742     const unsigned int keyS          = 45U;
2743     const unsigned int keyD          = 46U;
2744     const unsigned int keyF          = 47U;
2745     const unsigned int keyG          = 48U;
2746     const unsigned int keyH          = 49U;
2747     const unsigned int keyJ          = 50U;
2748     const unsigned int keyK          = 51U;
2749     const unsigned int keyL          = 52U;
2750     const unsigned int keyENTER      = 53U;
2751     const unsigned int keySHIFTLEFT  = 54U;
2752     const unsigned int keyZ          = 55U;
2753     const unsigned int keyX          = 56U;
2754     const unsigned int keyC          = 57U;
2755     const unsigned int keyV          = 58U;
2756     const unsigned int keyB          = 59U;
2757     const unsigned int keyN          = 60U;
2758     const unsigned int keyM          = 61U;
2759     const unsigned int keySHIFTRIGHT = 62U;
2760     const unsigned int keyARROWUP    = 63U;
2761     const unsigned int keyCTRLLEFT   = 64U;
2762     const unsigned int keyAPPLEFT    = 65U;
2763     const unsigned int keyALT        = 66U;
2764     const unsigned int keySPACE      = 67U;
2765     const unsigned int keyALTGR      = 68U;
2766     const unsigned int keyAPPRIGHT   = 69U;
2767     const unsigned int keyMENU       = 70U;
2768     const unsigned int keyCTRLRIGHT  = 71U;
2769     const unsigned int keyARROWLEFT  = 72U;
2770     const unsigned int keyARROWDOWN  = 73U;
2771     const unsigned int keyARROWRIGHT = 74U;
2772     const unsigned int keyPAD0       = 75U;
2773     const unsigned int keyPAD1       = 76U;
2774     const unsigned int keyPAD2       = 77U;
2775     const unsigned int keyPAD3       = 78U;
2776     const unsigned int keyPAD4       = 79U;
2777     const unsigned int keyPAD5       = 80U;
2778     const unsigned int keyPAD6       = 81U;
2779     const unsigned int keyPAD7       = 82U;
2780     const unsigned int keyPAD8       = 83U;
2781     const unsigned int keyPAD9       = 84U;
2782     const unsigned int keyPADADD     = 85U;
2783     const unsigned int keyPADSUB     = 86U;
2784     const unsigned int keyPADMUL     = 87U;
2785     const unsigned int keyPADDIV     = 88U;
2786 #endif
2787 
2788     const double valuePI = 3.14159265358979323846;   //!< Definition of the mathematical constant PI
2789 
2790     // Definition of a 7x11 font, used to return a default font for drawing text.
2791     const unsigned int font7x11[7*11*256/32] = {
2792       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,
2793       0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x7f0000,0x40000,0x0,0x0,0x4010c0a4,0x82000040,0x11848402,0x18480050,0x80430292,0x8023,0x9008000,
2794       0x40218140,0x4000040,0x21800402,0x18000051,0x1060500,0x8083,0x10000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x24002,0x4031,0x80000000,0x10000,
2795       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c0400,0x40020000,0x80070080,0x40440e00,0x0,0x0,0x1,0x88180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2796       0x0,0x200000,0x0,0x0,0x80000,0x0,0x0,0x20212140,0x5000020,0x22400204,0x240000a0,0x40848500,0x4044,0x80010038,0x20424285,0xa000020,
2797       0x42428204,0x2428e0a0,0x82090a14,0x4104,0x85022014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10240a7,0x88484040,0x40800000,0x270c3,0x87811e0e,
2798       0x7c70e000,0x78,0x3c23c1ef,0x1f3e1e89,0xf1c44819,0xa23cf0f3,0xc3cff120,0xc18307f4,0x4040400,0x20000,0x80080080,0x40200,0x0,
2799       0x40000,0x2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8188,0x50603800,0xf3c00000,0x1c004003,0xc700003e,0x18180,0xc993880,0x10204081,
2800       0x2071ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x7d1224,0x48906048,0x0,0x4000000,0x0,0x9000,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,
2801       0x0,0x10240aa,0x14944080,0x23610000,0x68940,0x40831010,0x8891306,0x802044,0x44522208,0x90202088,0x40448819,0xb242890a,0x24011111,
2802       0x49448814,0x4040a00,0xe2c3c7,0x8e3f3cb9,0xc1c44216,0xee38b0f2,0xe78f9120,0xc18507e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2803       0x101c207,0x88a04001,0x9c00000,0x2200a041,0x8200113a,0x8240,0x50a3110,0x2850a142,0x850c2081,0x2040204,0x8104592,0x142850a1,
2804       0x42cd1224,0x4888bc48,0x70e1c387,0xe3b3c70,0xe1c38e1c,0x38707171,0xc3870e1c,0x10791224,0x48906c41,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2805       0x10003ee,0x15140080,0x21810000,0x48840,0x40851020,0x8911306,0x31fd804,0x9c522408,0x90204088,0x4045081a,0xba42890a,0x24011111,
2806       0x49285024,0x2041b00,0x132408,0x910844c8,0x4044821b,0x7244c913,0x24041111,0x49488822,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2807       0x28204,0x85006001,0x6a414000,0x3a004043,0xc700113a,0x8245,0x50a3a00,0x2850a142,0x850c4081,0x2040204,0x81045d2,0x142850a1,
2808       0x24951224,0x48852250,0x8102040,0x81054089,0x12244204,0x8108992,0x24489122,0x991224,0x4888b222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2809       0x1000143,0xa988080,0x2147c01f,0x88840,0x83091c2c,0x1070f000,0xc000608,0xa48bc408,0x9e3c46f8,0x40460816,0xaa42f10b,0xc3811111,
2810       0x35102044,0x1041100,0xf22408,0x9f084488,0x40470212,0x62448912,0x6041111,0x55308846,0x8061c80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2811       0x1028704,0x8f805801,0x4be28fdf,0x220001f0,0x111a,0x60000182,0x82c5c710,0x44891224,0x489640f1,0xe3c78204,0x810e552,0x142850a1,
2812       0x18a51224,0x48822250,0x78f1e3c7,0x8f1f40f9,0xf3e7c204,0x8108912,0x24489122,0x7ea91224,0x4888a222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2813       0x10007e2,0x85648080,0x20010000,0x88841,0x8f8232,0x20881000,0xc1fc610,0xbefa2408,0x90204288,0x40450816,0xa642810a,0x4041110a,
2814       0x36282084,0x1042080,0x1122408,0x90084488,0x40450212,0x62448912,0x184110a,0x55305082,0x8042700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2815       0x1028207,0x82004801,0x68050040,0x1c000040,0x110a,0x60000001,0x45484d10,0x7cf9f3e7,0xcf944081,0x2040204,0x8104532,0x142850a1,
2816       0x18a51224,0x48822248,0x89122448,0x91244081,0x2040204,0x8108912,0x24489122,0xc91224,0x48852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x282,
2817       0x89630080,0x20010c00,0x30108842,0x810222,0x20882306,0x3001800,0x408a2208,0x90202288,0x40448814,0xa642810a,0x2041110a,0x26442104,
2818       0x840000,0x1122408,0x90084488,0x40448212,0x62448912,0x84130a,0x36485102,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x101c208,0x4f802801,
2819       0x8028040,0x40,0x130a,0x2,0x85e897a0,0x44891224,0x489c2081,0x2040204,0x8104532,0x142850a1,0x24cd1224,0x48823c44,0x89122448,
2820       0x91244081,0x2040204,0x8108912,0x24489122,0xc93264,0xc9852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100028f,0x109f0080,0x20010c00,
2821       0x303071f3,0xc7011c1c,0x4071c306,0x802010,0x3907c1ef,0x1f201e89,0xf3844f90,0xa23c80f2,0x17810e04,0x228223f4,0x840000,0xfbc3c7,
2822       0x8f083c88,0x40444212,0x6238f0f2,0x7039d04,0x228423e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1008780,0x2201800,0xf0014000,0x1f0,
2823       0x1d0a,0x5,0x851e140,0x83060c18,0x30671ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x42f8e1c3,0x8702205c,0x7cf9f3e7,0xcf9b3c78,0xf1e3c204,
2824       0x8107111,0xc3870e1c,0x10f1d3a7,0x4e823c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x40,0x40000400,0x200000,0x0,0x2,0x0,0x0,0x0,0x0,0x18,
2825       0x0,0x4,0x44007f,0x0,0x400,0x400000,0x8010,0x0,0x6002,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x200800,0x0,0x0,0x100a,
2826       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,
2827       0x400000,0x0,0x4,0x0,0x0,0x0,0x0,0xc,0x0,0x7,0x3c0000,0x0,0x3800,0x3800000,0x8010,0x0,0x1c001,0x881c0000,0x0,0x0,0x0,0x0,0x0,0x0,
2828       0x0,0x0,0x207000,0x0,0x0,0x100a,0xc00000,0x3c,0x0,0xc00,0x0,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x0,0x1c2070
2829     };
2830 
2831     // Definition of a 10x13 font (used in dialog boxes).
2832     const unsigned int font10x13[256*10*13/32] = {
2833       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2834       0x0,0x0,0x0,0x0,0x0,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,
2835       0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2836       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2837       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,
2838       0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2839       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,
2840       0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2841       0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001,
2842       0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801,
2843       0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0,
2844       0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0,
2845       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010,
2846       0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480,
2847       0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,
2848       0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010,
2849       0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008,
2850       0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006,
2851       0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088,
2852       0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000,
2853       0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220,
2854       0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208,
2855       0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040,
2856       0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508,
2857       0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088,
2858       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018,
2859       0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220,
2860       0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2861       0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484,
2862       0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808,
2863       0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264,
2864       0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010,
2865       0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100,
2866       0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800,
2867       0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,
2868       0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822,
2869       0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200,
2870       0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000,
2871       0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2872       0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8,
2873       0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008,
2874       0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000,
2875       0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220,
2876       0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402,
2877       0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980,
2878       0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421,
2879       0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0,
2880       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020,
2881       0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701,
2882       0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,
2883       0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c,
2884       0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0,
2885       0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000,
2886       0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000,
2887       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0,
2888       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,
2889       0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000,
2890       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,
2891       0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040
2892     };
2893 
2894     // Definition of a 8x17 font.
2895     const unsigned int font8x17[8*17*256/32] = {
2896       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2897       0x0,0x0,0x0,0x2400,0x2400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20081834,0x1c0000,0x20081800,0x20081800,0x342008,
2898       0x18340000,0x200818,0x80000,0x0,0x180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4200000,0x0,0x0,
2899       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x380000,0x4000,0x2000c00,0x40100840,0x70000000,0x0,0x0,0x1c,0x10700000,0x7,0x0,
2900       0x1800,0x1800,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1010242c,0x14140000,0x10102414,0x10102414,0x2c1010,0x242c1400,
2901       0x101024,0x14100038,0x0,0x240000,0x0,0x0,0x30000000,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x8100000,0x0,
2902       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x80000,0x10004000,0x2001000,0x40000040,0x10000000,0x0,0x0,0x10,0x10100000,0x4,
2903       0x0,0x18000000,0x0,0x0,0x0,0x34002400,0x2400,0x0,0x0,0x0,0x3c,0x0,0x8000000,0x0,0x60607800,0x0,0x140000,0x0,0x0,0x0,0x0,0x0,
2904       0x44,0x10081834,0x240000,0x10081800,0x10081800,0x1c341008,0x18340000,0x100818,0x84000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102812,
2905       0x8601c10,0x8100800,0x2,0x1c383e3e,0x67e1e7f,0x3e3c0000,0x38,0x1e087e1e,0x7c7f7f1e,0x417c1c42,0x4063611c,0x7e1c7e3e,0xfe414181,
2906       0x63827f10,0x40081000,0x8004000,0x2001000,0x40000040,0x10000000,0x0,0x10000000,0x10,0x10100000,0x3c000008,0x0,0x24003e00,
2907       0x3f007f00,0x0,0x0,0x2ce91800,0x1882,0x10101c,0xc2103c,0x143c3c00,0x3c00,0x18003c3c,0x10001f00,0x181c00,0x20200810,0x8080808,
2908       0x8083e1e,0x7f7f7f7f,0x7c7c7c7c,0x7c611c1c,0x1c1c1c00,0x1e414141,0x41824044,0x810242c,0x14180000,0x8102414,0x8102414,0x382c0810,
2909       0x242c1400,0x81024,0x14104014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102816,0x3e902010,0x10084910,0x4,0x22084343,0xa402102,0x41620000,
2910       0x44,0x33144121,0x42404021,0x41100444,0x40636122,0x43224361,0x10416381,0x22440310,0x20082800,0x4000,0x2001000,0x40000040,
2911       0x10000000,0x0,0x10000000,0x10,0x10100000,0x24000008,0x0,0x606100,0x68000300,0x8106c,0x34000000,0x4f0000,0x44,0x101020,0x441040,
2912       0x420200,0x4200,0x24000404,0x7d00,0x82200,0x20203010,0x14141414,0x14082821,0x40404040,0x10101010,0x42612222,0x22222200,0x23414141,
2913       0x41447e48,0x0,0x0,0x0,0x0,0x4000000,0x18,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10287f,0x49902010,0x10083e10,0x4,0x41080101,
2914       0x1a404002,0x41411818,0x1004004,0x21144140,0x41404040,0x41100448,0x40555141,0x41414140,0x10412281,0x14280610,0x20084400,0x1c7c1c,
2915       0x3e3c7c3a,0x5c703844,0x107f5c3c,0x7c3e3c3c,0x7e424281,0x66427e10,0x10100000,0x40100008,0x1010,0xa04000,0x48100610,0x100c3024,
2916       0x24000000,0x4f3c00,0x2c107e28,0x3820,0x42281060,0x9d1e12,0xbd00,0x24100818,0x427d00,0x82248,0x20200800,0x14141414,0x14142840,
2917       0x40404040,0x10101010,0x41514141,0x41414142,0x43414141,0x41284350,0x1c1c1c1c,0x1c1c6c1c,0x3c3c3c3c,0x70707070,0x3c5c3c3c,
2918       0x3c3c3c18,0x3e424242,0x42427c42,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102824,0x48623010,0x10081c10,0x8,0x41080103,0x127c5e04,
2919       0x41411818,0xe7f3808,0x4f144140,0x41404040,0x41100450,0x40555141,0x41414160,0x1041225a,0x1c280410,0x1008c600,0x226622,0x66661066,
2920       0x62100848,0x10496266,0x66663242,0x10426681,0x24220260,0x100c0000,0xf8280008,0x1010,0x606000,0x48280428,0x28042014,0x48000000,
2921       0x494200,0x52280228,0x105420,0x3cee1058,0xa12236,0xa500,0x18101004,0x427d00,0x8226c,0x76767e10,0x14141414,0x14142840,0x40404040,
2922       0x10101010,0x41514141,0x41414124,0x45414141,0x41284150,0x22222222,0x22221222,0x66666666,0x10101010,0x66626666,0x66666600,
2923       0x66424242,0x42226622,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100024,0x381c4900,0x10086bfe,0x8,0x4908021c,0x22036304,0x3e630000,
2924       0x70000710,0x51227e40,0x417f7f43,0x7f100470,0x40554941,0x43417e3e,0x1041225a,0x8100810,0x10080000,0x24240,0x42421042,0x42100850,
2925       0x10494242,0x42422040,0x1042245a,0x18240410,0x10103900,0x407c003e,0x1818,0x1c3e10,0x4f7c087c,0x7c002010,0x48000000,0x4008,
2926       0x527c0410,0x105078,0x2410104c,0xa13e6c,0x7f00b900,0xfe3c3c,0x421d18,0x1c1c36,0x38383810,0x22222222,0x22144e40,0x7f7f7f7f,
2927       0x10101010,0xf1494141,0x41414118,0x49414141,0x4110435c,0x2020202,0x2021240,0x42424242,0x10101010,0x42424242,0x424242ff,0x4e424242,
2928       0x42244224,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000fe,0xe664d00,0x10080810,0x380010,0x41080c03,0x42014108,0x633d0000,0x70000710,
2929       0x51224140,0x41404041,0x41100448,0x40494541,0x7e414203,0x1041145a,0x14101010,0x10080000,0x3e4240,0x427e1042,0x42100870,0x10494242,
2930       0x4242203c,0x1042245a,0x18241810,0x10104600,0xf8f60008,0x1010,0x600320,0x48f610f6,0xf6000000,0x187eff,0x3c04,0x5ef61810,0x105020,
2931       0x24fe0064,0x9d006c,0x138ad00,0x100000,0x420518,0x36,0xc0c0c020,0x22222222,0x22224840,0x40404040,0x10101010,0x41454141,0x41414118,
2932       0x51414141,0x41107e46,0x3e3e3e3e,0x3e3e7e40,0x7e7e7e7e,0x10101010,0x42424242,0x42424200,0x5a424242,0x42244224,0x0,0x0,0x0,
2933       0x0,0x0,0x0,0x0,0x0,0x28,0x9094500,0x10080010,0x10,0x41081801,0x7f014118,0x41010000,0xe7f3800,0x513e4140,0x41404041,0x41100444,
2934       0x40414541,0x40414101,0x10411466,0x36103010,0x8080000,0x424240,0x42401042,0x42100848,0x10494242,0x42422002,0x10423c5a,0x18142010,
2935       0x10100000,0x407c0010,0x1010,0x260140,0x487c307c,0x7c000000,0x180000,0x202,0x507c2010,0x105020,0x3c10003c,0x423e36,0x1004200,
2936       0x100000,0x420500,0x3e6c,0x41e0440,0x3e3e3e3e,0x3e3e7840,0x40404040,0x10101010,0x41454141,0x41414124,0x61414141,0x41104042,
2937       0x42424242,0x42425040,0x40404040,0x10101010,0x42424242,0x42424218,0x72424242,0x42144214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,
2938       0x49096200,0x8100010,0x18001810,0x22082043,0x2432310,0x61421818,0x1004010,0x4f634121,0x42404021,0x41104444,0x40414322,0x40234143,
2939       0x10411466,0x22106010,0x8080000,0x466622,0x66621066,0x42100844,0x10494266,0x66662042,0x10461824,0x24184010,0x10100000,0x24381010,
2940       0x34001018,0xda4320,0x68386038,0x38000000,0x0,0x4204,0x50384010,0x105420,0x4210100c,0x3c0012,0x3c00,0x0,0x460500,0x48,0xc020c44,
2941       0x63636363,0x63228821,0x40404040,0x10101010,0x42432222,0x22222242,0x62414141,0x41104042,0x46464646,0x46465022,0x62626262,
2942       0x10101010,0x66426666,0x66666618,0x66464646,0x46186618,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,0x3e063d00,0x8100000,0x18001820,
2943       0x1c3e7f3e,0x23c1e20,0x3e3c1818,0x10,0x20417e1e,0x7c7f401e,0x417c3842,0x7f41431c,0x401e40be,0x103e0866,0x41107f10,0x4080000,
2944       0x3a5c1c,0x3a3c103a,0x427c0842,0xe49423c,0x7c3e203c,0xe3a1824,0x66087e10,0x10100000,0x3c103010,0x245a1010,0x5a3e10,0x3f107f10,
2945       0x10000000,0x0,0x3c08,0x2e107e10,0x1038fc,0x101004,0x0,0x0,0xfe0000,0x7f0500,0x0,0x14041438,0x41414141,0x41418e1e,0x7f7f7f7f,
2946       0x7c7c7c7c,0x7c431c1c,0x1c1c1c00,0xbc3e3e3e,0x3e10405c,0x3a3a3a3a,0x3a3a6e1c,0x3c3c3c3c,0x7c7c7c7c,0x3c423c3c,0x3c3c3c00,
2947       0x7c3a3a3a,0x3a087c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x4200000,0x10000020,0x0,0x0,0x10,0x0,0x30000000,0x0,
2948       0x0,0x0,0x60000,0x0,0x1c,0x4380000,0x0,0x2,0x800,0x0,0x40020000,0x0,0x8000c,0x10600000,0x2010,0x48000000,0x240000,0x0,0x0,
2949       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,
2950       0x84008,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x20000040,0x0,0x0,0x20,0x0,0x1e000000,0x0,0x0,0x0,0x20000,0x0,
2951       0x0,0x2000000,0x0,0x26,0x800,0x0,0x40020000,0x0,0x100000,0x10000000,0x2030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x1000,0x0,
2952       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,
2953       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,
2954       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,
2955       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,
2956       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2957       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2958       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2959       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
2960 
2961     // Definition of a 10x19 font.
2962     const unsigned int font10x19[10*19*256/32] = {
2963       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2964       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,
2965       0x0,0x180181c0,0xe81b0300,0x1801,0x81c06c18,0x181c06c,0xe8180,0x181c0e81,0xb0000006,0x60701b,0x1800000,0x0,0x0,0x0,0x0,0x0,
2966       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2967       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,
2968       0x0,0x0,0x0,0x0,0x0,0x0,0xc030360,0xb81b0480,0xc03,0x3606c0c,0x303606c,0xb80c0,0x30360b81,0xb0000003,0xc0d81b,0x3000000,0x0,
2969       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,
2970       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,
2971       0x22000,0x0,0x0,0x0,0x0,0x0,0x0,0x30000,0x0,0xe0,0x38078000,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000c080,0x480,0x3000,
2972       0xc0800030,0xc08000,0x300,0xc080000,0xc,0x302000,0xc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x41c01,0xe020060c,
2973       0x800000,0x4,0x1e0703e0,0xf8060fc1,0xe1fe1e07,0x80000000,0x78,0x307e0,0x3c7c1fe7,0xf83c408f,0x80f10440,0x18660878,0x7e0787e0,
2974       0x78ff9024,0xa0140a0,0x27f83840,0x700e000,0x18000400,0x8000,0x70004002,0x410078,0x0,0x0,0x0,0x0,0x1808,0xc000000,0xf000000,
2975       0xe000000,0x1400,0x1e0001f,0x8007f800,0x0,0x0,0x3a3b,0x61400000,0x14202,0x20000,0x38002020,0x3c1b00,0x3e00000,0xf8,0x1c0001c0,
2976       0x78060001,0xf800000e,0x1e00020,0x8004020,0xc0300c0,0x300c0301,0xf83c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1821e0,0x781e0781,0xe0001f10,
2977       0x24090240,0xa02400f8,0x18018140,0xe81b0480,0x1801,0x81406c18,0x181406c,0x190e8180,0x18140e81,0xb0000006,0x60501b,0x184006c,
2978       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x26042202,0x200c06,0x800000,0x8,0x210d0611,0x40e0803,0x10026188,0x40000000,
2979       0x8c,0xf030418,0xc6431004,0xc64082,0x110840,0x18660884,0x41084410,0x8c081024,0xa012110,0x40082020,0x101b000,0xc000400,0x8000,
2980       0x80004002,0x410008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x18800000,0x10000000,0x2200,0x2300024,0x800,0x0,0x0,0x2e13,0x60800000,
2981       0x8104,0x20040,0x64001040,0x80401b07,0x80100000,0x1e000,0x22000020,0x40c0003,0xc8000002,0x3300020,0x8004020,0xc0300c0,0x300c0301,
2982       0x40c64010,0x4010008,0x2008020,0x43182210,0x84210842,0x10002190,0x24090240,0x9044018c,0xc030220,0xb81b0300,0xc03,0x2206c0c,
2983       0x302206c,0x1e0b80c0,0x30220b81,0xb0000003,0xc0881b,0x304006c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x241f2202,
2984       0x200802,0x4900000,0x8,0x21010408,0x20a0802,0x44090,0x20000000,0x4,0x11878408,0x80411004,0x804082,0x111040,0x1ce50986,0x40986409,
2985       0x81022,0x12012108,0x80102020,0x1031800,0x400,0x8000,0x80004000,0x10008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x10000000,
2986       0x10000000,0x18,0x4000044,0x1000,0x30180,0xd81b0000,0x13,0xe0000000,0x88,0x40,0x400018c0,0x80400018,0x61f00000,0x61800,0x22020020,
2987       0x4000007,0xc8000002,0x2100020,0x8038000,0x1e0781e0,0x781e0301,0x40804010,0x4010008,0x2008020,0x41142619,0x86619866,0x18002190,
2988       0x24090240,0x8887e104,0x0,0x0,0x0,0x0,0x0,0x2000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x2434a202,
2989       0x200802,0x3e00000,0x10,0x40810008,0x21a0804,0x44090,0x20000000,0x80040004,0x20848409,0x409004,0x1004082,0x112040,0x14a50902,
2990       0x40902409,0x81022,0x11321208,0x80202010,0x1060c00,0x7c5e0,0x781e8783,0xf07a5f0e,0x1c10808,0xfc5f078,0x5e07a170,0x7c7e1024,
2991       0xa016190,0x27f82008,0x2000000,0x20000000,0x10000000,0x80200024,0x4000044,0x2000,0x18180,0xc8320000,0x12,0xa1f00037,0x7f888,
2992       0x1e0,0x40410880,0x80600017,0xa2100000,0x5e800,0x22020040,0x38001027,0xc8000002,0x2100020,0x8004020,0x12048120,0x48120482,
2993       0x41004010,0x4010008,0x2008020,0x40942409,0x2409024,0x9044390,0x24090240,0x88841918,0x1f07c1f0,0x7c1f07c3,0x70781e07,0x81e07838,
2994       0xe0380e0,0x1f17c1e0,0x781e0781,0xe0001f90,0x24090240,0x9025e102,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xff241c41,
2995       0x1001,0x1c02000,0x10,0x40810008,0x6120f85,0xe0086190,0x20c03007,0x8007800c,0x27848419,0x409004,0x1004082,0x114040,0x14a48902,
2996       0x40902409,0x81022,0x11321205,0x602010,0x1000000,0x86610,0x84218840,0x80866182,0x411008,0x9261884,0x61086189,0x82101022,0x12012108,
2997       0x40082008,0x2000000,0x20030000,0x20000000,0x80200024,0x4000044,0x3006030,0xc018100,0x4c260000,0x12,0x26080048,0x83000850,
2998       0x20250,0x403e0500,0x8078002c,0x12302200,0x92400,0x1c0200c0,0x4001027,0xc8000002,0x3308820,0x8004020,0x12048120,0x48120482,
2999       0x41004010,0x4010008,0x2008020,0x40922409,0x2409024,0x8884690,0x24090240,0x85040920,0x21886218,0x86218860,0x88842108,0x42108408,
3000       0x2008020,0x21186210,0x84210842,0x10302190,0x24090240,0x88461084,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x4c240182,
3001       0x80001001,0x6b02000,0x20,0x4c810010,0x78220846,0x10081e10,0x20c0301c,0x1fe0e018,0x4d8487e1,0x409fe7,0xf9007f82,0x11a040,
3002       0x13248902,0x41102418,0xe0081022,0x11320c05,0x402008,0x1000000,0x2409,0x409020,0x81024082,0x412008,0x9240902,0x40902101,0x101022,
3003       0x11321208,0x40102008,0x2000000,0x7e0c8000,0xfc000003,0xf0fc0018,0x43802047,0x8c8040c8,0x32008300,0x44240000,0x0,0x4000048,
3004       0x8c801050,0x20440,0x40221dc0,0x808c0028,0x11d0667f,0x8009c400,0x1fc180,0x4001023,0xc8300002,0x1e0ccfb,0x3ec7b020,0x12048120,
3005       0x48120482,0x79007f9f,0xe7f9fe08,0x2008020,0xf0922409,0x2409024,0x8504490,0x24090240,0x85040920,0x802008,0x2008020,0x89004090,
3006       0x24090208,0x2008020,0x40902409,0x2409024,0x8304390,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
3007       0x481c0606,0xc8001001,0x802000,0x20,0x4c810020,0x4220024,0x8102108,0x60000070,0x3820,0x48884419,0x409004,0x10e4082,0x112040,
3008       0x13244902,0x7e1027e0,0x3c081021,0x21320c02,0x802008,0x1000000,0x7e409,0x409020,0x81024082,0x414008,0x9240902,0x40902101,
3009       0x80101022,0x11320c08,0x40202008,0x2038800,0x200bc000,0x20000000,0x80200003,0x80f04044,0xbc080bc,0x2f000200,0x0,0x0,0x6001048,
3010       0x8bc02020,0x20441,0xf8220200,0x80820028,0x1000cc00,0x80094400,0x201e0,0x78001021,0xc830000f,0x8000663c,0xf03c0c0,0x21084210,
3011       0x84210846,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8204890,0x24090240,0x82040930,0x1f87e1f8,0x7e1f87e0,0x89004090,
3012       0x24090208,0x2008020,0x40902409,0x2409024,0x8004690,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
3013       0x480719c4,0x48001001,0x81fc00,0x7800020,0x40810040,0x2420024,0x8104087,0xa0000070,0x3820,0x48884409,0x409004,0x1024082,0x111040,
3014       0x13244902,0x40102410,0x2081021,0x214a1202,0x1802008,0x1000000,0x182409,0x409fe0,0x81024082,0x41a008,0x9240902,0x40902100,
3015       0xf8101021,0x214a0c04,0x80c0c008,0x1847000,0x7c1ee000,0x20000000,0x8020000c,0x8c044,0x1ee181ee,0x7b800000,0x707,0xf3ff0000,
3016       0x3e0084f,0x9ee0c020,0x20440,0x40221fc0,0xc2002c,0x13f11000,0x87892400,0x20000,0x1020,0x48000000,0x3f011c6,0x31cc6180,0x21084210,
3017       0x84210844,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8505090,0x24090240,0x8204191c,0x60982609,0x82609823,0xf9007f9f,
3018       0xe7f9fe08,0x2008020,0x40902409,0x2409024,0x9fe4c90,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xfe048224,
3019       0x28001001,0x2000,0x40,0x40810080,0x27f8024,0x8104080,0x2000001c,0x1fe0e020,0x488fc409,0x409004,0x1024082,0x110840,0x10242902,
3020       0x40102408,0x2081021,0x214a1202,0x1002004,0x1000000,0x102409,0x409000,0x81024082,0x411008,0x9240902,0x40902100,0x6101021,
3021       0x214a0c04,0x81002008,0x2000000,0x201dc000,0x20000000,0x80200000,0x98044,0x1dc101dc,0x77000000,0x700,0x0,0x180448,0x1dc10020,
3022       0x20440,0x403e0200,0x620017,0xa000cc00,0x80052800,0x20000,0x1020,0x48000000,0x6606,0x206100,0x3f0fc3f0,0xfc3f0fc7,0xc1004010,
3023       0x4010008,0x2008020,0x4090a409,0x2409024,0x8886090,0x24090240,0x8207e106,0x40902409,0x2409024,0x81004010,0x4010008,0x2008020,
3024       0x40902409,0x2409024,0x8005890,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98048224,0x30001001,0x2000,
3025       0x40,0x21010100,0x2020024,0x8204080,0x40000007,0x80078000,0x48884408,0x80411004,0x824082,0x110840,0x10242986,0x40086409,0x2081021,
3026       0xe14a2102,0x2002004,0x1000000,0x106409,0x409000,0x81024082,0x410808,0x9240902,0x40902100,0x2101021,0x214a1202,0x82002008,
3027       0x2000000,0x300f8000,0x20000000,0x80fc001d,0xe4088044,0xf8200f8,0x3e000000,0x300,0x0,0x80c48,0xf820020,0x20640,0x40410200,
3028       0x803c0018,0x60006600,0x61800,0x0,0x1020,0x48000000,0xcc0a,0x20a100,0x21084210,0x84210844,0x40804010,0x4010008,0x2008020,
3029       0x4110a619,0x86619866,0x19046110,0x24090240,0x82040102,0x41906419,0x6419064,0x81004010,0x4010008,0x2008020,0x40902409,0x2409024,
3030       0x8307090,0x24090240,0x82840828,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x90248222,0x30000802,0x200c,0xc080,0x21010301,
3031       0x4021042,0x10202108,0xc0c03000,0x80040020,0x4d902418,0xc6431004,0xc24082,0x6210440,0x10241884,0x40084409,0x86080840,0xc0842102,
3032       0x4002002,0x1000000,0x18e610,0x84218820,0x80864082,0x410408,0x9240884,0x61086101,0x6101860,0xc0842103,0x4002008,0x2000000,
3033       0x10850180,0x20330000,0x80200013,0x26184024,0x5040050,0x14000000,0x0,0x0,0x4180848,0x85040020,0x20350,0x40000200,0x800c0007,
3034       0x80002200,0x1e000,0x0,0x1860,0x48000000,0x880a,0x40a188,0x40902409,0x2409028,0x40c64010,0x4010008,0x2008020,0x43106210,0x84210842,
3035       0x10006108,0x42108421,0x2040102,0x6398e639,0x8e6398e4,0x88842088,0x22088208,0x2008020,0x21102210,0x84210842,0x10306118,0x66198661,
3036       0x83061030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0x901f01c1,0xe8000802,0xc,0xc080,0x1e07c7f8,0xf8020f81,0xe0401e07,
3037       0x80c03000,0x20,0x279027e0,0x3c7c1fe4,0x3c408f,0x83c1027f,0x90241878,0x4007c404,0xf8080780,0xc0844082,0x7f82002,0x1000000,
3038       0xfa5e0,0x781e87c0,0x807a409f,0xc0410207,0x9240878,0x5e07a100,0xf80e0fa0,0xc0846183,0x7f82008,0x2000000,0xf020100,0x40321360,
3039       0x80200014,0xa3e0201f,0x8207f820,0x8000000,0x0,0x0,0x3e01037,0x207f820,0x201e1,0xfc000200,0x80040000,0x0,0x0,0x1fc000,0x17b0,
3040       0x48000000,0x12,0xc120f0,0x40902409,0x2409028,0x783c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1061e0,0x781e0781,0xe000be07,0x81e0781e,
3041       0x204017c,0x3e8fa3e8,0xfa3e8fa3,0x70781f07,0xc1f07c7f,0x1fc7f1fc,0x1e1021e0,0x781e0781,0xe0007e0f,0xa3e8fa3e,0x8305e030,0x0,
3042       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,
3043       0x0,0x0,0x2001,0x1000000,0x0,0x0,0x20000,0x400000,0x0,0x40002000,0x0,0x1,0x2008,0x2000000,0x100,0x40240000,0x80200008,0x40000000,
3044       0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80040000,0x0,0x0,0x0,0x1000,0x48000000,0x1f,0x181f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3045       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,
3046       0x0,0x0,0x0,0x6000,0x0,0x10000000,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x3800,0x7000000,0x0,0x0,0x840000,0x400000,0x0,0x40002000,
3047       0x0,0x2,0x2008,0x2000000,0x200,0x40440000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80780000,0x0,0x0,0x0,0x1000,0x48000400,
3048       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,
3049       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,
3050       0x780000,0x3800000,0x0,0x40002000,0x0,0xe,0x1808,0xc000000,0x3,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,
3051       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,
3052       0x0,0x0,0x0,0x0,0x0,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,
3053       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,
3054       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3055 
3056     // Definition of a 12x24 font.
3057      const unsigned int font12x24[12*24*256/32] = {
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,
3059        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,
3060        0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc001806,0xc81980,0x60000000,0xc001806,0x1980c00,0x18060198,0xc80c,
3061        0x180600,0xc8198000,0xc001,0x80601980,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3062        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3063        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,
3064        0x0,0x0,0x0,0x0,0x0,0x0,0x600300f,0x1301980,0x90000000,0x600300f,0x1980600,0x300f0198,0x13006,0x300f01,0x30198000,0x6003,
3065        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,
3066        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3067        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,
3068        0x80000000,0x90000000,0x3006019,0x80000300,0x60198000,0x3,0x601980,0x0,0x3006,0x1980000,0x60000000,0x0,0x0,0xe0000000,0x0,
3069        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3070        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,
3071        0x0,0x0,0x0,0x0,0x0,0xc800019,0x80000000,0x198000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x1001,0x420000,0x0,0x0,0x90000000,
3072        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000c06,0xc80001,0x10000000,0x18000c06,0x1800,0xc060000,0xc818,0xc0600,0xc8000000,
3073        0x18000,0xc0600000,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80660207,0x800f8060,0x300c004,0x0,0x6,
3074        0xe00703f,0x3f00383,0xf80f07fc,0x1f01f000,0x0,0xf8,0x607f,0x7c7e07,0xfe7fe0f8,0x6063fc1f,0x86066007,0xe7060f0,0x7f80f07f,
3075        0x81f8fff6,0x6606c03,0x70ee077f,0xe0786000,0xf0070000,0xc000060,0xc0,0x3e000,0x60006003,0x600fc00,0x0,0x0,0x0,0x0,0x0,0x3c0603,
3076        0xc0000000,0x7800000,0xf0000,0x0,0xf00001f,0x80001fe0,0x7fe000,0x0,0x0,0x0,0x168fe609,0x0,0x90e07,0x6000,0x3c000e,0x70000f8,
3077        0x1980001f,0x0,0x1f8,0xf00000f,0xf00180,0xfe000,0xe00e,0x1001,0x20060,0x6006006,0x600600,0x600fe07c,0x7fe7fe7f,0xe7fe3fc3,
3078        0xfc3fc3fc,0x7e07060f,0xf00f00,0xf00f0000,0xf360660,0x6606606e,0x76001e0,0xc00180f,0x1681981,0x10000000,0xc00180f,0x1980c00,
3079        0x180f0198,0x3801680c,0x180f01,0x68198000,0xc001,0x80f01980,0x18600198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,
3080        0x8044020c,0xc01f8060,0x2004004,0x0,0xc,0x3f81f07f,0x87f80383,0xf81f87fc,0x3f83f800,0x0,0x1fc,0x780607f,0x81fe7f87,0xfe7fe1fc,
3081        0x6063fc1f,0x860c6007,0xe7061f8,0x7fc1f87f,0xc3fcfff6,0x6606c03,0x30c6067f,0xe0783000,0xf00d8000,0x6000060,0xc0,0x7e000,0x60006003,
3082        0x600fc00,0x0,0x0,0xc00,0x0,0x0,0x7c0603,0xe0000000,0xfc00000,0x1f0000,0x0,0x900003f,0xc0003fe0,0x7fe000,0x0,0x0,0x0,0x1302660f,
3083        0x0,0xf0606,0x6004,0x7e0006,0x60601f8,0x19800001,0x80000000,0x1f8,0x19800010,0x81080300,0x3f2000,0x2011,0x1001,0x1c0060,0x6006006,
3084        0x600600,0x601fe1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f87061f,0x81f81f81,0xf81f8000,0x3fa60660,0x66066066,0x66003f0,0x6003009,
3085        0x1301981,0x10000000,0x6003009,0x1980600,0x30090198,0x1f013006,0x300901,0x30198000,0x6003,0x901980,0x30600198,0x0,0x0,0x0,
3086        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc0f8c,0xc0180060,0x6006044,0x40000000,0xc,0x3181b041,0xc41c0783,0x388018,
3087        0x71c71800,0x0,0x106,0x18c0f061,0xc38261c6,0x600384,0x60606001,0x86186007,0xe78630c,0x60e30c60,0xe7040606,0x630cc03,0x39c30c00,
3088        0xc0603000,0x3018c000,0x3000060,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,0x60000000,0x18400000,0x180000,
3089        0x0,0x19800070,0x40003600,0xc000,0x0,0x0,0x0,0x25a06,0x0,0x6030c,0x4,0xe20007,0xe060180,0xf000,0x80000000,0xf0000,0x10800000,
3090        0x80080600,0x7f2000,0x2020,0x80001001,0x20000,0xf00f00f,0xf00f00,0x601b0382,0x60060060,0x6000600,0x60060060,0x61c78630,0xc30c30c3,
3091        0xc30c000,0x30e60660,0x66066063,0xc600738,0x3006019,0x80000000,0xe0000000,0x3006019,0x80000300,0x60198000,0x3e000003,0x601980,
3092        0x0,0x3006,0x1980000,0x60600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc1fcc,0xc0180060,0x6006035,0x80000000,
3093        0x18,0x71c03000,0xc00c0583,0x300018,0x60c60c00,0x0,0x6,0x3060f060,0xc30060c6,0x600300,0x60606001,0x86306007,0x9e78670e,0x60670e60,
3094        0x66000606,0x630c606,0x19830c01,0xc0601800,0x30306000,0x60,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,
3095        0x60000000,0x18000000,0x300000,0x0,0x78060,0x6600,0x1c000,0x300c,0x39819c0,0x0,0x25a00,0x0,0x30c,0x4,0xc00003,0xc060180,0x30c1f,
3096        0x80000000,0x30c000,0x10800001,0x80700000,0x7f2000,0x2020,0x80001001,0x20060,0xf00f00f,0xf00f00,0xf01b0300,0x60060060,0x6000600,
3097        0x60060060,0x60c78670,0xe70e70e7,0xe70e000,0x70c60660,0x66066063,0xc7f8618,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0,
3098        0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x87ff3a4c,0xc0180060,0x400600e,0x600000,0x18,0x60c03000,
3099        0xc00c0d83,0x700018,0x60c60c00,0x20,0x400006,0x3060f060,0xc6006066,0x600600,0x60606001,0x86606006,0x966c6606,0x60660660,0x66000606,
3100        0x630c666,0xf019801,0x80601800,0x30603000,0x1f06f,0xf01ec0,0xf03fe1ec,0x6703e01f,0x61c0c06,0xdc6701f0,0x6f01ec0c,0xe1f87fc6,
3101        0xc60cc03,0x71c60c7f,0xc0600600,0x60000000,0x30000000,0x300000,0x40040,0x88060,0x6600,0x18000,0x300c,0x1981980,0x0,0x2421f,
3102        0x80003ce0,0x7fc198,0x601f,0xc02021,0x980600c0,0x40230,0x80000000,0x402000,0x19806003,0x80006,0xc7f2000,0x2020,0x80001001,
3103        0x420060,0xf00f00f,0xf00f00,0xf01b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x6606208,0x60e60660,0x66066061,
3104        0x987fc670,0x1f01f01f,0x1f01f01,0xf039c0f0,0xf00f00f,0xf03e03,0xe03e03e0,0x1f06701f,0x1f01f01,0xf01f0060,0x1e660c60,0xc60c60c6,
3105        0xc6f060c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x7ff3207,0x8c0c0000,0xc00300e,0x600000,0x30,0x60c03000,
3106        0xc01c0983,0xf0600030,0x31860c06,0x6001e0,0x78000e,0x23e1f861,0xc6006066,0x600600,0x60606001,0x86c06006,0x966c6606,0x60660660,
3107        0xe7000606,0x630c666,0xf01f803,0x600c00,0x30000000,0x3f87f,0x83f83fc3,0xf83fe3fc,0x7f83e01f,0x6380c07,0xfe7f83f8,0x7f83fc0d,
3108        0xf3fc7fc6,0xc71cc03,0x3183187f,0xc0600600,0x60000000,0xff806000,0x300000,0x40040,0x88070,0x6600,0x60030060,0x6001818,0x1883180,
3109        0x0,0x2423f,0xc0007ff0,0x607fc1f8,0x603f,0x80c01fc1,0xf80601e0,0x5f220,0x80420000,0x5f2000,0xf006006,0x80006,0xc7f2000,0x2020,
3110        0x82107c07,0xc03c0060,0x1f81f81f,0x81f81f80,0xf03b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x660671c,0x61660660,
3111        0x66066061,0xf860e6c0,0x3f83f83f,0x83f83f83,0xf87fe3f8,0x3f83f83f,0x83f83e03,0xe03e03e0,0x3f87f83f,0x83f83f83,0xf83f8060,
3112        0x3fc60c60,0xc60c60c3,0x187f8318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x883200,0x300c0000,0xc003035,0x80600000,
3113        0x30,0x66c03001,0xc0f81983,0xf86f0030,0x1f071c06,0x600787,0xfe1e001c,0x6261987f,0x86006067,0xfe7fc600,0x7fe06001,0x87c06006,
3114        0xf6646606,0x60e6067f,0xc3e00606,0x61986f6,0x600f007,0x600c00,0x30000000,0x21c71,0x830831c3,0x1c06031c,0x71c06003,0x6700c06,
3115        0x6671c318,0x71831c0f,0x16040c06,0xc318606,0x1b031803,0x80600600,0x60000000,0x30009000,0x300000,0x40040,0x7003e,0x67e0,0x90070090,
3116        0x9001818,0x8c3100,0x0,0x60,0x4000e730,0x900380f0,0x6034,0x80c018c7,0xfe060338,0xb0121,0x80c60000,0x909000,0x6008,0x1080006,
3117        0xc3f2000,0x2011,0x3180060,0x60060e0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0x60664660,0x66066066,
3118        0x66063b8,0x62660660,0x66066060,0xf06066c0,0x21c21c21,0xc21c21c2,0x1c466308,0x31c31c31,0xc31c0600,0x60060060,0x31871c31,0x83183183,
3119        0x18318000,0x71860c60,0xc60c60c3,0x18718318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1981a00,0xe03e0000,0xc003044,
3120        0x40600000,0x60,0x66c03001,0x80f03182,0x1c7f8030,0x3f83fc06,0x601e07,0xfe078038,0x6661987f,0x86006067,0xfe7fc61e,0x7fe06001,
3121        0x87e06006,0x66666606,0x7fc6067f,0x81f80606,0x61986f6,0x6006006,0x600600,0x30000000,0xc60,0xc60060c6,0xc06060c,0x60c06003,
3122        0x6e00c06,0x6660c60c,0x60c60c0e,0x6000c06,0xc318666,0x1f031803,0x600600,0x603c2000,0x30016800,0x1fe0000,0x1f81f8,0x1c1f,0x804067e1,
3123        0x68060168,0x16800810,0xc42300,0x0,0x60,0x20c331,0x68030060,0x6064,0x3fc1040,0xf006031c,0xa011e,0x818c7fe0,0x909000,0x7fe1f,
3124        0x80f00006,0xc0f2060,0xf80e,0x18c0780,0x780781c0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0xfc666660,
3125        0x66066066,0x66061f0,0x66660660,0x66066060,0x606066e0,0xc00c00,0xc00c00c0,0xc066600,0x60c60c60,0xc60c0600,0x60060060,0x60c60c60,
3126        0xc60c60c6,0xc60c000,0x61c60c60,0xc60c60c3,0x1860c318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1980f81,0x80373000,
3127        0xc003004,0x7fe0001,0xf0000060,0x60c03003,0x183180,0xc71c060,0x3181ec00,0x7000,0xe070,0x66619860,0xc6006066,0x60061e,0x60606001,
3128        0x87606006,0x66626606,0x7f860661,0xc01c0606,0x6198696,0xf00600e,0x600600,0x30000000,0x1fc60,0xc60060c7,0xfc06060c,0x60c06003,
3129        0x7c00c06,0x6660c60c,0x60c60c0c,0x7f00c06,0xc3b8666,0xe01b007,0x3c00600,0x3c7fe000,0xff03ec00,0x1fe0000,0x40040,0xe001,0xc0806603,
3130        0xec0e03ec,0x3ec00010,0x0,0x60000000,0x7f,0x10c3f3,0xec070060,0x6064,0x3fc1040,0x6000030c,0xa0100,0x3187fe1,0xf09f1000,0x7fe00,
3131        0x6,0xc012060,0x0,0xc63c03,0xc03c0380,0x19819819,0x81981981,0x98330600,0x60060060,0x6000600,0x60060060,0xfc662660,0x66066066,
3132        0x66060e0,0x6c660660,0x66066060,0x6060e630,0x1fc1fc1f,0xc1fc1fc1,0xfc3fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
3133        0xc60c7fe,0x62c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe02c6,0x3c633000,0xc003004,
3134        0x7fe0001,0xf00000c0,0x60c03006,0xc6180,0xc60c060,0x60c00c00,0x7000,0xe060,0x66639c60,0x66006066,0x600606,0x60606001,0x86306006,
3135        0x66636606,0x60060660,0xc0060606,0x61f8696,0xf00600c,0x600300,0x30000000,0x3fc60,0xc60060c7,0xfc06060c,0x60c06003,0x7c00c06,
3136        0x6660c60c,0x60c60c0c,0x1f80c06,0xc1b0666,0xe01b00e,0x3c00600,0x3c43c000,0x3007de00,0x600000,0x40040,0x30000,0x61006607,0xde0c07de,
3137        0x7de00000,0x0,0xf07fefff,0x1f,0x8008c3f7,0xde0e0060,0x6064,0xc01047,0xfe00018c,0xb013f,0x86300061,0xf0911000,0x6000,0x6,
3138        0xc012060,0x3f,0x8063c0cc,0x3cc0c700,0x39c39c39,0xc39c39c1,0x98630600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,
3139        0x66061f0,0x78660660,0x66066060,0x607fc618,0x3fc3fc3f,0xc3fc3fc3,0xfc7fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
3140        0xc60c7fe,0x64c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe0260,0x6661b000,0xc003000,
3141        0x600000,0xc0,0x60c0300c,0xc7fe0,0xc60c060,0x60c01c00,0x1e07,0xfe078060,0x6663fc60,0x66006066,0x600606,0x60606001,0x86386006,
3142        0x6636606,0x60060660,0xe0060606,0x60f039c,0x1b806018,0x600300,0x30000000,0x70c60,0xc60060c6,0x6060c,0x60c06003,0x7600c06,
3143        0x6660c60c,0x60c60c0c,0x1c0c06,0xc1b03fc,0xe01f01c,0xe00600,0x70000000,0x3007fc00,0x600000,0x40040,0x0,0x62006607,0xfc1807fc,
3144        0x7fc00000,0x0,0xf0000000,0x1,0xc004c307,0xfc1c0060,0x6064,0xc018c0,0x600000d8,0x5f200,0x3180060,0x50a000,0x6000,0x6,0xc012000,
3145        0x0,0xc601c0,0x4201c600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,0x66063b8,
3146        0x70660660,0x66066060,0x607f860c,0x70c70c70,0xc70c70c7,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,
3147        0x68c60c60,0xc60c60c1,0xf060c1f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3300260,0x6661e000,0xc003000,0x600000,
3148        0x180,0x71c03018,0xc7fe0,0xc60c0c0,0x60c01800,0x787,0xfe1e0060,0x6663fc60,0x630060c6,0x600306,0x60606001,0x86186006,0x661e70e,
3149        0x60070c60,0x60060606,0x60f039c,0x19806038,0x600180,0x30000000,0x60c60,0xc60060c6,0x6060c,0x60c06003,0x6700c06,0x6660c60c,
3150        0x60c60c0c,0xc0c06,0xc1b039c,0x1f00e018,0x600600,0x60000000,0x1803f800,0x600000,0x40040,0x39e00,0x63006603,0xf83803f8,0x3f800000,
3151        0x0,0x60000000,0x0,0xc00cc303,0xf8180060,0x6064,0xc01fc0,0x60060070,0x40200,0x18c0060,0x402000,0x6000,0x6,0xc012000,0x0,0x18c0140,
3152        0x2014600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0300,0x60060060,0x6000600,0x60060060,0x60c61e70,0xe70e70e7,0xe70e71c,0x60e60660,0x66066060,
3153        0x6060060c,0x60c60c60,0xc60c60c6,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,0x70c60c60,0xc60c60c0,
3154        0xe060c0e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33022e0,0x6670c000,0xc003000,0x600600,0x60180,0x31803030,
3155        0x41c0184,0x1831c0c0,0x71c23806,0x6001e0,0x780000,0x62630c60,0xe38261c6,0x600386,0x60606043,0x860c6006,0x661e30c,0x60030c60,
3156        0x740e0607,0xe0f039c,0x31c06030,0x600180,0x30000000,0x61c71,0x830831c3,0x406031c,0x60c06003,0x6300c06,0x6660c318,0x71831c0c,
3157        0x41c0c07,0x1c0e039c,0x1b00e030,0x600600,0x60000000,0x1c41b00e,0x601cc0,0x401f8,0x45240,0xe1803601,0xb03001b0,0x1b000000,
3158        0x0,0x0,0x41,0xc008e711,0xb0300060,0x6034,0x80c02020,0x60060030,0x30c00,0xc60000,0x30c000,0x0,0x7,0x1c012000,0x0,0x3180240,
3159        0x6024608,0x30c30c30,0xc30c30c3,0xc630382,0x60060060,0x6000600,0x60060060,0x61c61e30,0xc30c30c3,0xc30c208,0x70c70e70,0xe70e70e0,
3160        0x6060068c,0x61c61c61,0xc61c61c6,0x1cc62308,0x30430430,0x43040600,0x60060060,0x31860c31,0x83183183,0x18318060,0x31c71c71,
3161        0xc71c71c0,0xe07180e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2203fc0,0x663f6000,0x6006000,0x600600,0x60300,
3162        0x3f81fe7f,0xc7f80187,0xf83f80c0,0x3f83f006,0x600020,0x400060,0x33e6067f,0xc1fe7f87,0xfe6001fe,0x6063fc7f,0x60e7fe6,0x660e3f8,
3163        0x6001f860,0x37fc0603,0xfc06030c,0x30c0607f,0xe06000c0,0x30000000,0x7fc7f,0x83f83fc3,0xfc0603fc,0x60c7fe03,0x61807c6,0x6660c3f8,
3164        0x7f83fc0c,0x7f80fc3,0xfc0e039c,0x3180607f,0xc0600600,0x60000000,0xfc0e00c,0x601986,0x66040040,0x4527f,0xc0803fe0,0xe07fe0e0,
3165        0xe000000,0x0,0x0,0x7f,0x80107ff0,0xe07fc060,0x603f,0x83fe0000,0x60060018,0xf000,0x420000,0xf0000,0x7fe00,0x7,0xfe012000,
3166        0x0,0x2100640,0xc0643f8,0x60660660,0x66066067,0xec3e1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f860e3f,0x83f83f83,0xf83f8000,
3167        0x5fc3fc3f,0xc3fc3fc0,0x606006fc,0x7fc7fc7f,0xc7fc7fc7,0xfcffe3f8,0x3fc3fc3f,0xc3fc7fe7,0xfe7fe7fe,0x3f860c3f,0x83f83f83,
3168        0xf83f8060,0x7f83fc3f,0xc3fc3fc0,0x607f8060,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2201f80,0x3c1e7000,0x6006000,
3169        0x600,0x60300,0xe01fe7f,0xc3f00183,0xe01f0180,0x1f01e006,0x600000,0x60,0x3006067f,0x807c7e07,0xfe6000f8,0x6063fc3e,0x6067fe6,
3170        0x660e0f0,0x6000f060,0x3bf80601,0xf806030c,0x60e0607f,0xe06000c0,0x30000000,0x1ec6f,0xf01ec0,0xf80601ec,0x60c7fe03,0x61c03c6,
3171        0x6660c1f0,0x6f01ec0c,0x3f007c1,0xcc0e030c,0x71c0c07f,0xc0600600,0x60000000,0x7804018,0xe01186,0x66040040,0x39e3f,0x80401fe0,
3172        0x407fe040,0x4000000,0x0,0x0,0x3f,0x203ce0,0x407fc060,0x601f,0x3fe0000,0x60060018,0x0,0x0,0x0,0x7fe00,0x6,0xe6012000,0x0,
3173        0x7e0,0x1807e1f0,0x60660660,0x66066066,0x6c3e07c,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7e060e0f,0xf00f00,0xf00f0000,0x8f01f81f,
3174        0x81f81f80,0x60600670,0x1ec1ec1e,0xc1ec1ec1,0xec79c0f0,0xf80f80f,0x80f87fe7,0xfe7fe7fe,0x1f060c1f,0x1f01f01,0xf01f0000,0x4f01cc1c,
3175        0xc1cc1cc0,0xc06f00c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x6006000,0x600,0x600,0x0,0x0,0x0,0x0,
3176        0x600000,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x600060,0x30000000,0x0,0x0,0xc,0x3,0x0,0x0,0x60000c00,0x0,
3177        0x0,0xc000,0x600600,0x60000000,0x18,0xc03100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f8,0x0,0x0,0x0,0x0,0x6,
3178        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,
3179        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,
3180        0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0xc00,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x21c,0x3,0x0,0x0,0x60000c00,0x0,0x0,0xc000,
3181        0x7c0603,0xe0000000,0x10,0xc02300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f0,0x0,0x0,0x0,0x0,0x6,0x12000,0x1000000,
3182        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,
3183        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,
3184        0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x3f8,0x3e,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x3c0603,0xc0000000,
3185        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,
3186        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,
3187        0x0,0x0,0x0,0x0,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,
3188        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,
3189        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,
3190        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,
3191        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,
3192        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3193        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3194 
3195     // Definition of a 16x32 font.
3196     const unsigned int font16x32[16*32*256/32] = {
3197       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
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,
3199       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,
3200       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70000e0,0x3c00730,0xe7001c0,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0x730,0x70000e0,0x3c00730,
3201       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,
3202       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
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,
3204       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,
3205       0x0,0x0,0x18001c0,0x6600ff0,0xe7003e0,0x0,0x18001c0,0x6600e70,0x18001c0,0x6600e70,0xff0,0x18001c0,0x6600ff0,0xe700000,0x180,
3206       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,
3207       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
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,0x3c00000,
3209       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,
3210       0xc300ce0,0xe700630,0x0,0x1c00380,0xc300e70,0x1c00380,0xc300e70,0xce0,0x1c00380,0xc300ce0,0xe700000,0x1c0,0x3800c30,0xe700380,
3211       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,
3212       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3213       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,
3214       0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x700000,0x0,0x0,0x0,0x7c007c00,0x3e000000,
3215       0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000070,0x1800000,0xc60,0x0,0xe000070,0x1800000,0xe000070,
3216       0x1800000,0x0,0xe000070,0x1800000,0x0,0xe00,0x700180,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3217       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,
3218       0x0,0x0,0x3f0,0xfc0,0x0,0x7000000,0x38000000,0x1c0000,0xfc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,
3219       0x1801f00,0x0,0x0,0x1c,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7300000,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0xe700000,
3220       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,
3221       0xf80,0x70000e0,0x3c00730,0xe700c60,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0xe000730,0x70000e0,0x3c00730,0xe700000,0x700,
3222       0xe003c0,0xe7000e0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300000,0x803c00,0x7c00180,
3223       0xc00300,0x1000000,0x0,0x1c,0x3c007c0,0xfc007e0,0xe01ff8,0x3f03ffc,0x7e007c0,0x0,0x0,0x7c0,0x1c0,0x7f8003f0,0x7f007ff8,0x7ff803f0,
3224       0x70381ffc,0xff0700e,0x7000783c,0x783807c0,0x7fc007c0,0x7fc00fc0,0x7fff7038,0x700ee007,0x780f780f,0x7ffc03f0,0x70000fc0,0x3c00000,
3225       0x3000000,0x38000000,0x1c0000,0x1fc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x1801f80,0x0,0x1f80000,
3226       0x7e,0x0,0x0,0x2400000,0xfc00000,0x7ff0000,0x7ffc0000,0x0,0x0,0x0,0x0,0xf30fb0c,0x2400000,0x0,0x240780f,0x1c0,0xfc,0x780f,
3227       0x18003f0,0xe700000,0x7c00000,0x0,0xff0,0x3c00000,0x78007c0,0xc00000,0xff80000,0xf80,0x7c00000,0xc000c00,0x18001c0,0x1c001c0,
3228       0x1c001c0,0x1c003e0,0x7fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007838,0x7c007c0,0x7c007c0,0x7c00000,0x7c67038,
3229       0x70387038,0x7038780f,0x70001fe0,0x30000c0,0x2400f30,0xe700c60,0x0,0x30000c0,0x2400e70,0x30000c0,0x2400e70,0xf700f30,0x30000c0,
3230       0x2400f30,0xe700000,0x300,0xc00240,0xe7000c0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,
3231       0x630018c,0x807e00,0xfe00180,0xc00300,0x1000000,0x0,0x38,0xff01fc0,0x3ff01ff0,0x1e01ff8,0x7f83ffc,0x1ff80ff0,0x0,0x0,0xff0,
3232       0x1f003e0,0x7fe00ff8,0x7fc07ff8,0x7ff80ff8,0x70381ffc,0xff0701c,0x7000783c,0x78381ff0,0x7fe01ff0,0x7fe01ff0,0x7fff7038,0x781ee007,
3233       0x3c1e380e,0x7ffc0380,0x380001c0,0x3c00000,0x1800000,0x38000000,0x1c0000,0x3c00000,0x380001c0,0xe01c00,0x3800000,0x0,0x0,
3234       0x0,0x7000000,0x0,0x0,0x1e0,0x18003c0,0x0,0x3fc0000,0x70,0x0,0x0,0x6600000,0x1ff00000,0x1fff0000,0x7ffc0000,0x0,0x0,0x0,0x0,
3235       0xcf0239c,0x3c00000,0x0,0x3c0380e,0x1c0,0x2001fe,0x380e,0x18007f8,0xe700000,0x8600000,0x0,0xff0,0x7e00000,0x8c00870,0x1800000,
3236       0x1ff80000,0x180,0xc600000,0xc000c00,0x38001c0,0x3e003e0,0x3e003e0,0x3e001c0,0x7fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,
3237       0x7fc07838,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x1fec7038,0x70387038,0x7038380e,0x70003ce0,0x1800180,0x6600cf0,0xe7007c0,0x0,
3238       0x1800180,0x6600e70,0x1800180,0x6600e70,0x7c00cf0,0x1800180,0x6600cf0,0xe700000,0x180,0x1800660,0xe700180,0x38000e70,0x0,
3239       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630030c,0x3f0e700,0x1e200180,0x1800180,0x21100000,0x0,
3240       0x38,0x1e7819c0,0x38781038,0x1e01c00,0xf080038,0x1c381c38,0x0,0x0,0x1878,0x7fc03e0,0x70e01e18,0x70e07000,0x70001e18,0x703801c0,
3241       0x707038,0x70007c7c,0x7c381c70,0x70701c70,0x70703830,0x1c07038,0x381ce007,0x1c1c3c1e,0x3c0380,0x380001c0,0x7e00000,0xc00000,
3242       0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,0x70c0000,0xe0,
3243       0x0,0x0,0xc300000,0x38300000,0x3c700000,0x3c0000,0x0,0x0,0x0,0x0,0xce022f4,0x1800000,0x0,0x1803c1e,0x1c0,0x2003c2,0x3c1e,
3244       0x1800e08,0x7e0,0x300000,0x0,0x7e00000,0xe700000,0x600030,0x3000000,0x3f980000,0x180,0x18200000,0xc000c00,0x1e0001c0,0x3e003e0,
3245       0x3e003e0,0x3e003e0,0xfe01e18,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70e07c38,0x1c701c70,0x1c701c70,0x1c700000,0x3c787038,
3246       0x70387038,0x70383c1e,0x70003870,0xc00300,0xc300ce0,0x380,0x0,0xc00300,0xc300000,0xc00300,0xc300000,0xfc00ce0,0xc00300,0xc300ce0,
3247       0x0,0xc0,0x3000c30,0x300,0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630031c,0xff8c300,
3248       0x1c000180,0x1800180,0x39380000,0x0,0x70,0x1c3801c0,0x203c001c,0x3e01c00,0x1c000038,0x381c3838,0x0,0x0,0x1038,0xe0e03e0,0x70703c08,
3249       0x70707000,0x70003808,0x703801c0,0x707070,0x70007c7c,0x7c383838,0x70383838,0x70387010,0x1c07038,0x381c700e,0x1e3c1c1c,0x780380,
3250       0x1c0001c0,0xe700000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,
3251       0x0,0xe000000,0xe0,0x0,0x1000100,0x3800,0x70100000,0x38700000,0x780000,0x1c0,0x7801ce0,0xe380000,0x0,0x2264,0x0,0x0,0x1c1c,
3252       0x0,0x200780,0x1c1c,0x1800c00,0x1818,0x7f00000,0x0,0x18180000,0xc300000,0x600070,0x0,0x7f980000,0x180,0x18300000,0xc000c00,
3253       0x3000000,0x3e003e0,0x3e003e0,0x3e003e0,0xee03c08,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,
3254       0x38380000,0x38387038,0x70387038,0x70381c1c,0x7fc03870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbc00000,0x0,0x0,0x0,0x0,0x0,0x0,
3255       0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0xe88c300,0x1c000180,0x38001c0,
3256       0xfe00180,0x0,0x70,0x1c3801c0,0x1c001c,0x6e01c00,0x1c000078,0x381c3818,0x0,0x40000,0x40000038,0x1c0607e0,0x70703800,0x70707000,
3257       0x70003800,0x703801c0,0x7070e0,0x70007c7c,0x7c383838,0x70383838,0x70387000,0x1c07038,0x381c700e,0xf780e38,0x700380,0x1c0001c0,
3258       0x1c380000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,
3259       0xe000000,0xe0,0x0,0x1000100,0x4400,0x70000000,0x38700000,0x700000,0xe0,0x7001c70,0xe380000,0x0,0x2264,0x0,0x0,0xe38,0x0,
3260       0x200700,0xe38,0x1800c00,0x300c,0xc300000,0x0,0x300c0000,0xc300180,0x6003c0,0x0,0x7f980000,0x180,0x18300000,0xc000c00,0x1800000,
3261       0x7e007e0,0x7e007e0,0x7e003e0,0xee03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,0x38380000,
3262       0x38387038,0x70387038,0x70380e38,0x7ff039f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x40000,0x0,0x0,0x38000000,
3263       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0x1c80e700,0x1c000180,0x38001c0,0x3800180,
3264       0x0,0xe0,0x381c01c0,0x1c001c,0x6e01c00,0x38000070,0x381c381c,0x0,0x3c0000,0x78000078,0x38030770,0x70707800,0x70387000,0x70007000,
3265       0x703801c0,0x7071c0,0x7000745c,0x7638701c,0x7038701c,0x70387000,0x1c07038,0x1c38718e,0x7700f78,0xf00380,0xe0001c0,0x381c0000,
3266       0x7e0,0x39e003e0,0x79c03f0,0x3ffc079c,0x39e01fc0,0xfe01c1e,0x3807778,0x39e007e0,0x39e0079c,0x73c07e0,0x7ff83838,0x701ce007,
3267       0x783c701c,0x1ffc01c0,0x18001c0,0x0,0x1c000100,0xe0,0x0,0x1000100,0x4200,0x70000000,0x70700100,0xf00100,0x10000e0,0x7000c70,
3268       0xc700000,0x0,0x2204,0x7e00000,0x1e380100,0x1ffc0f78,0x0,0xf80700,0xf78,0x1800e00,0x63e6,0x18300000,0x0,0x6fe60000,0xe700180,
3269       0xc00060,0x3838,0x7f980000,0x180,0x18300000,0xc000c00,0x18001c0,0x7700770,0x7700770,0x77007f0,0xee07800,0x70007000,0x70007000,
3270       0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1008,0x707c7038,0x70387038,0x70380f78,0x707039c0,0x7e007e0,0x7e007e0,
3271       0x7e007e0,0x1f3c03e0,0x3f003f0,0x3f003f0,0x1fc01fc0,0x1fc01fc0,0x7f039e0,0x7e007e0,0x7e007e0,0x7e00380,0x7ce3838,0x38383838,
3272       0x3838701c,0x39e0701c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6307fff,0x1c807e0c,0xe000180,
3273       0x30000c0,0x3800180,0x0,0xe0,0x381c01c0,0x1c001c,0xce01fe0,0x38000070,0x381c381c,0x3800380,0xfc0000,0x7e0000f0,0x30030770,
3274       0x70707000,0x70387000,0x70007000,0x703801c0,0x707380,0x700076dc,0x7638701c,0x7038701c,0x70387800,0x1c07038,0x1c3873ce,0x7f00770,
3275       0xe00380,0xe0001c0,0x700e0000,0x1ff8,0x3ff00ff0,0xffc0ff8,0x3ffc0ffc,0x3bf01fc0,0xfe01c3c,0x3807f78,0x3bf00ff0,0x3ff00ffc,
3276       0x77e0ff0,0x7ff83838,0x3838e007,0x3c783838,0x1ffc01c0,0x18001c0,0x0,0x7ff00380,0x1e0,0x0,0x1000100,0x4200,0x78000000,0x70700380,
3277       0xe00380,0x3800060,0xe000e30,0x1c600000,0x0,0x2204,0xff00000,0x7f7c0380,0x1ffc0770,0x1c0,0x3fc0700,0x18040770,0x1800780,0x4e12,
3278       0x18300104,0x0,0x4c320000,0x7e00180,0x1c00030,0x3838,0x7f980000,0x180,0x18302080,0xc000c00,0x18001c0,0x7700770,0x7700770,
3279       0x7700770,0x1ee07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c381c,0x705c7038,0x70387038,
3280       0x70380770,0x70383b80,0x1ff81ff8,0x1ff81ff8,0x1ff81ff8,0x3fbe0ff0,0xff80ff8,0xff80ff8,0x1fc01fc0,0x1fc01fc0,0xff83bf0,0xff00ff0,
3281       0xff00ff0,0xff00380,0xffc3838,0x38383838,0x38383838,0x3ff03838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3282       0x0,0x1c0,0x7fff,0x1c803c38,0xf000000,0x70000e0,0xfe00180,0x0,0x1c0,0x381c01c0,0x3c0078,0xce01ff0,0x39e000f0,0x1c38381c,0x3800380,
3283       0x3e07ffc,0xf8001f0,0x307b0770,0x70e07000,0x70387000,0x70007000,0x703801c0,0x707700,0x700076dc,0x7638701c,0x7038701c,0x70387e00,
3284       0x1c07038,0x1c3873ce,0x3e007f0,0x1e00380,0x70001c0,0x0,0x1038,0x3c381e18,0x1c7c1e3c,0x3801e3c,0x3c7801c0,0xe01c78,0x380739c,
3285       0x3c781c38,0x3c381c3c,0x7c21e10,0x7003838,0x3838700e,0x1ef03838,0x3c01c0,0x18001c0,0x0,0x7fe007c0,0x1c0,0x0,0x1000100,0x6400,
3286       0x7e000000,0x707007c0,0x1e007c0,0x7c00070,0xe000638,0x18600000,0x0,0x0,0x1e100000,0x73ce07c0,0x3c07f0,0x1c0,0x7240700,0x1ddc3ffe,
3287       0x1800de0,0x8c01,0x1870030c,0x0,0x8c310000,0x3c00180,0x3800030,0x3838,0x7f980000,0x180,0x183030c0,0xc000c00,0x430001c0,0x7700770,
3288       0x7700770,0x7700770,0x1ce07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1c38,0x70dc7038,
3289       0x70387038,0x703807f0,0x70383b80,0x10381038,0x10381038,0x10381038,0x21e71e18,0x1e3c1e3c,0x1e3c1e3c,0x1c001c0,0x1c001c0,0x1e383c78,
3290       0x1c381c38,0x1c381c38,0x1c380380,0x1c383838,0x38383838,0x38383838,0x3c383838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3291       0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0x1e8000e0,0x1f000000,0x70000e0,0x39380180,0x0,0x1c0,0x3b9c01c0,0x3c07f0,0x18e01078,0x3bf800e0,
3292       0x7e0383c,0x3800380,0x1f807ffc,0x3f001c0,0x61ff0e38,0x7fc07000,0x70387ff0,0x7ff07000,0x7ff801c0,0x707f00,0x7000729c,0x7338701c,
3293       0x7070701c,0x70703fc0,0x1c07038,0x1e7873ce,0x1c003e0,0x3c00380,0x70001c0,0x0,0x1c,0x3c381c00,0x1c3c1c1c,0x3801c3c,0x383801c0,
3294       0xe01cf0,0x380739c,0x38381c38,0x3c381c3c,0x7801c00,0x7003838,0x3838700e,0xfe03c78,0x7801c0,0x18001c0,0x0,0x1c000c20,0xff8,
3295       0x0,0x1ff01ff0,0x3818,0x3fc00100,0x707e0c20,0x3c00c20,0xc200030,0xc000618,0x18c00000,0x0,0x0,0x1c000080,0xe1ce0c20,0x7803e0,
3296       0x1c0,0xe200700,0xff83ffe,0x1801878,0x9801,0x1cf0071c,0x7ffc0000,0x8c310000,0x7ffe,0x7000030,0x3838,0x3f980380,0x180,0xc6038e0,
3297       0x7f9c7f9c,0x3e1c01c0,0xe380e38,0xe380e38,0xe380f78,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,0x1c001c0,0xfe387338,0x701c701c,
3298       0x701c701c,0x701c0e70,0x719c7038,0x70387038,0x703803e0,0x70383b80,0x1c001c,0x1c001c,0x1c001c,0xe71c00,0x1c1c1c1c,0x1c1c1c1c,
3299       0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380000,0x3c383838,0x38383838,0x38383c78,0x3c383c78,0x0,0x0,0x0,0x0,
3300       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0xf800380,0x3f830000,0x70000e0,0x31080180,0x0,0x380,0x3b9c01c0,
3301       0x7807e0,0x38e00038,0x3c3800e0,0xff01c3c,0x3800380,0x7c000000,0x7c03c0,0x61870e38,0x7fc07000,0x70387ff0,0x7ff070fc,0x7ff801c0,
3302       0x707f80,0x7000739c,0x7338701c,0x7ff0701c,0x7fe00ff0,0x1c07038,0xe7073ce,0x1c003e0,0x3800380,0x38001c0,0x0,0x1c,0x381c3800,
3303       0x381c380e,0x380381c,0x383801c0,0xe01de0,0x380739c,0x3838381c,0x381c381c,0x7001e00,0x7003838,0x1c70718e,0x7e01c70,0xf00380,
3304       0x18001e0,0x1e000000,0x1c001bb0,0xff8,0x0,0x1000100,0xe0,0xff00300,0x707e1bb0,0x3801bb0,0x1bb00010,0x8000308,0x30c00000,0x0,
3305       0x0,0x1e0000c0,0xe1ce1bb0,0xf003e0,0x1c0,0x1c203ff8,0x63003e0,0x180181c,0x9801,0xfb00e38,0x7ffc0000,0x8fc10000,0x7ffe,0xe000860,
3306       0x3838,0x1f980380,0x180,0x7c01c70,0x1f001f0,0x1f003c0,0xe380e38,0xe380e38,0xe380e38,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,
3307       0x1c001c0,0xfe387338,0x701c701c,0x701c701c,0x701c07e0,0x731c7038,0x70387038,0x703803e0,0x70383980,0x1c001c,0x1c001c,0x1c001c,
3308       0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x387c3838,0x38383838,0x38381c70,
3309       0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc30,0x7f00e00,0x33c30000,0x70000e0,0x1007ffe,
3310       0x0,0x380,0x3b9c01c0,0xf00078,0x30e0001c,0x3c1c01c0,0x1c381fdc,0x0,0x70000000,0x1c0380,0x63030e38,0x70707000,0x70387000,0x700070fc,
3311       0x703801c0,0x707b80,0x7000739c,0x7338701c,0x7fc0701c,0x7fc001f0,0x1c07038,0xe703e5c,0x3e001c0,0x7800380,0x38001c0,0x0,0x7fc,
3312       0x381c3800,0x381c380e,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7001fc0,0x7003838,0x1c70718e,0x7c01c70,
3313       0xe01f00,0x180007c,0x7f8c0000,0x7fc03fb8,0x1c0,0x0,0x1000100,0x700,0x1f00600,0x70703fb8,0x7803fb8,0x3fb80000,0x8000000,0x180,
3314       0x0,0x0,0x1fc00060,0xe1ce3fb8,0xe001c0,0x1c0,0x1c203ff8,0xc1801c0,0x180c,0x9801,0x1c70,0xc0000,0x8cc10000,0x180,0xfe007c0,
3315       0x3838,0x7980380,0xff0,0xe38,0x3e003e00,0x3e000380,0xe380e38,0xe380e38,0xe380e38,0x38e07000,0x70007000,0x70007000,0x1c001c0,
3316       0x1c001c0,0x70387338,0x701c701c,0x701c701c,0x701c03c0,0x731c7038,0x70387038,0x703801c0,0x703838e0,0x7fc07fc,0x7fc07fc,0x7fc07fc,
3317       0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x38dc3838,0x38383838,0x38381c70,
3318       0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc60,0xf83878,0x71e30000,0x70000e0,0x1007ffe,
3319       0x7f0,0x380,0x381c01c0,0x1e0003c,0x60e0001c,0x381c01c0,0x381c079c,0x0,0x7c000000,0x7c0380,0x63031c1c,0x70307000,0x70387000,
3320       0x7000701c,0x703801c0,0x7071c0,0x7000739c,0x71b8701c,0x7000701c,0x71e00078,0x1c07038,0xe703e7c,0x7e001c0,0xf000380,0x38001c0,
3321       0x0,0x1ffc,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fc0,0x380739c,0x3838381c,0x381c381c,0x7000ff0,0x7003838,0x1ef03bdc,
3322       0x3800ee0,0x1e01f00,0x180007c,0x61fc0000,0x7fc07f3c,0x1c0,0x0,0x1000100,0x1800,0x780c00,0x70707f3c,0xf007f3c,0x7f3c0000,0x0,
3323       0x3c0,0x3ffcffff,0x0,0xff00030,0xe1fe7f3c,0x1e001c0,0x1c0,0x1c200700,0xc183ffe,0xe0c,0x9801,0x1ff038e0,0xc07f0,0x8c610000,
3324       0x180,0x0,0x3838,0x1980380,0x0,0x1ff0071c,0xe000e000,0xe0000f80,0x1c1c1c1c,0x1c1c1c1c,0x1c1c1e38,0x38e07000,0x70007000,0x70007000,
3325       0x1c001c0,0x1c001c0,0x703871b8,0x701c701c,0x701c701c,0x701c03c0,0x761c7038,0x70387038,0x703801c0,0x70703870,0x1ffc1ffc,0x1ffc1ffc,
3326       0x1ffc1ffc,0xfff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x389c3838,0x38383838,
3327       0x38380ee0,0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xfffc,0xbc60fc,0x70e30000,0x70000e0,
3328       0x180,0x7f0,0x700,0x381c01c0,0x3e0001c,0x7ffc001c,0x381c03c0,0x381c001c,0x0,0x1f807ffc,0x3f00380,0x63031ffc,0x70387000,0x70387000,
3329       0x7000701c,0x703801c0,0x7071e0,0x7000701c,0x71b8701c,0x7000701c,0x70f00038,0x1c07038,0x7e03e7c,0x77001c0,0xe000380,0x1c001c0,
3330       0x0,0x3c1c,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x70003f8,0x7003838,0xee03bdc,
3331       0x3c00ee0,0x3c00380,0x18000e0,0xf00000,0x1c007e7c,0x3c0,0x0,0x1000100,0x0,0x381800,0x70707e7c,0xe007e7c,0x7e7c0000,0x0,0x7c0,
3332       0x0,0x0,0x3f80018,0xe1fe7e7c,0x3c001c0,0x1c0,0x1c200700,0xc183ffe,0xf0c,0x8c01,0x38e0,0xc07f0,0x8c710000,0x180,0x0,0x3838,
3333       0x1980000,0x0,0x71c,0x7000f0,0x700f00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x3fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
3334       0x703871b8,0x701c701c,0x701c701c,0x701c07e0,0x7c1c7038,0x70387038,0x703801c0,0x7ff03838,0x3c1c3c1c,0x3c1c3c1c,0x3c1c3c1c,
3335       0x3fff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x391c3838,0x38383838,0x38380ee0,
3336       0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffc,0x9c01ce,0x70f60000,0x70000e0,0x180,
3337       0x0,0x700,0x381c01c0,0x780001c,0x7ffc001c,0x381c0380,0x381c003c,0x0,0x3e07ffc,0xf800380,0x63031ffc,0x70387000,0x70387000,
3338       0x7000701c,0x703801c0,0x7070f0,0x7000701c,0x71b8701c,0x7000701c,0x70700038,0x1c07038,0x7e03e7c,0xf7801c0,0x1e000380,0x1c001c0,
3339       0x0,0x381c,0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7000078,0x7003838,0xee03a5c,
3340       0x7c00fe0,0x78001c0,0x18001c0,0x0,0x1c003ef8,0x380,0x0,0x1000100,0x810,0x383000,0x70703ef8,0x1e003ef8,0x3ef80000,0x0,0x7c0,
3341       0x0,0x0,0x78000c,0xe1c03ef8,0x78001c0,0x1c0,0x1c200700,0x63001c0,0x18003f8,0x4e12,0x1c70,0xc0000,0x4c320000,0x180,0x0,0x3838,
3342       0x1980000,0x0,0xe38,0x700118,0x701e00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x7fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
3343       0x703871b8,0x701c701c,0x701c701c,0x701c0e70,0x7c1c7038,0x70387038,0x703801c0,0x7fc0381c,0x381c381c,0x381c381c,0x381c381c,
3344       0x78e03800,0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x3b1c3838,0x38383838,0x38380fe0,
3345       0x381c0fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1860,0x9c0186,0x707e0000,0x30000c0,0x180,
3346       0x0,0xe00,0x183801c0,0xf00001c,0xe0001c,0x181c0380,0x381c0038,0x0,0xfc0000,0x7e000000,0x61873c1e,0x70383800,0x70707000,0x7000381c,
3347       0x703801c0,0x707070,0x7000701c,0x70f83838,0x70003838,0x70780038,0x1c07038,0x7e03c3c,0xe3801c0,0x1c000380,0xe001c0,0x0,0x381c,
3348       0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01ef0,0x380739c,0x3838381c,0x381c381c,0x7000038,0x7003838,0xfe03e7c,0xfe007c0,
3349       0x70001c0,0x18001c0,0x0,0xe001ff0,0x380,0x0,0x1000100,0x162c,0x381800,0x30701ff0,0x1c001ff0,0x1ff00000,0x0,0x3c0,0x0,0x0,
3350       0x380018,0xe1c01ff0,0x70001c0,0x1c0,0x1c200700,0xff801c0,0x18000f0,0x63e6,0xe38,0x0,0x6c3e0000,0x0,0x0,0x3838,0x1980000,0x0,
3351       0x1c70,0xf0000c,0xf01c00,0x3c1e3c1e,0x3c1e3c1e,0x3c1e3c1c,0x70e03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x707070f8,
3352       0x38383838,0x38383838,0x38381c38,0x38387038,0x70387038,0x703801c0,0x7000381c,0x381c381c,0x381c381c,0x381c381c,0x70e03800,
3353       0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0380,0x3e1c3838,0x38383838,0x383807c0,0x381c07c0,
3354       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18c0,0x9c0186,0x783c0000,0x38001c0,0x180,0x3800000,
3355       0x3800e00,0x1c3801c0,0x1e00003c,0xe00038,0x1c1c0780,0x381c0038,0x3800380,0x3c0000,0x78000000,0x61ff380e,0x70383808,0x70707000,
3356       0x7000381c,0x703801c0,0x40707078,0x7000701c,0x70f83838,0x70003838,0x70384038,0x1c07038,0x7e03c3c,0x1e3c01c0,0x3c000380,0xe001c0,
3357       0x0,0x383c,0x3c381c00,0x1c3c1c00,0x3801c3c,0x383801c0,0xe01c78,0x380739c,0x38381c38,0x3c381c3c,0x7000038,0x7003878,0x7c01e78,
3358       0x1ef007c0,0xf0001c0,0x18001c0,0x0,0xe000ee0,0x7800380,0xe380000,0x1001ff0,0x2242,0x40380c00,0x38700ee0,0x3c000ee0,0xee00000,
3359       0x0,0x0,0x0,0x0,0x380030,0xe1c00ee0,0xf0001c0,0x1c0,0xe200700,0xdd801c0,0x1800038,0x300c,0x71c,0x0,0x300c0000,0x0,0x0,0x3838,
3360       0x1980000,0x0,0x38e0,0xb0000c,0xb01c08,0x380e380e,0x380e380e,0x380e380e,0x70e03808,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
3361       0x707070f8,0x38383838,0x38383838,0x3838381c,0x38387038,0x70387038,0x703801c0,0x7000381c,0x383c383c,0x383c383c,0x383c383c,
3362       0x70e01c00,0x1c001c00,0x1c001c00,0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383878,0x38783878,0x387807c0,
3363       0x3c3807c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x18c0,0x10b801ce,0x3c3e0000,0x38001c0,0x180,
3364       0x3800000,0x3801c00,0x1e7801c0,0x3c002078,0xe02078,0x1c380700,0x1c3810f0,0x3800380,0x40000,0x40000380,0x307b380e,0x70701e18,
3365       0x70e07000,0x70001c1c,0x703801c0,0x60e0703c,0x7000701c,0x70f83c78,0x70003c70,0x703c70f0,0x1c03870,0x3c01c3c,0x3c1c01c0,0x78000380,
3366       0x7001c0,0x0,0x3c7c,0x3c381e18,0x1c7c1e0c,0x3801c3c,0x383801c0,0xe01c38,0x3c0739c,0x38381c38,0x3c381c3c,0x7001078,0x7803c78,
3367       0x7c01c38,0x1c780380,0x1e0001c0,0x18001c0,0x0,0x70c06c0,0x7000380,0xe300000,0x1000100,0x2142,0x70f00600,0x3c7006c0,0x780006c0,
3368       0x6c00000,0x0,0x0,0x0,0x0,0x10780060,0x73e206c0,0x1e0001c0,0x1c0,0x7240700,0x180c01c0,0x1800018,0x1818,0x30c,0x0,0x18180000,
3369       0x0,0x0,0x3c78,0x1980000,0x0,0x30c0,0x130000c,0x1301c18,0x380e380e,0x380e380e,0x380e380e,0x70e01e18,0x70007000,0x70007000,
3370       0x1c001c0,0x1c001c0,0x70e070f8,0x3c783c78,0x3c783c78,0x3c781008,0x7c783870,0x38703870,0x387001c0,0x70003a3c,0x3c7c3c7c,0x3c7c3c7c,
3371       0x3c7c3c7c,0x79f11e18,0x1e0c1e0c,0x1e0c1e0c,0x1c001c0,0x1c001c0,0x1c783838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383c78,0x3c783c78,
3372       0x3c780380,0x3c380380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x38c0,0x1ff800fc,0x1fee0000,
3373       0x1800180,0x180,0x3800000,0x3801c00,0xff01ffc,0x3ffc3ff0,0xe03ff0,0xff00700,0x1ff81fe0,0x3800380,0x0,0x380,0x3000780f,0x7ff00ff8,
3374       0x7fc07ff8,0x70000ffc,0x70381ffc,0x7fe0701c,0x7ff8701c,0x70781ff0,0x70001ff0,0x701c7ff0,0x1c01fe0,0x3c01c38,0x380e01c0,0x7ffc0380,
3375       0x7001c0,0x0,0x1fdc,0x3ff00ff0,0xffc0ffc,0x3800fdc,0x38383ffe,0xe01c3c,0x1fc739c,0x38380ff0,0x3ff00ffc,0x7001ff0,0x3f81fb8,
3376       0x7c01c38,0x3c3c0380,0x1ffc01c0,0x18001c0,0x0,0x3fc0380,0x7000380,0xc70718c,0x1000100,0x2244,0x7ff00200,0x1fff0380,0x7ffc0380,
3377       0x3800000,0x0,0x0,0x0,0x0,0x1ff000c0,0x7f7e0380,0x1ffc01c0,0x1c0,0x3fc3ffe,0x1c0,0x1800018,0x7e0,0x104,0x0,0x7e00000,0x7ffe,
3378       0x0,0x3fde,0x1980000,0x0,0x2080,0x3300018,0x3300ff0,0x780f780f,0x780f780f,0x780f780e,0xf0fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,
3379       0x1ffc1ffc,0x7fc07078,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x7ff01fe0,0x1fe01fe0,0x1fe001c0,0x70003bf8,0x1fdc1fdc,0x1fdc1fdc,
3380       0x1fdc1fdc,0x3fbf0ff0,0xffc0ffc,0xffc0ffc,0x3ffe3ffe,0x3ffe3ffe,0xff03838,0xff00ff0,0xff00ff0,0xff00000,0x3ff01fb8,0x1fb81fb8,
3381       0x1fb80380,0x3ff00380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x31c0,0x7e00078,0x7cf0000,0x1800180,
3382       0x0,0x3800000,0x3803800,0x3c01ffc,0x3ffc0fe0,0xe01fc0,0x3e00e00,0x7e00f80,0x3800380,0x0,0x380,0x18007007,0x7fc003f0,0x7f007ff8,
3383       0x700003f0,0x70381ffc,0x3f80701e,0x7ff8701c,0x707807c0,0x700007c0,0x701e1fc0,0x1c00fc0,0x3c01818,0x780f01c0,0x7ffc0380,0x3801c0,
3384       0x0,0xf9c,0x39e003e0,0x79c03f0,0x380079c,0x38383ffe,0xe01c1e,0x7c739c,0x383807e0,0x39e0079c,0x7000fc0,0x1f80f38,0x3801c38,
3385       0x781e0380,0x1ffc01c0,0x18001c0,0x0,0x1f80100,0xe000700,0x1c60718c,0x1000100,0x1e3c,0x1fc00100,0x7ff0100,0x7ffc0100,0x1000000,
3386       0x0,0x0,0x0,0x0,0xfc00080,0x3e3c0100,0x1ffc01c0,0x1c0,0xf83ffe,0x1c0,0x1800838,0x0,0x0,0x0,0x0,0x7ffe,0x0,0x3b9e,0x1980000,
3387       0x0,0x0,0x2300038,0x23003e0,0x70077007,0x70077007,0x70077007,0xe0fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007078,
3388       0x7c007c0,0x7c007c0,0x7c00000,0xc7c00fc0,0xfc00fc0,0xfc001c0,0x700039f0,0xf9c0f9c,0xf9c0f9c,0xf9c0f9c,0x1f1e03e0,0x3f003f0,
3389       0x3f003f0,0x3ffe3ffe,0x3ffe3ffe,0x7e03838,0x7e007e0,0x7e007e0,0x7e00000,0x63e00f38,0xf380f38,0xf380380,0x39e00380,0x0,0x0,
3390       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,
3391       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,
3392       0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1c0,0x18001c0,0x0,0x0,0xe000700,0x18600000,0x1000100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3393       0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800ff0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0x1800000,0x0,0x6300070,0x6300000,0x0,
3394       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,
3395       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,
3396       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,
3397       0x0,0x0,0x1c,0x0,0xe00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1e0,0x18003c0,0x0,0x0,0xc000700,0x18c00000,0x1000000,0x0,
3398       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x18007e0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000,
3399       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,
3400       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,
3401       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,
3402       0x3f0,0xfc0,0x0,0x0,0x0,0x0,0x838,0x0,0x1e00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0xf00,0xfc,0x1801f80,0x0,0x0,0x8008e00,0x30c00000,
3403       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,
3404       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,
3405       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,
3406       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,
3407       0x0,0x0,0xff0,0x0,0x1fc00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3e00,0x7c,0x1801f00,0x0,0x0,0x800fe00,0x0,0x0,0x0,0x0,0x0,0x0,
3408       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7c00000,0x0,0x3001fc,0x300000,
3409       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,
3410       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,
3411       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,
3412       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,
3413       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,
3414       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,
3415       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3416       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,0x0,
3417       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3418       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3419       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3420       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
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,
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,
3423       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3424       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3425       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3426       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3427       0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3428 
3429     // Definition of a 19x38 font.
3430     const unsigned int font19x38[19*38*256/32] = {
3431       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3432       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3433       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,
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,0x3800007,0x3c003,0x86000000,
3435       0x1e00000,0x3,0x80000700,0x3c00000,0x380000,0x70003c00,0x0,0xe1800e,0x1c00,0xf000e18,0x0,0x0,0x700000e0,0x780000,0x7000,0x0,
3436       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3437       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3438       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3439       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,
3440       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0000e,0x7e003,0xe60071c0,0x7f80000,0x1,0xc0000e00,0x7e0038e,0x1c0000,
3441       0xe0007e00,0x38e00000,0xf98007,0x3800,0x1f800f98,0x1c70000,0x0,0x380001c0,0xfc0071,0xc000e000,0x0,0x0,0x0,0x0,0x3e00000,0x0,
3442       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3443       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
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,
3445       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,
3446       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0001c,0xe7006,0x7c0071c0,0xe180000,0x0,0xe0001c00,0xe70038e,0xe0001,0xc000e700,0x38e00000,
3447       0x19f0003,0x80007000,0x39c019f0,0x1c70000,0x0,0x1c000380,0x1ce0071,0xc001c000,0x0,0x0,0x0,0x0,0x7f00000,0x0,0x0,0x0,0x0,0x0,
3448       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3449       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
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,0x3c00000,
3451       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,
3452       0x0,0x0,0x700038,0x1c3806,0x3c0071c0,0xc0c0000,0x0,0x70003800,0x1c38038e,0x70003,0x8001c380,0x38e00000,0x18f0001,0xc000e000,
3453       0x70e018f0,0x1c70000,0x0,0xe000700,0x3870071,0xc0038000,0x0,0x0,0x0,0x0,0xe380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3454       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3455       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3456       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,
3457       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,
3458       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,
3459       0xe,0x380,0x1800000,0xe00000,0x38001800,0x0,0x38,0xe00,0x6000000,0x0,0x1,0xc0000070,0x300000,0x3800,0x0,0x0,0x0,0x0,0x0,0x0,
3460       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,
3461       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,
3462       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,
3463       0x0,0x0,0xc3000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800000,0x0,0x0,0x0,0xe0,0x1c000f,0xc0000000,0x0,0x0,
3464       0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000007,0x3c003,0xc6000000,0xc180000,0x7,0x700,
3465       0x3c00000,0x700000,0x70003c00,0x0,0xf1801c,0x1c00,0xf000f18,0x0,0x0,0xe00000e0,0x780000,0x7000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3466       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,
3467       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,
3468       0x7,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf800e,0x3e0000,0x0,0x0,0x0,0x1e00000,0x0,0x1,
3469       0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7cc00,0x660,0x0,0x0,0x66000000,0x0,0x0,0x0,0x0,0x7,0x1c000000,0x0,0x0,0x0,0x3fe00000,
3470       0x0,0x0,0x7000000,0x0,0x0,0x0,0x3e0,0x7c001f,0xe0000000,0x0,0x0,0x0,0xe1c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3471       0x0,0x0,0x0,0x1f80,0x380000e,0x7e007,0xe60071c0,0xc180000,0x3,0x80000e00,0x7e0038e,0x380000,0xe0007e00,0x38e00f00,0x1f9800e,
3472       0x3800,0x1f801f98,0x1c70000,0x0,0x700001c0,0xfc0071,0xc000e007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3473       0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61c00600,0x1e00007e,0x70000,0x18003000,0x1800000,0x0,0x0,0x1c01f0,0x7e003f,0xc003f800,
3474       0x1e03ffc,0x7f01ff,0xfc03f000,0x7e000000,0x0,0x0,0xfc0,0x1e,0x7fe000,0x7e03fe00,0x3fff07ff,0xe007e038,0x383ffe0,0xff81c01,
3475       0xe1c000f8,0xf8f00e0,0xfc01ffc,0x3f00ff,0xc000fe07,0xfffc7007,0x1c007700,0x73c01ef,0x78ffff,0xfe0380,0xfe000,0x38000000,0x1800000,
3476       0x700000,0x38,0x1f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0xfc0000,
3477       0x0,0x7f00000,0x0,0x1,0x98000000,0x7f00000,0x3ffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0xcf81f,0xee3807e0,0x0,0x0,0x7e03c01e,0x1c,
3478       0x0,0x1f800000,0xf0078038,0xfc007,0x1c000000,0xfe00000,0x0,0x0,0x3fe000f0,0xf,0xc001f800,0x6000000,0xffc000,0x0,0x1c0007e0,
3479       0x360,0x6c0010,0x70000700,0xf0001e,0x3c000,0x78000f00,0x7f800ff,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,
3480       0x7807007,0xe000fc00,0x1f8003f0,0x7e0000,0x1f867,0x70e00e,0x1c01c380,0x38f00787,0x3fe0,0x180000c,0x66006,0x7c0071c0,0xe380000,
3481       0x1,0x80000c00,0x660038e,0x180000,0xc0006600,0x38e0078e,0x19f0006,0x3000,0x198019f0,0x1c70000,0x0,0x30000180,0xcc0071,0xc000c007,
3482       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,
3483       0x38003800,0x1800000,0x0,0x0,0x3807fc,0x1fe00ff,0xf00ffe00,0x3e03ffc,0xff81ff,0xfc07fc01,0xff800000,0x0,0x0,0x3fe0,0xfe001e,
3484       0x7ff801,0xff83ff80,0x3fff07ff,0xe01ff838,0x383ffe0,0xff81c03,0xc1c000f8,0xf8f80e0,0x3ff01fff,0xffc0ff,0xf003ff87,0xfffc7007,
3485       0x1e00f700,0x71c03c7,0x70ffff,0xfe01c0,0xfe000,0x7c000000,0xc00000,0x700000,0x38,0x3f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,
3486       0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0x3fe0000,0x0,0xff00000,0x0,0x3,0xc000000,0x1ffc0000,0xfffe00,
3487       0xffff0,0x0,0x0,0x0,0x0,0x0,0xc781f,0xee3803c0,0x0,0x0,0x3c01c01c,0x1c,0xc000,0x7fc00000,0x70070038,0x3fe007,0x1c000000,0x1ff80000,
3488       0x0,0x0,0x3fe003fc,0x1f,0xe003fc00,0xc000000,0x3ffc000,0x0,0x7c000ff0,0x60,0xc0000,0x30000700,0xf0001e,0x3c000,0x78000f00,
3489       0x3f000ff,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x7c0701f,0xf803ff00,0x7fe00ffc,0x1ff8000,0x7fe67,
3490       0x70e00e,0x1c01c380,0x38700707,0x7ff0,0xc00018,0xc3006,0x3c0071c0,0x7f00000,0x0,0xc0001800,0xc30038e,0xc0001,0x8000c300,0x38e003fc,
3491       0x18f0003,0x6000,0x30c018f0,0x1c70000,0x0,0x18000300,0x1860071,0xc0018007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3492       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe1801fc0,0x618001ff,0x70000,0x30001800,0x21840000,0x0,0x0,0x380ffe,0x1fe00ff,
3493       0xfc0fff00,0x3e03ffc,0x1ff81ff,0xfc0ffe03,0xffc00000,0x0,0x0,0x7ff0,0x3ff803f,0x7ffc03,0xffc3ffc0,0x3fff07ff,0xe03ffc38,0x383ffe0,
3494       0xff81c07,0x81c000f8,0xf8f80e0,0x7ff81fff,0x81ffe0ff,0xf80fff87,0xfffc7007,0xe00e700,0x70e0387,0x80f0ffff,0xe001c0,0xe000,
3495       0xfe000000,0xe00000,0x700000,0x38,0x3c,0x1c,0x1c00,0x1c00700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x78000e,0x3c000,
3496       0x0,0x7ff0000,0x0,0xf100000,0x0,0x7,0xe000000,0x7ffc0000,0x1fffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0x3,0xf780180,0x0,0x0,0x1801e03c,
3497       0x1c,0xc000,0xffc00000,0x780f0038,0x786000,0x7f00,0x18380000,0x0,0xfe00,0x30c,0x10,0x70020e00,0x1c000000,0x7f8c000,0x0,0x6c001c38,
3498       0x60,0xc0000,0x70000700,0x1f8003f,0x7e000,0xfc001f80,0x3f000ff,0xf03ffc1f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,
3499       0x7c0703f,0xfc07ff80,0xfff01ffe,0x3ffc000,0xffec7,0x70e00e,0x1c01c380,0x38780f07,0xf070,0xe00038,0x1c3800,0x0,0x3e00000,0x0,
3500       0xe0003800,0x1c380000,0xe0003,0x8001c380,0x3e0,0x3,0x8000e000,0x70e00000,0x0,0x0,0x1c000700,0x3870000,0x38007,0x0,0x0,0x0,
3501       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe3807ff0,0xc0c003c1,0x70000,0x70001c00,
3502       0x718e0000,0x0,0x0,0x700f1e,0x1ce00c0,0x3c0c0f80,0x7e03800,0x3e08000,0x381e0f03,0xc1e00000,0x0,0x0,0x7078,0x783c03f,0x701e07,
3503       0xc1c383e0,0x38000700,0x7c1c38,0x3801c00,0x381c0f,0x1c000fc,0x1f8f80e0,0x78781c07,0x81e1e0e0,0x780f0180,0xe007007,0xe00e380,
3504       0xe0f0783,0x80e0000e,0xe000e0,0xe001,0xef000000,0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,
3505       0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xf830000,0x0,0x1e000000,0x0,0x0,0x10000,0x780c0000,0x3e38000,0xe0,0x0,0x0,0x0,0x0,0x0,0x3,
3506       0xd580000,0x0,0x0,0xe038,0x1c,0xc000,0xf0400000,0x380e0038,0x702000,0x1ffc0,0xc0000,0x0,0x3ff80,0x606,0x0,0x30000600,0x0,
3507       0x7f8c000,0x0,0xc001818,0x60,0xc0003,0xe0000700,0x1f8003f,0x7e000,0xfc001f80,0x73801ee,0x7c1c1c,0x38000,0x70000e00,0xe0001,
3508       0xc0003800,0x700383e,0x7c0703c,0x3c078780,0xf0f01e1e,0x3c3c000,0xf0f87,0x70e00e,0x1c01c380,0x38380e07,0xe038,0x0,0x0,0x0,
3509       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,
3510       0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xc380fff0,0xc0c00380,0x70000,0x70001c00,0x3dbc0070,0x0,0x0,0x701e0f,0xe0000,0x1e000380,
3511       0x6e03800,0x7800000,0x781c0707,0x80e00000,0x0,0x0,0x4038,0xe00c03f,0x700e07,0x4380f0,0x38000700,0x700438,0x3801c00,0x381c0e,
3512       0x1c000ec,0x1b8fc0e0,0xf03c1c03,0xc3c0f0e0,0x3c1e0000,0xe007007,0xe00e380,0xe070703,0xc1e0001e,0xe000e0,0xe001,0xc7000000,
3513       0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xe010000,0x0,
3514       0x1c000000,0x10,0x20000,0x6c000,0xf0000000,0x3838000,0x1e0,0x0,0xf000f,0xf1e00,0x78f00000,0x0,0x3,0xdd80000,0x0,0x0,0xf078,
3515       0x0,0xc001,0xe0000000,0x1c1c0038,0x700000,0x3c1e0,0xc0000,0x0,0x783c0,0x606,0x0,0x30000e00,0x0,0xff8c000,0x0,0xc00300c,0x60,
3516       0xc0003,0xe0000000,0x1f8003f,0x7e000,0xfc001f80,0x73801ce,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x7e07078,
3517       0x1e0f03c1,0xe0783c0f,0x781e000,0x1c0787,0x70e00e,0x1c01c380,0x383c1e07,0xff00e038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x878,
3518       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,
3519       0x1c7000,0xc301e630,0xc0c00380,0x70000,0xe0000e00,0xff00070,0x0,0x0,0xe01c07,0xe0000,0xe000380,0xce03800,0x7000000,0x701c0707,
3520       0x600000,0x0,0x4000010,0x38,0x1c00e07f,0x80700e0e,0x38070,0x38000700,0xe00038,0x3801c00,0x381c1c,0x1c000ec,0x1b8ec0e0,0xe01c1c01,
3521       0xc38070e0,0x1c1c0000,0xe007007,0x701c380,0xe078e01,0xc1c0003c,0xe00070,0xe003,0x83800000,0x7f,0x71f000,0x3e003e38,0x3f007ff,
3522       0xe01f1c1c,0x7801fc00,0x3fc00701,0xe01c0077,0x8f071e00,0xf801c7c,0x7c700e,0x3e01fc03,0xfff8380e,0xe007700,0x73c0787,0x387ffc,
3523       0x70000e,0x1c000,0x0,0xe000000,0x0,0x1c000000,0x10,0x20000,0xc2000,0xe0000000,0x3838000,0x3c0,0x0,0xf000f,0x78e00,0x70e00000,
3524       0x0,0x3,0xc980fe0,0x1f0,0xf8000007,0xffc07070,0x0,0x3f801,0xc0000000,0x1e3c0038,0x700000,0x70070,0x7fc0000,0x0,0xe00e0,0x606,
3525       0x1c0000,0x70007c00,0x380e,0xff8c000,0x0,0xc00300c,0x60,0xc0000,0x70000000,0x3fc007f,0x800ff001,0xfe003fc0,0x73801ce,0xe0001c,
3526       0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,0x7607070,0xe0e01c1,0xc0383807,0x700e000,0x1c0387,0x70e00e,0x1c01c380,0x381c1c07,
3527       0xffc0e0f8,0x3f8007f,0xfe001,0xfc003f80,0x7f007e3,0xe003e001,0xf8003f00,0x7e000fc,0xfe001f,0xc003f800,0x7f00003c,0x38f0007,
3528       0xc000f800,0x1f0003e0,0x7c0007,0x8003f0c3,0x80e0701c,0xe0381c0,0x70700387,0x1f01c00e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3529       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0xc0c00380,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03c07,
3530       0x800e0000,0xe000380,0x1ce03800,0x7000000,0x701c0707,0x7003c0,0x780000,0x3c00001e,0x38,0x18006073,0x80700e0e,0x38070,0x38000700,
3531       0xe00038,0x3801c00,0x381c38,0x1c000ee,0x3b8ee0e1,0xe01e1c01,0xc78078e0,0x1c1c0000,0xe007007,0x701c387,0xe03de00,0xe3800038,
3532       0xe00070,0xe007,0x1c00000,0x1ff,0xc077f801,0xff807fb8,0xff807ff,0xe03fdc1d,0xfc01fc00,0x3fc00703,0xc01c007f,0xdf877f00,0x3fe01dfe,
3533       0xff700e,0xff07ff03,0xfff8380e,0x700f700,0x71e0f03,0x80707ffc,0x70000e,0x1c000,0x0,0x1c000008,0x0,0x1c000000,0x10,0x20000,
3534       0x82000,0xe0000000,0x7038000,0x80000380,0x2000040,0x7000e,0x38700,0xf1e00000,0x0,0x3,0xc183ff8,0x3fd,0xfc008007,0xffc038e0,
3535       0x0,0xffc01,0xc0008008,0xe380038,0x380000,0xe3e38,0x1ffc0040,0x80000000,0x1cfc70,0x606,0x1c0000,0xe0007c00,0x380e,0xff8c000,
3536       0x0,0xc00300c,0x8100060,0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0x73801ce,0xe0001c,0x38000,0x70000e00,0xe0001,
3537       0xc0003800,0x7003807,0x77070f0,0xf1e01e3,0xc03c7807,0x8f00f080,0x83c0787,0x70e00e,0x1c01c380,0x380e3807,0xffe0e1c0,0xffe01ff,
3538       0xc03ff807,0xff00ffe0,0x1ffc0ff7,0xf01ff807,0xfc00ff80,0x1ff003fe,0xfe001f,0xc003f800,0x7f0003fc,0x3bf801f,0xf003fe00,0x7fc00ff8,
3539       0x1ff0007,0x8007fd83,0x80e0701c,0xe0381c0,0x70380707,0x7f80e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3540       0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0x618081c0,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03803,0x800e0000,0xe000380,0x18e03800,
3541       0xf000000,0xf01c0707,0x7003c0,0x780000,0xfc00001f,0x80000078,0x301e6073,0x80700e1c,0x38038,0x38000700,0x1c00038,0x3801c00,
3542       0x381c70,0x1c000e6,0x338ee0e1,0xc00e1c01,0xc70038e0,0x1c1c0000,0xe007007,0x701c387,0xe01dc00,0xf7800078,0xe00070,0xe00e,0xe00000,
3543       0x3ff,0xe07ffc03,0xffc0fff8,0x1ffc07ff,0xe07ffc1d,0xfe01fc00,0x3fc00707,0x801c007f,0xdf877f80,0x7ff01fff,0x1fff00e,0xff07ff03,
3544       0xfff8380e,0x700e380,0xe0e0e03,0x80707ffc,0x70000e,0x1c000,0x0,0x7ffc001c,0x0,0x1c000000,0x10,0x20000,0x82000,0xe0000000,
3545       0x7038001,0xc0000780,0x70000e0,0x3800e,0x38700,0xe1c00000,0x0,0x3,0xc183ff8,0x7ff,0xfc01c007,0xffc03de0,0x0,0x1ffc01,0xc001c01c,
3546       0xf780038,0x3c0000,0xcff18,0x380c00c1,0x80000000,0x18fe30,0x30c,0x1c0001,0xc0000e00,0x380e,0xff8c000,0x0,0xc00300c,0xc180060,
3547       0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x877070e0,
3548       0x71c00e3,0x801c7003,0x8e0071c0,0x1c380fc7,0x70e00e,0x1c01c380,0x380f7807,0x1e0e380,0x1fff03ff,0xe07ffc0f,0xff81fff0,0x3ffe0fff,
3549       0xf03ffc0f,0xfe01ffc0,0x3ff807ff,0xfe001f,0xc003f800,0x7f0007fe,0x3bfc03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x800fff83,0x80e0701c,
3550       0xe0381c0,0x70380707,0xffc0e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,
3551       0xfff1c600,0x7f8381e0,0x70000,0xc0000600,0xff00070,0x0,0x0,0x1c03803,0x800e0000,0xe000f00,0x38e03fe0,0xe000000,0xe00e0e07,
3552       0x7003c0,0x780007,0xf0ffff87,0xf00000f0,0x307fe0f3,0xc0703c1c,0x38038,0x38000700,0x1c00038,0x3801c00,0x381ce0,0x1c000e6,0x338e70e1,
3553       0xc00e1c01,0xc70038e0,0x3c1e0000,0xe007007,0x783c38f,0x8e01fc00,0x770000f0,0xe00038,0xe01c,0x700000,0x381,0xe07c1e07,0xc0c1e0f8,
3554       0x3c1e0038,0xf07c1f,0xe001c00,0x1c0070f,0x1c0079,0xf3c7c380,0xf0781f07,0x83c1f00f,0xc10f0300,0x1c00380e,0x700e380,0xe0f1e03,
3555       0xc0f00078,0x70000e,0x1c000,0x0,0xfff8003e,0x0,0x3c000000,0x10,0x20000,0xc6000,0xf0000000,0x7038003,0xe0000f00,0xf8001f0,
3556       0x3801c,0x18300,0xe1800000,0x0,0x3,0xc187818,0x70f,0x9e03e000,0x7801dc0,0x1c,0x3cc401,0xc000efb8,0x7f7f0038,0x3f0000,0x1ce11c,
3557       0x300c01c3,0x80000000,0x38c638,0x3fc,0x1c0003,0x80000600,0x380e,0xff8c000,0x0,0xc00300c,0xe1c0060,0xc0010,0x70000700,0x79e00f3,
3558       0xc01e7803,0xcf0079e0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,
3559       0x8e0070e0,0x38381dc7,0x70e00e,0x1c01c380,0x38077007,0xf0e700,0x1c0f0381,0xe0703c0e,0x781c0f0,0x381e083e,0x787c0c1e,0xf03c1e0,
3560       0x783c0f07,0x800e0001,0xc0003800,0x7000fff,0x3e1c078,0x3c0f0781,0xe0f03c1e,0x783c000,0x1e0f03,0x80e0701c,0xe0381c0,0x70380f07,
3561       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,
3562       0xc0000700,0x3dbc0070,0x0,0x0,0x1c03803,0x800e0000,0x1e01fe00,0x70e03ff8,0xe3e0001,0xe007fc07,0x80f003c0,0x78001f,0xc0ffff81,
3563       0xfc0001e0,0x30e1e0e1,0xc07ff81c,0x38038,0x3ffe07ff,0xc1c0003f,0xff801c00,0x381de0,0x1c000e7,0x738e70e1,0xc00e1c03,0xc70038e0,
3564       0x780f8000,0xe007007,0x383838d,0x8e00f800,0x7f0000e0,0xe00038,0xe000,0x0,0x200,0xf0780e07,0x8041c078,0x380e0038,0xe03c1e,
3565       0xf001c00,0x1c0071e,0x1c0070,0xe1c783c0,0xe0381e03,0x8380f00f,0xe0000,0x1c00380e,0x381c380,0xe07bc01,0xc0e00078,0x70000e,
3566       0x1c000,0x0,0x1c000061,0x0,0x38000000,0x10,0x20000,0x7c000,0x7c000000,0x703fc06,0x10000e00,0x18400308,0x1801c,0x1c381,0xc3800000,
3567       0x0,0x0,0x7000,0xe0f,0xe061000,0x7801fc0,0x1c,0x38c001,0xc0007ff0,0x7fff0038,0x77c000,0x19c00c,0x301c0387,0x0,0x30c618,0xf0,
3568       0x1c0007,0x600,0x380e,0x7f8c007,0x80000000,0xc001818,0x70e03fc,0x387f871f,0xe0e00700,0x70e00e1,0xc01c3803,0x870070e0,0xe1c038f,
3569       0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,0x8e007070,0x703839c7,0x70e00e,
3570       0x1c01c380,0x3807f007,0x70e700,0x10078200,0xf0401e08,0x3c10078,0x200f001c,0x3878041c,0x70380e0,0x701c0e03,0x800e0001,0xc0003800,
3571       0x7001e0f,0x3c1e070,0x1c0e0381,0xc070380e,0x701c000,0x1c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80e07038,0x0,0x0,0x0,0x0,0x0,
3572       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600e600,0x7803f0,0x1,0xc0000700,0x718e0070,0x0,0x0,0x38038c3,
3573       0x800e0000,0x3c01f800,0x60e03ffc,0xeff8001,0xc001f003,0xc1f003c0,0x7800fe,0xffff80,0x3f8003c0,0x60c0e0e1,0xc07fe01c,0x38038,
3574       0x3ffe07ff,0xc1c07e3f,0xff801c00,0x381fe0,0x1c000e3,0x638e30e1,0xc00e1c07,0x870038ff,0xf00ff800,0xe007007,0x38381cd,0x9c007000,
3575       0x3e0001e0,0xe0001c,0xe000,0x0,0x0,0x70780f0f,0x3c078,0x70070038,0x1e03c1c,0x7001c00,0x1c0073c,0x1c0070,0xe1c701c1,0xe03c1e03,
3576       0xc780f00f,0xe0000,0x1c00380e,0x381c387,0xe03f801,0xc0e000f0,0x70000e,0x1c007,0xe0100000,0x1c0000cd,0x80000003,0xffc00000,
3577       0x3ff,0x807ff000,0xe0,0x7fc00060,0x703fc0c,0xd8001e00,0x3360066c,0x1c018,0xc181,0x83000000,0x0,0x0,0x7000,0x300e07,0xe0cd800,
3578       0xf000f80,0x1c,0x78c00f,0xff0038e0,0x3e00038,0xe1e000,0x19800c,0x383c070e,0x7fffc00,0x30fc18,0x0,0xffff80e,0x20e00,0x380e,
3579       0x7f8c007,0x80000000,0xc001c38,0x38703ff,0xf87fff0f,0xcfe00f00,0x70e00e1,0xc01c3803,0x870070e0,0x1e1e078f,0xe1c0001f,0xff03ffe0,
3580       0x7ffc0fff,0x800e0001,0xc0003800,0x700ff83,0x871870e0,0x71c00e3,0x801c7003,0x8e007038,0xe03871c7,0x70e00e,0x1c01c380,0x3803e007,
3581       0x70e700,0x38000,0x70000e00,0x1c00038,0x7001c,0x38f00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7001c07,0x380e0f0,0x1e1e03c3,
3582       0xc078780f,0xf01e000,0x3c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80f07038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3583       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600ff00,0x1e00778,0x38000001,0xc0000700,0x21843fff,0xe0000000,0x0,0x38039e3,0x800e0000,
3584       0x7c01fe00,0xe0e0203e,0xeffc001,0xc00ffe03,0xff700000,0x7f0,0x0,0x7f00380,0x618060e1,0xc07ffc1c,0x38038,0x3ffe07ff,0xc1c07e3f,
3585       0xff801c00,0x381ff0,0x1c000e3,0x638e38e1,0xc00e1fff,0x870038ff,0xc003fe00,0xe007007,0x38381cd,0x9c00f800,0x3e0003c0,0xe0001c,
3586       0xe000,0x0,0x0,0x7070070e,0x38038,0x70070038,0x1c01c1c,0x7001c00,0x1c00778,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0xfc000,
3587       0x1c00380e,0x381c3c7,0x1e01f001,0xe1e001e0,0xf0000e,0x1e01f,0xf8300000,0x1c00019c,0xc0000003,0xffc00000,0x10,0x20000,0x700,
3588       0x1ff000c0,0x703fc19,0xcc003c00,0x67300ce6,0xc038,0xc181,0x83000000,0x0,0x0,0x7e00,0x180e07,0xe19cc00,0x1e000f80,0x1c,0x70c00f,
3589       0xff007070,0x3e00038,0xe0f000,0x19800c,0x1fec0e1c,0x7fffc00,0x30f818,0x0,0xffff81f,0xf003fc00,0x380e,0x3f8c007,0x80000000,
3590       0x7f800ff0,0x1c3803f,0xe007fc00,0xff800e00,0x70e00e1,0xc01c3803,0x870070e0,0x1c0e070f,0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,
3591       0xc0003800,0x700ff83,0x871c70e0,0x71c00e3,0x801c7003,0x8e00701d,0xc038e1c7,0x70e00e,0x1c01c380,0x3803e007,0x70e3c0,0x38000,
3592       0x70000e00,0x1c00038,0x7001c,0x38e00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7003c07,0x8380e0e0,0xe1c01c3,0x80387007,
3593       0xe00e1ff,0xfe381b83,0x80e0701c,0xe0381c0,0x701e1e07,0x707878,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3594       0x0,0x0,0x0,0x0,0x1c,0x3,0xe007fe0,0x7800e3c,0x38000001,0xc0000700,0x1803fff,0xe0000000,0x0,0x70039c3,0x800e0000,0xf8000f80,
3595       0xc0e0000e,0xf83c003,0xc01e0f01,0xff700000,0x7c0,0x0,0x1f00780,0x618061c0,0xe0701e1c,0x38038,0x38000700,0x1c07e38,0x3801c00,
3596       0x381e78,0x1c000e3,0xe38e18e1,0xc00e1fff,0x70038ff,0xe0007f80,0xe007007,0x1c701dd,0x9c00f800,0x1c000780,0xe0000e,0xe000,0x0,
3597       0x7f,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x7fc00,0x1c00380e,
3598       0x1c381c7,0x1c01f000,0xe1c001c0,0xfe0000e,0xfe1f,0xfff00000,0x7ff003fc,0xe0000003,0xffc00000,0x10,0x20000,0x3800,0x3fc0180,
3599       0x703803f,0xce007800,0xff381fe7,0x30,0x0,0xc0,0x0,0x0,0x3fe0,0xc0e07,0xfe3fce00,0x1c000700,0x1c,0x70c00f,0xff006030,0x1c00000,
3600       0xe07800,0x19800c,0xfcc1c38,0x7fffc00,0x30d818,0x0,0xffff81f,0xf001f800,0x380e,0xf8c007,0x80000000,0x7f8007e0,0xe1c3fe,0x7fc00f,
3601       0xf8001e00,0xe0701c0,0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700ff83,0x870c70e0,
3602       0x71c00e3,0x801c7003,0x8e00700f,0x8038c1c7,0x70e00e,0x1c01c380,0x3801c007,0xf0e3e0,0x3ff807f,0xf00ffe01,0xffc03ff8,0x7ff03ff,
3603       0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe383383,0x80e0701c,
3604       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,
3605       0x3c1e1c1c,0x38000001,0xc0000700,0x1803fff,0xe0000007,0xf8000000,0x7003803,0x800e0001,0xf0000381,0xc0e00007,0xf01e003,0x801c0700,
3606       0x7c700000,0x7c0,0x0,0x1f00700,0x618061c0,0xe0700e1c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381e38,0x1c000e1,0xc38e1ce1,
3607       0xc00e1ffc,0x70038e0,0xf0000780,0xe007007,0x1c701dd,0xdc01fc00,0x1c000780,0xe0000e,0xe000,0x0,0x1ff,0xf070070e,0x38038,0x7fff0038,
3608       0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3ff00,0x1c00380e,0x1c381cd,0x9c00e000,0xe1c003c0,
3609       0xf80000e,0x3e18,0x3ff00000,0xffe007fd,0xf0000000,0x38000000,0x10,0x20000,0x1c000,0x3c0300,0x703807f,0xdf007801,0xff7c3fef,
3610       0x80000000,0x0,0x3e0,0x7ffe7ff,0xff000000,0x1ff8,0x60e07,0xfe7fdf00,0x3c000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0xf03800,
3611       0x19800c,0x1c38,0x1c07,0xf830cc18,0x0,0x1c0000,0x0,0x380e,0x18c007,0x80000000,0x0,0xe1cfe0,0x1fc003f,0x80003c00,0xe0701c0,
3612       0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,
3613       0x8e007007,0x3981c7,0x70e00e,0x1c01c380,0x3801c007,0x1e0e0f8,0xfff81ff,0xf03ffe07,0xffc0fff8,0x1fff07ff,0xf8e0003f,0xff87fff0,
3614       0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe386383,0x80e0701c,0xe0381c0,0x700e1c07,
3615       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,
3616       0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0003,0xe00001c3,0x80e00007,0xe00e007,0x80380380,0x700000,0x7f0,0x0,0x7f00700,
3617       0x618061ff,0xe070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381c3c,0x1c000e1,0xc38e1ce1,0xc00e1c00,0x70038e0,0x700003c0,
3618       0xe007007,0x1c701d8,0xdc03dc00,0x1c000f00,0xe00007,0xe000,0x0,0x3ff,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007fc,
3619       0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3f00,0x1c00380e,0x1c381cd,0x9c01f000,0x73800780,0xfe0000e,0xfe10,0x7c00000,0x1c000ffb,
3620       0xf8000000,0x38000000,0x10,0x20000,0x20000,0x1e0700,0x70380ff,0xbf80f003,0xfefe7fdf,0xc0000000,0x0,0x3f0,0x7ffe7ff,0xff000000,
3621       0x1f8,0x30e07,0xfeffbf80,0x78000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0x783800,0x1ce11c,0xe1c,0x1c07,0xf838ce38,0x0,0x1c0000,
3622       0x0,0x380e,0x18c000,0x0,0x0,0x1c38c00,0x1800030,0x7800,0xfff01ff,0xe03ffc07,0xff80fff0,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,
3623       0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,0x8e00700f,0x803b81c7,0x70e00e,0x1c01c380,0x3801c007,0xffe0e03c,
3624       0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0fff,0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,
3625       0x80387007,0xe00e000,0x38c383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3626       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0063c,0x40619c0f,0x30000001,0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0007,0xc00001c3,
3627       0xfffc0007,0xe00e007,0x380380,0xf00000,0xfe,0xffff80,0x3f800700,0x618063ff,0xf070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,
3628       0x381c1e,0x1c000e0,0x38e0ee1,0xc00e1c00,0x70038e0,0x380001c0,0xe007007,0x1ef01d8,0xdc038e00,0x1c001e00,0xe00007,0xe000,0x0,
3629       0x7c0,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0079e,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x780,0x1c00380e,
3630       0xe701cd,0x9c01f000,0x73800f00,0xe0000e,0xe000,0x0,0x1c0007f7,0xf0000000,0x70000000,0x10,0x20000,0x0,0xe0e00,0x703807f,0x7f01e001,
3631       0xfdfc3fbf,0x80000000,0x0,0x7f0,0x0,0x0,0x3c,0x18e07,0x7f7f00,0xf0000700,0x1c,0x70c001,0xc0007070,0x1c00000,0x3e7000,0xcff18,
3632       0x3ffc070e,0x1c07,0xf818c630,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x3870000,0xe000fc00,0x380f000,0x1fff83ff,0xf07ffe0f,
3633       0xffc1fff8,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870770e0,0x71c00e3,0x801c7003,0x8e00701d,
3634       0xc03f01c7,0x70e00e,0x1c01c380,0x3801c007,0xffc0e01c,0x3e0387c0,0x70f80e1f,0x1c3e038,0x7c071e1c,0xe00038,0x70000,0xe0001c00,
3635       0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x398383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,
3636       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,
3637       0x70,0x0,0x0,0x1c003c07,0x800e000f,0x1c3,0xfffc0007,0xe00e007,0x380380,0xe00000,0x1f,0xc0ffff81,0xfc000700,0x618063ff,0xf070070e,
3638       0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0e,0x1c000e0,0x38e0ee1,0xe01e1c00,0x78078e0,0x380001c0,0xe007007,0xee01f8,0xfc078f00,
3639       0x1c001c00,0xe00003,0x8000e000,0x0,0x700,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0070e,0x1c0070,0xe1c701c1,
3640       0xc01c1c01,0xc700700e,0x380,0x1c00380e,0xe700ed,0xb803f800,0x77800f00,0x70000e,0x1c000,0x0,0xe0003f7,0xe0000000,0x70000000,
3641       0x10,0x20000,0x1c0e0,0xe1c00,0x703803f,0x7e01c000,0xfdf81fbf,0x0,0x0,0x3f0,0x0,0x0,0x1c,0x1ce07,0x3f7e00,0xf0000700,0x1c,
3642       0x70c001,0xc00038e0,0x1c00038,0xf7000,0xe3e38,0x3ffc0387,0x1c00,0x1cc770,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x70e0001,
3643       0xe001fe00,0x780e000,0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0ffe,0xe0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,
3644       0x70770f0,0xf1e01e3,0xc03c7807,0x8f00f038,0xe03e03c7,0x70e00e,0x1c01c380,0x3801c007,0xff00e00e,0x38038700,0x70e00e1c,0x1c38038,
3645       0x70071c1c,0xe00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x3b0383,0x80e0701c,
3646       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,
3647       0xc0de03,0xe0000001,0xc0000700,0x70,0x0,0x0,0x1c001c07,0xe001e,0x1c3,0xfffc0007,0x600e00e,0x380380,0xe00000,0x7,0xf0ffff87,
3648       0xf0000000,0x60c0e380,0x7070070e,0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0f,0x1c000e0,0x38e06e0,0xe01c1c00,0x38070e0,
3649       0x1c0001c0,0xe007007,0xee00f8,0xf80f0700,0x1c003c00,0xe00003,0x8000e000,0x0,0x700,0x70780f0f,0x3c078,0x70000038,0x1e03c1c,
3650       0x7001c00,0x1c0070f,0x1c0070,0xe1c701c1,0xe03c1e03,0xc780f00e,0x380,0x1c00380e,0xe700f8,0xf807bc00,0x3f001e00,0x70000e,0x1c000,
3651       0x0,0xe0001ff,0xc0000000,0x70000000,0x10,0x20000,0x33110,0xe0e00,0x383801f,0xfc03c000,0x7ff00ffe,0x0,0x0,0x3e0,0x0,0x0,0x1c,
3652       0x38e07,0x1ffc01,0xe0000700,0x1c,0x78c001,0xc0007ff0,0x1c00038,0x7c000,0x70070,0x1c3,0x80001c00,0xe00e0,0x0,0x1c0000,0x0,
3653       0x380e,0x18c000,0x0,0x0,0xe1c0001,0xe0010700,0x780e000,0x1c038380,0x70700e0e,0x1c1c038,0x78070e0e,0xe0001c,0x38000,0x70000e00,
3654       0xe0001,0xc0003800,0x7003807,0x7037070,0xe0e01c1,0xc0383807,0x700e070,0x701c0387,0x70e00e,0x1c01c380,0x3801c007,0xe00e,0x38038700,
3655       0x70e00e1c,0x1c38038,0x70071c1c,0xf00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003c07,0x8380e0f0,0x1e1e03c3,0xc078780f,
3656       0xf01e007,0x803e0783,0x80e0701c,0xe0381c0,0x7003f007,0x80f00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3657       0x0,0x0,0x0,0x0,0x0,0x6,0x1800061c,0xc0de01,0xc0000000,0xc0000e00,0x70,0xf0000,0x3c00,0x38001c0f,0xe003c,0x3c0,0xe0000e,0x701e00e,
3658       0x3c0780,0x1e003c0,0x780000,0xfc00001f,0x80000000,0x60e1e780,0x78700f07,0x4380f0,0x38000700,0xf00e38,0x3801c00,0xc0781c07,
3659       0x81c000e0,0x38e07e0,0xe03c1c00,0x380f0e0,0x1e0003c0,0xe00780f,0xee00f0,0x780e0780,0x1c007800,0xe00001,0xc000e000,0x0,0x700,
3660       0xf0780e07,0x8041c078,0x38020038,0xe03c1c,0x7001c00,0x1c00707,0x801c0070,0xe1c701c0,0xe0381e03,0x8380f00e,0x80380,0x1c003c1e,
3661       0x7e00f8,0xf80f1e00,0x3f003c00,0x70000e,0x1c000,0x0,0xf0100f7,0x80078000,0x700078f0,0x10,0x7ff000,0x61208,0x1e0700,0x383800f,
3662       0x78078000,0x3de007bc,0x0,0x0,0x0,0x0,0x0,0x401c,0x70e0f,0xf7803,0xc0000700,0x1c,0x38c001,0xc000efb8,0x1c00038,0x1e000,0x3c1e0,
3663       0xc1,0x80000000,0x783c0,0x0,0x0,0x0,0x3c1e,0x18c000,0x0,0x0,0xc180003,0x60000300,0xd80e010,0x3c03c780,0x78f00f1e,0x1e3c03c,
3664       0x70039c0e,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x703f070,0x1e0e03c1,0xc078380f,0x701e0e0,0x381c0787,
3665       0x80f0f01e,0x1e03c3c0,0x7801c007,0xe00e,0x38078700,0xf0e01e1c,0x3c38078,0x700f1c1c,0x78041c,0x1038020,0x70040e00,0x800e0001,
3666       0xc0003800,0x7001c07,0x380e070,0x1c0e0381,0xc070380e,0x701c007,0x801e0703,0xc1e0783c,0xf0781e0,0xf003f007,0x80e00fc0,0x0,
3667       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xe,0x1801867c,0xc0cf83,0xe0000000,0xe0000e00,
3668       0x70,0xf0000,0x3c00,0x38000f1e,0xe0070,0x180780,0xe0603e,0x783c01e,0x1e0f01,0x7c003c0,0x780000,0x3c00001e,0x700,0x307fe700,
3669       0x38701e07,0xc1c383e0,0x38000700,0x7c1e38,0x3801c00,0xe0f01c03,0x81c000e0,0x38e03e0,0x78781c00,0x1e1e0e0,0xe180780,0xe003c1e,
3670       0x7c00f0,0x781e03c0,0x1c007000,0xe00001,0xc000e000,0x0,0x783,0xf07c1e07,0xc0c1e0f8,0x3e0e0038,0xf07c1c,0x7001c00,0x1c00703,
3671       0xc01e0070,0xe1c701c0,0xf0781f07,0x83c1f00e,0xe0f80,0x1e003c3e,0x7e00f8,0xf80e0e00,0x3f003800,0x70000e,0x1c000,0x0,0x7830077,
3672       0xf0000,0x700078f0,0x10,0x20000,0x41208,0xc03c0380,0x3c38007,0x70070000,0x1dc003b8,0x0,0x0,0x0,0x0,0x0,0x707c,0x6070f,0x86077003,
3673       0x80000700,0x1c,0x3ec401,0xc001c01c,0x1c00038,0xf000,0x1ffc0,0x40,0x80000000,0x3ff80,0x0,0x0,0x0,0x3e3e,0x18c000,0x0,0x0,
3674       0x8100006,0x60000300,0x1980f070,0x3801c700,0x38e0071c,0xe3801c,0x70039c0e,0x7c1c1c,0x38000,0x70000e00,0xe0001,0xc0003800,
3675       0x700383e,0x701f03c,0x3c078780,0xf0f01e1e,0x3c3c1c0,0x1c3f0f03,0xc1e0783c,0xf0781e0,0xf001c007,0xe81e,0x3c1f8783,0xf0f07e1e,
3676       0xfc3c1f8,0x783f1e3e,0x187c0c1f,0x703e0e0,0x7c1c0f83,0x800e0001,0xc0003800,0x7001e0f,0x380e078,0x3c0f0781,0xe0f03c1e,0x783c007,
3677       0x801e0f03,0xc3e0787c,0xf0f81e1,0xf003f007,0xc1e00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3678       0x0,0x0,0x1c,0xe,0x3801fff8,0x6187ff,0xe0000000,0xe0000e00,0x70,0xf0000,0x3c00,0x38000ffe,0x1fff0ff,0xfe1fff80,0xe07ffc,0x3ffc01c,
3679       0x1fff01,0xff8003c0,0x780000,0x4000010,0x700,0x301e6700,0x387ffe03,0xffc3ffc0,0x3fff0700,0x3ffe38,0x383ffe0,0xfff01c03,0xc1fff8e0,
3680       0x38e03e0,0x7ff81c00,0x1ffe0e0,0xf1fff80,0xe003ffe,0x7c00f0,0x781c01c0,0x1c00ffff,0xe00001,0xc000e000,0x0,0x3ff,0x707ffc03,
3681       0xffc0fff8,0x1ffe0038,0x7ffc1c,0x707fff0,0x1c00701,0xc00ff070,0xe1c701c0,0x7ff01fff,0x1fff00e,0xfff00,0xff81fee,0x7e00f0,
3682       0x781e0f00,0x1e007ffc,0x70000e,0x1c000,0x0,0x3ff003e,0xf0000,0xe00070e0,0x60830010,0x20000,0x41208,0xfffc01c0,0x1fffe03,0xe00ffff0,
3683       0xf8001f0,0x0,0x0,0x0,0x0,0x0,0x7ff8,0xc07fd,0xfe03e007,0xffc00700,0x1c,0x1ffc1f,0xffc08008,0x1c00038,0x7000,0x7f00,0x0,0x0,
3684       0xfe00,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0x6,0x60000700,0x19807ff0,0x3801c700,0x38e0071c,0xe3801c,0x70039c0f,0xf03ffc1f,
3685       0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,0x701f03f,0xfc07ff80,0xfff01ffe,0x3ffc080,0x83fff03,0xffe07ffc,0xfff81ff,
3686       0xf001c007,0xeffc,0x1ffb83ff,0x707fee0f,0xfdc1ffb8,0x3ff70ff7,0xf83ffc0f,0xff01ffe0,0x3ffc07ff,0x83fff87f,0xff0fffe1,0xfffc0ffe,
3687       0x380e03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x803ffe01,0xfee03fdc,0x7fb80ff,0x7001e007,0xffc00780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3688       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x3801fff0,0x7f83fe,0x70000000,0xe0000e00,0x0,0xf0000,0x3c00,0x700007fc,
3689       0x1fff0ff,0xfe1ffe00,0xe07ff8,0x1ff801c,0xffe01,0xff0003c0,0x780000,0x0,0x700,0x38000f00,0x3c7ffc01,0xff83ff80,0x3fff0700,
3690       0x1ffc38,0x383ffe0,0x7fe01c01,0xe1fff8e0,0x38e03e0,0x3ff01c00,0xffc0e0,0x71fff00,0xe001ffc,0x7c00f0,0x783c01e0,0x1c00ffff,
3691       0xe00000,0xe000e000,0x0,0x1ff,0x7077f801,0xff807fb8,0xffc0038,0x3fdc1c,0x707fff0,0x1c00701,0xe007f070,0xe1c701c0,0x3fe01dfe,
3692       0xff700e,0x7fe00,0xff80fee,0x3c0070,0x703c0780,0x1e007ffc,0x70000e,0x1c000,0x0,0x1fe001c,0xe0000,0xe000e1c0,0x71c78010,0x20000,
3693       0x21318,0xfff800c0,0xfffe01,0xc00ffff0,0x70000e0,0x0,0x0,0x0,0x0,0x0,0x3ff0,0x1803fd,0xfe01c007,0xffc00700,0x1c,0xffc1f,0xffc00000,
3694       0x1c00038,0x7000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0xc,0x60000e00,0x31803fe0,0x7801ef00,0x3de007bc,
3695       0xf7801e,0xf003fc0f,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x701f01f,0xf803ff00,0x7fe00ffc,0x1ff8000,
3696       0x67fe01,0xffc03ff8,0x7ff00ff,0xe001c007,0xeff8,0xffb81ff,0x703fee07,0xfdc0ffb8,0x1ff70ff7,0xf81ff807,0xfe00ffc0,0x1ff803ff,
3697       0x3fff87f,0xff0fffe1,0xfffc07fc,0x380e01f,0xf003fe00,0x7fc00ff8,0x1ff0000,0x37fc00,0xfee01fdc,0x3fb807f,0x7001e007,0x7f800780,
3698       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,
3699       0x0,0xe0000,0x3c00,0x700001f0,0x1fff0ff,0xfe07f800,0xe01fe0,0x7e0038,0x3f800,0xfc0003c0,0x700000,0x0,0x700,0x18000e00,0x1c7ff000,
3700       0x7e03fe00,0x3fff0700,0x7f038,0x383ffe0,0x1f801c00,0xf1fff8e0,0x38e01e0,0xfc01c00,0x3f80e0,0x787fc00,0xe0007f0,0x7c00f0,0x387800f0,
3701       0x1c00ffff,0xe00000,0xe000e000,0x0,0xfc,0x7071f000,0x3f003e38,0x3f00038,0x1f1c1c,0x707fff0,0x1c00700,0xf003f070,0xe1c701c0,
3702       0x1f801c7c,0x7c700e,0x1f800,0x3f8078e,0x3c0070,0x707803c0,0x1c007ffc,0x70000e,0x1c000,0x0,0x7c0008,0x1e0000,0xe000e1c0,0x71c30010,
3703       0x20000,0x1e1f0,0x3fe00020,0x3ffe00,0x800ffff0,0x2000040,0x0,0x0,0x0,0x0,0x0,0xfc0,0x3001f0,0x78008007,0xffc00700,0x1c,0x3f81f,
3704       0xffc00000,0x1c00038,0x407000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x39c7,0x18c000,0x0,0x0,0x18,0x60001c00,0x61801f80,0x7000ee00,
3705       0x1dc003b8,0x77000e,0xe001f80f,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,0x700f007,0xe000fc00,0x1f8003f0,
3706       0x7e0000,0xe1f800,0x7f000fe0,0x1fc003f,0x8001c007,0xe7f0,0x7e380fc,0x701f8e03,0xf1c07e38,0xfc703c1,0xe003f001,0xf8003f00,
3707       0x7e000fc,0x3fff87f,0xff0fffe1,0xfffc03f8,0x380e00f,0xc001f800,0x3f0007e0,0xfc0000,0x61f800,0x78e00f1c,0x1e3803c,0x7001c007,
3708       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,
3709       0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
3710       0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
3711       0x70000e,0x1c000,0x0,0x0,0x1c0000,0xe000c180,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
3712       0x0,0x38,0x70e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x2000,0x0,0x1f,0xf8003800,0x7fe00000,0x0,0x0,0x0,0x0,0x4000,
3713       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,
3714       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,
3715       0x0,0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e000,
3716       0x0,0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
3717       0x70000e,0x1c000,0x0,0x0,0x1c0001,0xe001c380,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
3718       0x0,0x38,0x7fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x3000,0x0,0x1f,0xf8007000,0x7fe00000,0x0,0x0,0x0,0x0,0x6000,
3719       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,
3720       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,
3721       0x0,0x380000,0x1,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x3c18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf000,
3722       0x0,0x0,0x0,0x0,0x0,0xfe0000,0x380fe000,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x38000000,
3723       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,
3724       0x38,0x1f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x1800,0x0,0x0,0x6000e000,0x1800000,0x0,0x0,0x0,0x0,0x3000,0x0,
3725       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,
3726       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,
3727       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,
3728       0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x0,0x0,0x0,0x0,0x607800,0x0,0x3c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x78000000,
3729       0x3f800e,0x3f8000,0x0,0x0,0x300043,0xc0018200,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
3730       0x0,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x11800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x23000,0x0,0x0,
3731       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,
3732       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,
3733       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,
3734       0xfe000,0x0,0x0,0x0,0x0,0x0,0x7ff000,0x0,0x7f800000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf8000000,0x3f800e,0x3f8000,0x0,
3735       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,
3736       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,
3737       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,
3738       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3739       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,
3740       0x7f000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf0000000,0xf800e,0x3e0000,0x0,0x0,0x7f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3741       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,
3742       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,
3743       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,
3744       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3745       0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x1fc000,0x0,0x7e000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xc0000000,0xe,0x0,
3746       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,
3747       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,
3748       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,
3749       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3750       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,
3751       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,
3752       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3753       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3754 
3755     // Definition of a 29x57 font.
3756     const unsigned int font29x57[29*57*256/32] = {
3757       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3758       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3759       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3760       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3761       0x0,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,
3762       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,
3763       0xc0000000,0x0,0x7c00,0xf80,0x7e000,0x0,0x7c00000,0xf80000,0x7e000000,0x0,0x0,0x1f00,0x3e0,0x1f800,0x0,0x0,0x0,0x3,0xe0000000,
3764       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,
3765       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3766       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3767       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3768       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3769       0x0,0x0,0x0,0x0,0x0,0x0,0x3c3c00,0x0,0x0,0x3,0xc3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,
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,0x3e0000,
3771       0x1f0000,0x7e00000,0xf838001f,0xf80001f,0xf0000000,0x0,0x3e00,0x1f00,0x7e000,0x3e1f000,0x3e00000,0x1f00000,0x7e00003e,0x1f000000,
3772       0x3e0,0xe0000f80,0x7c0,0x1f800,0x3e0e00,0x7c3e000,0x0,0x1,0xf0000000,0xf800003f,0x1f0f,0x800001f0,0x0,0x0,0x0,0x0,0x0,0x0,
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,0x0,0x0,0x0,0x0,0x0,
3774       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3775       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3776       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3777       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e7800,0x0,0x0,
3778       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,
3779       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x1e0000,0xff00001,0xfe38001f,0xf80003f,
3780       0xf8000000,0x0,0x1e00,0x1e00,0xff000,0x3e1f000,0x1e00000,0x1e00000,0xff00003e,0x1f000000,0x7f8,0xe0000780,0x780,0x3fc00,0x7f8e00,
3781       0x7c3e000,0x0,0x0,0xf0000000,0xf000007f,0x80001f0f,0x800001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3782       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3783       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3784       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3785       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3786       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xef000,0x0,0x0,0x0,0xef000000,0x0,0x0,0x0,0x0,0x0,0x0,
3787       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,
3788       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000,0x3c0000,0x1e780003,0xfff8001f,0xf80003c,0x78000000,0x0,0xf00,0x3c00,0x1e7800,
3789       0x3e1f000,0xf00000,0x3c00001,0xe780003e,0x1f000000,0xfff,0xe00003c0,0xf00,0x79e00,0xfffe00,0x7c3e000,0x0,0x0,0x78000001,0xe00000f3,
3790       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,
3791       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3792       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3793       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3794       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3795       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3796       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,
3797       0x0,0x78000,0x780000,0x3c3c0003,0x8ff0001f,0xf800078,0x3c000000,0x0,0x780,0x7800,0x3c3c00,0x3e1f000,0x780000,0x7800003,0xc3c0003e,
3798       0x1f000000,0xe3f,0xc00001e0,0x1e00,0xf0f00,0xe3fc00,0x7c3e000,0x0,0x0,0x3c000003,0xc00001e1,0xe0001f0f,0x80000780,0x0,0x0,
3799       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,
3800       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3801       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3802       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3803       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3804       0x0,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,
3805       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,
3806       0x83e0001f,0xf800070,0x1c000000,0x0,0x3c0,0xf000,0x781e00,0x3e1f000,0x3c0000,0xf000007,0x81e0003e,0x1f000000,0xe0f,0x800000f0,
3807       0x3c00,0x1e0780,0xe0f800,0x7c3e000,0x0,0x0,0x1e000007,0x800003c0,0xf0001f0f,0x80000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf8000000,
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,
3809       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3810       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3811       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3812       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3813       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3814       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,
3815       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,
3816       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3817       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3818       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3819       0x0,0x0,0x0,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,
3820       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,
3821       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,
3822       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,
3823       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x3e000,0x3e00000,0x0,0x78,0x3c000000,0x0,0x1f000,0x3e0,
3824       0x3e000,0x0,0x1f000000,0x3e0000,0x3e000000,0x0,0x0,0x7c00,0xf8,0xf800,0x0,0x0,0x0,0xf,0x80000000,0x1f00001f,0x0,0x3e,0x0,
3825       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3826       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,
3827       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80000,
3828       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3829       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,
3830       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,
3831       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,
3832       0x0,0x0,0xf80000,0x7c000,0x3e00000,0xf0380000,0x70,0x1c000000,0x0,0xf800,0x7c0,0x3e000,0x0,0xf800000,0x7c0000,0x3e000000,
3833       0x0,0x3c0,0xe0003e00,0x1f0,0xf800,0x3c0e00,0x0,0x0,0x7,0xc0000000,0x3e00001f,0x0,0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3834       0x0,0x0,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,
3835       0xf8,0xf8000,0x1c000,0x0,0x0,0x0,0x0,0x1f,0xc0000000,0x1ff8,0xff00,0x0,0x0,0x3fe000,0x0,0x1fc00001,0xfe000000,0x0,0x0,0x0,
3836       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,
3837       0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x780000,0x1,0xe0000000,0x0,0x780000,0x3,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,
3838       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,
3839       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,
3840       0x0,0x0,0x1ff,0x1f0f8,0x0,0xff000,0x0,0x0,0x0,0x3f,0xff00000f,0x80000000,0xfe0,0x3f80,0xf00,0x0,0x0,0x0,0x1,0xf8000003,0xe0000000,
3841       0x1c00,0xe000,0xe00,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,
3842       0x7f0000,0x0,0x1fc07000,0x0,0x0,0x0,0x0,0x0,0x3f800,0x780000,0x78000,0x7f00001,0xfc38001f,0xf800070,0x1c000000,0x0,0x7800,
3843       0x780,0x7f000,0x3e1f000,0x7800000,0x780000,0x7f00003e,0x1f0003f0,0x7f0,0xe0001e00,0x1e0,0x1fc00,0x7f0e00,0x7c3e000,0x0,0x3,
3844       0xc0000000,0x3c00003f,0x80001f0f,0x80000078,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3845       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x1e078000,0x30000000,0x3ff,0xc00001e0,0xf0,
3846       0x78000,0x1c000,0x0,0x0,0x0,0x0,0x1e0007f,0xf000007e,0x1ffff,0x7ffe0,0x1f80,0x3ffff80,0xfff803,0xfffff800,0xfff80007,0xff800000,
3847       0x0,0x0,0x0,0x0,0x1ffe00,0x0,0xfe0003,0xfff80000,0x3ffe01ff,0xe00003ff,0xffe01fff,0xff0003ff,0xe01e0007,0x803ffff0,0xfff80,
3848       0x3c000fc0,0x7800001f,0x8003f07e,0x1e000f,0xfe0007ff,0xf00003ff,0x8007ffe0,0x1fff8,0x7fffffe,0xf0003c1,0xe000079e,0xf1f,0x1f3e0,
3849       0x1f01ff,0xfff8003f,0xf003c000,0x7fe0,0x3f00,0x0,0x3c0000,0x1,0xe0000000,0x0,0x780000,0xf,0xfe000000,0x78000,0x3c00,0xf000,
3850       0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xfc0000f0,0x3fe00,0x0,0x0,0xfff00,0x0,0x0,0x3fe000,
3851       0x0,0x0,0x0,0x1dc0,0x0,0x3fff00,0x0,0x3ffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff1c07ff,0x3c0f001e,0x3c000000,
3852       0x0,0x0,0x1e3c0,0xf80007c,0x0,0x780000,0x0,0xfff8000,0x3e00,0x1f00000,0x7ff,0xc001f0f8,0x0,0x3ffc00,0x0,0x0,0x0,0x3f,0xff00003f,
3853       0xe0000000,0x3ff8,0xffe0,0x1e00,0x0,0xfffc00,0x0,0x7,0xf800000f,0xf8000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,
3854       0x3f800001,0xfc00003f,0xf80000ff,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,
3855       0xfc00,0x3c001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x0,0x7ff8f0f0,0x3c0780,0x1e03c00,0xf01e000,0x783e0001,0xf01e0000,0xffe00,
3856       0x3c0000,0xf0000,0x7700001,0xfe38001f,0xf800070,0x1c000000,0x0,0x3c00,0xf00,0x77000,0x3e1f000,0x3c00000,0xf00000,0x7700003e,
3857       0x1f0000f8,0xc0007f8,0xe0000f00,0x3c0,0x1dc00,0x7f8e00,0x7c3e000,0x0,0x1,0xe0000000,0x7800003b,0x80001f0f,0x800000f0,0x1e0000,
3858       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,
3859       0x0,0x0,0x780000,0x3c1e0000,0x1e070000,0x300001f0,0x7ff,0xc00001e0,0x1e0,0x7c000,0x1c000,0x0,0x0,0x0,0x0,0x3c000ff,0xf80007fe,
3860       0x3ffff,0x801ffff8,0x1f80,0x3ffff80,0x3fff803,0xfffff801,0xfffc000f,0xffc00000,0x0,0x0,0x0,0x0,0x7fff80,0x0,0xfe0003,0xffff0000,
3861       0xffff01ff,0xfc0003ff,0xffe01fff,0xff000fff,0xf01e0007,0x803ffff0,0xfff80,0x3c001f80,0x7800001f,0xc007f07e,0x1e001f,0xff0007ff,
3862       0xfc0007ff,0xc007fffc,0x3fffc,0x7fffffe,0xf0003c1,0xf0000f9e,0xf0f,0x8003e1e0,0x1e01ff,0xfff8003f,0xf001e000,0x7fe0,0x3f00,
3863       0x0,0x1e0000,0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,
3864       0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x1fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x3de0,0x0,0x7fff80,0x0,0xfffff80,
3865       0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe7bc07ff,0x3e1f000f,0x78000000,0x0,0x0,0xf780,0x7800078,0x0,0x780000,0x180000,
3866       0x1fff8000,0x1e00,0x1e0003c,0xfff,0xc001f0f8,0x0,0x7ffe00,0x0,0x0,0x0,0x3f,0xff00007f,0xf0000000,0x3ffc,0xfff0,0x3c00,0x0,
3867       0x7fffc00,0x0,0x7,0xf800003f,0xfe000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xe00001ff,
3868       0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000fc00,0x3c003ffe,0x1fff0,
3869       0xfff80,0x7ffc00,0x3ffe000,0x0,0xfffce0f0,0x3c0780,0x1e03c00,0xf01e000,0x781e0001,0xe01e0000,0x3fff00,0x1e0000,0x1e0000,0xf780003,
3870       0xcf78001f,0xf800078,0x3c000000,0x0,0x1e00,0x1e00,0xf7800,0x3e1f000,0x1e00000,0x1e00000,0xf780003e,0x1f0000fc,0x7c000f3d,
3871       0xe0000780,0x780,0x3de00,0xf3de00,0x7c3e000,0x0,0x0,0xf0000000,0xf000007b,0xc0001f0f,0x800001e0,0x1e0000,0x3e1f00,0x0,0x0,
3872       0x0,0x0,0x0,0x0,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,
3873       0x3c1e0000,0x1e0f0000,0x300007fc,0xfff,0xc00001e0,0x1e0,0x3c000,0x1c000,0x0,0x0,0x0,0x0,0x3c001ff,0xfc001ffe,0x3ffff,0xc01ffffc,
3874       0x3f80,0x3ffff80,0x7fff803,0xfffff803,0xfffe001f,0xffe00000,0x0,0x0,0x0,0x0,0xffff80,0x7f800,0xfe0003,0xffff8001,0xffff01ff,
3875       0xff0003ff,0xffe01fff,0xff001fff,0xf01e0007,0x803ffff0,0xfff80,0x3c003f00,0x7800001f,0xc007f07f,0x1e003f,0xff8007ff,0xff000fff,
3876       0xe007ffff,0x7fffc,0x7fffffe,0xf0003c0,0xf0000f1e,0xf07,0x8003c1f0,0x3e01ff,0xfff8003f,0xf001e000,0x7fe0,0x7f80,0x0,0xe0000,
3877       0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
3878       0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x3fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x78f0,0x0,0xffff80,0x0,0x3fffff80,0x1f,
3879       0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc7f80070,0x3e1f0007,0x70000000,0x0,0x0,0x7700,0x7c000f8,0x0,0x780000,0x180000,
3880       0x3fff8000,0x1f00,0x3e0003c,0x1f03,0xc001f0f8,0x0,0x703f00,0x0,0x0,0x0,0x3f,0xff0000f0,0xf8000000,0x303e,0xc0f8,0x7800,0x0,
3881       0xffffc00,0x0,0x7,0x3800003e,0x3e000000,0x1c00,0xe000,0x3c00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00000f,0xe00001ff,
3882       0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000fe00,0x3c007fff,0x3fff8,
3883       0x1fffc0,0xfffe00,0x7fff000,0x1,0xffffc0f0,0x3c0780,0x1e03c00,0xf01e000,0x781f0003,0xe01e0000,0x3fff80,0xe0000,0x3c0000,0x1e3c0003,
3884       0x8ff0001f,0xf80003c,0x78000000,0x0,0xe00,0x3c00,0x1e3c00,0x3e1f000,0xe00000,0x3c00001,0xe3c0003e,0x1f00007f,0xf8000e3f,0xc0000380,
3885       0xf00,0x78f00,0xe3fc00,0x7c3e000,0x0,0x0,0x70000001,0xe00000f1,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,
3886       0x0,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,
3887       0x30000ffe,0xf80,0xc00001e0,0x3c0,0x1e000,0x101c040,0x0,0x0,0x0,0x0,0x78003f0,0x7e001ffe,0x3f807,0xe01f00fe,0x3f80,0x3ffff80,
3888       0x7e01803,0xfffff007,0xe03f003f,0x3f00000,0x0,0x0,0x0,0x0,0xfc0fc0,0x3ffe00,0xfe0003,0xffffc003,0xf81f01ff,0xff8003ff,0xffe01fff,
3889       0xff003f01,0xf01e0007,0x803ffff0,0xfff80,0x3c007e00,0x7800001f,0xc007f07f,0x1e007e,0xfc007ff,0xff801f83,0xf007ffff,0x800fc07c,
3890       0x7fffffe,0xf0003c0,0xf0000f0f,0x1e07,0xc007c0f8,0x7c01ff,0xfff8003c,0xf000,0x1e0,0xffc0,0x0,0xf0000,0x1,0xe0000000,0x0,0x780000,
3891       0x3e,0x0,0x78000,0x3c00,0xf000,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0x800000f0,0x1f80,
3892       0x0,0x0,0x7e0780,0x0,0x0,0x1f82000,0x0,0x0,0x0,0x7070,0x0,0x1f80f80,0x0,0x7fffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,
3893       0x0,0x1,0xc3f80070,0x3f3f0007,0xf0000000,0x0,0x0,0x7f00,0x3e001f0,0x0,0x780000,0x180000,0x7f018000,0xf80,0x7c0003c,0x3e00,
3894       0x4001f0f8,0xfe00,0x400f00,0x0,0x0,0x0,0x7f000000,0xe0,0x38000000,0x1e,0x38,0x7800,0x0,0x1ffe1c00,0x0,0x0,0x38000078,0xf000000,
3895       0x1c00,0xe000,0x7f800,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xf00001ff,0xffc03f81,0xf007ffff,0xc03ffffe,
3896       0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf800fe00,0x3c00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,
3897       0x3,0xf07fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x780f8007,0xc01e0000,0x7e0fc0,0xf0000,0x3c0000,0x1c1c0003,0x87f0001f,0xf80003f,
3898       0xf8000000,0x0,0xf00,0x3c00,0x1c1c00,0x3e1f000,0xf00000,0x3c00001,0xc1c0003e,0x1f00003f,0xc0000e1f,0xc00003c0,0xf00,0x70700,
3899       0xe1fc00,0x7c3e000,0x0,0x0,0x78000001,0xe00000e0,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3900       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,
3901       0x1f00,0x1e0,0x3c0,0x1e000,0x3c1c1e0,0x0,0x0,0x0,0x0,0x78007c0,0x1f001f9e,0x3c001,0xf010003e,0x7780,0x3c00000,0xf800000,0xf007,
3902       0xc01f007c,0x1f80000,0x0,0x0,0x0,0x0,0xe003e0,0x7fff00,0x1ef0003,0xc007e007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x301e0007,
3903       0x80007800,0x780,0x3c00fc00,0x7800001f,0xe00ff07f,0x1e00f8,0x3e00780,0x1fc03e00,0xf807801f,0xc01f001c,0xf000,0xf0003c0,0xf0000f0f,
3904       0x1e03,0xc00f8078,0x780000,0xf0003c,0xf000,0x1e0,0x1f3e0,0x0,0x78000,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,
3905       0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0xf0,0xf80,0x0,0x0,0xf80180,0x0,0x0,0x1e00000,
3906       0x0,0x0,0x0,0xe038,0x0,0x3e00380,0x0,0xfe0f0000,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc0f00070,0x3b370003,0xe0000000,
3907       0x0,0x0,0x3e00,0x1e001e0,0x0,0x780000,0x180000,0x7c000000,0x780,0x780003c,0x3c00,0x0,0x7ffc0,0x780,0x0,0x0,0x3,0xffe00000,
3908       0x1c0,0x3c000000,0xe,0x38,0xf000,0x0,0x3ffe1c00,0x0,0x0,0x38000078,0xf000000,0x1c00,0xe000,0x7f000,0xf000,0x3de000,0x1ef0000,
3909       0xf780000,0x7bc00003,0xde00001e,0xf00003e7,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
3910       0xe0001e03,0xfc00fe00,0x3c01f007,0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x7,0xc01f80f0,0x3c0780,0x1e03c00,0xf01e000,0x78078007,
3911       0x801e0000,0x7803c0,0x78000,0x780000,0x380e0003,0x81e00000,0x1f,0xf0000000,0x0,0x780,0x7800,0x380e00,0x0,0x780000,0x7800003,
3912       0x80e00000,0x1ff,0x80000e07,0x800001e0,0x1e00,0xe0380,0xe07800,0x0,0x0,0x0,0x3c000003,0xc00001c0,0x70000000,0x780,0x1e0000,
3913       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3914       0x780000,0x3c1e0000,0x3c0e0007,0xfff01c07,0x1e00,0x1e0,0x780,0xf000,0x3e1c3e0,0x0,0x0,0x0,0x0,0xf0007c0,0x1f00181e,0x20000,
3915       0xf000001f,0xf780,0x3c00000,0x1f000000,0x1f00f,0x800f8078,0xf80000,0x0,0x0,0x0,0x0,0x8003e0,0x1fc0f80,0x1ef0003,0xc001e007,
3916       0x800101e0,0x7e003c0,0x1e00,0x7800,0x101e0007,0x80007800,0x780,0x3c00f800,0x7800001e,0xe00ef07f,0x801e00f0,0x1e00780,0x7c03c00,
3917       0x78078007,0xc01e0004,0xf000,0xf0003c0,0x78001e0f,0x1e03,0xe00f807c,0xf80000,0x1f0003c,0x7800,0x1e0,0x3e1f0,0x0,0x3c000,0x1,
3918       0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,
3919       0x1e,0xf0,0x780,0x0,0x0,0x1f00080,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x1e03c,0x0,0x3c00080,0x0,0xf80f0000,0x0,0x1f0000,0x0,0x0,
3920       0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x3bf70003,0xe0000000,0x0,0x0,0x3e00,0x1f003e0,0x0,0x780000,0x180000,0x78000000,0x7c0,0xf80003c,
3921       0x3c00,0x0,0x1f01f0,0x780,0x0,0x0,0xf,0x80f80000,0x1c0,0x1c000000,0xe,0x38,0x1e000,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,0x7800000,
3922       0x1c00,0xe000,0x7fc00,0xf000,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x80007800,0x10078000,0x3c0000,
3923       0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00ff00,0x3c01e003,0xc00f001e,0x7800f0,0x3c00780,0x1e003c00,
3924       0x7,0x800f00f0,0x3c0780,0x1e03c00,0xf01e000,0x7807c00f,0x801e0000,0xf803c0,0x3c000,0xf00000,0x780f0000,0x0,0x7,0xc0000000,
3925       0x0,0x3c0,0xf000,0x780f00,0x0,0x3c0000,0xf000007,0x80f00000,0x7ff,0xc0000000,0xf0,0x3c00,0x1e03c0,0x0,0x0,0x0,0x0,0x1e000007,
3926       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,
3927       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c1e001f,0xfff03803,0x80001e00,0x1e0,0x780,0xf000,0xf9cf80,
3928       0x0,0x0,0x0,0x0,0xf000780,0xf00001e,0x0,0xf800000f,0xe780,0x3c00000,0x1e000000,0x1e00f,0x78078,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,
3929       0x3f003c0,0x1ef0003,0xc000f00f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,0x3c01f000,0x7800001e,0xe00ef07f,
3930       0x801e01f0,0x1e00780,0x3c07c00,0x78078003,0xc03e0000,0xf000,0xf0003c0,0x78001e0f,0x1e01,0xf01f003c,0xf00000,0x3e0003c,0x7800,
3931       0x1e0,0x7c0f8,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,
3932       0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x8,0x40,0x0,0x7e0000,0x7c00000,0x1,0xf00f0000,
3933       0x0,0x3e0000,0x0,0x3f,0xfc0,0xfc3f0,0xfc3f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,0xf003c0,0x0,0x0,0x180000,0xf8000000,
3934       0x3c0,0xf00003c,0x3c00,0x0,0x3c0078,0x7ff80,0x0,0x0,0x1e,0x3c0000,0x1c0,0x1c000000,0xe,0xf0,0x0,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,
3935       0x7800000,0x1c00,0xe000,0x3c00,0x0,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x8000f800,0x78000,0x3c0000,
3936       0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00ff00,0x3c03e003,0xc01f001e,0xf800f0,0x7c00780,0x3e003c00,
3937       0xf,0x800f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803c00f,0x1fffc0,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3938       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,
3939       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x781e003f,0xfff03803,
3940       0x80001e00,0x1e0,0xf80,0xf000,0x3dde00,0x0,0x0,0x0,0x0,0xf000f00,0x780001e,0x0,0x7800000f,0x1e780,0x3c00000,0x3e000000,0x3e00f,
3941       0x780f0,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,0x7c001e0,0x3ef8003,0xc000f00f,0x1e0,0xf003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,
3942       0x3c03e000,0x7800001e,0xf01ef07b,0xc01e01e0,0xf00780,0x3e07800,0x3c078003,0xe03c0000,0xf000,0xf0003c0,0x78001e0f,0x1e00,0xf01e003e,
3943       0x1f00000,0x3c0003c,0x7800,0x1e0,0x78078,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,
3944       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,
3945       0xe70000,0x7800000,0x1,0xe00f0000,0x0,0x3c0000,0x0,0x3f,0xfc0,0xfc1f0,0x1f83f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,
3946       0xf807c0,0x0,0x0,0x180000,0xf0000000,0x3e0,0x1f00003c,0x3e00,0x0,0x70001c,0x3fff80,0x0,0x0,0x38,0xe0000,0x1c0,0x1c000078,
3947       0x1c,0x1fe0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x7df000,0x3ef8000,0x1f7c0000,0xfbe00007,
3948       0xdf00003c,0x780003c7,0x8000f000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f780,
3949       0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0xf80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803e01f,0x1ffff8,0xf001e0,
3950       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,
3951       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3952       0x780000,0x3c1e0000,0x781e003e,0x30703803,0x80001e00,0x1e0,0xf00,0x7800,0xff800,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,
3953       0x0,0x7800000f,0x3c780,0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x2000000,0x800000,0x1e0,0x78000e0,0x3c78003,
3954       0xc000f01e,0x1e0,0xf803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x701cf07b,0xc01e01e0,0xf00780,0x1e07800,
3955       0x3c078001,0xe03c0000,0xf000,0xf0003c0,0x7c003e0f,0x1e00,0xf83e001e,0x1e00000,0x7c0003c,0x3c00,0x1e0,0xf807c,0x0,0x0,0x1fe0001,
3956       0xe1fc0000,0x7f00003,0xf8780007,0xf000003c,0x7f0,0x783f0,0x0,0x0,0x7800000,0x1e00000,0x3e0f8000,0xfc00007,0xf8000007,0xf00001fc,
3957       0xf,0xc0003fc0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,0x1818000,
3958       0x7800000,0x1,0xe00f0000,0x0,0x7c0000,0x0,0x1f,0x80001f80,0x7c1f8,0x1f83e0,0x0,0x0,0x0,0x70,0x38c70007,0xf8000000,0x7f03,
3959       0xf0000000,0x0,0x780780,0x0,0x0,0xfe0000,0xf0000000,0x1e0,0x1e00003c,0x3f00,0x0,0xe07f0e,0x7fff80,0x0,0x0,0x70,0x70000,0x1c0,
3960       0x1c000078,0x3c,0x1fc0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x78f000,0x3c78000,0x1e3c0000,
3961       0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
3962       0xf80f780,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0x1f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801e01e,0x1ffffc,
3963       0xf007e0,0x3fc000,0x1fe0000,0xff00000,0x7f800003,0xfc00001f,0xe0000fc0,0xfc00007f,0xfe0,0x7f00,0x3f800,0x1fc000,0x0,0x0,0x0,
3964       0x1,0xf000001f,0x80000ff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x1f80000,0x1fc1e000,0x0,0x0,0x0,0x0,0x1e1fc0,0x0,0x0,0x0,0x0,
3965       0x0,0x0,0x0,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,
3966       0x781c007c,0x30003803,0x80001f00,0x1e0,0xf00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,0x0,0x7800000f,0x3c780,
3967       0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x1e000000,0xf00000,0x3e0,0xf0000e0,0x3c78003,0xc000f01e,0x1e0,0x7803c0,
3968       0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c0f8000,0x7800001e,0x701cf079,0xe01e01e0,0xf00780,0x1e07800,0x3c078001,0xe03c0000,
3969       0xf000,0xf0003c0,0x3c003c0f,0x3e00,0x787c001f,0x3e00000,0xf80003c,0x3c00,0x1e0,0x1f003e,0x0,0x0,0x1fffc001,0xe7ff0000,0x3ffe000f,
3970       0xfe78003f,0xfc001fff,0xfe001ffc,0xf0078ffc,0x1ffc00,0x7ff000,0x7800f80,0x1e0000f,0x7f1fc01e,0x3ff0001f,0xfe00079f,0xfc0007ff,
3971       0x3c003c7f,0xf001fff8,0x1fffff0,0x3c003c0,0xf0000f1e,0xf1f,0x7c1f0,0x1f00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3c00000,0x100000,
3972       0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7800000,0x1,0xe00f0000,0x1000000,0xf80000,0x40000002,0xf,0x80001f00,0x7e0f8,0x1f07c0,
3973       0x0,0x0,0x0,0x70,0x38c7003f,0xff000000,0xff8f,0xf8000100,0xffffe,0x7c0f80,0x0,0x0,0x3ffc000,0xf0000020,0x1001f0,0x3c00003c,
3974       0x1f80,0x0,0x1c3ffc7,0x7c0780,0x0,0x0,0xe3,0xff038000,0xe0,0x38000078,0x78,0x1ff0,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,
3975       0x7800000,0x1c00,0xe000,0xe00,0xf000,0x78f000,0x3c78000,0x1e3c0000,0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,
3976       0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,
3977       0x4000200f,0x3f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801f03e,0x1ffffe,0xf01fe0,0x3fff800,0x1fffc000,0xfffe0007,0xfff0003f,
3978       0xff8001ff,0xfc003ff3,0xfe0003ff,0xe0007ff8,0x3ffc0,0x1ffe00,0xfff000,0x3ff80001,0xffc0000f,0xfe00007f,0xf000003f,0xf8003c7f,
3979       0xe0003ffc,0x1ffe0,0xfff00,0x7ff800,0x3ffc000,0x1f80000,0xfff1c03c,0x3c01e0,0x1e00f00,0xf007800,0x781f0001,0xf01e7ff0,0x7c0007c,
3980       0x0,0x0,0x0,0x0,0x0,0x0,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,
3981       0x3c1e003f,0xfffff078,0x30003803,0x80000f00,0x1e0,0x1f00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x3c000f00,0x780001e,0x0,0x7800000f,
3982       0x78780,0x3c00000,0x3c000000,0x7c00f,0x780f0,0x3c0007,0xe000003f,0x0,0xfe000000,0xfe0000,0x3c0,0x1f000070,0x7c7c003,0xc000f01e,
3983       0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c1f0000,0x7800001e,0x783cf079,0xe01e03c0,0xf00780,0x1e0f000,0x3c078001,
3984       0xe03c0000,0xf000,0xf0003c0,0x3c003c07,0x81f03c00,0x7c7c000f,0x87c00000,0xf00003c,0x1e00,0x1e0,0x3e001f,0x0,0x0,0x3fffe001,
3985       0xefff8000,0x7fff001f,0xff78007f,0xfe001fff,0xfe003ffe,0xf0079ffe,0x1ffc00,0x7ff000,0x7801f00,0x1e0000f,0xffbfe01e,0x7ff8003f,
3986       0xff0007bf,0xfe000fff,0xbc003cff,0xf803fffc,0x1fffff0,0x3c003c0,0x78001e1e,0xf0f,0x800f80f0,0x1e00ff,0xffe0001e,0xf0,0x780,
3987       0x0,0x0,0x3c00000,0x380000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1008000,0x7800000,0x3,0xe00f0000,0x3800000,0xf00000,0xe0000007,
3988       0xf,0x80001f00,0x3e0f8,0x1e07c0,0x0,0x0,0x0,0x70,0x3807007f,0xff800000,0x1ffdf,0xfc000380,0xffffe,0x3e1f00,0x0,0x0,0xfffe000,
3989       0xf0000030,0x3800f8,0x7c00003c,0xfc0,0x0,0x18780c3,0xf00780,0x80100,0x0,0xc3,0xffc18000,0xf0,0x78000078,0xf0,0xf0,0x0,0x3c003c0,
3990       0xfffe1c00,0x0,0x0,0x380000f0,0x7800801,0x1c00,0xe000,0x1e00,0xf000,0xf8f800,0x7c7c000,0x3e3e0001,0xf1f0000f,0x8f80007c,0x7c000787,
3991       0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078001,0xe03c000f,
3992       0x1e00078,0xf0003c0,0x78001e00,0xe000701f,0x3fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x7800f87c,0x1e007f,0xf07e00,0x7fffc00,0x3fffe001,
3993       0xffff000f,0xfff8007f,0xffc003ff,0xfe007ff7,0xff0007ff,0xf000fffc,0x7ffe0,0x3fff00,0x1fff800,0x3ff80001,0xffc0000f,0xfe00007f,
3994       0xf00000ff,0xf8003cff,0xf0007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x1f80001,0xfffb803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,
3995       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,
3996       0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e003f,0xfffff078,0x30001c07,0xf80,0x1e0,0x1e00,0x3c00,0xff800,0x1e0000,0x0,0x0,0x0,0x3c001e00,
3997       0x3c0001e,0x0,0x7800001e,0x70780,0x3c00000,0x78000000,0x78007,0x800f00f0,0x3e0007,0xe000003f,0x3,0xfe000000,0xff8000,0x7c0,
3998       0x1e000070,0x783c003,0xc001f01e,0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c3e0000,0x7800001e,0x3838f079,
3999       0xe01e03c0,0x780780,0x1e0f000,0x1e078001,0xe03c0000,0xf000,0xf0003c0,0x3c007c07,0x81f03c00,0x3ef80007,0x87800000,0x1f00003c,
4000       0x1e00,0x1e0,0x7c000f,0x80000000,0x0,0x3ffff001,0xffffc000,0xffff003f,0xff7800ff,0xff001fff,0xfe007ffe,0xf007bffe,0x1ffc00,
4001       0x7ff000,0x7803e00,0x1e0000f,0xffffe01e,0xfff8007f,0xff8007ff,0xff001fff,0xbc003dff,0xf807fffc,0x1fffff0,0x3c003c0,0x78001e0f,
4002       0x1e07,0xc01f00f0,0x1e00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7c00000,0x7c0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1018000,0x7800000,
4003       0x3,0xc00f0000,0x7c00000,0x1f00001,0xf000000f,0x80000007,0xc0003e00,0x1e07c,0x3e0780,0x0,0x0,0x0,0x70,0x380700ff,0xff800000,
4004       0x3ffff,0xfe0007c0,0xffffe,0x1e1e00,0x0,0x780000,0x1fffe000,0xf0000078,0x7c0078,0x7800003c,0xff0,0x0,0x38e0003,0x80f00780,
4005       0x180300,0x0,0x1c3,0x81e1c000,0x7f,0xf0000078,0x1e0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800c01,0x80001c00,
4006       0xe000,0x603e00,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x7800078,0x3c000f87,0x8001e000,0x78000,0x3c0000,0x1e00000,
4007       0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f01,0xf000f81e,
4008       0x7bc0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007878,0x1e001f,0xf0f800,0x7fffe00,0x3ffff001,0xffff800f,0xfffc007f,0xffe003ff,
4009       0xff007fff,0xff800fff,0xf001fffe,0xffff0,0x7fff80,0x3fffc00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00001ff,0xfc003dff,0xf000ffff,
4010       0x7fff8,0x3fffc0,0x1fffe00,0xffff000,0x1f80003,0xffff803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,0xe01ffffc,0x3c00078,0x0,
4011       0x0,0x0,0x0,0x0,0x0,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,
4012       0x3c1e003f,0xfffff078,0x30001e0f,0x300780,0x1e0,0x1e00,0x3c00,0x3dde00,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf800003e,
4013       0xf0780,0x3dfc000,0x783f8000,0xf8007,0xc01f00f0,0x3e0007,0xe000003f,0x1f,0xfc000000,0x7ff000,0xf80,0x3e007c70,0x783c003,0xc001e03c,
4014       0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,0x80007800,0x780,0x3c7c0000,0x7800001e,0x3878f078,0xf01e03c0,0x780780,0x1e0f000,0x1e078001,
4015       0xe03e0000,0xf000,0xf0003c0,0x1e007807,0x83f03c00,0x3ef00007,0xcf800000,0x3e00003c,0xf00,0x1e0,0xf80007,0xc0000000,0x0,0x3e01f801,
4016       0xfe07e001,0xf80f007e,0x7f801f8,0x1f801fff,0xfe00fc0f,0xf007f83f,0x1ffc00,0x7ff000,0x7807c00,0x1e0000f,0x87e1e01f,0xe0fc00fc,
4017       0xfc007f8,0x1f803f03,0xfc003df0,0x3807e03c,0x1fffff0,0x3c003c0,0x78003e0f,0x1e03,0xe03e00f8,0x3e00ff,0xffe0001e,0xf0,0x780,
4018       0x0,0x0,0x7800000,0xfe0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7c00000,0x3,0xc00f0000,0xfe00000,0x3e00003,0xf800001f,
4019       0xc0000007,0xc0003e00,0x1e03c,0x3c0f80,0x0,0x0,0x0,0x70,0x380700fc,0x7800000,0x7c1fe,0x3e000fe0,0xffffe,0x1f3e00,0x0,0x780000,
4020       0x3f98e000,0xf000003c,0xfcf8007c,0xf800003c,0x3ffc,0x0,0x31c0001,0x80f00f80,0x380700,0x0,0x183,0x80e0c000,0x3f,0xe0000078,
4021       0x3c0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x38000078,0xf000e01,0xc003ffe0,0x1fff00,0x7ffc00,0xf000,0xf07800,0x783c000,0x3c1e0001,
4022       0xe0f0000f,0x7800078,0x3c000f07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
4023       0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf801f01e,0xf3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007cf8,
4024       0x1e000f,0x80f0f000,0x7c03f00,0x3e01f801,0xf00fc00f,0x807e007c,0x3f003e0,0x1f80707f,0x8f801f80,0xf003f03f,0x1f81f8,0xfc0fc0,
4025       0x7e07e00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00003ff,0xfc003fc1,0xf801f81f,0x800fc0fc,0x7e07e0,0x3f03f00,0x1f81f800,0x1f80007,
4026       0xe07f003c,0x3c01e0,0x1e00f00,0xf007800,0x780f8003,0xe01fe07e,0x3e000f8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4027       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3f,0xfffff078,0x30000ffe,0x1f007c0,0x0,0x1e00,
4028       0x3c00,0xf9cf80,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf00000fc,0x1e0780,0x3fff800,0x78ffe000,0xf0003,0xe03e00f0,
4029       0x3e0007,0xe000003f,0x7f,0xe01fffff,0xf00ffc00,0x1f80,0x3c01ff70,0x783c003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,
4030       0x80007800,0x780,0x3cfc0000,0x7800001e,0x3c78f078,0xf01e03c0,0x780780,0x3e0f000,0x1e078003,0xc01f0000,0xf000,0xf0003c0,0x1e007807,
4031       0x83f83c00,0x1ff00003,0xcf000000,0x3e00003c,0xf00,0x1e0,0x0,0x0,0x0,0x20007801,0xfc03e003,0xe003007c,0x3f803e0,0x7c0003c,
4032       0xf807,0xf007e00f,0x3c00,0xf000,0x780f800,0x1e0000f,0x87e1f01f,0x803c00f8,0x7c007f0,0xf803e01,0xfc003f80,0x80f8004,0x3c000,
4033       0x3c003c0,0x3c003c0f,0x1e03,0xe03e0078,0x3c0000,0x7c0001e,0xf0,0x780,0x0,0x0,0x3ffff800,0x1ff0000,0x0,0x7800000,0x0,0x18,
4034       0xc0,0x0,0x1818000,0x3e00000,0x3,0xc00f0000,0x1ff00000,0x3e00007,0xfc00003f,0xe0000003,0xc0003c00,0xf03c,0x3c0f00,0x0,0x0,
4035       0x0,0x70,0x380701f0,0x800000,0x780fc,0x1e001ff0,0x7c,0xf3c00,0x0,0x780000,0x7e182000,0xf000001f,0xfff00ffc,0xffc0003c,0x3cfe,
4036       0x0,0x31c0001,0x80f01f80,0x780f00,0x0,0x183,0x80e0c000,0xf,0x80000078,0x780,0x38,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x38000078,
4037       0xf000f01,0xe003ffe0,0x1fff00,0x7ff800,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x78000f8,0x3e000f07,0x8003c000,0x78000,
4038       0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
4039       0x78000f00,0x7c03e01e,0x1e3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78003cf0,0x1e0007,0x80f1e000,0x4000f00,0x20007801,0x3c008,
4040       0x1e0040,0xf00200,0x780403f,0x7803e00,0x3007c00f,0x803e007c,0x1f003e0,0xf801f00,0x780000,0x3c00000,0x1e000000,0xf00007f0,
4041       0x3e003f00,0x7801f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e003c,0x3c01e0,0x1e00f00,0xf007800,0x78078003,
4042       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,
4043       0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xf078007c,0x300007fc,0x7e00fe0,0x0,0x1e00,0x3c00,0x3e1c3e0,0x1e0000,0x0,0x0,0x0,0xf0001e00,
4044       0x3c0001e,0x1,0xf000fff8,0x1e0780,0x3fffe00,0x79fff000,0x1f0001,0xfffc00f0,0x7e0007,0xe000003f,0x3ff,0x801fffff,0xf003ff80,
4045       0x3f00,0x3c03fff0,0xf01e003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3df80000,0x7800001e,
4046       0x1c70f078,0x781e03c0,0x780780,0x3c0f000,0x1e078007,0xc01f8000,0xf000,0xf0003c0,0x1e007807,0x83f83c00,0xfe00003,0xff000000,
4047       0x7c00003c,0x780,0x1e0,0x0,0x0,0x0,0x7c01,0xf801f007,0xc00100f8,0x1f803c0,0x3c0003c,0x1f003,0xf007c00f,0x80003c00,0xf000,
4048       0x783f000,0x1e0000f,0x3c0f01f,0x3e01f0,0x3e007e0,0x7c07c00,0xfc003f00,0xf0000,0x3c000,0x3c003c0,0x3c003c0f,0x1e01,0xf07c007c,
4049       0x7c0000,0xfc0001e,0xf0,0x780,0x0,0x0,0x3ffff000,0x3838000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0xff0000,0x3f00000,0x3,0xc00fff00,
4050       0x38380000,0x7c0000e,0xe000070,0x70000001,0xe0003c00,0xf01e,0x780e00,0x0,0x0,0x0,0x0,0x1e0,0x0,0x780f8,0xf003838,0xfc,0xffc00,
4051       0x0,0x780000,0x7c180000,0xf000000f,0xffe00fff,0xffc0003c,0x783f,0x80000000,0x6380000,0xc0f83f80,0xf81f00,0x0,0x303,0x80e06000,
4052       0x0,0x78,0xf00,0x78,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x3800003c,0x3e000f81,0xf003ffe0,0x1fff00,0x1fc000,0xf000,0x1e03c00,
4053       0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e000f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,
4054       0x3c000001,0xe0001e00,0x3c0f0f0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3e07c01e,0x1e3c0f0,0x3c0780,0x1e03c00,
4055       0xf01e000,0x78003ff0,0x1e0007,0x80f1e000,0xf80,0x7c00,0x3e000,0x1f0000,0xf80000,0x7c0001e,0x3c07c00,0x10078007,0x803c003c,
4056       0x1e001e0,0xf000f00,0x780000,0x3c00000,0x1e000000,0xf00007c0,0x1e003e00,0x7c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,
4057       0xf,0x801f003c,0x3c01e0,0x1e00f00,0xf007800,0x7807c007,0xc01f801f,0x1f001f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4058       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xe078003c,0x300001f0,0x3f801ff0,0x0,
4059       0x3c00,0x1e00,0x3c1c1e0,0x1e0000,0x0,0x0,0x0,0xf0001e0f,0x3c0001e,0x3,0xe000fff0,0x3c0780,0x3ffff00,0x7bfff800,0x1e0000,0x7ff00078,
4060       0x7e0007,0xe000003f,0x1ffc,0x1fffff,0xf0007ff0,0x7e00,0x3c07c3f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,
4061       0x1fffff,0x80007800,0x780,0x3ffc0000,0x7800001e,0x1ef0f078,0x781e03c0,0x780780,0x7c0f000,0x1e07801f,0x800ff000,0xf000,0xf0003c0,
4062       0xf00f807,0x83b83c00,0xfc00001,0xfe000000,0xf800003c,0x780,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0xc00000f0,0xf80780,0x3c0003c,
4063       0x1e001,0xf007c007,0x80003c00,0xf000,0x787e000,0x1e0000f,0x3c0f01f,0x1e01e0,0x1e007c0,0x3c07800,0x7c003f00,0xf0000,0x3c000,
4064       0x3c003c0,0x3e007c07,0x80003c00,0xf8f8003c,0x780000,0xf80001e,0xf0,0x780,0x0,0x0,0x7ffff000,0x601c000,0x3,0xffff0000,0x0,
4065       0xfff,0xf8007fff,0xc0000000,0x7e003c,0x1fe0000,0xc0003,0xc00fff00,0x601c0000,0xf800018,0x70000c0,0x38000001,0xe0007800,0x701e,
4066       0x701e00,0x0,0x0,0x0,0x0,0x1e0,0x6,0x700f8,0xf00601c,0xf8,0x7f800,0x0,0x780000,0xf8180000,0xf000000f,0x87c00fff,0xffc0003c,
4067       0xf01f,0xc0000000,0x6380000,0xc07ff780,0x1f03e03,0xfffffe00,0x303,0x81c06000,0x0,0x1ffff,0xfe001e00,0x180f8,0x0,0x3c003c0,
4068       0x3ffe1c00,0x3f00000,0x0,0x3800003f,0xfe0007c0,0xf8000000,0x18000000,0xc0000006,0x1f000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,
4069       0x3c000f0,0x1e001f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f0f0,
4070       0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f0f801e,0x3c3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,
4071       0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07c00,0xf0007,0x8078003c,0x3c001e0,0x1e000f00,0x780000,0x3c00000,
4072       0x1e000000,0xf0000f80,0x1f003e00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0xf,0x3f003c,0x3c01e0,0x1e00f00,0xf007800,
4073       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,
4074       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe078003f,0xb0000000,0xfc003cf0,0x0,0x3c00,0x1e00,0x101c040,0x1e0000,0x0,0x0,0x1,
4075       0xe0001e1f,0x83c0001e,0x7,0xe000fff0,0x3c0780,0x3c03f80,0x7fc0fc00,0x1e0000,0xfff80078,0xfe0007,0xe000003f,0x7fe0,0x1fffff,
4076       0xf0000ffc,0xfc00,0x780f81f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3ffc0000,
4077       0x7800001e,0x1ef0f078,0x3c1e03c0,0x780780,0x1fc0f000,0x1e07ffff,0x7ff00,0xf000,0xf0003c0,0xf00f007,0xc3b87c00,0x7c00001,0xfe000000,
4078       0xf800003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0x800000f0,0xf80780,0x1e0003c,0x1e001,0xf0078007,0x80003c00,0xf000,0x78fc000,
4079       0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,0x3c07800,0x7c003e00,0xf0000,0x3c000,0x3c003c0,0x1e007807,0x80003c00,0x7df0003c,0x780000,
4080       0x1f00001e,0xf0,0x780,0x0,0x0,0x7800000,0xe7ce000,0x3,0xffff0000,0x0,0xfff,0xf8007fff,0xc0000000,0x1f0,0xffe000,0x1c0003,
4081       0xc00fff00,0xe7ce0000,0xf800039,0xf38001cf,0x9c000000,0xe0007800,0x780e,0x701c00,0x0,0x0,0x0,0x0,0x1e0,0x7,0xf0078,0xf00e7ce,
4082       0x1f0,0x7f800,0x0,0x780000,0xf0180000,0xf000000e,0x1c0001f,0xe000003c,0xf007,0xe0000000,0x6380000,0xc03fe780,0x3e07c03,0xfffffe00,
4083       0x303,0xffc06000,0x0,0x1ffff,0xfe003ffe,0x1fff0,0x0,0x3c003c0,0x1ffe1c00,0x3f00000,0x7,0xffc0001f,0xfc0003e0,0x7c000001,0xfc00000f,
4084       0xe000007f,0x1e000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,
4085       0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,
4086       0x783c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07800,
4087       0xf0003,0xc078001e,0x3c000f0,0x1e000780,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,
4088       0x7800780,0x3c003c00,0xf,0x7f003c,0x3c01e0,0x1e00f00,0xf007800,0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4089       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,
4090       0xf0007cf8,0x7800000,0x3c00,0x1e00,0x1c000,0x1e0000,0x0,0x0,0x1,0xe0001e1f,0x83c0001e,0xf,0xc000fff8,0x780780,0x2000f80,0x7f803e00,
4091       0x3e0003,0xfffe007c,0x1fe0000,0x0,0x3ff00,0x0,0x1ff,0x8001f000,0x780f00f0,0x1f00f003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,
4092       0xfe03c00f,0xf81fffff,0x80007800,0x780,0x3ffe0000,0x7800001e,0xee0f078,0x3c1e03c0,0x7807ff,0xff80f000,0x1e07fffe,0x3ffe0,
4093       0xf000,0xf0003c0,0xf00f003,0xc7bc7800,0xfc00000,0xfc000001,0xf000003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xe000f80f,0x800001e0,
4094       0xf80f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x79f8000,0x1e0000f,0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003e00,
4095       0xf0000,0x3c000,0x3c003c0,0x1e007807,0x81e03c00,0x7df0003e,0xf80000,0x3e00003e,0xf0,0x7c0,0xfc000,0x80000000,0x7800000,0x1e7cf000,
4096       0x3,0xffff0000,0x0,0x18,0xc0,0x0,0xf80,0x7ffc00,0x380003,0xc00fff01,0xe7cf0000,0x1f000079,0xf3c003cf,0x9e000000,0xe0007000,
4097       0x380e,0xe01c00,0x0,0x0,0x0,0x0,0x1e0,0x3,0x800f0078,0xf01e7cf,0x3e0,0x3f000,0x0,0x780000,0xf018001f,0xfff8001e,0x1e0000f,
4098       0xc000003c,0xf003,0xe0000000,0x6380000,0xc00fc780,0x7c0f803,0xfffffe00,0x303,0xfe006000,0x0,0x1ffff,0xfe003ffe,0x1ffe0,0x0,
4099       0x3c003c0,0xffe1c00,0x3f00000,0x7,0xffc00007,0xf00001f0,0x3e00001f,0xfc0000ff,0xe00007ff,0x3e000,0x3e01e00,0x1f00f000,0xf8078007,
4100       0xc03c003e,0x1e001e0,0xf001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,
4101       0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000fc0,
4102       0x1e0007,0x80f1f000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c0f800,0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,
4103       0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1e,0xf7803c,0x3c01e0,0x1e00f00,
4104       0xf007800,0x7803e00f,0x801e000f,0x80f803e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4105       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe0f0000f,0xff00001f,0x8000f87c,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,
4106       0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x1f,0x800000fe,0xf00780,0x7c0,0x7f001e00,0x3c0007,0xe03f003f,0x3fe0000,0x0,0x3fc00,0x0,
4107       0x7f,0x8001e000,0x781f00f0,0x1e00f003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3f9f0000,0x7800001e,
4108       0xfe0f078,0x3c1e03c0,0x7807ff,0xff00f000,0x1e07fff8,0xfff8,0xf000,0xf0003c0,0xf81f003,0xc7bc7800,0xfe00000,0x78000003,0xe000003c,
4109       0x1e0,0x1e0,0x0,0x0,0x0,0x1fffc01,0xe000780f,0x1e0,0x780f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7bf0000,0x1e0000f,
4110       0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xf8000,0x3c000,0x3c003c0,0x1f00f807,0x81f03c00,0x3fe0001e,0xf00000,0x7c00007c,
4111       0xf0,0x3e0,0x3ff801,0x80000000,0x7800000,0x3cfcf800,0x3,0xffff0000,0x0,0x18,0xc0,0x0,0x7c00,0x1fff00,0x700003,0xc00f0003,
4112       0xcfcf8000,0x3e0000f3,0xf3e0079f,0x9f000000,0xf000,0x1000,0x0,0x0,0x0,0x0,0x0,0x1f0,0x1,0xc00f0078,0xf03cfcf,0x800007c0,0x1e000,
4113       0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x8000003c,0xf001,0xf0000000,0x6380000,0xc0000000,0xf81f003,0xfffffe00,0x303,
4114       0x87006000,0x0,0x1ffff,0xfe003ffe,0x7f00,0x0,0x3c003c0,0x3fe1c00,0x3f00000,0x7,0xffc00000,0xf8,0x1f0001ff,0xf0000fff,0x80007ffc,
4115       0xfc000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf001e07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,
4116       0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3fc001e,0x1e03c0f0,0x3c0780,
4117       0x1e03c00,0xf01e000,0x78000780,0x1e0007,0x80f0fc00,0x3fff80,0x1fffc00,0xfffe000,0x7fff0003,0xfff8001f,0xffc0001e,0x3c0f000,
4118       0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,0x3c00000,0x1e000000,0xf0001e00,0xf803c00,0x3c078001,0xe03c000f,0x1e00078,
4119       0xf0003c0,0x78001e07,0xfffffe1e,0x1e7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801e00f,0x1e0007,0x807803c0,0x0,0x0,0x0,0x0,0x0,
4120       0x0,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,
4121       0xffc0007e,0xf03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x3f,0x3e,0xf00780,0x3c0,0x7e001e00,
4122       0x7c000f,0x800f001f,0xffde0000,0x0,0x3e000,0x0,0xf,0x8003e000,0x781e0070,0x1e00f003,0xc001f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,
4123       0xf81e0007,0x80007800,0x780,0x3f1f0000,0x7800001e,0x7c0f078,0x1e1e03c0,0x7807ff,0xfc00f000,0x1e07fffe,0xffc,0xf000,0xf0003c0,
4124       0x781e003,0xc71c7800,0x1ff00000,0x78000003,0xe000003c,0x1e0,0x1e0,0x0,0x0,0x0,0xffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,
4125       0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7f000,0x3c000,
4126       0x3c003c0,0xf00f007,0xc1f07c00,0x1fc0001f,0x1f00000,0xfc000ff8,0xf0,0x1ff,0xfffe07,0x80000000,0x7800000,0x7ffcfc00,0x0,0xf000000,
4127       0x0,0x18,0xc0,0x0,0x3e000,0x1ff80,0xe00003,0xc00f0007,0xffcfc000,0x3e0001ff,0xf3f00fff,0x9f800000,0x6000,0x0,0x0,0x7c000,
4128       0x0,0x0,0x0,0xfe,0x0,0xe00f007f,0xff07ffcf,0xc0000fc0,0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x80000000,0xf800,
4129       0xf0000000,0x6380000,0xc0000000,0x1f03c000,0x1e00,0x303,0x83806000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xfe1c00,0x3f00000,0x0,
4130       0x0,0x3c,0xf801fff,0xfff8,0x7ffc0,0x1f8000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf003c07,0x8003c000,0x78000,
4131       0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
4132       0x78000f00,0x1f8001e,0x1e03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e000f,0x80f0ff00,0x1ffff80,0xffffc00,0x7fffe003,
4133       0xffff001f,0xfff800ff,0xffc007ff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,
4134       0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x3c7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801f01f,
4135       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,
4136       0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00000,0xfff003f0,0x1f00f03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x7ff80000,0x3,
4137       0xc0001e0f,0x3c0001e,0x7e,0x1f,0x1e00780,0x3e0,0x7e000f00,0x78000f,0x7800f,0xff9e0000,0x0,0x3fc00,0x0,0x7f,0x8003c000,0x781e0070,
4138       0x3e00f803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3e0f8000,0x7800001e,0x7c0f078,0x1e1e03c0,
4139       0x7807ff,0xf000f000,0x1e07807f,0xfe,0xf000,0xf0003c0,0x781e003,0xc71c7800,0x3ef00000,0x78000007,0xc000003c,0x1e0,0x1e0,0x0,
4140       0x0,0x0,0x1ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,
4141       0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7ff80,0x3c000,0x3c003c0,0xf00f003,0xc1f07800,0x1fc0000f,0x1e00000,0xf8000ff0,0xf0,
4142       0xff,0xffffff,0x80000000,0x3fffc000,0xfff9fe00,0x0,0xf000000,0x0,0x18,0xc0,0x0,0x1f0000,0x1fc0,0x1c00003,0xc00f000f,0xff9fe000,
4143       0x7c0003ff,0xe7f81fff,0x3fc00000,0x0,0x0,0x0,0xfe000,0x1ffffc0f,0xfffffc00,0x0,0xff,0xf0000000,0x700f007f,0xff0fff9f,0xe0000f80,
4144       0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00fff,0xffc00000,0xf800,0xf0000000,0x6380000,0xc0ffff80,0x3e078000,0x1e00,0x7ff80303,
4145       0x83c06000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,0x0,0x7f,0xff00001e,0x7c1fff0,0xfff80,0x7ffc00,0x3f0000,0x7c01f00,
4146       0x3e00f801,0xf007c00f,0x803e007c,0x1f003e0,0xf803c07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
4147       0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f8001e,0x3c03c0f0,0x3c0780,0x1e03c00,0xf01e000,
4148       0x78000780,0x1e001f,0xf07f80,0x3ffff80,0x1ffffc00,0xffffe007,0xffff003f,0xfff801ff,0xffc03fff,0xffc0f000,0x1fffff,0xc0fffffe,
4149       0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,
4150       0xfffffe1e,0x787803c,0x3c01e0,0x1e00f00,0xf007800,0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4151       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,
4152       0x7800000,0x3c00,0x1e00,0x0,0x7fffff80,0x0,0x7ff80000,0x7,0x80001e00,0x3c0001e,0xfc,0xf,0x1e00780,0x1e0,0x7c000f00,0x78000f,
4153       0x78007,0xff1e0000,0x0,0x3ff00,0x0,0x1ff,0x8003c000,0x781e0070,0x3c007803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,
4154       0x80007800,0x780,0x3c07c000,0x7800001e,0x7c0f078,0xf1e03c0,0x780780,0xf000,0x1e07801f,0x3e,0xf000,0xf0003c0,0x781e003,0xcf1c7800,
4155       0x3cf80000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,0x0,0x0,0x3ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,
4156       0x80003c00,0xf000,0x7ff8000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3fff0,0x3c000,0x3c003c0,0xf81f003,
4157       0xc3b87800,0xf80000f,0x1e00001,0xf0000ff0,0xf0,0xff,0xf03fff,0x80000000,0x3fff8001,0xfff1ff00,0x0,0xf000000,0x0,0x18,0xc0,
4158       0x0,0x380000,0x7c0,0x3c00003,0xc00f001f,0xff1ff000,0xf80007ff,0xc7fc3ffe,0x3fe00000,0x0,0x0,0x0,0x1ff000,0x7ffffe1f,0xffffff00,
4159       0x0,0x7f,0xfe000000,0x780f007f,0xff1fff1f,0xf0001f00,0x1e000,0x0,0x780001,0xe0180000,0xf000001c,0xe00fff,0xffc00000,0x7c00,
4160       0xf0000000,0x31c0001,0x80ffff80,0x3e078000,0x1e00,0x7ff80183,0x81c0c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,
4161       0x0,0x7f,0xff00001e,0x7c7ff03,0xc03ff8fe,0x1ffc0f0,0x7e0000,0x7800f00,0x3c007801,0xe003c00f,0x1e0078,0xf003c0,0x7803c07,0x8003c000,
4162       0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,
4163       0xf0001e0,0x78000f00,0x3fc001e,0x7803c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e007f,0xf03fe0,0x7ffff80,0x3ffffc01,
4164       0xffffe00f,0xffff007f,0xfff803ff,0xffc07fff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,
4165       0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x707803c,0x3c01e0,0x1e00f00,0xf007800,
4166       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,
4167       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x30f81f00,0xffe1e00f,0x87800000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,
4168       0x7,0x80001e00,0x3c0001e,0x1f8,0x7,0x83c00780,0x1e0,0x7c000f00,0xf8001e,0x3c001,0xfc1e0000,0x0,0x7fe0,0x0,0xffc,0x3c000,0x781e0070,
4169       0x3ffff803,0xc000783c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x380f078,0xf1e03c0,
4170       0x780780,0xf000,0x1e07800f,0x8000001e,0xf000,0xf0003c0,0x3c3c003,0xcf1e7800,0x7c780000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,
4171       0x0,0x0,0x7f003c01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7f7c000,0x1e0000f,0x3c0f01e,
4172       0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfff8,0x3c000,0x3c003c0,0x781e003,0xc3b87800,0x1fc00007,0x83e00003,0xe0000ff8,0xf0,
4173       0x1ff,0xc007fe,0x0,0x7fff8001,0xffe3ff00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x3c0,0x7800003,0xc00f001f,0xfe3ff000,0xf80007ff,
4174       0x8ffc3ffc,0x7fe00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x1f,0xff000000,0x3c0f007f,0xff1ffe3f,0xf0003e00,0x1e000,0x0,0x780001,
4175       0xe0180000,0xf000001e,0x1e00fff,0xffc00000,0x3f00,0xf0000000,0x31c0001,0x80ffff80,0x1f03c000,0x1e00,0x7ff80183,0x81c0c000,
4176       0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x7f,0xff00003c,0xf87f007,0xc03f83ff,0x81fc01f0,0x7c0000,0x7ffff00,0x3ffff801,
4177       0xffffc00f,0xfffe007f,0xfff003ff,0xff807fff,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
4178       0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf003c0f0,0x3c0780,0x1e03c00,0xf01e000,
4179       0x78000780,0x1ffffe,0xf00ff0,0xfe00780,0x7f003c03,0xf801e01f,0xc00f00fe,0x7807f0,0x3c0ffff,0xffc0f000,0x1fffff,0xc0fffffe,
4180       0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
4181       0x1e,0xf07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783e,0x1e0007,0x801e0f80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4182       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x307c0801,0xe1f1e00f,0x87000000,
4183       0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,0xf,0x1e00,0x3c0001e,0x3f0,0x7,0x83fffffc,0x1e0,0x7c000f00,0xf0001e,0x3c000,0x3e0000,
4184       0x0,0x1ffc,0x1fffff,0xf0007ff0,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x3c000,0x781e0007,0x80007800,
4185       0x780,0x3c03e000,0x7800001e,0xf078,0x79e03c0,0x780780,0xf000,0x1e078007,0x8000000f,0xf000,0xf0003c0,0x3c3c001,0xee0ef000,
4186       0xf87c0000,0x7800001f,0x3c,0x78,0x1e0,0x0,0x0,0x0,0x7c003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
4187       0xf000,0x7e3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x1ffc,0x3c000,0x3c003c0,0x781e003,0xe3b8f800,
4188       0x1fc00007,0x83c00007,0xc00000fc,0xf0,0x3e0,0x8001f8,0x0,0x7800000,0xffc7fe00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,
4189       0xf000003,0xc00f000f,0xfc7fe001,0xf00003ff,0x1ff81ff8,0xffc00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x3,0xff800000,0x1e0f0078,
4190       0xffc7f,0xe0007c00,0x1e000,0x0,0x780001,0xe0180000,0xf000000e,0x1c00007,0x80000000,0x1f81,0xe0000000,0x38e0003,0x80000000,
4191       0xf81f000,0x1e00,0x7ff801c3,0x80e1c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf8,0x1f070007,0xc03803ff,0xc1c001f0,
4192       0xf80000,0xfffff00,0x7ffff803,0xffffc01f,0xfffe00ff,0xfff007ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,
4193       0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f00f,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,0xf003c0f0,
4194       0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1ffffc,0xf003f8,0xf800780,0x7c003c03,0xe001e01f,0xf00f8,0x7807c0,0x3c0fc1e,0xf000,
4195       0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,
4196       0xf0003c0,0x78001e00,0x1e,0x1e07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783c,0x1e0007,0x801e0f00,0x0,0x0,0x0,0x0,0x0,0x0,
4197       0x0,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,
4198       0xc071e007,0xcf000000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0xf,0xf00,0x780001e,0x7e0,0x7,0x83fffffc,0x1e0,0x7c000f00,0x1f0001e,
4199       0x3c000,0x3c0000,0x0,0x3ff,0x801fffff,0xf003ff80,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,
4200       0x80007800,0x780,0x3c01f000,0x7800001e,0xf078,0x79e03c0,0xf00780,0xf000,0x3e078007,0xc000000f,0xf000,0xf0003c0,0x3c3c001,
4201       0xee0ef000,0xf03e0000,0x7800003e,0x3c,0x78,0x1e0,0x0,0x0,0x0,0xf8003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,
4202       0x80003c00,0xf000,0x7c3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfc,0x3c000,0x3c003c0,0x3c3e001,0xe7b8f000,
4203       0x3fe00007,0xc7c0000f,0xc000003e,0xf0,0x7c0,0x0,0x0,0x7c00000,0x7fcffc00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,0x1e000003,
4204       0xc00f0007,0xfcffc003,0xe00001ff,0x3ff00ff9,0xff800000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x1f800000,0xf0f0078,0x7fcff,
4205       0xc000fc00,0x1e000,0x0,0x780001,0xe0180000,0xf000000f,0x87c00007,0x80000000,0xfe3,0xe0000000,0x18780c3,0x0,0x7c0f800,0x1e00,
4206       0xc3,0x80e18000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x1f0,0x3e00000f,0xc0000303,0xe00003f0,0xf00000,0xfffff80,
4207       0x7ffffc03,0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,
4208       0x3c000001,0xe0001e00,0x780f00f,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1f0f801f,0xe00780f0,0x3c0780,0x1e03c00,
4209       0xf01e000,0x78000780,0x1ffff8,0xf000f8,0x1f000780,0xf8003c07,0xc001e03e,0xf01f0,0x780f80,0x3c1f01e,0xf000,0x1e0000,0xf00000,
4210       0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
4211       0x1e,0x3c07803c,0x3c01e0,0x1e00f00,0xf007800,0x78007c7c,0x1e0007,0x801f1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4212       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c00000,0x303c0003,0x8039e003,0xef000000,
4213       0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0xfc0,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,
4214       0x0,0x7f,0xe01fffff,0xf00ffc00,0x3c000,0x781f00f0,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,0x80007800,
4215       0x780,0x3c01f000,0x7800001e,0xf078,0x7de01e0,0xf00780,0x7800,0x3c078003,0xc000000f,0xf000,0xf0003c0,0x3e7c001,0xee0ef001,
4216       0xf01e0000,0x7800003e,0x3c,0x3c,0x1e0,0x0,0x0,0x0,0xf0003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
4217       0xf000,0x781f000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0x7df00003,
4218       0xc780000f,0x8000003e,0xf0,0x780,0x0,0x0,0x3c00000,0x3fcff800,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x1f00fc,0x1e0,0x1e000001,
4219       0xe00f0003,0xfcff8003,0xe00000ff,0x3fe007f9,0xff000000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x7c00000,0xf0f0078,0x3fcff,0x8000f800,
4220       0x1e000,0x0,0x780001,0xe0180000,0xf000001f,0xffe00007,0x8000003c,0x7ff,0xc0000000,0x1c3ffc7,0x0,0x3e07c00,0x1e00,0xe3,0x80738000,
4221       0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x3e0,0x7c00001d,0xc0000001,0xe0000770,0x1f00000,0xfffff80,0x7ffffc03,
4222       0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
4223       0xe0001e00,0x780f00f,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0x3e07c01f,0xc00780f0,0x3c0780,0x1e03c00,0xf01e000,
4224       0x78000780,0x1fffc0,0xf0007c,0x1e000780,0xf0003c07,0x8001e03c,0xf01e0,0x780f00,0x3c1e01e,0xf000,0x1e0000,0xf00000,0x7800000,
4225       0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1e,0x7807803c,
4226       0x3c01e0,0x1e00f00,0xf007800,0x78003c78,0x1e0007,0x800f1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4227       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x83c00000,0x303c0003,0x8039e001,0xee000000,0x1e00,0x3c00,
4228       0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0x1f80,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,0x0,0x1f,0xfc1fffff,
4229       0xf07ff000,0x0,0x780f00f0,0x78003c03,0xc000781e,0x1e0,0xf803c0,0x1e00,0x1e000,0x781e0007,0x80007800,0x780,0x3c00f800,0x7800001e,
4230       0xf078,0x3de01e0,0xf00780,0x7800,0x3c078003,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfe0ff003,0xe01f0000,0x7800007c,0x3c,0x3c,
4231       0x1e0,0x0,0x0,0x0,0xf0007c01,0xe000f80f,0x800001e0,0xf80f00,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x780f800,0x1e0000f,
4232       0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003c00,0x1e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0xf8f80003,0xe780001f,0x1e,
4233       0xf0,0x780,0x0,0x0,0x3c00000,0x1ffff000,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x3bc1de,0x1e0,0xf000001,0xe00f0001,0xffff0007,0xc000007f,
4234       0xffc003ff,0xfe000000,0x0,0x0,0x0,0xfe000,0x0,0x0,0x0,0x0,0x3c00000,0x1e0f0078,0x1ffff,0x1f000,0x1e000,0x0,0x780000,0xf0180000,
4235       0xf000001f,0xfff00007,0x8000003c,0x1ff,0x80000000,0xe0ff0e,0x0,0x1f03e00,0x1e00,0x70,0x70000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,
4236       0xe1c00,0x0,0x0,0x0,0x7c0,0xf8000019,0xc0000000,0xe0000670,0x1e00000,0xf000780,0x78003c03,0xc001e01e,0xf00f0,0x780780,0x3c0f807,
4237       0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf80f007,0xbc03c001,0xe01e000f,
4238       0xf00078,0x78003c0,0x3c001e00,0x7c03e00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,
4239       0xf0007c07,0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0xf800,0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,
4240       0xf0001e00,0x7803c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1f8001f,0xf00f803c,0x3c01e0,0x1e00f00,0xf007800,
4241       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,
4242       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x3c00000,0x303c0003,0x8039f001,0xfe000000,0x1e00,0x3c00,0x0,0x1e0000,0x0,0x0,0x3c,0xf00,
4243       0x780001e,0x3f00,0x7,0x80000780,0x3e0,0x3e000f00,0x3c0001e,0x3c000,0x7c0000,0x0,0x3,0xfe000000,0xff8000,0x0,0x3c0f81f0,0xf0001e03,
4244       0xc000780f,0x1e0,0xf003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x780,0x3c007c00,0x7800001e,0xf078,0x3de01e0,0xf00780,0x7800,
4245       0x3c078001,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfc07f003,0xe00f0000,0x78000078,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
4246       0xf000f007,0x800000f0,0xf80780,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
4247       0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78001,0xe71df000,0xf8f80001,0xef80003e,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,
4248       0xfffe000,0x0,0x3e000000,0x0,0x18,0x7fff,0xc0000000,0x60c306,0x1e0,0x7800001,0xe00f0000,0xfffe0007,0x8000003f,0xff8001ff,
4249       0xfc000000,0x0,0x0,0x0,0x7c000,0x0,0x0,0x0,0x0,0x3c00000,0x3c0f0078,0xfffe,0x3e000,0x1e000,0x0,0x780000,0xf0180000,0xf000003c,
4250       0xfcf80007,0x8000003c,0x7f,0x0,0x70001c,0x0,0xf81f00,0x0,0x38,0xe0000,0x0,0x0,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf81,
4251       0xf0000039,0xc0000000,0xe0000e70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,0x8000f000,0x78000,
4252       0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f007,0xbc03c001,0xe01e000f,0xf00078,0x78003c0,
4253       0x3c001e00,0xf801f00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,0x8003e03c,
4254       0x1f01e0,0xf80f00,0x7c1e01e,0x7800,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,
4255       0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xe00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef8,0x1f000f,
4256       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,
4257       0x0,0x0,0xf,0x3c00000,0x307c0003,0x8038f000,0xfc000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e00003c,0x780,0xf00001e,
4258       0x7e00,0xf,0x80000780,0x3c0,0x3e001e00,0x3c0001f,0x7c000,0x780007,0xe000003f,0x0,0xfe000000,0xfe0000,0x0,0x3c07c3f0,0xf0001e03,
4259       0xc000f80f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x4000f80,0x3c003c00,0x7800001e,0xf078,0x1fe01f0,0x1f00780,
4260       0x7c00,0x7c078001,0xf000001f,0xf000,0xf0003c0,0x1e78001,0xfc07f007,0xc00f8000,0x780000f8,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
4261       0xf000f007,0xc00000f0,0xf80780,0x3c,0x1f003,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
4262       0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78000,0xfe0fe001,0xf07c0001,0xef00007c,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,
4263       0x7cfc000,0xfc00000,0x3c00000f,0xc3f00000,0x18,0x7fff,0xc0000000,0x406303,0x3e0,0x3c00001,0xf00f0000,0x7cfc000f,0x8000001f,
4264       0x3f0000f9,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x780700f8,0x7cfc,0x7c000,0x1e000,0x0,0x780000,0xf8180000,
4265       0xf0000070,0x3c0007,0x8000003c,0x3f,0x80000000,0x3c0078,0x0,0x780f00,0x0,0x1e,0x3c0000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,0xe1c00,
4266       0x0,0x0,0x0,0xf01,0xe0000071,0xc0000000,0xe0001c70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
4267       0x8000f800,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00f003,0xfc03e003,0xe01f001f,
4268       0xf800f8,0x7c007c0,0x3e003e01,0xf000f80f,0xf00f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,
4269       0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0x7c00,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,
4270       0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xc00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef0,
4271       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,
4272       0x0,0x0,0x0,0x0,0x780000,0xf,0x3800040,0x30780003,0x8038f800,0x78000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
4273       0x780,0x1f00001e,0xfc00,0x20001f,0x780,0x80007c0,0x1f001e00,0x7c0000f,0x78000,0xf80007,0xe000003f,0x0,0x1e000000,0xf00000,
4274       0x3c000,0x3c03fff0,0xf0001e03,0xc001f007,0x800101e0,0x7e003c0,0x1e00,0x7800,0x781e0007,0x80007800,0x6000f00,0x3c003e00,0x7800001e,
4275       0xf078,0x1fe00f0,0x1e00780,0x3c00,0x78078000,0xf020001e,0xf000,0x7800780,0xff0001,0xfc07f00f,0x8007c000,0x780001f0,0x3c,0xf,
4276       0x1e0,0x0,0x0,0x0,0xf800fc01,0xf801f007,0xc00100f8,0x1f807c0,0x40003c,0xf807,0xf0078007,0x80003c00,0xf000,0x7803e00,0x1f0000f,
4277       0x3c0f01e,0x1e01f0,0x3e007e0,0x7c07c00,0xfc003c00,0x1e,0x3e000,0x3e007c0,0x1ff8000,0xfe0fe003,0xe03e0001,0xff0000fc,0x1e,
4278       0xf0,0x780,0x0,0x0,0x1f00080,0x3cf8000,0xfc00000,0x3c00001f,0x83f00000,0x18,0xc0,0x0,0xc06203,0x40003c0,0x1c00000,0xf80f0000,
4279       0x3cf8001f,0xf,0x3e000079,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x700780fc,0x3cf8,0xfc000,0x1e000,0x0,0x780000,
4280       0x7c180000,0xf0000020,0x100007,0x8000003c,0xf,0x80000000,0x1f01f0,0x0,0x380700,0x0,0xf,0x80f80000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,
4281       0xe1c00,0x0,0x0,0x0,0xe01,0xc0000071,0xc0000001,0xc0001c70,0x1e00040,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
4282       0x80007800,0x10078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00f003,0xfc01e003,0xc00f001e,
4283       0x7800f0,0x3c00780,0x1e003c00,0xe000700f,0x800f0078,0x7803c0,0x3c01e00,0x1e00f000,0xf0000780,0x1e0000,0xf0003c,0x1f001f80,
4284       0xf800fc07,0xc007e03e,0x3f01f0,0x1f80f80,0xfc1e01f,0x7c00,0x100f8000,0x807c0004,0x3e00020,0x1f000100,0x780000,0x3c00000,0x1e000000,
4285       0xf0000f80,0x1f003c00,0x3c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,0x1f8000f,0x801f003e,0x7c01f0,0x3e00f80,0x1f007c00,
4286       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,
4287       0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0xf,0x7800078,0x31f80001,0xc070fc00,0xfc000000,0x1e00,0x7c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
4288       0x7c0,0x1f00001e,0x1f000,0x38003f,0x780,0xe000f80,0x1f803e00,0x780000f,0x800f8000,0x1f00007,0xe000003f,0x0,0x2000000,0x800000,
4289       0x3c000,0x3e01ff71,0xf0001f03,0xc007f007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x781e0007,0x80007800,0x7801f00,0x3c001f00,0x7800001e,
4290       0xf078,0xfe00f8,0x3e00780,0x3e00,0xf8078000,0xf838003e,0xf000,0x7c00f80,0xff0000,0xfc07e00f,0x8003c000,0x780001e0,0x3c,0xf,
4291       0x1e0,0x0,0x0,0x0,0xf801fc01,0xfc03e003,0xe003007c,0x3f803e0,0x1c0003c,0xfc0f,0xf0078007,0x80003c00,0xf000,0x7801f00,0xf8000f,
4292       0x3c0f01e,0x1e00f8,0x7c007f0,0xf803e01,0xfc003c00,0x8003e,0x1f000,0x1e00fc0,0xff0000,0xfe0fe007,0xc01f0000,0xfe0000f8,0x1e,
4293       0xf0,0x780,0x0,0x0,0xf80180,0x1cf0000,0x1f800000,0x3c00001f,0x83e00000,0x18,0xc0,0x0,0xc06203,0x70007c0,0xe00000,0x7e0f0000,
4294       0x1cf0001e,0x7,0x3c000039,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x7c00000,0xe00780fc,0x2001cf0,0xf8000,0x1e000,0x0,
4295       0x780000,0x7e182000,0xf0000000,0x7,0x8000003c,0x7,0xc0000000,0x7ffc0,0x0,0x180300,0x0,0x3,0xffe00000,0x0,0x0,0x0,0x0,0x0,
4296       0x3f00fc0,0xe1c00,0x0,0x0,0x0,0xc01,0x800000e1,0xc0000003,0xc0003870,0x1f001c0,0x3e0003e1,0xf0001f0f,0x8000f87c,0x7c3e0,0x3e1f00,
4297       0x1f1e007,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e03,0xfc00f001,0xfc01f007,
4298       0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x4000201f,0xc01f007c,0xf803e0,0x7c01f00,0x3e00f801,0xf0000780,0x1e0000,0xf0007c,
4299       0x1f003f80,0xf801fc07,0xc00fe03e,0x7f01f0,0x3f80f80,0x1fc1f03f,0x803e00,0x3007c003,0x803e001c,0x1f000e0,0xf800700,0x780000,
4300       0x3c00000,0x1e000000,0xf00007c0,0x3e003c00,0x3c01f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e001e,0xfc00f0,
4301       0x7e00780,0x3f003c01,0xf8000fe0,0x1fc03e,0x3f800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4302       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,0xfff00001,0xe0f07f03,0xfe000000,0xf00,0x7800,0x0,
4303       0x1e0000,0xfc0000,0x0,0x7e0000f0,0x3f0,0x7e000fff,0xfc03ffff,0xf83f00fe,0x780,0xfc03f80,0xfc0fc00,0xf800007,0xe03f0018,0x7e00007,
4304       0xe000003f,0x0,0x0,0x0,0x3c000,0x1e007c71,0xe0000f03,0xffffe003,0xf01f01ff,0xff8003ff,0xffe01e00,0x3f01,0xf81e0007,0x803ffff0,
4305       0x7e03f00,0x3c000f00,0x7ffffe1e,0xf078,0xfe007e,0xfc00780,0x1f83,0xf0078000,0x783f00fe,0xf000,0x3f03f00,0xff0000,0xfc07e01f,
4306       0x3e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7e07fc01,0xfe07e001,0xf80f007e,0x7f801f8,0xfc0003c,0x7ffe,0xf0078007,
4307       0x807ffffe,0xf000,0x7801f00,0xfff00f,0x3c0f01e,0x1e00fc,0xfc007f8,0x1f803f03,0xfc003c00,0xf80fc,0x1fff0,0x1f83fc0,0xff0000,
4308       0xfc07e007,0xc01f0000,0xfe0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfe0780,0xfe0000,0x1f000000,0x3c00001f,0x7c00e03,0x81c00018,
4309       0xc0,0x0,0x406203,0x7e01fc0,0x700000,0x7fffff80,0xfe0003f,0xffffc003,0xf800001f,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f0,
4310       0x1f800001,0xc007c1fe,0x6000fe0,0x1ffffe,0x1e000,0x0,0x780000,0x3f98e03f,0xffff8000,0x7,0x8000003c,0x7,0xc0000000,0xfe00,
4311       0x0,0x80100,0x0,0x0,0x7f000000,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3f83fe8,0xe1c00,0x0,0x0,0x0,0x801,0xc1,0xc0000007,0x80003070,
4312       0xfc0fc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc03f01,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,
4313       0xffff001f,0xfff800ff,0xffc01fff,0xf800f001,0xfc00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,0x1f,0xf07e003f,0x3f001f8,
4314       0x1f800fc0,0xfc007e07,0xe0000780,0x1e0000,0xf301f8,0xfc0ff80,0x7e07fc03,0xf03fe01f,0x81ff00fc,0xff807e0,0x7fc0f87f,0x81801f80,
4315       0xf003f01f,0x801f80fc,0xfc07e0,0x7e03f00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff807e0,0x7e003c00,0x3c01f81f,0x800fc0fc,0x7e07e0,
4316       0x3f03f00,0x1f81f800,0x1f8000f,0xe07e001f,0x83fc00fc,0x1fe007e0,0xff003f07,0xf8000fe0,0x1fe07e,0x3f800,0x0,0x0,0x0,0x0,0x0,
4317       0x0,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,
4318       0xffe00000,0xffe03fff,0xdf000000,0xf00,0x7800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0x1ff,0xfc000fff,0xfc03ffff,0xf83ffffc,0x780,
4319       0xfffff00,0x7fff800,0xf000007,0xffff001f,0xffe00007,0xe000003f,0x0,0x0,0x0,0x3c000,0x1e000001,0xe0000f03,0xffffc001,0xffff01ff,
4320       0xff0003ff,0xffe01e00,0x1fff,0xf81e0007,0x803ffff0,0x7fffe00,0x3c000f80,0x7ffffe1e,0xf078,0xfe003f,0xff800780,0xfff,0xf0078000,
4321       0x7c3ffffc,0xf000,0x3ffff00,0xff0000,0xf803e01e,0x1e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7fffbc01,0xffffc000,
4322       0xffff003f,0xfff800ff,0xffc0003c,0x3ffe,0xf0078007,0x807ffffe,0xf000,0x7800f80,0x7ff00f,0x3c0f01e,0x1e007f,0xff8007ff,0xff001fff,
4323       0xbc003c00,0xffffc,0x1fff0,0x1fffbc0,0xff0000,0x7c07c00f,0x800f8000,0x7e0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7fff80,0x7c0000,
4324       0x1f000000,0x3c00001e,0x7c00f07,0xc1e00018,0xc0,0x0,0x60e303,0x7ffff80,0x380000,0x3fffff80,0x7c0003f,0xffffc001,0xf000000f,
4325       0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff800003,0x8003ffff,0xfe0007c0,0x1ffffe,0x1e000,0x0,0x780000,0x1fffe03f,0xffff8000,
4326       0x7,0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3fffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x1c1,
4327       0xc000000f,0x7070,0x7fffc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,
4328       0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000f001,0xfc007fff,0x3fff8,0x1fffc0,0xfffe00,0x7fff000,0x3b,0xfffc003f,
4329       0xfff001ff,0xff800fff,0xfc007fff,0xe0000780,0x1e0000,0xf3fff8,0xffff780,0x7fffbc03,0xfffde01f,0xffef00ff,0xff7807ff,0xfbc0ffff,
4330       0xff800fff,0xf001ffff,0x800ffffc,0x7fffe0,0x3ffff00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff803ff,0xfc003c00,0x3c00ffff,0x7fff8,
4331       0x3fffc0,0x1fffe00,0xffff000,0x1f,0xfffc001f,0xffbc00ff,0xfde007ff,0xef003fff,0x780007e0,0x1ffffc,0x1f800,0x0,0x0,0x0,0x0,
4332       0x0,0x0,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,
4333       0xffc00000,0x7fc01fff,0x9f800000,0xf80,0xf800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0xff,0xf8000fff,0xfc03ffff,0xf83ffff8,0x780,
4334       0xffffe00,0x7fff000,0xf000003,0xfffe001f,0xffc00007,0xe000003f,0x0,0x0,0x0,0x3c000,0xf000003,0xe0000f83,0xffff0000,0xffff01ff,
4335       0xfc0003ff,0xffe01e00,0xfff,0xf01e0007,0x803ffff0,0x7fffc00,0x3c0007c0,0x7ffffe1e,0xf078,0x7e003f,0xff000780,0x7ff,0xe0078000,
4336       0x3c3ffff8,0xf000,0x1fffe00,0x7e0000,0xf803e03e,0x1f000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x3fff3c01,0xefff8000,
4337       0x7ffe001f,0xff78007f,0xff80003c,0x1ffc,0xf0078007,0x807ffffe,0xf000,0x78007c0,0x3ff00f,0x3c0f01e,0x1e003f,0xff0007bf,0xfe000fff,
4338       0xbc003c00,0xffff8,0xfff0,0xfff3c0,0x7e0000,0x7c07c01f,0x7c000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3fff80,0x380000,
4339       0x3e000000,0x7c00003e,0x7801f07,0xc1e00018,0xc0,0x0,0x39c1ce,0x7ffff00,0x1c0000,0xfffff80,0x380003f,0xffffc000,0xe0000007,
4340       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff000007,0x1ffcf,0xfe000380,0x1ffffe,0x1e000,0x0,0x780000,0xfffe03f,0xffff8000,0x7,
4341       0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x381,
4342       0xc000001e,0xe070,0x7fff80,0x7c0001f3,0xe0000f9f,0x7cf8,0x3e7c0,0x1f3e00,0xfbe007,0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,
4343       0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000f000,0xfc007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x79,0xfff8001f,
4344       0xffe000ff,0xff0007ff,0xf8003fff,0xc0000780,0x1e0000,0xf3fff0,0x7ffe780,0x3fff3c01,0xfff9e00f,0xffcf007f,0xfe7803ff,0xf3c07ff3,
4345       0xff8007ff,0xe000ffff,0x7fff8,0x3fffc0,0x1fffe00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff801ff,0xf8003c00,0x3c007ffe,0x3fff0,
4346       0x1fff80,0xfffc00,0x7ffe000,0x1d,0xfff8000f,0xff3c007f,0xf9e003ff,0xcf001ffe,0x780007c0,0x1efff8,0x1f000,0x0,0x0,0x0,0x0,
4347       0x0,0x0,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,
4348       0xfe000000,0x1f000fff,0xfc00000,0x780,0xf000,0x0,0x0,0xf80000,0x0,0x7e0001e0,0x7f,0xf0000fff,0xfc03ffff,0xf81ffff0,0x780,
4349       0x7fff800,0x1ffe000,0x1f000000,0xfff8001f,0xff000007,0xe000003e,0x0,0x0,0x0,0x3c000,0xf800003,0xc0000783,0xfff80000,0x3ffe01ff,
4350       0xe00003ff,0xffe01e00,0x7ff,0xc01e0007,0x803ffff0,0x3fff800,0x3c0003c0,0x7ffffe1e,0xf078,0x7e000f,0xfe000780,0x3ff,0xc0078000,
4351       0x3e1fffe0,0xf000,0x7ff800,0x7e0000,0xf803e07c,0xf800,0x780003ff,0xfffc003c,0x3,0xc00001e0,0x0,0x0,0x0,0xffe3c01,0xe7ff0000,
4352       0x3ffc000f,0xfe78003f,0xfe00003c,0x7f0,0xf0078007,0x807ffffe,0xf000,0x78003e0,0xff00f,0x3c0f01e,0x1e001f,0xfe00079f,0xfc0007ff,
4353       0x3c003c00,0x7ffe0,0x1ff0,0x7fe3c0,0x7e0000,0x7c07c03e,0x3e000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfff00,0x100000,
4354       0x3e000000,0x7800003c,0xf800f07,0xc1e00018,0xc0,0x0,0x1f80fc,0x3fffc00,0xc0000,0x3ffff80,0x100003f,0xffffc000,0x40000002,
4355       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xfc000006,0xff87,0xfc000100,0x1ffffe,0x1e000,0x0,0x780000,0x3ffc03f,0xffff8000,0x7,
4356       0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dff9f8,0xe1c00,0x0,0x0,0x0,0x0,0x3ff,
4357       0xf800003c,0xfffe,0x1ffe00,0x780000f3,0xc000079e,0x3cf0,0x1e780,0xf3c00,0x7bc007,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,
4358       0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,0xf000,0xfc001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x70,0xfff00007,
4359       0xff80003f,0xfc0001ff,0xe0000fff,0x780,0x1e0000,0xf3ffe0,0x1ffc780,0xffe3c00,0x7ff1e003,0xff8f001f,0xfc7800ff,0xe3c03fe1,
4360       0xff0003ff,0xc0007ffc,0x3ffe0,0x1fff00,0xfff800,0xfffffc07,0xffffe03f,0xffff01ff,0xfff800ff,0xf0003c00,0x3c003ffc,0x1ffe0,
4361       0xfff00,0x7ff800,0x3ffc000,0x38,0xfff00007,0xfe3c003f,0xf1e001ff,0x8f000ffc,0x780007c0,0x1e7ff0,0x1f000,0x0,0x0,0x0,0x0,0x0,
4362       0x0,0x0,0x0,0x0,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,
4363       0x1fc,0x0,0x780,0xf000,0x0,0x0,0x1f80000,0x0,0x1e0,0x1f,0xc0000000,0x0,0x1ff80,0x0,0xffc000,0x7f8000,0x0,0x3fe00007,0xfc000000,
4364       0x7e,0x0,0x0,0x0,0x0,0x7c00000,0x0,0x0,0xff00000,0x0,0x0,0xfe,0x0,0x0,0x3fc000,0x0,0x0,0x0,0x3,0xf8000000,0xff,0xc0000000,
4365       0x1ff00,0x0,0x1fe000,0x0,0x0,0x0,0x0,0x3c,0x3,0xc00001e0,0x0,0x0,0x0,0x3f80000,0x1fc0000,0x7f00003,0xf8000007,0xf0000000,
4366       0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x7,0xf8000787,0xf00001fc,0x3c000000,0x7f80,0x0,0x1f8000,0x0,0x0,0x0,0x7c000000,0x1e,
4367       0xf0,0x780,0x0,0x0,0x3fc00,0x0,0x3c000000,0x7800003c,0xf000601,0xc00018,0xc0,0x0,0x0,0x3fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4368       0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xf0000000,0x7e03,0xf0000000,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x3c,0x2007,0x80000000,0x0,0x0,
4369       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c7e0f0,0xe1c00,0x0,0x3800000,0x0,0x0,0x3ff,0xf8000078,0xfffe,0x7f800,0x0,0x0,0x0,0x0,
4370       0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,0x7f0000,0x70,0x3fc00001,0xfe00000f,0xf000007f,
4371       0x800003fc,0x0,0x0,0xff00,0x7f0000,0x3f80000,0x1fc00000,0xfe000007,0xf000003f,0x80001f80,0xfc00007f,0xfe0,0x7f00,0x3f800,
4372       0x1fc000,0x0,0x0,0x0,0x3f,0xc0000000,0xff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x78,0x3fc00001,0xf800000f,0xc000007e,0x3f0,0x7c0,
4373       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,
4374       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,
4375       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,
4376       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,
4377       0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,0x1e,0xf0,0x780,0x0,0x0,0x0,0x0,0x3c000000,0x78000078,0xf000000,0x18,0xc0,0x0,0x0,0x0,
4378       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,
4379       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0x1800000,0x0,0x0,0x3ff,0xf80000f0,0xfffe,0x0,0x0,0x0,0x0,
4380       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,
4381       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,
4382       0x0,0x0,0x0,0x0,0x0,0x0,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,
4383       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,
4384       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,
4385       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,
4386       0x1f,0xf0,0xf80,0x0,0x0,0x0,0x0,0x78000000,0xf8000078,0x1e000000,0x8,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4387       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,
4388       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,
4389       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,
4390       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,
4391       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,
4392       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,
4393       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,
4394       0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x1f,0x800000f0,0x1f80,0x0,0x0,0x0,0x0,
4395       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,
4396       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,
4397       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,
4398       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,
4399       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,
4400       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,
4401       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,
4402       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4003,0xe0000000,0x0,0x1f000,0x0,0x0,
4403       0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x1,0xf0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0x70000001,0xf00000e0,
4404       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,
4405       0x0,0x0,0x3c,0xff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,0x0,0x0,0x1,0xc00003ff,
4406       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,
4407       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,
4408       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,
4409       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,
4410       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,
4411       0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780f,0xc0000000,0x0,0x3e000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
4412       0x0,0x0,0x0,0x0,0x3,0xe0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0xf0000103,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4413       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,
4414       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x21e00000,0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,
4415       0x0,0x0,0x0,0x0,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,
4416       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,
4417       0x0,0x0,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,
4418       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,
4419       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,
4420       0x0,0x0,0x7fff,0xc0000000,0x0,0x3ffe000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0xe0000000,0x7,0xfc0000f0,
4421       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,
4422       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,
4423       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,
4424       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,
4425       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,
4426       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4427       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4428       0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff,0x80000000,0x0,0x3ffc000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
4429       0x0,0x0,0x0,0x0,0x7f,0xc0000000,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x0,0x0,0x1ff,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4430       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,
4431       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,
4432       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,
4433       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,
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,
4435       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4436       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x3ffe,0x0,0x0,0x3ff8000,0x0,0x0,0x0,
4437       0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0x80000000,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x80000000,0x0,0x0,0x0,0x0,
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,
4439       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,
4440       0x0,0x0,0x0,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,
4441       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,
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,
4443       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4444       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8,0x0,0x0,0x3fe0000,
4445       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,
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,
4447       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,
4448       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4449       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x1e0000,0x1f80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4450       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4451       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4452       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4453       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4454       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4455       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4456       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4457       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
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,
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,
4460       0x0,0x0,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,
4461       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4462       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4463       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4464       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
4465 
4466     // Definition of a 40x38 'danger' color logo.
4467     const unsigned char logo40x38[4576] = {
4468       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,
4469       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,
4470       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,
4471       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,
4472       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,
4473       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,
4474       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,
4475       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,
4476       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,
4477       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,
4478       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,
4479       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,
4480       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,
4481       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,
4482       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,
4483       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,
4484       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,
4485       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,
4486       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,
4487       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,
4488       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,
4489       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,
4490       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,
4491       200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0};
4492 
4493     //! Display a warning message.
4494     /**
4495         \param format is a C-string describing the format of the message, as in <tt>std::printf()</tt>.
4496     **/
4497     inline void warn(const char *format, ...) {
4498       if (cimg::exception_mode()>=1) {
4499         char message[8192];
4500         cimg_std::va_list ap;
4501         va_start(ap,format);
4502         cimg_std::vsprintf(message,format,ap);
4503         va_end(ap);
4504 #ifdef cimg_strict_warnings
4505         throw CImgWarningException(message);
4506 #else
4507         cimg_std::fprintf(cimg_stdout,"\n%s# CImg Warning%s :\n%s\n",cimg::t_red,cimg::t_normal,message);
4508 #endif
4509       }
4510     }
4511 
4512     // Execute an external system command.
4513     /**
4514        \note This function is similar to <tt>std::system()</tt>
4515        and is here because using the <tt>std::</tt> version on
4516        Windows may open undesired consoles.
4517      **/
4518     inline int system(const char *const command, const char *const module_name=0) {
4519 #if cimg_OS==2
4520       PROCESS_INFORMATION pi;
4521       STARTUPINFO si;
4522       cimg_std::memset(&pi,0,sizeof(PROCESS_INFORMATION));
4523       cimg_std::memset(&si,0,sizeof(STARTUPINFO));
4524       GetStartupInfo(&si);
4525       si.cb = sizeof(si);
4526       si.wShowWindow = SW_HIDE;
4527       si.dwFlags |= SW_HIDE;
4528       const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);
4529       if (res) {
4530         WaitForSingleObject(pi.hProcess, INFINITE);
4531         CloseHandle(pi.hThread);
4532         CloseHandle(pi.hProcess);
4533         return 0;
4534       } else
4535 #endif
4536         return cimg_std::system(command);
4537       return module_name?0:1;
4538     }
4539 
4540     //! Return a reference to a temporary variable of type T.
4541     template<typename T>
4542     inline T& temporary(const T&) {
4543       static T temp;
4544       return temp;
4545     }
4546 
4547     //! Exchange values of variables \p a and \p b.
4548     template<typename T>
4549     inline void swap(T& a, T& b) { T t = a; a = b; b = t; }
4550 
4551     //! Exchange values of variables (\p a1,\p a2) and (\p b1,\p b2).
4552     template<typename T1, typename T2>
4553     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) {
4554       cimg::swap(a1,b1); cimg::swap(a2,b2);
4555     }
4556 
4557     //! Exchange values of variables (\p a1,\p a2,\p a3) and (\p b1,\p b2,\p b3).
4558     template<typename T1, typename T2, typename T3>
4559     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) {
4560       cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3);
4561     }
4562 
4563     //! Exchange values of variables (\p a1,\p a2,...,\p a4) and (\p b1,\p b2,...,\p b4).
4564     template<typename T1, typename T2, typename T3, typename T4>
4565     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) {
4566       cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);
4567     }
4568 
4569     //! Exchange values of variables (\p a1,\p a2,...,\p a5) and (\p b1,\p b2,...,\p b5).
4570     template<typename T1, typename T2, typename T3, typename T4, typename T5>
4571     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) {
4572       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);
4573     }
4574 
4575     //! Exchange values of variables (\p a1,\p a2,...,\p a6) and (\p b1,\p b2,...,\p b6).
4576     template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
4577     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) {
4578       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
4579     }
4580 
4581     //! Exchange values of variables (\p a1,\p a2,...,\p a7) and (\p b1,\p b2,...,\p b7).
4582     template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
4583     inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
4584                      T7& a7, T7& b7) {
4585       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);
4586     }
4587 
4588     //! Exchange values of variables (\p a1,\p a2,...,\p a8) and (\p b1,\p b2,...,\p b8).
4589     template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
4590     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,
4591                      T7& a7, T7& b7, T8& a8, T8& b8) {
4592       cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);
4593     }
4594 
4595     //! Return the current endianness of the CPU.
4596     /**
4597        \return \c false for "Little Endian", \c true for "Big Endian".
4598     **/
4599     inline bool endianness() {
4600       const int x = 1;
4601       return ((unsigned char*)&x)[0]?false:true;
4602     }
4603 
4604     //! Invert endianness of a memory buffer.
4605     template<typename T>
4606     inline void invert_endianness(T* const buffer, const unsigned int size) {
4607       if (size) switch (sizeof(T)) {
4608       case 1 : break;
4609       case 2 : { for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer; ) {
4610         const unsigned short val = *(--ptr);
4611         *ptr = (unsigned short)((val>>8)|((val<<8)));
4612       }} break;
4613       case 4 : { for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer; ) {
4614         const unsigned int val = *(--ptr);
4615         *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24);
4616       }} break;
4617       default : { for (T* ptr = buffer+size; ptr>buffer; ) {
4618         unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);
4619         for (int i=0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe));
4620       }}
4621       }
4622     }
4623 
4624     //! Invert endianness of a single variable.
4625     template<typename T>
4626     inline T& invert_endianness(T& a) {
4627       invert_endianness(&a,1);
4628       return a;
4629     }
4630 
4631     //! Get the value of a system timer with a millisecond precision.
4632     inline unsigned long time() {
4633 #if cimg_OS==1
4634       struct timeval st_time;
4635       gettimeofday(&st_time,0);
4636       return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
4637 #elif cimg_OS==2
4638       static SYSTEMTIME st_time;
4639       GetSystemTime(&st_time);
4640       return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
4641 #else
4642       return 0;
4643 #endif
4644     }
4645 
4646     //! Sleep for a certain numbers of milliseconds.
4647     /**
4648        This function frees the CPU ressources during the sleeping time.
4649        It may be used to temporize your program properly, without wasting CPU time.
4650     **/
4651     inline void sleep(const unsigned int milliseconds) {
4652 #if cimg_OS==1
4653       struct timespec tv;
4654       tv.tv_sec = milliseconds/1000;
4655       tv.tv_nsec = (milliseconds%1000)*1000000;
4656       nanosleep(&tv,0);
4657 #elif cimg_OS==2
4658       Sleep(milliseconds);
4659 #endif
4660     }
4661 
4662     inline unsigned int _sleep(const unsigned int milliseconds, unsigned long& timer) {
4663       if (!timer) timer = cimg::time();
4664       const unsigned long current_time = cimg::time();
4665       if (current_time>=timer+milliseconds) { timer = current_time; return 0; }
4666       const unsigned long time_diff = timer + milliseconds - current_time;
4667       timer = current_time + time_diff;
4668       cimg::sleep(time_diff);
4669       return (unsigned int)time_diff;
4670     }
4671 
4672     //! Wait for a certain number of milliseconds since the last call.
4673     /**
4674        This function is equivalent to sleep() but the waiting time is computed with regard to the last call
4675        of wait(). It may be used to temporize your program properly.
4676     **/
4677     inline unsigned int wait(const unsigned int milliseconds) {
4678       static unsigned long timer = 0;
4679       if (!timer) timer = cimg::time();
4680       return _sleep(milliseconds,timer);
4681     }
4682 
4683     // Use a specific srand initialization to avoid multi-threads to have to the
4684     // same series of random numbers (executed only once for a single program).
4685     inline void srand() {
4686       static bool first_time = true;
4687       if (first_time) {
4688         cimg_std::srand(cimg::time());
4689         unsigned char *const rand_ptr = new unsigned char[1+cimg_std::rand()%2048];
4690         cimg_std::srand((unsigned int)cimg_std::rand() + *(unsigned int*)(void*)rand_ptr);
4691         delete[] rand_ptr;
4692         first_time = false;
4693       }
4694     }
4695 
4696     //! Return a left bitwise-rotated number.
4697     template<typename T>
4698     inline const T rol(const T a, const unsigned int n=1) {
4699       return n?(T)((a<<n)|(a>>((sizeof(T)<<3)-n))):a;
4700     }
4701 
4702     //! Return a right bitwise-rotated number.
4703     template<typename T>
4704     inline const T ror(const T a, const unsigned int n=1) {
4705       return n?(T)((a>>n)|(a<<((sizeof(T)<<3)-n))):a;
4706     }
4707 
4708     //! Return the absolute value of a number.
4709     /**
4710        \note This function is different from <tt>std::abs()</tt> or <tt>std::fabs()</tt>
4711        because it is able to consider a variable of any type, without cast needed.
4712     **/
4713     template<typename T>
4714     inline T abs(const T a) {
4715       return a>=0?a:-a;
4716     }
4717     inline bool abs(const bool a) {
4718       return a;
4719     }
4720     inline unsigned char abs(const unsigned char a) {
4721       return a;
4722     }
4723     inline unsigned short abs(const unsigned short a) {
4724       return a;
4725     }
4726     inline unsigned int abs(const unsigned int a) {
4727       return a;
4728     }
4729     inline unsigned long abs(const unsigned long a) {
4730       return a;
4731     }
4732     inline double abs(const double a) {
4733       return cimg_std::fabs(a);
4734     }
4735     inline float abs(const float a) {
4736       return (float)cimg_std::fabs((double)a);
4737     }
4738     inline int abs(const int a) {
4739       return cimg_std::abs(a);
4740     }
4741 
4742     //! Return the square of a number.
4743     template<typename T>
4744     inline T sqr(const T val) {
4745       return val*val;
4746     }
4747 
4748     //! Return 1 + log_10(x).
4749     inline int xln(const int x) {
4750       return x>0?(int)(1+cimg_std::log10((double)x)):1;
4751     }
4752 
4753     //! Return the minimum value between two numbers.
4754     template<typename t1, typename t2>
4755     inline typename cimg::superset<t1,t2>::type min(const t1& a, const t2& b) {
4756       typedef typename cimg::superset<t1,t2>::type t1t2;
4757       return (t1t2)(a<=b?a:b);
4758     }
4759 
4760     //! Return the minimum value between three numbers.
4761     template<typename t1, typename t2, typename t3>
4762     inline typename cimg::superset2<t1,t2,t3>::type min(const t1& a, const t2& b, const t3& c) {
4763       typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
4764       return (t1t2t3)cimg::min(cimg::min(a,b),c);
4765     }
4766 
4767     //! Return the minimum value between four numbers.
4768     template<typename t1, typename t2, typename t3, typename t4>
4769     inline typename cimg::superset3<t1,t2,t3,t4>::type min(const t1& a, const t2& b, const t3& c, const t4& d) {
4770       typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
4771       return (t1t2t3t4)cimg::min(cimg::min(a,b,c),d);
4772     }
4773 
4774     //! Return the maximum value between two numbers.
4775     template<typename t1, typename t2>
4776     inline typename cimg::superset<t1,t2>::type max(const t1& a, const t2& b) {
4777       typedef typename cimg::superset<t1,t2>::type t1t2;
4778       return (t1t2)(a>=b?a:b);
4779     }
4780 
4781     //! Return the maximum value between three numbers.
4782     template<typename t1, typename t2, typename t3>
4783     inline typename cimg::superset2<t1,t2,t3>::type max(const t1& a, const t2& b, const t3& c) {
4784       typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
4785       return (t1t2t3)cimg::max(cimg::max(a,b),c);
4786     }
4787 
4788     //! Return the maximum value between four numbers.
4789     template<typename t1, typename t2, typename t3, typename t4>
4790     inline typename cimg::superset3<t1,t2,t3,t4>::type max(const t1& a, const t2& b, const t3& c, const t4& d) {
4791       typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
4792       return (t1t2t3t4)cimg::max(cimg::max(a,b,c),d);
4793     }
4794 
4795     //! Return the sign of a number.
4796     template<typename T>
4797     inline T sign(const T x) {
4798       return (x<0)?(T)(-1):(x==0?(T)0:(T)1);
4799     }
4800 
4801     //! Return the nearest power of 2 higher than a given number.
4802     template<typename T>
4803     inline unsigned long nearest_pow2(const T x) {
4804       unsigned long i = 1;
4805       while (x>i) i<<=1;
4806       return i;
4807     }
4808 
4809     //! Return the modulo of a number.
4810     /**
4811        \note This modulo function accepts negative and floating-points modulo numbers, as well as
4812        variable of any type.
4813     **/
4814     template<typename T>
4815     inline T mod(const T& x, const T& m) {
4816       const double dx = (double)x, dm = (double)m;
4817       if (x<0) { return (T)(dm+dx+dm*cimg_std::floor(-dx/dm)); }
4818       return (T)(dx-dm*cimg_std::floor(dx/dm));
4819     }
4820     inline int mod(const bool x, const bool m) {
4821       return m?(x?1:0):0;
4822     }
4823     inline int mod(const char x, const char m) {
4824       return x>=0?x%m:(x%m?m+x%m:0);
4825     }
4826     inline int mod(const short x, const short m) {
4827       return x>=0?x%m:(x%m?m+x%m:0);
4828     }
4829     inline int mod(const int x, const int m) {
4830       return x>=0?x%m:(x%m?m+x%m:0);
4831     }
4832     inline int mod(const long x, const long m) {
4833       return x>=0?x%m:(x%m?m+x%m:0);
4834     }
4835     inline int mod(const unsigned char x, const unsigned char m) {
4836       return x%m;
4837     }
4838     inline int mod(const unsigned short x, const unsigned short m) {
4839       return x%m;
4840     }
4841     inline int mod(const unsigned int x, const unsigned int m) {
4842       return x%m;
4843     }
4844     inline int mod(const unsigned long x, const unsigned long m) {
4845       return x%m;
4846     }
4847 
4848     //! Return the minmod of two numbers.
4849     /**
4850        <i>minmod(\p a,\p b)</i> is defined to be :
4851        - <i>minmod(\p a,\p b) = min(\p a,\p b)</i>, if \p a and \p b have the same sign.
4852        - <i>minmod(\p a,\p b) = 0</i>, if \p a and \p b have different signs.
4853     **/
4854     template<typename T>
4855     inline T minmod(const T a, const T b) {
4856       return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));
4857     }
4858 
4859     //! Return a random variable between [0,1] with respect to an uniform distribution.
4860     inline double rand() {
4861       static bool first_time = true;
4862       if (first_time) { cimg::srand(); first_time = false; }
4863       return (double)cimg_std::rand()/RAND_MAX;
4864     }
4865 
4866     //! Return a random variable between [-1,1] with respect to an uniform distribution.
4867     inline double crand() {
4868       return 1-2*cimg::rand();
4869     }
4870 
4871     //! Return a random variable following a gaussian distribution and a standard deviation of 1.
4872     inline double grand() {
4873       double x1, w;
4874       do {
4875         const double x2 = 2*cimg::rand() - 1.0;
4876         x1 = 2*cimg::rand()-1.0;
4877         w = x1*x1 + x2*x2;
4878       } while (w<=0 || w>=1.0);
4879       return x1*cimg_std::sqrt((-2*cimg_std::log(w))/w);
4880     }
4881 
4882     //! Return a random variable following a Poisson distribution of parameter z.
4883     inline unsigned int prand(const double z) {
4884       if (z<=1.0e-10) return 0;
4885       if (z>100.0) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z);
4886       unsigned int k = 0;
4887       const double y = std::exp(-z);
4888       for (double s = 1.0; s>=y; ++k) s*=cimg::rand();
4889       return k-1;
4890     }
4891 
4892     //! Return a rounded number.
4893     /**
4894        \param x is the number to be rounded.
4895        \param y is the rounding precision.
4896        \param rounding_type defines the type of rounding (0=nearest, -1=backward, 1=forward).
4897     **/
4898     inline double round(const double x, const double y, const int rounding_type=0) {
4899       if (y<=0) return x;
4900       const double delta = cimg::mod(x,y);
4901       if (delta==0.0) return x;
4902       const double
4903         backward = x - delta,
4904         forward = backward + y;
4905       return rounding_type<0?backward:(rounding_type>0?forward:(2*delta<y?backward:forward));
4906     }
4907 
4908     inline double _pythagore(double a, double b) {
4909       const double absa = cimg::abs(a), absb = cimg::abs(b);
4910       if (absa>absb) { const double tmp = absb/absa; return absa*cimg_std::sqrt(1.0+tmp*tmp); }
4911       else { const double tmp = absa/absb; return (absb==0?0:absb*cimg_std::sqrt(1.0+tmp*tmp)); }
4912     }
4913 
4914     //! Remove the 'case' of an ASCII character.
4915     inline char uncase(const char x) {
4916       return (char)((x<'A'||x>'Z')?x:x-'A'+'a');
4917     }
4918 
4919     //! Remove the 'case' of a C string.
4920     /**
4921        Acts in-place.
4922     **/
4923     inline void uncase(char *const string) {
4924       if (string) for (char *ptr = string; *ptr; ++ptr) *ptr = uncase(*ptr);
4925     }
4926 
4927     //! Read a float number from a C-string.
4928     /**
4929        \note This function is quite similar to <tt>std::atof()</tt>,
4930        but that it allows the retrieval of fractions as in "1/2".
4931     **/
4932     inline float atof(const char *const str) {
4933       float x = 0,y = 1;
4934       if (!str) return 0; else { cimg_std::sscanf(str,"%g/%g",&x,&y); return x/y; }
4935     }
4936 
4937     //! Compute the length of a C-string.
4938     /**
4939        \note This function is similar to <tt>std::strlen()</tt>
4940        and is here because some old compilers do not
4941        define the <tt>std::</tt> version.
4942     **/
4943     inline int strlen(const char *const s) {
4944       if (!s) return -1;
4945       int k = 0;
4946       for (const char *ns = s; *ns; ++ns) ++k;
4947       return k;
4948     }
4949 
4950     //! Compare the first \p n characters of two C-strings.
4951     /**
4952        \note This function is similar to <tt>std::strncmp()</tt>
4953        and is here because some old compilers do not
4954        define the <tt>std::</tt> version.
4955     **/
4956     inline int strncmp(const char *const s1, const char *const s2, const int l) {
4957       if (!s1) return s2?-1:0;
4958       const char *ns1 = s1, *ns2 = s2;
4959       int k, diff = 0; for (k = 0; k<l && !(diff = *ns1-*ns2); ++k) { ++ns1; ++ns2; }
4960       return k!=l?diff:0;
4961     }
4962 
4963     //! Compare the first \p n characters of two C-strings, ignoring the case.
4964     /**
4965        \note This function is similar to <tt>std::strncasecmp()</tt>
4966        and is here because some old compilers do not
4967        define the <tt>std::</tt> version.
4968     **/
4969     inline int strncasecmp(const char *const s1, const char *const s2, const int l) {
4970       if (!s1) return s2?-1:0;
4971       const char *ns1 = s1, *ns2 = s2;
4972       int k, diff = 0; for (k = 0; k<l && !(diff = uncase(*ns1)-uncase(*ns2)); ++k) { ++ns1; ++ns2; }
4973       return k!=l?diff:0;
4974     }
4975 
4976     //! Compare two C-strings.
4977     /**
4978        \note This function is similar to <tt>std::strcmp()</tt>
4979        and is here because some old compilers do not
4980        define the <tt>std::</tt> version.
4981     **/
4982     inline int strcmp(const char *const s1, const char *const s2) {
4983       const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
4984       return cimg::strncmp(s1,s2,1+(l1<l2?l1:l2));
4985     }
4986 
4987     //! Compare two C-strings, ignoring the case.
4988     /**
4989        \note This function is similar to <tt>std::strcasecmp()</tt>
4990        and is here because some old compilers do not
4991        define the <tt>std::</tt> version.
4992     **/
4993     inline int strcasecmp(const char *const s1, const char *const s2) {
4994       const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
4995       return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2));
4996     }
4997 
4998     //! Find a character in a C-string.
4999     inline int strfind(const char *const s, const char c) {
5000       if (!s) return -1;
5001       int l; for (l = cimg::strlen(s); l>=0 && s[l]!=c; --l) {}
5002       return l;
5003     }
5004 
5005     //! Remove useless delimiters on the borders of a C-string
5006     inline bool strpare(char *const s, const char delimiter=' ', const bool symmetric=false) {
5007       if (!s) return false;
5008       const int l = cimg::strlen(s);
5009       int p, q;
5010       if (symmetric) for (p = 0, q = l-1; p<q && s[p]==delimiter && s[q]==delimiter; ++p) --q;
5011       else {
5012         for (p = 0; p<l && s[p]==delimiter; ) ++p;
5013         for (q = l-1; q>p && s[q]==delimiter; ) --q;
5014       }
5015       const int n = q - p + 1;
5016       if (n!=l) { cimg_std::memmove(s,s+p,n); s[n] = '\0'; return true; }
5017       return false;
5018     }
5019 
5020     //! Remove useless spaces and symmetric delimiters ', " and ` from a C-string.
5021     inline void strclean(char *const s) {
5022       if (!s) return;
5023       strpare(s,' ',false);
5024       for (bool need_iter = true; need_iter; ) {
5025         need_iter = false;
5026         need_iter |= strpare(s,'\'',true);
5027         need_iter |= strpare(s,'\"',true);
5028         need_iter |= strpare(s,'`',true);
5029       }
5030     }
5031 
5032     //! Replace explicit escape sequences '\x' in C-strings (where x in [ntvbrfa?'"0]).
5033     inline void strescape(char *const s) {
5034 #define cimg_strescape(ci,co) case ci: *nd = co; break;
5035       char *ns, *nd;
5036       for (ns = nd = s; *ns; ++ns, ++nd)
5037         if (*ns=='\\') switch (*(++ns)) {
5038             cimg_strescape('n','\n');
5039             cimg_strescape('t','\t');
5040             cimg_strescape('v','\v');
5041             cimg_strescape('b','\b');
5042             cimg_strescape('r','\r');
5043             cimg_strescape('f','\f');
5044             cimg_strescape('a','\a');
5045             cimg_strescape('\\','\\');
5046             cimg_strescape('\?','\?');
5047             cimg_strescape('\'','\'');
5048             cimg_strescape('\"','\"');
5049             cimg_strescape('\0','\0');
5050           }
5051         else *nd = *ns;
5052       *nd = 0;
5053     }
5054 
5055     //! Compute the basename of a filename.
5056     inline const char* basename(const char *const s)  {
5057       return (cimg_OS!=2)?(s?s+1+cimg::strfind(s,'/'):0):(s?s+1+cimg::strfind(s,'\\'):0);
5058     }
5059 
5060     // Generate a random filename.
5061     inline const char* filenamerand() {
5062       static char id[9] = { 0,0,0,0,0,0,0,0,0 };
5063       cimg::srand();
5064       for (unsigned int k=0; k<8; ++k) {
5065         const int v = (int)cimg_std::rand()%3;
5066         id[k] = (char)(v==0?('0'+(cimg_std::rand()%10)):(v==1?('a'+(cimg_std::rand()%26)):('A'+(cimg_std::rand()%26))));
5067       }
5068       return id;
5069     }
5070 
5071     // Convert filename into a Windows-style filename.
5072     inline void winformat_string(char *const s) {
5073       if (s && s[0]) {
5074 #if cimg_OS==2
5075         char *const ns = new char[MAX_PATH];
5076         if (GetShortPathNameA(s,ns,MAX_PATH)) cimg_std::strcpy(s,ns);
5077 #endif
5078       }
5079     }
5080 
5081     //! Return or set path to store temporary files.
5082     inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false) {
5083 #define _cimg_test_temporary_path(p) \
5084       if (!path_found) { \
5085         cimg_std::sprintf(st_path,"%s",p); \
5086         cimg_std::sprintf(tmp,"%s%s%s",st_path,cimg_OS==2?"\\":"/",filetmp); \
5087         if ((file=cimg_std::fopen(tmp,"wb"))!=0) { cimg_std::fclose(file); cimg_std::remove(tmp); path_found = true; } \
5088       }
5089       static char *st_path = 0;
5090       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5091       if (user_path) {
5092         if (!st_path) st_path = new char[1024];
5093         cimg_std::memset(st_path,0,1024);
5094         cimg_std::strncpy(st_path,user_path,1023);
5095       } else if (!st_path) {
5096         st_path = new char[1024];
5097         cimg_std::memset(st_path,0,1024);
5098         bool path_found = false;
5099         char tmp[1024], filetmp[512];
5100         cimg_std::FILE *file = 0;
5101         cimg_std::sprintf(filetmp,"%s.tmp",cimg::filenamerand());
5102         char *tmpPath = getenv("TMP");
5103         if (!tmpPath) { tmpPath = getenv("TEMP"); winformat_string(tmpPath); }
5104         if (tmpPath) _cimg_test_temporary_path(tmpPath);
5105 #if cimg_OS==2
5106         _cimg_test_temporary_path("C:\\WINNT\\Temp");
5107         _cimg_test_temporary_path("C:\\WINDOWS\\Temp");
5108         _cimg_test_temporary_path("C:\\Temp");
5109         _cimg_test_temporary_path("C:");
5110         _cimg_test_temporary_path("D:\\WINNT\\Temp");
5111         _cimg_test_temporary_path("D:\\WINDOWS\\Temp");
5112         _cimg_test_temporary_path("D:\\Temp");
5113         _cimg_test_temporary_path("D:");
5114 #else
5115         _cimg_test_temporary_path("/tmp");
5116         _cimg_test_temporary_path("/var/tmp");
5117 #endif
5118         if (!path_found) {
5119           st_path[0]='\0';
5120           cimg_std::strcpy(tmp,filetmp);
5121           if ((file=cimg_std::fopen(tmp,"wb"))!=0) { cimg_std::fclose(file); cimg_std::remove(tmp); path_found = true; }
5122         }
5123         if (!path_found)
5124           throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n"
5125                                 "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n"
5126                                 "#define cimg_temporary_path \"path\" (before including 'CImg.h')");
5127       }
5128       return st_path;
5129     }
5130 
5131     // Return or set path to the "Program files/" directory (windows only).
5132 #if cimg_OS==2
5133     inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false) {
5134       static char *st_path = 0;
5135       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5136       if (user_path) {
5137         if (!st_path) st_path = new char[1024];
5138         cimg_std::memset(st_path,0,1024);
5139         cimg_std::strncpy(st_path,user_path,1023);
5140       } else if (!st_path) {
5141         st_path = new char[MAX_PATH];
5142         cimg_std::memset(st_path,0,MAX_PATH);
5143         // Note : in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler).
5144 #if !defined(__INTEL_COMPILER)
5145         if (!SHGetSpecialFolderPathA(0,st_path,0x0026,false)) {
5146           const char *pfPath = getenv("PROGRAMFILES");
5147           if (pfPath) cimg_std::strncpy(st_path,pfPath,MAX_PATH-1);
5148           else cimg_std::strcpy(st_path,"C:\\PROGRA~1");
5149         }
5150 #else
5151         cimg_std::strcpy(st_path,"C:\\PROGRA~1");
5152 #endif
5153       }
5154       return st_path;
5155     }
5156 #endif
5157 
5158     //! Return or set path to the ImageMagick's \c convert tool.
5159     inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false) {
5160       static char *st_path = 0;
5161       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5162       if (user_path) {
5163         if (!st_path) st_path = new char[1024];
5164         cimg_std::memset(st_path,0,1024);
5165         cimg_std::strncpy(st_path,user_path,1023);
5166       } else if (!st_path) {
5167         st_path = new char[1024];
5168         cimg_std::memset(st_path,0,1024);
5169         bool path_found = false;
5170         cimg_std::FILE *file = 0;
5171 #if cimg_OS==2
5172         const char *pf_path = programfiles_path();
5173         if (!path_found) {
5174           cimg_std::sprintf(st_path,".\\convert.exe");
5175           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5176         }
5177         { for (int k=32; k>=10 && !path_found; --k) {
5178           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k);
5179           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5180         }}
5181         { for (int k=9; k>=0 && !path_found; --k) {
5182           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k);
5183           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5184         }}
5185         { for (int k=32; k>=0 && !path_found; --k) {
5186           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k);
5187           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5188         }}
5189         { for (int k=32; k>=10 && !path_found; --k) {
5190           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k);
5191           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5192         }}
5193         { for (int k=9; k>=0 && !path_found; --k) {
5194           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k);
5195           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5196         }}
5197         { for (int k=32; k>=0 && !path_found; --k) {
5198           cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k);
5199           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5200         }}
5201         { for (int k=32; k>=10 && !path_found; --k) {
5202           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\convert.exe",k);
5203           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5204         }}
5205         { for (int k=9; k>=0 && !path_found; --k) {
5206           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\convert.exe",k);
5207           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5208         }}
5209         { for (int k=32; k>=0 && !path_found; --k) {
5210           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d\\convert.exe",k);
5211           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5212         }}
5213         { for (int k=32; k>=10 && !path_found; --k) {
5214           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
5215           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5216         }}
5217         { for (int k=9; k>=0 && !path_found; --k) {
5218           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
5219           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5220         }}
5221         { for (int k=32; k>=0 && !path_found; --k) {
5222           cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
5223           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5224         }}
5225         { for (int k=32; k>=10 && !path_found; --k) {
5226           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\convert.exe",k);
5227           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5228         }}
5229         { for (int k=9; k>=0 && !path_found; --k) {
5230           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\convert.exe",k);
5231           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5232         }}
5233         { for (int k=32; k>=0 && !path_found; --k) {
5234           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d\\convert.exe",k);
5235           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5236         }}
5237         { for (int k=32; k>=10 && !path_found; --k) {
5238           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
5239           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5240         }}
5241         { for (int k=9; k>=0 && !path_found; --k) {
5242           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
5243           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5244         }}
5245         { for (int k=32; k>=0 && !path_found; --k) {
5246           cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
5247           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5248         }}
5249         if (!path_found) cimg_std::strcpy(st_path,"convert.exe");
5250 #else
5251         if (!path_found) {
5252           cimg_std::sprintf(st_path,"./convert");
5253           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5254         }
5255         if (!path_found) cimg_std::strcpy(st_path,"convert");
5256 #endif
5257         winformat_string(st_path);
5258       }
5259       return st_path;
5260     }
5261 
5262     //! Return path of the GraphicsMagick's \c gm tool.
5263     inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false) {
5264       static char *st_path = 0;
5265       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5266       if (user_path) {
5267         if (!st_path) st_path = new char[1024];
5268         cimg_std::memset(st_path,0,1024);
5269         cimg_std::strncpy(st_path,user_path,1023);
5270       } else if (!st_path) {
5271         st_path = new char[1024];
5272         cimg_std::memset(st_path,0,1024);
5273         bool path_found = false;
5274         cimg_std::FILE *file = 0;
5275 #if cimg_OS==2
5276         const char* pf_path = programfiles_path();
5277         if (!path_found) {
5278           cimg_std::sprintf(st_path,".\\gm.exe");
5279           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5280         }
5281         { for (int k=32; k>=10 && !path_found; --k) {
5282           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k);
5283           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5284         }}
5285         { for (int k=9; k>=0 && !path_found; --k) {
5286           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k);
5287           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5288         }}
5289         { for (int k=32; k>=0 && !path_found; --k) {
5290           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k);
5291           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5292         }}
5293         { for (int k=32; k>=10 && !path_found; --k) {
5294           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k);
5295           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5296         }}
5297         { for (int k=9; k>=0 && !path_found; --k) {
5298           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k);
5299           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5300         }}
5301         { for (int k=32; k>=0 && !path_found; --k) {
5302           cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k);
5303           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5304         }}
5305         { for (int k=32; k>=10 && !path_found; --k) {
5306           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\gm.exe",k);
5307           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5308         }}
5309         { for (int k=9; k>=0 && !path_found; --k) {
5310           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\gm.exe",k);
5311           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5312         }}
5313         { for (int k=32; k>=0 && !path_found; --k) {
5314           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d\\gm.exe",k);
5315           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5316         }}
5317         { for (int k=32; k>=10 && !path_found; --k) {
5318           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
5319           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5320         }}
5321         { for (int k=9; k>=0 && !path_found; --k) {
5322           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
5323           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5324         }}
5325         { for (int k=32; k>=0 && !path_found; --k) {
5326           cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
5327           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5328         }}
5329         { for (int k=32; k>=10 && !path_found; --k) {
5330           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\gm.exe",k);
5331           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5332         }}
5333         { for (int k=9; k>=0 && !path_found; --k) {
5334           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\gm.exe",k);
5335           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5336         }}
5337         { for (int k=32; k>=0 && !path_found; --k) {
5338           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d\\gm.exe",k);
5339           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5340         }}
5341         { for (int k=32; k>=10 && !path_found; --k) {
5342           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
5343           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5344         }}
5345         { for (int k=9; k>=0 && !path_found; --k) {
5346           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
5347           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5348         }}
5349         { for (int k=32; k>=0 && !path_found; --k) {
5350           cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
5351           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5352         }}
5353         if (!path_found) cimg_std::strcpy(st_path,"gm.exe");
5354 #else
5355         if (!path_found) {
5356           cimg_std::sprintf(st_path,"./gm");
5357           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5358         }
5359         if (!path_found) cimg_std::strcpy(st_path,"gm");
5360 #endif
5361         winformat_string(st_path);
5362       }
5363       return st_path;
5364     }
5365 
5366     //! Return or set path of the \c XMedcon tool.
5367     inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false) {
5368       static char *st_path = 0;
5369       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5370       if (user_path) {
5371         if (!st_path) st_path = new char[1024];
5372         cimg_std::memset(st_path,0,1024);
5373         cimg_std::strncpy(st_path,user_path,1023);
5374       } else if (!st_path) {
5375         st_path = new char[1024];
5376         cimg_std::memset(st_path,0,1024);
5377         bool path_found = false;
5378         cimg_std::FILE *file = 0;
5379 #if cimg_OS==2
5380         const char* pf_path = programfiles_path();
5381         if (!path_found) {
5382           cimg_std::sprintf(st_path,".\\medcon.bat");
5383           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5384         }
5385         if (!path_found) {
5386           cimg_std::sprintf(st_path,".\\medcon.exe");
5387           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5388         }
5389         if (!path_found) {
5390           cimg_std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.bat",pf_path);
5391           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5392         }
5393         if (!path_found) {
5394           cimg_std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.exe",pf_path);
5395           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5396         }
5397         if (!path_found) cimg_std::strcpy(st_path,"medcon.bat");
5398 #else
5399         if (!path_found) {
5400           cimg_std::sprintf(st_path,"./medcon");
5401           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5402         }
5403         if (!path_found) cimg_std::strcpy(st_path,"medcon");
5404 #endif
5405         winformat_string(st_path);
5406       }
5407       return st_path;
5408     }
5409 
5410     //! Return or set path to the 'ffmpeg' command.
5411     inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false) {
5412       static char *st_path = 0;
5413       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5414       if (user_path) {
5415         if (!st_path) st_path = new char[1024];
5416         cimg_std::memset(st_path,0,1024);
5417         cimg_std::strncpy(st_path,user_path,1023);
5418       } else if (!st_path) {
5419         st_path = new char[1024];
5420         cimg_std::memset(st_path,0,1024);
5421         bool path_found = false;
5422         cimg_std::FILE *file = 0;
5423 #if cimg_OS==2
5424         if (!path_found) {
5425           cimg_std::sprintf(st_path,".\\ffmpeg.exe");
5426           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5427         }
5428         if (!path_found) cimg_std::strcpy(st_path,"ffmpeg.exe");
5429 #else
5430         if (!path_found) {
5431           cimg_std::sprintf(st_path,"./ffmpeg");
5432           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5433         }
5434         if (!path_found) cimg_std::strcpy(st_path,"ffmpeg");
5435 #endif
5436         winformat_string(st_path);
5437       }
5438       return st_path;
5439     }
5440 
5441     //! Return or set path to the 'gzip' command.
5442     inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false) {
5443       static char *st_path = 0;
5444       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5445       if (user_path) {
5446         if (!st_path) st_path = new char[1024];
5447         cimg_std::memset(st_path,0,1024);
5448         cimg_std::strncpy(st_path,user_path,1023);
5449       } else if (!st_path) {
5450         st_path = new char[1024];
5451         cimg_std::memset(st_path,0,1024);
5452         bool path_found = false;
5453         cimg_std::FILE *file = 0;
5454 #if cimg_OS==2
5455         if (!path_found) {
5456           cimg_std::sprintf(st_path,".\\gzip.exe");
5457           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5458         }
5459         if (!path_found) cimg_std::strcpy(st_path,"gzip.exe");
5460 #else
5461         if (!path_found) {
5462           cimg_std::sprintf(st_path,"./gzip");
5463           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5464         }
5465         if (!path_found) cimg_std::strcpy(st_path,"gzip");
5466 #endif
5467         winformat_string(st_path);
5468       }
5469       return st_path;
5470     }
5471 
5472     //! Return or set path to the 'gunzip' command.
5473     inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false) {
5474       static char *st_path = 0;
5475       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5476       if (user_path) {
5477         if (!st_path) st_path = new char[1024];
5478         cimg_std::memset(st_path,0,1024);
5479         cimg_std::strncpy(st_path,user_path,1023);
5480       } else if (!st_path) {
5481         st_path = new char[1024];
5482         cimg_std::memset(st_path,0,1024);
5483         bool path_found = false;
5484         cimg_std::FILE *file = 0;
5485 #if cimg_OS==2
5486         if (!path_found) {
5487           cimg_std::sprintf(st_path,".\\gunzip.exe");
5488           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5489         }
5490         if (!path_found) cimg_std::strcpy(st_path,"gunzip.exe");
5491 #else
5492         if (!path_found) {
5493           cimg_std::sprintf(st_path,"./gunzip");
5494           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5495         }
5496         if (!path_found) cimg_std::strcpy(st_path,"gunzip");
5497 #endif
5498         winformat_string(st_path);
5499       }
5500       return st_path;
5501     }
5502 
5503     //! Return or set path to the 'dcraw' command.
5504     inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false) {
5505       static char *st_path = 0;
5506       if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5507       if (user_path) {
5508         if (!st_path) st_path = new char[1024];
5509         cimg_std::memset(st_path,0,1024);
5510         cimg_std::strncpy(st_path,user_path,1023);
5511       } else if (!st_path) {
5512         st_path = new char[1024];
5513         cimg_std::memset(st_path,0,1024);
5514         bool path_found = false;
5515         cimg_std::FILE *file = 0;
5516 #if cimg_OS==2
5517         if (!path_found) {
5518           cimg_std::sprintf(st_path,".\\dcraw.exe");
5519           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5520         }
5521         if (!path_found) cimg_std::strcpy(st_path,"dcraw.exe");
5522 #else
5523         if (!path_found) {
5524           cimg_std::sprintf(st_path,"./dcraw");
5525           if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5526         }
5527         if (!path_found) cimg_std::strcpy(st_path,"dcraw");
5528 #endif
5529         winformat_string(st_path);
5530       }
5531       return st_path;
5532     }
5533 
5534     //! Split a filename into two strings 'body' and 'extension'.
5535     inline const char *split_filename(const char *const filename, char *const body=0) {
5536       if (!filename) { if (body) body[0]='\0'; return 0; }
5537       int l = cimg::strfind(filename,'.');
5538       if (l>=0) { if (body) { cimg_std::strncpy(body,filename,l); body[l]='\0'; }}
5539       else { if (body) cimg_std::strcpy(body,filename); l = (int)cimg::strlen(filename)-1; }
5540       return filename+l+1;
5541     }
5542 
5543     //! Create a numbered version of a filename.
5544     inline char* number_filename(const char *const filename, const int number, const unsigned int n, char *const string) {
5545       if (!filename) { if (string) string[0]='\0'; return 0; }
5546       char format[1024],body[1024];
5547       const char *ext = cimg::split_filename(filename,body);
5548       if (n>0) cimg_std::sprintf(format,"%s_%%.%ud.%s",body,n,ext);
5549       else cimg_std::sprintf(format,"%s_%%d.%s",body,ext);
5550       cimg_std::sprintf(string,format,number);
5551       return string;
5552     }
5553 
5554     //! Open a file, and check for possible errors.
5555     inline cimg_std::FILE *fopen(const char *const path, const char *const mode) {
5556       if(!path || !mode)
5557         throw CImgArgumentException("cimg::fopen() : File '%s', cannot open with mode '%s'.",
5558                                     path?path:"(null)",mode?mode:"(null)");
5559       if (path[0]=='-') return (mode[0]=='r')?stdin:stdout;
5560       cimg_std::FILE *dest = cimg_std::fopen(path,mode);
5561       if (!dest)
5562         throw CImgIOException("cimg::fopen() : File '%s', cannot open file %s",
5563                               path,mode[0]=='r'?"for reading.":(mode[0]=='w'?"for writing.":"."),path);
5564       return dest;
5565     }
5566 
5567     //! Close a file, and check for possible errors.
5568     inline int fclose(cimg_std::FILE *file) {
5569       if (!file) warn("cimg::fclose() : Can't close (null) file");
5570       if (!file || file==stdin || file==stdout) return 0;
5571       const int errn = cimg_std::fclose(file);
5572       if (errn!=0) warn("cimg::fclose() : Error %d during file closing",errn);
5573       return errn;
5574     }
5575 
5576     //! Try to guess the image format of a filename, using its magick numbers.
5577     inline const char *file_type(cimg_std::FILE *const file, const char *const filename) {
5578       static const char
5579         *const _pnm = "pnm",
5580         *const _bmp = "bmp",
5581         *const _gif = "gif",
5582         *const _jpeg = "jpeg",
5583         *const _off = "off",
5584         *const _pan = "pan",
5585         *const _png = "png",
5586         *const _tiff = "tiff";
5587       if (!filename && !file) throw CImgArgumentException("cimg::file_type() : Cannot load (null) filename.");
5588       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
5589       const char *ftype = 0, *head;
5590       char header[2048], item[1024];
5591       const unsigned char *const uheader = (unsigned char*)header;
5592       int err;
5593       const unsigned int siz = (unsigned int)cimg_std::fread(header,2048,1,nfile);   // Read first 2048 bytes.
5594       if (!file) cimg::fclose(nfile);
5595       if (!ftype) { // Check for BMP format.
5596         if (header[0]=='B' && header[1]=='M') ftype = _bmp;
5597       }
5598       if (!ftype) { // Check for GIF format.
5599         if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' &&
5600             (header[4]=='7' || header[4]=='9')) ftype = _gif;
5601       }
5602       if (!ftype) { // Check for JPEG format.
5603         if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) ftype = _jpeg;
5604       }
5605       if (!ftype) { // Check for OFF format.
5606         if (header[0]=='O' && header[1]=='F' && header[2]=='F' && header[3]=='\n') ftype = _off;
5607       }
5608       if (!ftype) { // Check for PAN format.
5609         if (header[0]=='P' && header[1]=='A' && header[2]=='N' && header[3]=='D' && header[4]=='O' &&
5610             header[5]=='R' && header[6]=='E') ftype = _pan;
5611       }
5612       if (!ftype) { // Check for PNG format.
5613         if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 &&
5614             uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) ftype = _png;
5615       }
5616       if (!ftype) { // Check for PNM format.
5617         head = header;
5618         while (head<header+siz && (err=cimg_std::sscanf(head,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err))
5619           head+=1+(err?cimg::strlen(item):0);
5620         if (cimg_std::sscanf(item," P%d",&err)==1) ftype = _pnm;
5621       }
5622       if (!ftype) { // Check for TIFF format.
5623         if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) ftype = _tiff;
5624       }
5625       return ftype;
5626     }
5627 
5628     //! Read file data, and check for possible errors.
5629     template<typename T>
5630     inline int fread(T *const ptr, const unsigned int nmemb, cimg_std::FILE *stream) {
5631       if (!ptr || nmemb<=0 || !stream)
5632         throw CImgArgumentException("cimg::fread() : Can't read %u x %u bytes of file pointer '%p' in buffer '%p'",
5633                                     nmemb,sizeof(T),stream,ptr);
5634       const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
5635       unsigned int toread = nmemb, alread = 0, ltoread = 0, lalread = 0;
5636       do {
5637         ltoread = (toread*sizeof(T))<wlimitT?toread:wlimit;
5638         lalread = (unsigned int)cimg_std::fread((void*)(ptr+alread),sizeof(T),ltoread,stream);
5639         alread+=lalread;
5640         toread-=lalread;
5641       } while (ltoread==lalread && toread>0);
5642       if (toread>0) warn("cimg::fread() : File reading problems, only %u/%u elements read",alread,nmemb);
5643       return alread;
5644     }
5645 
5646     //! Write data to a file, and check for possible errors.
5647     template<typename T>
5648     inline int fwrite(const T *ptr, const unsigned int nmemb, cimg_std::FILE *stream) {
5649       if (!ptr || !stream)
5650         throw CImgArgumentException("cimg::fwrite() : Can't write %u x %u bytes of file pointer '%p' from buffer '%p'",
5651                                     nmemb,sizeof(T),stream,ptr);
5652       if (nmemb<=0) return 0;
5653       const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
5654       unsigned int towrite = nmemb, alwrite = 0, ltowrite = 0, lalwrite = 0;
5655       do {
5656         ltowrite = (towrite*sizeof(T))<wlimitT?towrite:wlimit;
5657         lalwrite = (unsigned int)cimg_std::fwrite((void*)(ptr+alwrite),sizeof(T),ltowrite,stream);
5658         alwrite+=lalwrite;
5659         towrite-=lalwrite;
5660       } while (ltowrite==lalwrite && towrite>0);
5661       if (towrite>0) warn("cimg::fwrite() : File writing problems, only %u/%u elements written",alwrite,nmemb);
5662       return alwrite;
5663     }
5664 
5665     inline const char* option(const char *const name, const int argc, const char *const *const argv,
5666                               const char *defaut, const char *const usage=0) {
5667       static bool first = true, visu = false;
5668       const char *res = 0;
5669       if (first) {
5670         first=false;
5671         visu = (cimg::option("-h",argc,argv,(char*)0)!=0);
5672         visu |= (cimg::option("-help",argc,argv,(char*)0)!=0);
5673         visu |= (cimg::option("--help",argc,argv,(char*)0)!=0);
5674       }
5675       if (!name && visu) {
5676         if (usage) {
5677           cimg_std::fprintf(cimg_stdout,"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);
5678           cimg_std::fprintf(cimg_stdout," : %s",usage);
5679         }
5680         if (defaut) cimg_std::fprintf(cimg_stdout,"%s\n",defaut);
5681       }
5682       if (name) {
5683         if (argc>0) {
5684           int k = 0;
5685           while (k<argc && cimg::strcmp(argv[k],name)) ++k;
5686           res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
5687         } else res = defaut;
5688         if (visu && usage) cimg_std::fprintf(cimg_stdout,"    %s%-16s%s %-24s %s%s%s\n",
5689                                         cimg::t_bold,name,cimg::t_normal,res?res:"0",cimg::t_green,usage,cimg::t_normal);
5690       }
5691       return res;
5692     }
5693 
5694     inline bool option(const char *const name, const int argc, const char *const *const argv,
5695                        const bool defaut, const char *const usage=0) {
5696       const char *s = cimg::option(name,argc,argv,(char*)0);
5697       const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut;
5698       cimg::option(name,0,0,res?"true":"false",usage);
5699       return res;
5700     }
5701 
5702     inline int option(const char *const name, const int argc, const char *const *const argv,
5703                       const int defaut, const char *const usage=0) {
5704       const char *s = cimg::option(name,argc,argv,(char*)0);
5705       const int res = s?cimg_std::atoi(s):defaut;
5706       char tmp[256];
5707       cimg_std::sprintf(tmp,"%d",res);
5708       cimg::option(name,0,0,tmp,usage);
5709       return res;
5710     }
5711 
5712     inline char option(const char *const name, const int argc, const char *const *const argv,
5713                        const char defaut, const char *const usage=0) {
5714       const char *s = cimg::option(name,argc,argv,(char*)0);
5715       const char res = s?s[0]:defaut;
5716       char tmp[8];
5717       tmp[0] = res; tmp[1] ='\0';
5718       cimg::option(name,0,0,tmp,usage);
5719       return res;
5720     }
5721 
5722     inline float option(const char *const name, const int argc, const char *const *const argv,
5723                         const float defaut, const char *const usage=0) {
5724       const char *s = cimg::option(name,argc,argv,(char*)0);
5725       const float res = s?cimg::atof(s):defaut;
5726       char tmp[256];
5727       cimg_std::sprintf(tmp,"%g",res);
5728       cimg::option(name,0,0,tmp,usage);
5729       return res;
5730     }
5731 
5732     inline double option(const char *const name, const int argc, const char *const *const argv,
5733                          const double defaut, const char *const usage=0) {
5734       const char *s = cimg::option(name,argc,argv,(char*)0);
5735       const double res = s?cimg::atof(s):defaut;
5736       char tmp[256];
5737       cimg_std::sprintf(tmp,"%g",res);
5738       cimg::option(name,0,0,tmp,usage);
5739       return res;
5740     }
5741 
5742     inline const char* argument(const unsigned int nb, const int argc, const char *const *const argv, const unsigned int nb_singles=0, ...) {
5743       for (int k = 1, pos = 0; k<argc;) {
5744         const char *const item = argv[k];
5745         bool option = (*item=='-'), single_option = false;
5746         if (option) {
5747           va_list ap;
5748           va_start(ap,nb_singles);
5749           for (unsigned int i=0; i<nb_singles; ++i) if (!cimg::strcasecmp(item,va_arg(ap,char*))) { single_option = true; break; }
5750           va_end(ap);
5751         }
5752         if (option) { ++k; if (!single_option) ++k; }
5753         else { if (pos++==(int)nb) return item; else ++k; }
5754       }
5755       return 0;
5756     }
5757 
5758     //! Print information about %CImg environment variables.
5759     /**
5760        Printing is done on the standard error output.
5761     **/
5762     inline void info() {
5763       char tmp[1024] = { 0 };
5764       cimg_std::fprintf(cimg_stdout,"\n %sCImg Library %u.%u.%u%s, compiled with the following flags :\n\n",
5765                    cimg::t_red,
5766                    cimg_version/100,
5767                    (cimg_version/10)%10,
5768                    cimg_version%10,
5769                    cimg::t_normal
5770       );
5771 
5772       cimg_std::fprintf(cimg_stdout,"  > Operating System :       %s%-13s%s %s('cimg_OS'=%d)%s\n",
5773                    cimg::t_bold,
5774                    cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"),
5775                    cimg::t_normal,cimg::t_green,
5776                    cimg_OS,
5777                    cimg::t_normal);
5778 
5779       cimg_std::fprintf(cimg_stdout,"  > CPU endianness :         %s%s Endian%s\n",
5780                    cimg::t_bold,
5781                    cimg::endianness()?"Big":"Little",
5782                    cimg::t_normal);
5783 
5784 #ifdef cimg_use_visualcpp6
5785       cimg_std::fprintf(cimg_stdout,"  > Using Visual C++ 6.0 :       %s%-13s%s %s('cimg_use_visualcpp6' defined)%s\n",
5786                    cimg::t_bold,"Yes",cimg::t_normal,cimg::t_green,cimg::t_normal);
5787 #endif
5788 
5789       cimg_std::fprintf(cimg_stdout,"  > Debug messages :         %s%-13s%s %s('cimg_debug'=%d)%s\n",
5790                    cimg::t_bold,
5791                    cimg_debug==0?"Quiet":(cimg_debug==1?"Console":(cimg_debug==2?"Dialog":(cimg_debug==3?"Console+Warnings":"Dialog+Warnings"))),
5792                    cimg::t_normal,cimg::t_green,
5793                    cimg_debug,
5794                    cimg::t_normal);
5795 
5796       cimg_std::fprintf(cimg_stdout,"  > Stricts warnings :       %s%-13s%s %s('cimg_strict_warnings' %s)%s\n",
5797                    cimg::t_bold,
5798 #ifdef cimg_strict_warnings
5799                    "Yes",cimg::t_normal,cimg::t_green,"defined",
5800 #else
5801                    "No",cimg::t_normal,cimg::t_green,"undefined",
5802 #endif
5803                    cimg::t_normal);
5804 
5805       cimg_std::fprintf(cimg_stdout,"  > Using VT100 messages :   %s%-13s%s %s('cimg_use_vt100' %s)%s\n",
5806                    cimg::t_bold,
5807 #ifdef cimg_use_vt100
5808                    "Yes",cimg::t_normal,cimg::t_green,"defined",
5809 #else
5810                    "No",cimg::t_normal,cimg::t_green,"undefined",
5811 #endif
5812                    cimg::t_normal);
5813 
5814       cimg_std::fprintf(cimg_stdout,"  > Display type :           %s%-13s%s %s('cimg_display'=%d)%s\n",
5815                    cimg::t_bold,
5816                    cimg_display==0?"No display":
5817                    (cimg_display==1?"X11":
5818                     (cimg_display==2?"Windows GDI":
5819                      (cimg_display==3?"Carbon":"Unknow"))),
5820                    cimg::t_normal,cimg::t_green,
5821                    cimg_display,
5822                    cimg::t_normal);
5823 
5824 #if cimg_display==1
5825       cimg_std::fprintf(cimg_stdout,"  > Using XShm for X11 :     %s%-13s%s %s('cimg_use_xshm' %s)%s\n",
5826                    cimg::t_bold,
5827 #ifdef cimg_use_xshm
5828                    "Yes",cimg::t_normal,cimg::t_green,"defined",
5829 #else
5830                    "No",cimg::t_normal,cimg::t_green,"undefined",
5831 #endif
5832                    cimg::t_normal);
5833 
5834       cimg_std::fprintf(cimg_stdout,"  > Using XRand for X11 :    %s%-13s%s %s('cimg_use_xrandr' %s)%s\n",
5835                    cimg::t_bold,
5836 #ifdef cimg_use_xrandr
5837                    "Yes",cimg::t_normal,cimg::t_green,"defined",
5838 #else
5839                    "No",cimg::t_normal,cimg::t_green,"undefined",
5840 #endif
5841                    cimg::t_normal);
5842 #endif
5843       cimg_std::fprintf(cimg_stdout,"  > Using OpenMP :           %s%-13s%s %s('cimg_use_openmp' %s)%s\n",
5844                    cimg::t_bold,
5845 #ifdef cimg_use_openmp
5846                    "Yes",cimg::t_normal,cimg::t_green,"defined",
5847 #else
5848                    "No",cimg::t_normal,cimg::t_green,"undefined",
5849 #endif
5850                    cimg::t_normal);
5851       cimg_std::fprintf(cimg_stdout,"  > Using PNG library :      %s%-13s%s %s('cimg_use_png' %s)%s\n",
5852                    cimg::t_bold,
5853 #ifdef cimg_use_png
5854                    "Yes",cimg::t_normal,cimg::t_green,"defined",
5855 #else
5856                    "No",cimg::t_normal,cimg::t_green,"undefined",
5857 #endif
5858                    cimg::t_normal);
5859       cimg_std::fprintf(cimg_stdout,"  > Using JPEG library :     %s%-13s%s %s('cimg_use_jpeg' %s)%s\n",
5860                    cimg::t_bold,
5861 #ifdef cimg_use_jpeg
5862                    "Yes",cimg::t_normal,cimg::t_green,"defined",
5863 #else
5864                    "No",cimg::t_normal,cimg::t_green,"undefined",
5865 #endif
5866                    cimg::t_normal);
5867 
5868       cimg_std::fprintf(cimg_stdout,"  > Using TIFF library :     %s%-13s%s %s('cimg_use_tiff' %s)%s\n",
5869                    cimg::t_bold,
5870 #ifdef cimg_use_tiff
5871                    "Yes",cimg::t_normal,cimg::t_green,"defined",
5872 #else
5873                    "No",cimg::t_normal,cimg::t_green,"undefined",
5874 #endif
5875                    cimg::t_normal);
5876 
5877       cimg_std::fprintf(cimg_stdout,"  > Using Magick++ library : %s%-13s%s %s('cimg_use_magick' %s)%s\n",
5878                    cimg::t_bold,
5879 #ifdef cimg_use_magick
5880                    "Yes",cimg::t_normal,cimg::t_green,"defined",
5881 #else
5882                    "No",cimg::t_normal,cimg::t_green,"undefined",
5883 #endif
5884                    cimg::t_normal);
5885 
5886       cimg_std::fprintf(cimg_stdout,"  > Using FFTW3 library :    %s%-13s%s %s('cimg_use_fftw3' %s)%s\n",
5887                    cimg::t_bold,
5888 #ifdef cimg_use_fftw3
5889                    "Yes",cimg::t_normal,cimg::t_green,"defined",
5890 #else
5891                    "No",cimg::t_normal,cimg::t_green,"undefined",
5892 #endif
5893                    cimg::t_normal);
5894 
5895       cimg_std::fprintf(cimg_stdout,"  > Using LAPACK library :   %s%-13s%s %s('cimg_use_lapack' %s)%s\n",
5896                    cimg::t_bold,
5897 #ifdef cimg_use_lapack
5898                    "Yes",cimg::t_normal,cimg::t_green,"defined",
5899 #else
5900                    "No",cimg::t_normal,cimg::t_green,"undefined",
5901 #endif
5902                    cimg::t_normal);
5903 
5904       cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::imagemagick_path());
5905       cimg_std::fprintf(cimg_stdout,"  > Path of ImageMagick :    %s%-13s%s\n",
5906                    cimg::t_bold,
5907                    tmp,
5908                    cimg::t_normal);
5909 
5910       cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::graphicsmagick_path());
5911       cimg_std::fprintf(cimg_stdout,"  > Path of GraphicsMagick : %s%-13s%s\n",
5912                    cimg::t_bold,
5913                    tmp,
5914                    cimg::t_normal);
5915 
5916       cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::medcon_path());
5917       cimg_std::fprintf(cimg_stdout,"  > Path of 'medcon' :       %s%-13s%s\n",
5918                    cimg::t_bold,
5919                    tmp,
5920                    cimg::t_normal);
5921 
5922       cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::temporary_path());
5923       cimg_std::fprintf(cimg_stdout,"  > Temporary path :         %s%-13s%s\n",
5924                    cimg::t_bold,
5925                    tmp,
5926                    cimg::t_normal);
5927 
5928       cimg_std::fprintf(cimg_stdout,"\n");
5929     }
5930 
5931     // Declare LAPACK function signatures if necessary.
5932     //
5933 #ifdef cimg_use_lapack
5934     template<typename T>
5935     inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) {
5936       dgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
5937     }
5938 
5939     inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) {
5940       sgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
5941     }
5942 
5943     template<typename T>
5944     inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {
5945       dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
5946     }
5947 
5948     inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) {
5949       sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
5950     }
5951 
5952     template<typename T>
5953     inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN,
5954                       T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) {
5955       dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
5956     }
5957 
5958     inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN,
5959                       float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) {
5960       sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
5961     }
5962 
5963     template<typename T>
5964     inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) {
5965       int one = 1;
5966       dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
5967     }
5968 
5969     inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) {
5970       int one = 1;
5971       sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
5972     }
5973 
5974     template<typename T>
5975     inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {
5976       dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
5977     }
5978 
5979     inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) {
5980       ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
5981     }
5982 #endif
5983 
5984     // End of the 'cimg' namespace
5985   }
5986 
5987   /*------------------------------------------------
5988    #
5989    #
5990    #   Definition of mathematical operators and
5991    #   external functions.
5992    #
5993    #
5994    -------------------------------------------------*/
5995   //
5996   // These functions are extern to any classes and can be used for a "functional-style" programming,
5997   // such as writing :
5998   //                     cos(img);
5999   // instead of          img.get_cos();
6000   //
6001   // Note that only the arithmetic operators and functions are implemented here.
6002   //
6003 
6004 #ifdef cimg_use_visualcpp6
6005   template<typename t>
6006   inline CImg<t> operator+(const CImg<t>& img, const t val) {
6007     return CImg<t>(img,false)+=val;
6008   }
6009 #else
6010   template<typename t1, typename t2>
6011   inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const t2 val) {
6012     typedef typename cimg::superset<t1,t2>::type t1t2;
6013     return CImg<t1t2>(img,false)+=val;
6014  }
6015 #endif
6016 
6017 #ifdef cimg_use_visualcpp6
6018   template<typename t>
6019   inline CImg<t> operator+(const t val, const CImg<t>& img) {
6020     return img + val;
6021   }
6022 #else
6023   template<typename t1, typename t2>
6024   inline CImg<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImg<t2>& img) {
6025     return img + val;
6026   }
6027 #endif
6028 
6029 #ifdef cimg_use_visualcpp6
6030   template<typename t>
6031   inline CImgList<t> operator+(const CImgList<t>& list, const t val) {
6032     return CImgList<t>(list)+=val;
6033   }
6034 #else
6035   template<typename t1, typename t2>
6036   inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const t2 val) {
6037     typedef typename cimg::superset<t1,t2>::type t1t2;
6038     return CImgList<t1t2>(list)+=val;
6039   }
6040 #endif
6041 
6042 #ifdef cimg_use_visualcpp6
6043   template<typename t>
6044   inline CImgList<t> operator+(const t val, const CImgList<t>& list) {
6045     return list + val;
6046   }
6047 #else
6048   template<typename t1, typename t2>
6049   inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImgList<t2>& list) {
6050     return list + val;
6051   }
6052 #endif
6053 
6054   template<typename t1, typename t2>
6055   inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img1, const CImg<t2>& img2) {
6056     typedef typename cimg::superset<t1,t2>::type t1t2;
6057     return CImg<t1t2>(img1,false)+=img2;
6058   }
6059 
6060   template<typename t1, typename t2>
6061   inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const CImgList<t2>& list) {
6062     typedef typename cimg::superset<t1,t2>::type t1t2;
6063     return CImgList<t1t2>(list)+=img;
6064   }
6065 
6066   template<typename t1, typename t2>
6067   inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const CImg<t2>& img) {
6068     return img + list;
6069   }
6070 
6071   template<typename t1, typename t2>
6072   inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list1, const CImgList<t2>& list2) {
6073     typedef typename cimg::superset<t1,t2>::type t1t2;
6074     return CImgList<t1t2>(list1)+=list2;
6075   }
6076 
6077 #ifdef cimg_use_visualcpp6
6078   template<typename t>
6079   inline CImg<t> operator-(const CImg<t>& img, const t val) {
6080     return CImg<t>(img,false)-=val;
6081   }
6082 #else
6083   template<typename t1, typename t2>
6084   inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const t2 val) {
6085     typedef typename cimg::superset<t1,t2>::type t1t2;
6086     return CImg<t1t2>(img,false)-=val;
6087   }
6088 #endif
6089 
6090 #ifdef cimg_use_visualcpp6
6091   template<typename t>
6092   inline CImg<t> operator-(const t val, const CImg<t>& img) {
6093     return CImg<t>(img.width,img.height,img.depth,img.dim,val)-=img;
6094   }
6095 #else
6096   template<typename t1, typename t2>
6097   inline CImg<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImg<t2>& img) {
6098     typedef typename cimg::superset<t1,t2>::type t1t2;
6099     return CImg<t1t2>(img.width,img.height,img.depth,img.dim,(t1t2)val)-=img;
6100   }
6101 #endif
6102 
6103 #ifdef cimg_use_visualcpp6
6104   template<typename t>
6105   inline CImgList<t> operator-(const CImgList<t>& list, const t val) {
6106     return CImgList<t>(list)-=val;
6107   }
6108 #else
6109   template<typename t1, typename t2>
6110   inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const t2 val) {
6111     typedef typename cimg::superset<t1,t2>::type t1t2;
6112     return CImgList<t1t2>(list)-=val;
6113   }
6114 #endif
6115 
6116 #ifdef cimg_use_visualcpp6
6117   template<typename t>
6118   inline CImgList<double> operator-(const t val, const CImgList<t>& list) {
6119     CImgList<t> res(list.size);
6120     cimglist_for(res,l) res[l] = val - list[l];
6121     return res;
6122   }
6123 #else
6124   template<typename t1, typename t2>
6125   inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImgList<t2>& list) {
6126     typedef typename cimg::superset<t1,t2>::type t1t2;
6127     CImgList<t1t2> res(list.size);
6128     cimglist_for(res,l) res[l] = val - list[l];
6129     return res;
6130   }
6131 #endif
6132 
6133   template<typename t1, typename t2>
6134   inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img1, const CImg<t2>& img2) {
6135     typedef typename cimg::superset<t1,t2>::type t1t2;
6136     return CImg<t1t2>(img1,false)-=img2;
6137   }
6138 
6139   template<typename t1, typename t2>
6140   inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const CImgList<t2>& list) {
6141     typedef typename cimg::superset<t1,t2>::type t1t2;
6142     CImgList<t1t2> res(list.size);
6143     cimglist_for(res,l) res[l] = img - list[l];
6144     return res;
6145   }
6146 
6147   template<typename t1, typename t2>
6148   inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const CImg<t2>& img) {
6149     typedef typename cimg::superset<t1,t2>::type t1t2;
6150     return CImgList<t1t2>(list)-=img;
6151   }
6152 
6153   template<typename t1, typename t2>
6154   inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list1, const CImgList<t2>& list2) {
6155     typedef typename cimg::superset<t1,t2>::type t1t2;
6156     return CImgList<t1t2>(list1)-=list2;
6157   }
6158 
6159 #ifdef cimg_use_visualcpp6
6160   template<typename t>
6161   inline CImg<t> operator*(const CImg<t>& img, const double val) {
6162     return CImg<t>(img,false)*=val;
6163   }
6164 #else
6165   template<typename t1, typename t2>
6166   inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const t2 val) {
6167     typedef typename cimg::superset<t1,t2>::type t1t2;
6168     return CImg<t1t2>(img,false)*=val;
6169   }
6170 #endif
6171 
6172 #ifdef cimg_use_visualcpp6
6173   template<typename t>
6174   inline CImg<t> operator*(const double val, const CImg<t>& img) {
6175     return img*val;
6176   }
6177 #else
6178   template<typename t1, typename t2>
6179   inline CImg<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImg<t2>& img) {
6180     return img*val;
6181   }
6182 #endif
6183 
6184 #ifdef cimg_use_visualcpp6
6185   template<typename t>
6186   inline CImgList<t> operator*(const CImgList<t>& list, const double val) {
6187     return CImgList<t>(list)*=val;
6188   }
6189 #else
6190   template<typename t1, typename t2>
6191   inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const t2 val) {
6192     typedef typename cimg::superset<t1,t2>::type t1t2;
6193     return CImgList<t1t2>(list)*=val;
6194   }
6195 #endif
6196 
6197 #ifdef cimg_use_visualcpp6
6198   template<typename t>
6199   inline CImgList<t> operator*(const double val, const CImgList<t>& list) {
6200     return list*val;
6201   }
6202 #else
6203   template<typename t1, typename t2>
6204   inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImgList<t2>& list) {
6205     return list*val;
6206   }
6207 #endif
6208 
6209   template<typename t1, typename t2>
6210   inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img1, const CImg<t2>& img2) {
6211     typedef typename cimg::superset<t1,t2>::type t1t2;
6212     if (img1.width!=img2.height)
6213       throw CImgArgumentException("operator*() : can't multiply a matrix (%ux%u) by a matrix (%ux%u)",
6214                                   img1.width,img1.height,img2.width,img2.height);
6215     CImg<t1t2> res(img2.width,img1.height);
6216     t1t2 val;
6217 #ifdef cimg_use_openmp
6218 #pragma omp parallel for if (img1.size()>=1000 && img2.size()>=1000) private(val)
6219 #endif
6220     cimg_forXY(res,i,j) { val = 0; cimg_forX(img1,k) val+=img1(k,j)*img2(i,k); res(i,j) = val; }
6221     return res;
6222   }
6223 
6224   template<typename t1, typename t2>
6225   inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const CImgList<t2>& list) {
6226     typedef typename cimg::superset<t1,t2>::type t1t2;
6227     CImgList<t1t2> res(list.size);
6228     cimglist_for(res,l) res[l] = img*list[l];
6229     return res;
6230   }
6231 
6232   template<typename t1, typename t2>
6233   inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const CImg<t2>& img) {
6234     typedef typename cimg::superset<t1,t2>::type t1t2;
6235     CImgList<t1t2> res(list.size);
6236     cimglist_for(res,l) res[l] = list[l]*img;
6237     return res;
6238   }
6239 
6240   template<typename t1, typename t2>
6241   inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list1, const CImgList<t2>& list2) {
6242     typedef typename cimg::superset<t1,t2>::type t1t2;
6243     CImgList<t1t2> res(cimg::min(list1.size,list2.size));
6244     cimglist_for(res,l) res[l] = list1[l]*list2[l];
6245     return res;
6246   }
6247 
6248 #ifdef cimg_use_visualcpp6
6249   template<typename t>
6250   inline CImg<t> operator/(const CImg<t>& img, const double val) {
6251     return CImg<t>(img,false)/=val;
6252   }
6253 #else
6254   template<typename t1, typename t2>
6255   inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const t2 val) {
6256     typedef typename cimg::superset<t1,t2>::type t1t2;
6257     return CImg<t1t2>(img,false)/=val;
6258   }
6259 #endif
6260 
6261 #ifdef cimg_use_visualcpp6
6262   template<typename t>
6263   inline CImg<t> operator/(const double val, CImg<t>& img) {
6264     return val*img.get_invert();
6265   }
6266 #else
6267   template<typename t1, typename t2>
6268   inline CImg<typename cimg::superset<t1,t2>::type> operator/(const t1 val, CImg<t2>& img) {
6269     return val*img.get_invert();
6270   }
6271 #endif
6272 
6273 #ifdef cimg_use_visualcpp6
6274   template<typename t>
6275   inline CImgList<t> operator/(const CImgList<t>& list, const double val) {
6276     return CImgList<t>(list)/=val;
6277   }
6278 #else
6279   template<typename t1, typename t2>
6280   inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const t2 val) {
6281     typedef typename cimg::superset<t1,t2>::type t1t2;
6282     return CImgList<t1t2>(list)/=val;
6283   }
6284 #endif
6285 
6286 #ifdef cimg_use_visualcpp6
6287   template<typename t>
6288   inline CImgList<t> operator/(const double val, const CImgList<t>& list) {
6289     CImgList<t> res(list.size);
6290     cimglist_for(res,l) res[l] = val/list[l];
6291     return res;
6292   }
6293 #else
6294   template<typename t1, typename t2>
6295   inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const t1 val, const CImgList<t2>& list) {
6296     typedef typename cimg::superset<t1,t2>::type t1t2;
6297     CImgList<t1t2> res(list.size);
6298     cimglist_for(res,l) res[l] = val/list[l];
6299     return res;
6300   }
6301 #endif
6302 
6303   template<typename t1, typename t2>
6304   inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img1, const CImg<t2>& img2) {
6305     typedef typename cimg::superset<t1,t2>::type t1t2;
6306     return CImg<t1t2>(img1,false)*=img2.get_invert();
6307   }
6308 
6309   template<typename t1, typename t2>
6310   inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const CImgList<t2>& list) {
6311     typedef typename cimg::superset<t1,t2>::type t1t2;
6312     CImgList<t1t2> res(list.size);
6313     cimglist_for(res,l) res[l] = img/list[l];
6314     return res;
6315   }
6316 
6317   template<typename t1, typename t2>
6318   inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const CImg<t2>& img) {
6319     typedef typename cimg::superset<t1,t2>::type t1t2;
6320     return CImgList<t1t2>(list)/=img;
6321   }
6322 
6323   template<typename t1, typename t2>
6324   inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list1, const CImgList<t2>& list2) {
6325     typedef typename cimg::superset<t1,t2>::type t1t2;
6326     return CImgList<t1t2>(list1)/=list2;
6327   }
6328 
6329   template<typename T>
6330   inline CImg<_cimg_Tfloat> sqr(const CImg<T>& instance) {
6331     return instance.get_sqr();
6332   }
6333 
6334   template<typename T>
6335   inline CImg<_cimg_Tfloat> sqrt(const CImg<T>& instance) {
6336     return instance.get_sqrt();
6337   }
6338 
6339   template<typename T>
6340   inline CImg<_cimg_Tfloat> exp(const CImg<T>& instance) {
6341     return instance.get_exp();
6342   }
6343 
6344   template<typename T>
6345   inline CImg<_cimg_Tfloat> log(const CImg<T>& instance) {
6346     return instance.get_log();
6347   }
6348 
6349   template<typename T>
6350   inline CImg<_cimg_Tfloat> log10(const CImg<T>& instance) {
6351     return instance.get_log10();
6352   }
6353 
6354   template<typename T>
6355   inline CImg<_cimg_Tfloat> abs(const CImg<T>& instance) {
6356     return instance.get_abs();
6357   }
6358 
6359   template<typename T>
6360   inline CImg<_cimg_Tfloat> cos(const CImg<T>& instance) {
6361     return instance.get_cos();
6362   }
6363 
6364   template<typename T>
6365   inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) {
6366     return instance.get_sin();
6367   }
6368 
6369   template<typename T>
6370   inline CImg<_cimg_Tfloat> tan(const CImg<T>& instance) {
6371     return instance.get_tan();
6372   }
6373 
6374   template<typename T>
6375   inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) {
6376     return instance.get_acos();
6377   }
6378 
6379   template<typename T>
6380   inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) {
6381     return instance.get_asin();
6382   }
6383 
6384   template<typename T>
6385   inline CImg<_cimg_Tfloat> atan(const CImg<T>& instance) {
6386     return instance.get_atan();
6387   }
6388 
6389   template<typename T>
6390   inline CImg<T> transpose(const CImg<T>& instance) {
6391     return instance.get_transpose();
6392   }
6393 
6394   template<typename T>
6395   inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance) {
6396     return instance.get_invert();
6397   }
6398 
6399   template<typename T>
6400   inline CImg<_cimg_Tfloat> pseudoinvert(const CImg<T>& instance) {
6401     return instance.get_pseudoinvert();
6402   }
6403 
6404   /*-------------------------------------------
6405    #
6406    #
6407    #
6408    # Definition of the CImgDisplay structure
6409    #
6410    #
6411    #
6412    --------------------------------------------*/
6413 
6414   //! This class represents a window which can display \ref CImg images and handles mouse and keyboard events.
6415   /**
6416      Creating a \c CImgDisplay instance opens a window that can be used to display a \c CImg<T> image
6417      of a \c CImgList<T> image list inside. When a display is created, associated window events
6418      (such as mouse motion, keyboard and window size changes) are handled and can be easily
6419      detected by testing specific \c CImgDisplay data fields.
6420      See \ref cimg_displays for a complete tutorial on using the \c CImgDisplay class.
6421   **/
6422 
6423   struct CImgDisplay {
6424 
6425     //! Width of the display
6426     unsigned int width;
6427 
6428     //! Height of the display
6429     unsigned int height;
6430 
6431     //! Normalization type used for the display
6432     unsigned int normalization;
6433 
6434     //! Display title
6435     char* title;
6436 
6437     //! X-pos of the display on the screen
6438     volatile int window_x;
6439 
6440     //! Y-pos of the display on the screen
6441     volatile int window_y;
6442 
6443     //! Width of the underlying window
6444     volatile unsigned int window_width;
6445 
6446     //! Height of the underlying window
6447     volatile unsigned int window_height;
6448 
6449     //! X-coordinate of the mouse pointer on the display
6450     volatile int mouse_x;
6451 
6452     //! Y-coordinate of the mouse pointer on the display
6453     volatile int mouse_y;
6454 
6455     //! Button state of the mouse
6456     volatile unsigned int buttons[512];
6457     volatile unsigned int& button;
6458 
6459     //! Wheel state of the mouse
6460     volatile int wheel;
6461 
6462     //! Key value if pressed
6463     volatile unsigned int& key;
6464     volatile unsigned int keys[512];
6465 
6466     //! Key value if released
6467     volatile unsigned int& released_key;
6468     volatile unsigned int released_keys[512];
6469 
6470     //! Closed state of the window
6471     volatile bool is_closed;
6472 
6473     //! Resized state of the window
6474     volatile bool is_resized;
6475 
6476     //! Moved state of the window
6477     volatile bool is_moved;
6478 
6479     //! Event state of the window
6480     volatile bool is_event;
6481 
6482     //! Current state of the corresponding key (exists for all referenced keys).
6483     volatile bool is_keyESC;
6484     volatile bool is_keyF1;
6485     volatile bool is_keyF2;
6486     volatile bool is_keyF3;
6487     volatile bool is_keyF4;
6488     volatile bool is_keyF5;
6489     volatile bool is_keyF6;
6490     volatile bool is_keyF7;
6491     volatile bool is_keyF8;
6492     volatile bool is_keyF9;
6493     volatile bool is_keyF10;
6494     volatile bool is_keyF11;
6495     volatile bool is_keyF12;
6496     volatile bool is_keyPAUSE;
6497     volatile bool is_key1;
6498     volatile bool is_key2;
6499     volatile bool is_key3;
6500     volatile bool is_key4;
6501     volatile bool is_key5;
6502     volatile bool is_key6;
6503     volatile bool is_key7;
6504     volatile bool is_key8;
6505     volatile bool is_key9;
6506     volatile bool is_key0;
6507     volatile bool is_keyBACKSPACE;
6508     volatile bool is_keyINSERT;
6509     volatile bool is_keyHOME;
6510     volatile bool is_keyPAGEUP;
6511     volatile bool is_keyTAB;
6512     volatile bool is_keyQ;
6513     volatile bool is_keyW;
6514     volatile bool is_keyE;
6515     volatile bool is_keyR;
6516     volatile bool is_keyT;
6517     volatile bool is_keyY;
6518     volatile bool is_keyU;
6519     volatile bool is_keyI;
6520     volatile bool is_keyO;
6521     volatile bool is_keyP;
6522     volatile bool is_keyDELETE;
6523     volatile bool is_keyEND;
6524     volatile bool is_keyPAGEDOWN;
6525     volatile bool is_keyCAPSLOCK;
6526     volatile bool is_keyA;
6527     volatile bool is_keyS;
6528     volatile bool is_keyD;
6529     volatile bool is_keyF;
6530     volatile bool is_keyG;
6531     volatile bool is_keyH;
6532     volatile bool is_keyJ;
6533     volatile bool is_keyK;
6534     volatile bool is_keyL;
6535     volatile bool is_keyENTER;
6536     volatile bool is_keySHIFTLEFT;
6537     volatile bool is_keyZ;
6538     volatile bool is_keyX;
6539     volatile bool is_keyC;
6540     volatile bool is_keyV;
6541     volatile bool is_keyB;
6542     volatile bool is_keyN;
6543     volatile bool is_keyM;
6544     volatile bool is_keySHIFTRIGHT;
6545     volatile bool is_keyARROWUP;
6546     volatile bool is_keyCTRLLEFT;
6547     volatile bool is_keyAPPLEFT;
6548     volatile bool is_keyALT;
6549     volatile bool is_keySPACE;
6550     volatile bool is_keyALTGR;
6551     volatile bool is_keyAPPRIGHT;
6552     volatile bool is_keyMENU;
6553     volatile bool is_keyCTRLRIGHT;
6554     volatile bool is_keyARROWLEFT;
6555     volatile bool is_keyARROWDOWN;
6556     volatile bool is_keyARROWRIGHT;
6557     volatile bool is_keyPAD0;
6558     volatile bool is_keyPAD1;
6559     volatile bool is_keyPAD2;
6560     volatile bool is_keyPAD3;
6561     volatile bool is_keyPAD4;
6562     volatile bool is_keyPAD5;
6563     volatile bool is_keyPAD6;
6564     volatile bool is_keyPAD7;
6565     volatile bool is_keyPAD8;
6566     volatile bool is_keyPAD9;
6567     volatile bool is_keyPADADD;
6568     volatile bool is_keyPADSUB;
6569     volatile bool is_keyPADMUL;
6570     volatile bool is_keyPADDIV;
6571 
6572     //! Fullscreen state of the display
6573     bool is_fullscreen;
6574 
6575     float fps_fps, min, max;
6576     unsigned long timer, fps_frames, fps_timer;
6577 
6578 #ifdef cimgdisplay_plugin
6579 #include cimgdisplay_plugin
6580 #endif
6581 #ifdef cimgdisplay_plugin1
6582 #include cimgdisplay_plugin1
6583 #endif
6584 #ifdef cimgdisplay_plugin2
6585 #include cimgdisplay_plugin2
6586 #endif
6587 #ifdef cimgdisplay_plugin3
6588 #include cimgdisplay_plugin3
6589 #endif
6590 #ifdef cimgdisplay_plugin4
6591 #include cimgdisplay_plugin4
6592 #endif
6593 #ifdef cimgdisplay_plugin5
6594 #include cimgdisplay_plugin5
6595 #endif
6596 #ifdef cimgdisplay_plugin6
6597 #include cimgdisplay_plugin6
6598 #endif
6599 #ifdef cimgdisplay_plugin7
6600 #include cimgdisplay_plugin7
6601 #endif
6602 #ifdef cimgdisplay_plugin8
6603 #include cimgdisplay_plugin8
6604 #endif
6605 
6606     //! Create an empty display window.
6607     CImgDisplay():
6608       width(0),height(0),normalization(0),title(0),
6609       window_x(0),window_y(0),window_width(0),window_height(0),
6610       mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
6611       is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
6612       min(0),max(0) {}
6613 
6614     //! Create a display window with a specified size \p pwidth x \p height.
6615     /** \param dimw Width of the display window.
6616         \param dimh Height of the display window.
6617         \param title Title of the display window.
6618         \param normalization_type Normalization type of the display window (0=none, 1=always, 2=once).
6619         \param fullscreen_flag : Fullscreen mode.
6620         \param closed_flag : Initially visible mode.
6621         A black image will be initially displayed in the display window.
6622     **/
6623     CImgDisplay(const unsigned int dimw, const unsigned int dimh, const char *title=0,
6624                 const unsigned int normalization_type=3,
6625                 const bool fullscreen_flag=false, const bool closed_flag=false):
6626       width(0),height(0),normalization(0),title(0),
6627       window_x(0),window_y(0),window_width(0),window_height(0),
6628       mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
6629       is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
6630       min(0),max(0) {
6631       assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
6632     }
6633 
6634     //! Create a display window from an image.
6635     /** \param img : Image that will be used to create the display window.
6636         \param title : Title of the display window
6637         \param normalization_type : Normalization type of the display window.
6638         \param fullscreen_flag : Fullscreen mode.
6639         \param closed_flag : Initially visible mode.
6640     **/
6641     template<typename T>
6642     CImgDisplay(const CImg<T>& img, const char *title=0,
6643                 const unsigned int normalization_type=3,
6644                 const bool fullscreen_flag=false, const bool closed_flag=false):
6645       width(0),height(0),normalization(0),title(0),
6646       window_x(0),window_y(0),window_width(0),window_height(0),
6647       mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
6648       is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
6649       assign(img,title,normalization_type,fullscreen_flag,closed_flag);
6650     }
6651 
6652     //! Create a display window from an image list.
6653     /** \param list : The list of images to display.
6654         \param title : Title of the display window
6655         \param normalization_type : Normalization type of the display window.
6656         \param fullscreen_flag : Fullscreen mode.
6657         \param closed_flag : Initially visible mode.
6658     **/
6659     template<typename T>
6660     CImgDisplay(const CImgList<T>& list, const char *title=0,
6661                 const unsigned int normalization_type=3,
6662                 const bool fullscreen_flag=false, const bool closed_flag=false):
6663       width(0),height(0),normalization(0),title(0),
6664       window_x(0),window_y(0),window_width(0),window_height(0),
6665       mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
6666       is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
6667       assign(list,title,normalization_type,fullscreen_flag,closed_flag);
6668     }
6669 
6670     //! Create a display window by copying another one.
6671     /**
6672         \param disp  : Display window to copy.
6673     **/
6674     CImgDisplay(const CImgDisplay& disp):
6675       width(0),height(0),normalization(0),title(0),
6676       window_x(0),window_y(0),window_width(0),window_height(0),
6677       mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
6678       is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
6679       assign(disp);
6680     }
6681 
6682     //! Destructor.
6683     ~CImgDisplay() {
6684       assign();
6685     }
6686 
6687     //! Assignment operator.
6688     CImgDisplay& operator=(const CImgDisplay& disp) {
6689       return assign(disp);
6690     }
6691 
6692     //! Return true is display is empty.
6693     bool is_empty() const {
6694       return (!width || !height);
6695     }
6696 
6697     //! Return true if display is not empty.
6698     operator bool() const {
6699       return !is_empty();
6700     }
6701 
6702     //! Return display width.
6703     int dimx() const {
6704       return (int)width;
6705     }
6706 
6707     //! Return display height.
6708     int dimy() const {
6709       return (int)height;
6710     }
6711 
6712     //! Return display window width.
6713     int window_dimx() const {
6714       return (int)window_width;
6715     }
6716 
6717     //! Return display window height.
6718     int window_dimy() const {
6719       return (int)window_height;
6720     }
6721 
6722     //! Return X-coordinate of the window.
6723     int window_posx() const {
6724       return window_x;
6725     }
6726 
6727     //! Return Y-coordinate of the window.
6728     int window_posy() const {
6729       return window_y;
6730     }
6731 
6732     //! Synchronized waiting function. Same as cimg::wait().
6733     CImgDisplay& wait(const unsigned int milliseconds) {
6734       cimg::_sleep(milliseconds,timer);
6735       return *this;
6736     }
6737 
6738     //! Wait for an event occurring on the current display.
6739     CImgDisplay& wait() {
6740       if (!is_empty()) wait(*this);
6741       return *this;
6742     }
6743 
6744     //! Wait for any event occurring on the display \c disp1.
6745     static void wait(CImgDisplay& disp1) {
6746       disp1.is_event = 0;
6747       while (!disp1.is_event) wait_all();
6748     }
6749 
6750     //! Wait for any event occurring either on the display \c disp1 or \c disp2.
6751     static void wait(CImgDisplay& disp1, CImgDisplay& disp2) {
6752       disp1.is_event = disp2.is_event = 0;
6753       while (!disp1.is_event && !disp2.is_event) wait_all();
6754     }
6755 
6756     //! Wait for any event occurring either on the display \c disp1, \c disp2 or \c disp3.
6757     static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) {
6758       disp1.is_event = disp2.is_event = disp3.is_event = 0;
6759       while (!disp1.is_event && !disp2.is_event && !disp3.is_event) wait_all();
6760     }
6761 
6762     //! Wait for any event occurring either on the display \c disp1, \c disp2, \c disp3 or \c disp4.
6763     static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) {
6764       disp1.is_event = disp2.is_event = disp3.is_event = disp4.is_event = 0;
6765       while (!disp1.is_event && !disp2.is_event && !disp3.is_event && !disp4.is_event) wait_all();
6766     }
6767 
6768     //! Return the frame per second rate.
6769     float frames_per_second() {
6770       if (!fps_timer) fps_timer = cimg::time();
6771       const float delta = (cimg::time()-fps_timer)/1000.0f;
6772       ++fps_frames;
6773       if (delta>=1) {
6774         fps_fps = fps_frames/delta;
6775         fps_frames = 0;
6776         fps_timer = cimg::time();
6777       }
6778       return fps_fps;
6779     }
6780 
6781     //! Display an image list CImgList<T> into a display window.
6782     /** First, all images of the list are appended into a single image used for visualization,
6783         then this image is displayed in the current display window.
6784         \param list     : The list of images to display.
6785         \param axis     : The axis used to append the image for visualization. Can be 'x' (default),'y','z' or 'v'.
6786         \param align : Defines the relative alignment of images when displaying images of different sizes.
6787         Can be '\p c' (centered, which is the default), '\p p' (top alignment) and '\p n' (bottom alignment).
6788     **/
6789     template<typename T>
6790     CImgDisplay& display(const CImgList<T>& list, const char axis='x', const char align='p') {
6791       return display(list.get_append(axis,align));
6792     }
6793 
6794     //! Display an image CImg<T> into a display window.
6795     template<typename T>
6796     CImgDisplay& operator<<(const CImg<T>& img) {
6797       return display(img);
6798     }
6799 
6800     //! Display an image CImg<T> into a display window.
6801     template<typename T>
6802     CImgDisplay& operator<<(const CImgList<T>& list) {
6803       return display(list);
6804     }
6805 
6806     //! Resize a display window with the size of an image.
6807     /** \param img    : Input image. \p image.width and \p image.height give the new dimensions of the display window.
6808         \param redraw : If \p true (default), the current displayed image in the display window will
6809         be bloc-interpolated to fit the new dimensions. If \p false, a black image will be drawn in the resized window.
6810     **/
6811     template<typename T>
6812     CImgDisplay& resize(const CImg<T>& img, const bool redraw=true) {
6813       return resize(img.width,img.height,redraw);
6814     }
6815 
6816     //! Resize a display window using the size of the given display \p disp.
6817     CImgDisplay& resize(const CImgDisplay& disp, const bool redraw=true) {
6818       return resize(disp.width,disp.height,redraw);
6819     }
6820 
6821     //! Resize a display window in its current size.
6822     CImgDisplay& resize(const bool redraw=true) {
6823       resize(window_width,window_height,redraw);
6824       return *this;
6825     }
6826 
6827     //! Set fullscreen mode.
6828     CImgDisplay& fullscreen(const bool redraw=true) {
6829       if (is_empty() || is_fullscreen) return *this;
6830       return toggle_fullscreen(redraw);
6831     }
6832 
6833     //! Set normal screen mode.
6834     CImgDisplay& normalscreen(const bool redraw=true) {
6835       if (is_empty() || !is_fullscreen) return *this;
6836       return toggle_fullscreen(redraw);
6837     }
6838 
6839     // Inner routine used for fast resizing of buffer to display size.
6840     template<typename t, typename T>
6841     static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,
6842                                t *ptrd, const unsigned int wd, const unsigned int hd) {
6843       unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd+1], *poffx, *poffy;
6844       float s, curr, old;
6845       s = (float)ws/wd;
6846       poffx = offx; curr = 0; for (unsigned int x=0; x<wd; ++x) { old=curr; curr+=s; *(poffx++) = (unsigned int)curr-(unsigned int)old; }
6847       s = (float)hs/hd;
6848       poffy = offy; curr = 0; for (unsigned int y=0; y<hd; ++y) { old=curr; curr+=s; *(poffy++) = ws*((unsigned int)curr-(unsigned int)old); }
6849       *poffy = 0;
6850       poffy = offy;
6851       {for (unsigned int y=0; y<hd; ) {
6852         const T *ptr = ptrs;
6853         poffx = offx;
6854         for (unsigned int x=0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); }
6855         ++y;
6856         unsigned int dy=*(poffy++);
6857         for (;!dy && y<hd; cimg_std::memcpy(ptrd, ptrd-wd, sizeof(t)*wd), ++y, ptrd+=wd, dy=*(poffy++)) {}
6858         ptrs+=dy;
6859       }}
6860       delete[] offx; delete[] offy;
6861     }
6862 
6863     //! Clear all events of the current display.
6864     CImgDisplay& flush() {
6865       cimg_std::memset((void*)buttons,0,512*sizeof(unsigned int));
6866       cimg_std::memset((void*)keys,0,512*sizeof(unsigned int));
6867       cimg_std::memset((void*)released_keys,0,512*sizeof(unsigned int));
6868       is_keyESC = is_keyF1 = is_keyF2 = is_keyF3 = is_keyF4 = is_keyF5 = is_keyF6 = is_keyF7 = is_keyF8 = is_keyF9 =
6869         is_keyF10 = is_keyF11 = is_keyF12 = is_keyPAUSE = is_key1 = is_key2 = is_key3 = is_key4 = is_key5 = is_key6 =
6870         is_key7 = is_key8 = is_key9 = is_key0 = is_keyBACKSPACE = is_keyINSERT = is_keyHOME = is_keyPAGEUP = is_keyTAB =
6871         is_keyQ = is_keyW = is_keyE = is_keyR = is_keyT = is_keyY = is_keyU = is_keyI = is_keyO = is_keyP = is_keyDELETE =
6872         is_keyEND = is_keyPAGEDOWN = is_keyCAPSLOCK = is_keyA = is_keyS = is_keyD = is_keyF = is_keyG = is_keyH = is_keyJ =
6873         is_keyK = is_keyL = is_keyENTER = is_keySHIFTLEFT = is_keyZ = is_keyX = is_keyC = is_keyV = is_keyB = is_keyN =
6874         is_keyM = is_keySHIFTRIGHT = is_keyARROWUP = is_keyCTRLLEFT = is_keyAPPLEFT = is_keyALT = is_keySPACE = is_keyALTGR = is_keyAPPRIGHT =
6875         is_keyMENU = is_keyCTRLRIGHT = is_keyARROWLEFT = is_keyARROWDOWN = is_keyARROWRIGHT = is_keyPAD0 = is_keyPAD1 = is_keyPAD2 =
6876         is_keyPAD3 = is_keyPAD4 = is_keyPAD5 = is_keyPAD6 = is_keyPAD7 = is_keyPAD8 = is_keyPAD9 = is_keyPADADD = is_keyPADSUB =
6877         is_keyPADMUL = is_keyPADDIV = false;
6878       is_resized = is_moved = is_event = false;
6879       fps_timer = fps_frames = timer = wheel = 0;
6880       mouse_x = mouse_y = -1;
6881       fps_fps = 0;
6882       return *this;
6883     }
6884 
6885     // Update 'is_key' fields.
6886     void update_iskey(const unsigned int key, const bool pressed=true) {
6887 #define _cimg_iskey_case(k) if (key==cimg::key##k) is_key##k = pressed;
6888       _cimg_iskey_case(ESC); _cimg_iskey_case(F1); _cimg_iskey_case(F2); _cimg_iskey_case(F3);
6889       _cimg_iskey_case(F4); _cimg_iskey_case(F5); _cimg_iskey_case(F6); _cimg_iskey_case(F7);
6890       _cimg_iskey_case(F8); _cimg_iskey_case(F9); _cimg_iskey_case(F10); _cimg_iskey_case(F11);
6891       _cimg_iskey_case(F12); _cimg_iskey_case(PAUSE); _cimg_iskey_case(1); _cimg_iskey_case(2);
6892       _cimg_iskey_case(3); _cimg_iskey_case(4); _cimg_iskey_case(5); _cimg_iskey_case(6);
6893       _cimg_iskey_case(7); _cimg_iskey_case(8); _cimg_iskey_case(9); _cimg_iskey_case(0);
6894       _cimg_iskey_case(BACKSPACE); _cimg_iskey_case(INSERT); _cimg_iskey_case(HOME);
6895       _cimg_iskey_case(PAGEUP); _cimg_iskey_case(TAB); _cimg_iskey_case(Q); _cimg_iskey_case(W);
6896       _cimg_iskey_case(E); _cimg_iskey_case(R); _cimg_iskey_case(T); _cimg_iskey_case(Y);
6897       _cimg_iskey_case(U); _cimg_iskey_case(I); _cimg_iskey_case(O); _cimg_iskey_case(P);
6898       _cimg_iskey_case(DELETE); _cimg_iskey_case(END); _cimg_iskey_case(PAGEDOWN);
6899       _cimg_iskey_case(CAPSLOCK); _cimg_iskey_case(A); _cimg_iskey_case(S); _cimg_iskey_case(D);
6900       _cimg_iskey_case(F); _cimg_iskey_case(G); _cimg_iskey_case(H); _cimg_iskey_case(J);
6901       _cimg_iskey_case(K); _cimg_iskey_case(L); _cimg_iskey_case(ENTER);
6902       _cimg_iskey_case(SHIFTLEFT); _cimg_iskey_case(Z); _cimg_iskey_case(X); _cimg_iskey_case(C);
6903       _cimg_iskey_case(V); _cimg_iskey_case(B); _cimg_iskey_case(N); _cimg_iskey_case(M);
6904       _cimg_iskey_case(SHIFTRIGHT); _cimg_iskey_case(ARROWUP); _cimg_iskey_case(CTRLLEFT);
6905       _cimg_iskey_case(APPLEFT); _cimg_iskey_case(ALT); _cimg_iskey_case(SPACE); _cimg_iskey_case(ALTGR);
6906       _cimg_iskey_case(APPRIGHT); _cimg_iskey_case(MENU); _cimg_iskey_case(CTRLRIGHT);
6907       _cimg_iskey_case(ARROWLEFT); _cimg_iskey_case(ARROWDOWN); _cimg_iskey_case(ARROWRIGHT);
6908       _cimg_iskey_case(PAD0); _cimg_iskey_case(PAD1); _cimg_iskey_case(PAD2);
6909       _cimg_iskey_case(PAD3); _cimg_iskey_case(PAD4); _cimg_iskey_case(PAD5);
6910       _cimg_iskey_case(PAD6); _cimg_iskey_case(PAD7); _cimg_iskey_case(PAD8);
6911       _cimg_iskey_case(PAD9); _cimg_iskey_case(PADADD); _cimg_iskey_case(PADSUB);
6912       _cimg_iskey_case(PADMUL); _cimg_iskey_case(PADDIV);
6913     }
6914 
6915     //! Test if any key has been pressed.
6916     bool is_key(const bool remove=false) {
6917       for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs) { if (remove) *ptrs = 0; return true; }
6918       return false;
6919     }
6920 
6921     //! Test if a key has been pressed.
6922     bool is_key(const unsigned int key1, const bool remove) {
6923       for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs==key1) { if (remove) *ptrs = 0; return true; }
6924       return false;
6925     }
6926 
6927     //! Test if a key sequence has been typed.
6928     bool is_key(const unsigned int key1, const unsigned int key2, const bool remove) {
6929       const unsigned int seq[] = { key1, key2 };
6930       return is_key(seq,2,remove);
6931     }
6932 
6933     //! Test if a key sequence has been typed.
6934     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const bool remove) {
6935       const unsigned int seq[] = { key1, key2, key3 };
6936       return is_key(seq,3,remove);
6937     }
6938 
6939     //! Test if a key sequence has been typed.
6940     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6941                  const unsigned int key4, const bool remove) {
6942       const unsigned int seq[] = { key1, key2, key3, key4 };
6943       return is_key(seq,4,remove);
6944     }
6945 
6946     //! Test if a key sequence has been typed.
6947     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6948                 const unsigned int key4, const unsigned int key5, const bool remove) {
6949       const unsigned int seq[] = { key1, key2, key3, key4, key5 };
6950       return is_key(seq,5,remove);
6951     }
6952 
6953     //! Test if a key sequence has been typed.
6954     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6955                 const unsigned int key4, const unsigned int key5, const unsigned int key6, const bool remove) {
6956       const unsigned int seq[] = { key1, key2, key3, key4, key5, key6 };
6957       return is_key(seq,6,remove);
6958     }
6959 
6960     //! Test if a key sequence has been typed.
6961     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6962                 const unsigned int key4, const unsigned int key5, const unsigned int key6,
6963                 const unsigned int key7, const bool remove) {
6964       const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7 };
6965       return is_key(seq,7,remove);
6966     }
6967 
6968     //! Test if a key sequence has been typed.
6969     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6970                 const unsigned int key4, const unsigned int key5, const unsigned int key6,
6971                 const unsigned int key7, const unsigned int key8, const bool remove) {
6972       const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8 };
6973       return is_key(seq,8,remove);
6974     }
6975 
6976     //! Test if a key sequence has been typed.
6977     bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6978                 const unsigned int key4, const unsigned int key5, const unsigned int key6,
6979                 const unsigned int key7, const unsigned int key8, const unsigned int key9, const bool remove) {
6980       const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8, key9 };
6981       return is_key(seq,9,remove);
6982     }
6983 
6984     //! Test if a key sequence has been typed.
6985     bool is_key(const unsigned int *const keyseq, const unsigned int N, const bool remove=true) {
6986       if (keyseq && N) {
6987         const unsigned int *const ps_end = keyseq+N-1, k = *ps_end, *const pk_end = (unsigned int*)keys+1+512-N;
6988         for (unsigned int *pk = (unsigned int*)keys; pk<pk_end; ) {
6989           if (*(pk++)==k) {
6990             bool res = true;
6991             const unsigned int *ps = ps_end, *pk2 = pk;
6992             for (unsigned int i=1; i<N; ++i) res = (*(--ps)==*(pk2++));
6993             if (res) {
6994               if (remove) cimg_std::memset((void*)(pk-1),0,sizeof(unsigned int)*N);
6995               return true;
6996             }
6997           }
6998         }
6999       }
7000       return false;
7001     }
7002 
7003     // Find the good width and height of a window to display an image (internal routine).
7004 #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false),CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
7005     static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1,
7006                                    const int dmin=128, const int dmax=-85,const bool return_last=false) {
7007       unsigned int nw = dx + (dz>1?dz:0), nh = dy + (dz>1?dz:0);
7008       const unsigned int
7009         sw = CImgDisplay::screen_dimx(), sh = CImgDisplay::screen_dimy(),
7010         mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin,
7011         mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin,
7012         Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax,
7013         Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax;
7014       if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0); nw = mw; }
7015       if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0); nh = mh; }
7016       if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0); nw = Mw; }
7017       if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0); nh = Mh; }
7018       if (nw<mw) nw = mw;
7019       if (nh<mh) nh = mh;
7020       if (return_last) return nh;
7021       return nw;
7022     }
7023 
7024     // When no display available
7025     //---------------------------
7026 #if cimg_display==0
7027 
7028     //! Return the width of the screen resolution.
7029     static int screen_dimx() {
7030       return 0;
7031     }
7032 
7033     //! Return the height of the screen resolution.
7034     static int screen_dimy() {
7035       return 0;
7036     }
7037 
7038     //! Wait for a window event in any CImg window.
7039     static void wait_all() {}
7040 
7041     //! In-place version of the destructor.
7042     CImgDisplay& assign() {
7043       return *this;
7044     }
7045 
7046     //! In-place version of the previous constructor.
7047     CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
7048                         const unsigned int normalization_type=3,
7049                         const bool fullscreen_flag=false, const bool closed_flag=false) {
7050       throw CImgDisplayException("CImgDisplay() : Display has been required but is not available (cimg_display=0)");
7051       const char* avoid_warning = title + dimw + dimh + normalization_type + (int)fullscreen_flag + (int)closed_flag;
7052       (void)avoid_warning;
7053       return *this;
7054     }
7055 
7056     //! In-place version of the previous constructor.
7057     template<typename T>
7058     CImgDisplay& assign(const CImg<T>& img, const char *title=0,
7059                         const unsigned int normalization_type=3,
7060                         const bool fullscreen_flag=false, const bool closed_flag=false) {
7061       throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
7062       const char* avoid_warning = title + img.width + normalization_type + (int)fullscreen_flag + (int)closed_flag;
7063       avoid_warning = 0;
7064       return assign(0,0);
7065     }
7066 
7067     //! In-place version of the previous constructor.
7068     template<typename T>
7069     CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
7070                         const unsigned int normalization_type=3,
7071                         const bool fullscreen_flag=false, const bool closed_flag=false) {
7072       throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
7073       const char* avoid_warning = title + list.size + normalization_type + (int)fullscreen_flag + (int)closed_flag;
7074       (void)avoid_warning;
7075       return assign(0,0);
7076     }
7077 
7078     //! In-place version of the previous constructor.
7079     CImgDisplay& assign(const CImgDisplay &disp) {
7080       return assign(disp.width,disp.height);
7081     }
7082 
7083     //! Resize window.
7084     CImgDisplay& resize(const int width, const int height, const bool redraw=true) {
7085       int avoid_warning = width | height | (int)redraw;
7086       (void)avoid_warning;
7087       return *this;
7088     }
7089 
7090     //! Toggle fullscreen mode.
7091     CImgDisplay& toggle_fullscreen(const bool redraw=true) {
7092       bool avoid_warning = redraw;
7093       (void)avoid_warning;
7094       return *this;
7095     }
7096 
7097     //! Show a closed display.
7098     CImgDisplay& show() {
7099       return *this;
7100     }
7101 
7102     //! Close a visible display.
7103     CImgDisplay& close() {
7104       return *this;
7105     }
7106 
7107     //! Move window.
7108     CImgDisplay& move(const int posx, const int posy) {
7109       int avoid_warning = posx | posy;
7110       (void)avoid_warning;
7111       return *this;
7112     }
7113 
7114     //! Show mouse pointer.
7115     CImgDisplay& show_mouse() {
7116       return *this;
7117     }
7118 
7119     //! Hide mouse pointer.
7120     CImgDisplay& hide_mouse() {
7121       return *this;
7122     }
7123 
7124     //! Move mouse pointer to a specific location.
7125     CImgDisplay& set_mouse(const int posx, const int posy) {
7126       int avoid_warning = posx | posy;
7127       (void)avoid_warning;
7128       return *this;
7129     }
7130 
7131     //! Set the window title.
7132     CImgDisplay& set_title(const char *format, ...) {
7133       const char *avoid_warning = format;
7134       (void)avoid_warning;
7135       return *this;
7136     }
7137 
7138     //! Display an image in a window.
7139     template<typename T>
7140     CImgDisplay& display(const CImg<T>& img) {
7141       unsigned int avoid_warning = img.width;
7142       (void)avoid_warning;
7143       return *this;
7144     }
7145 
7146     //! Re-paint image content in window.
7147     CImgDisplay& paint() {
7148       return *this;
7149     }
7150 
7151     //! Render image buffer into GDI native image format.
7152     template<typename T>
7153     CImgDisplay& render(const CImg<T>& img) {
7154       unsigned int avoid_warning = img.width;
7155       (void)avoid_warning;
7156       return *this;
7157     }
7158 
7159     //! Take a snapshot of the display in the specified image.
7160     template<typename T>
7161     const CImgDisplay& snapshot(CImg<T>& img) const {
7162       img.assign(width,height,1,3,0);
7163       return *this;
7164     }
7165 
7166     // X11-based display
7167     //-------------------
7168 #elif cimg_display==1
7169     Atom wm_delete_window, wm_delete_protocol;
7170     Window window, background_window;
7171     Colormap colormap;
7172     XImage *image;
7173     void *data;
7174 #ifdef cimg_use_xshm
7175     XShmSegmentInfo *shminfo;
7176 #endif
7177 
7178     static int screen_dimx() {
7179       int res = 0;
7180       if (!cimg::X11attr().display) {
7181         Display *disp = XOpenDisplay((cimg_std::getenv("DISPLAY")?cimg_std::getenv("DISPLAY"):":0.0"));
7182         if (!disp)
7183           throw CImgDisplayException("CImgDisplay::screen_dimx() : Can't open X11 display.");
7184         res = DisplayWidth(disp,DefaultScreen(disp));
7185         XCloseDisplay(disp);
7186       } else {
7187 #ifdef cimg_use_xrandr
7188         if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
7189           res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width;
7190         else
7191 #endif
7192           res = DisplayWidth(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
7193       }
7194       return res;
7195     }
7196 
7197     static int screen_dimy() {
7198       int res = 0;
7199       if (!cimg::X11attr().display) {
7200         Display *disp = XOpenDisplay((cimg_std::getenv("DISPLAY") ? cimg_std::getenv("DISPLAY") : ":0.0"));
7201         if (!disp)
7202           throw CImgDisplayException("CImgDisplay::screen_dimy() : Can't open X11 display.");
7203         res = DisplayHeight(disp,DefaultScreen(disp));
7204         XCloseDisplay(disp);
7205       } else {
7206 #ifdef cimg_use_xrandr
7207         if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
7208           res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height;
7209         else
7210 #endif
7211           res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
7212       }
7213       return res;
7214     }
7215 
7216     static void wait_all() {
7217       if (cimg::X11attr().display) {
7218         XLockDisplay(cimg::X11attr().display);
7219         bool flag = true;
7220         XEvent event;
7221         while (flag) {
7222           XNextEvent(cimg::X11attr().display, &event);
7223           for (unsigned int i = 0; i<cimg::X11attr().nb_wins; ++i)
7224             if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window) {
7225               cimg::X11attr().wins[i]->_handle_events(&event);
7226               if (cimg::X11attr().wins[i]->is_event) flag = false;
7227             }
7228         }
7229         XUnlockDisplay(cimg::X11attr().display);
7230       }
7231     }
7232 
7233     void _handle_events(const XEvent *const pevent) {
7234       XEvent event = *pevent;
7235       switch (event.type) {
7236       case ClientMessage : {
7237         if ((int)event.xclient.message_type==(int)wm_delete_protocol &&
7238             (int)event.xclient.data.l[0]==(int)wm_delete_window) {
7239           XUnmapWindow(cimg::X11attr().display,window);
7240           mouse_x = mouse_y = -1;
7241           if (button) { cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button = 0; }
7242           if (key) { cimg_std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
7243           if (released_key) { cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
7244           is_closed = is_event = true;
7245         }
7246       } break;
7247       case ConfigureNotify : {
7248         while (XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event)) {}
7249         const unsigned int
7250           nw = event.xconfigure.width,
7251           nh = event.xconfigure.height;
7252         const int
7253           nx = event.xconfigure.x,
7254           ny = event.xconfigure.y;
7255         if (nw && nh && (nw!=window_width || nh!=window_height)) {
7256           window_width = nw;
7257           window_height = nh;
7258           mouse_x = mouse_y = -1;
7259           XResizeWindow(cimg::X11attr().display,window,window_width,window_height);
7260           is_resized = is_event = true;
7261         }
7262         if (nx!=window_x || ny!=window_y) {
7263           window_x = nx;
7264           window_y = ny;
7265           is_moved = is_event = true;
7266         }
7267       } break;
7268       case Expose : {
7269         while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event)) {}
7270         _paint(false);
7271         if (is_fullscreen) {
7272           XWindowAttributes attr;
7273           XGetWindowAttributes(cimg::X11attr().display, window, &attr);
7274           while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
7275           XSetInputFocus(cimg::X11attr().display, window, RevertToParent, CurrentTime);
7276         }
7277       } break;
7278       case ButtonPress : {
7279         do {
7280         mouse_x = event.xmotion.x;
7281         mouse_y = event.xmotion.y;
7282         if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7283           switch (event.xbutton.button) {
7284           case 1 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=1; is_event = true; break;
7285           case 2 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=4; is_event = true; break;
7286           case 3 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=2; is_event = true; break;
7287           }
7288         } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event));
7289       } break;
7290       case ButtonRelease : {
7291         do {
7292         mouse_x = event.xmotion.x;
7293         mouse_y = event.xmotion.y;
7294         if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7295           switch (event.xbutton.button) {
7296           case 1 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~1U; is_event = true; break;
7297           case 2 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~4U; is_event = true; break;
7298           case 3 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~2U; is_event = true; break;
7299           case 4 : ++wheel; is_event = true; break;
7300           case 5 : --wheel; is_event = true; break;
7301           }
7302         } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event));
7303       } break;
7304       case KeyPress : {
7305         char tmp;
7306         KeySym ksym;
7307         XLookupString(&event.xkey,&tmp,1,&ksym,0);
7308         update_iskey((unsigned int)ksym,true);
7309         if (key) cimg_std::memmove((void*)(keys+1),(void*)keys,512-1);
7310         key = (unsigned int)ksym;
7311         if (released_key) { cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
7312         is_event = true;
7313       } break;
7314       case KeyRelease : {
7315         char tmp;
7316         KeySym ksym;
7317         XLookupString(&event.xkey,&tmp,1,&ksym,0);
7318         update_iskey((unsigned int)ksym,false);
7319         if (key) { cimg_std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
7320         if (released_key) cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1);
7321         released_key = (unsigned int)ksym;
7322         is_event = true;
7323       } break;
7324       case EnterNotify: {
7325         while (XCheckWindowEvent(cimg::X11attr().display,window,EnterWindowMask,&event)) {}
7326         mouse_x = event.xmotion.x;
7327         mouse_y = event.xmotion.y;
7328         if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7329       } break;
7330       case LeaveNotify : {
7331         while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event)) {}
7332         mouse_x = mouse_y =-1;
7333         is_event = true;
7334       } break;
7335       case MotionNotify : {
7336         while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event)) {}
7337         mouse_x = event.xmotion.x;
7338         mouse_y = event.xmotion.y;
7339         if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7340         is_event = true;
7341       } break;
7342       }
7343     }
7344 
7345     static void* _events_thread(void *arg) {
7346       arg = 0;
7347       XEvent event;
7348       pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
7349       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
7350       for (;;) {
7351         XLockDisplay(cimg::X11attr().display);
7352         bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event);
7353         if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display,
7354                                                       ExposureMask|StructureNotifyMask|ButtonPressMask|
7355                                                       KeyPressMask|PointerMotionMask|EnterWindowMask|LeaveWindowMask|
7356                                                       ButtonReleaseMask|KeyReleaseMask,&event);
7357         if (event_flag) {
7358           for (unsigned int i=0; i<cimg::X11attr().nb_wins; ++i)
7359             if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window)
7360               cimg::X11attr().wins[i]->_handle_events(&event);
7361         }
7362         XUnlockDisplay(cimg::X11attr().display);
7363         pthread_testcancel();
7364         cimg::sleep(7);
7365       }
7366       return 0;
7367     }
7368 
7369     void _set_colormap(Colormap& colormap, const unsigned int dim) {
7370       XColor palette[256];
7371       switch (dim) {
7372       case 1 : { // palette for greyscale images
7373         for (unsigned int index=0; index<256; ++index) {
7374           palette[index].pixel = index;
7375           palette[index].red = palette[index].green = palette[index].blue = (unsigned short)(index<<8);
7376           palette[index].flags = DoRed | DoGreen | DoBlue;
7377         }
7378       } break;
7379       case 2 : { // palette for RG images
7380         for (unsigned int index=0, r=8; r<256; r+=16)
7381           for (unsigned int g=8; g<256; g+=16) {
7382             palette[index].pixel = index;
7383             palette[index].red = palette[index].blue = (unsigned short)(r<<8);
7384             palette[index].green = (unsigned short)(g<<8);
7385             palette[index++].flags = DoRed | DoGreen | DoBlue;
7386           }
7387       } break;
7388       default : { // palette for RGB images
7389         for (unsigned int index=0, r=16; r<256; r+=32)
7390           for (unsigned int g=16; g<256; g+=32)
7391             for (unsigned int b=32; b<256; b+=64) {
7392               palette[index].pixel = index;
7393               palette[index].red = (unsigned short)(r<<8);
7394               palette[index].green = (unsigned short)(g<<8);
7395               palette[index].blue = (unsigned short)(b<<8);
7396               palette[index++].flags = DoRed | DoGreen | DoBlue;
7397             }
7398       }
7399       }
7400       XStoreColors(cimg::X11attr().display,colormap,palette,256);
7401     }
7402 
7403     void _map_window() {
7404       XWindowAttributes attr;
7405       XEvent event;
7406       bool exposed = false, mapped = false;
7407       XMapRaised(cimg::X11attr().display,window);
7408       XSync(cimg::X11attr().display,False);
7409       do {
7410         XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask | ExposureMask,&event);
7411         switch (event.type) {
7412         case MapNotify : mapped = true; break;
7413         case Expose : exposed = true; break;
7414         default : XSync(cimg::X11attr().display, False); cimg::sleep(10);
7415         }
7416       } while (!(exposed && mapped));
7417       do {
7418         XGetWindowAttributes(cimg::X11attr().display, window, &attr);
7419         if (attr.map_state!=IsViewable) { XSync(cimg::X11attr().display,False); cimg::sleep(10); }
7420       } while (attr.map_state != IsViewable);
7421       window_x = attr.x;
7422       window_y = attr.y;
7423     }
7424 
7425     void _paint(const bool wait_expose=true) {
7426       if (!is_closed) {
7427         if (wait_expose) {
7428           static XEvent event;
7429           event.xexpose.type = Expose;
7430           event.xexpose.serial = 0;
7431           event.xexpose.send_event = True;
7432           event.xexpose.display = cimg::X11attr().display;
7433           event.xexpose.window = window;
7434           event.xexpose.x = 0;
7435           event.xexpose.y = 0;
7436           event.xexpose.width = dimx();
7437           event.xexpose.height = dimy();
7438           event.xexpose.count = 0;
7439           XSendEvent(cimg::X11attr().display, window, False, 0, &event);
7440         } else {
7441 #ifdef cimg_use_xshm
7442           if (shminfo) XShmPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height,False);
7443           else
7444 #endif
7445             XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
7446           XSync(cimg::X11attr().display, False);
7447         }
7448       }
7449     }
7450 
7451     template<typename T>
7452     void _resize(T foo, const unsigned int ndimx, const unsigned int ndimy, const bool redraw) {
7453       foo = 0;
7454 #ifdef cimg_use_xshm
7455       if (shminfo) {
7456         XShmSegmentInfo *nshminfo = new XShmSegmentInfo;
7457         XImage *nimage = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7458                                          cimg::X11attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy);
7459         if (!nimage) {
7460           delete nshminfo;
7461           return;
7462         } else {
7463           nshminfo->shmid = shmget(IPC_PRIVATE, ndimx*ndimy*sizeof(T), IPC_CREAT | 0777);
7464           if (nshminfo->shmid==-1) {
7465             XDestroyImage(nimage);
7466             delete nshminfo;
7467             return;
7468           } else {
7469             nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0);
7470             if (nshminfo->shmaddr==(char*)-1) {
7471               shmctl(nshminfo->shmid,IPC_RMID,0);
7472               XDestroyImage(nimage);
7473               delete nshminfo;
7474               return;
7475             } else {
7476               nshminfo->readOnly = False;
7477               cimg::X11attr().shm_enabled = true;
7478               XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
7479               XShmAttach(cimg::X11attr().display, nshminfo);
7480               XSync(cimg::X11attr().display, False);
7481               XSetErrorHandler(oldXErrorHandler);
7482               if (!cimg::X11attr().shm_enabled) {
7483                 shmdt(nshminfo->shmaddr);
7484                 shmctl(nshminfo->shmid,IPC_RMID,0);
7485                 XDestroyImage(nimage);
7486                 delete nshminfo;
7487                 return;
7488               } else {
7489                 T *const ndata = (T*)nimage->data;
7490                 if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
7491                 else cimg_std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
7492                 XShmDetach(cimg::X11attr().display, shminfo);
7493                 XDestroyImage(image);
7494                 shmdt(shminfo->shmaddr);
7495                 shmctl(shminfo->shmid,IPC_RMID,0);
7496                 delete shminfo;
7497                 shminfo = nshminfo;
7498                 image = nimage;
7499                 data = (void*)ndata;
7500               }
7501             }
7502           }
7503         }
7504       } else
7505 #endif
7506         {
7507           T *ndata = (T*)cimg_std::malloc(ndimx*ndimy*sizeof(T));
7508           if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
7509           else cimg_std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
7510           data = (void*)ndata;
7511           XDestroyImage(image);
7512           image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7513                                cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,ndimx,ndimy,8,0);
7514         }
7515     }
7516 
7517     void _init_fullscreen() {
7518       background_window = 0;
7519       if (is_fullscreen && !is_closed) {
7520 #ifdef cimg_use_xrandr
7521         int foo;
7522         if (XRRQueryExtension(cimg::X11attr().display,&foo,&foo)) {
7523           XRRRotations(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display), &cimg::X11attr().curr_rotation);
7524           if (!cimg::X11attr().resolutions) {
7525             cimg::X11attr().resolutions = XRRSizes(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display),&foo);
7526             cimg::X11attr().nb_resolutions = (unsigned int)foo;
7527           }
7528           if (cimg::X11attr().resolutions) {
7529             cimg::X11attr().curr_resolution = 0;
7530             for (unsigned int i=0; i<cimg::X11attr().nb_resolutions; ++i) {
7531               const unsigned int
7532                 nw = (unsigned int)(cimg::X11attr().resolutions[i].width),
7533                 nh = (unsigned int)(cimg::X11attr().resolutions[i].height);
7534               if (nw>=width && nh>=height &&
7535                   nw<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width) &&
7536                   nh<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height))
7537                 cimg::X11attr().curr_resolution = i;
7538             }
7539             if (cimg::X11attr().curr_resolution>0) {
7540               XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
7541               XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
7542                                  cimg::X11attr().curr_resolution, cimg::X11attr().curr_rotation, CurrentTime);
7543               XRRFreeScreenConfigInfo(config);
7544               XSync(cimg::X11attr().display, False);
7545             }
7546           }
7547         }
7548         if (!cimg::X11attr().resolutions)
7549           cimg::warn("CImgDisplay::_create_window() : Xrandr extension is not supported by the X server.");
7550 #endif
7551         const unsigned int sx = screen_dimx(), sy = screen_dimy();
7552         XSetWindowAttributes winattr;
7553         winattr.override_redirect = True;
7554         if (sx!=width || sy!=height) {
7555           background_window = XCreateWindow(cimg::X11attr().display,
7556                                             RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),0,0,
7557                                             sx,sy,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
7558           const unsigned int bufsize = sx*sy*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
7559           void *background_data = cimg_std::malloc(bufsize);
7560           cimg_std::memset(background_data,0,bufsize);
7561           XImage *background_image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7562                                                   cimg::X11attr().nb_bits,ZPixmap,0,(char*)background_data,sx,sy,8,0);
7563           XEvent event;
7564           XSelectInput(cimg::X11attr().display,background_window,StructureNotifyMask);
7565           XMapRaised(cimg::X11attr().display,background_window);
7566           do XWindowEvent(cimg::X11attr().display,background_window,StructureNotifyMask,&event);
7567           while (event.type!=MapNotify);
7568 #ifdef cimg_use_xshm
7569           if (shminfo) XShmPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy,False);
7570           else
7571 #endif
7572             XPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy);
7573           XWindowAttributes attr;
7574           XGetWindowAttributes(cimg::X11attr().display, background_window, &attr);
7575           while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
7576           XDestroyImage(background_image);
7577         }
7578       }
7579     }
7580 
7581     void _desinit_fullscreen() {
7582       if (is_fullscreen) {
7583         XUngrabKeyboard(cimg::X11attr().display,CurrentTime);
7584 #ifdef cimg_use_xrandr
7585         if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution) {
7586           XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
7587           XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
7588                              0, cimg::X11attr().curr_rotation, CurrentTime);
7589           XRRFreeScreenConfigInfo(config);
7590           XSync(cimg::X11attr().display, False);
7591           cimg::X11attr().curr_resolution = 0;
7592         }
7593 #endif
7594         if (background_window) XDestroyWindow(cimg::X11attr().display,background_window);
7595         background_window = 0;
7596         is_fullscreen = false;
7597       }
7598     }
7599 
7600     static int _assign_xshm(Display *dpy, XErrorEvent *error) {
7601       dpy = 0; error = 0;
7602       cimg::X11attr().shm_enabled = false;
7603       return 0;
7604     }
7605 
7606     void _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
7607                  const unsigned int normalization_type=3,
7608                  const bool fullscreen_flag=false, const bool closed_flag=false) {
7609 
7610       // Allocate space for window title
7611       const int s = cimg::strlen(ptitle)+1;
7612       char *tmp_title = s?new char[s]:0;
7613       if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
7614 
7615       // Destroy previous display window if existing
7616       if (!is_empty()) assign();
7617 
7618       // Open X11 display if necessary.
7619       if (!cimg::X11attr().display) {
7620         static bool xinit_threads = false;
7621         if (!xinit_threads) { XInitThreads(); xinit_threads = true; }
7622         cimg::X11attr().nb_wins = 0;
7623         cimg::X11attr().display = XOpenDisplay((cimg_std::getenv("DISPLAY")?cimg_std::getenv("DISPLAY"):":0.0"));
7624         if (!cimg::X11attr().display)
7625           throw CImgDisplayException("CImgDisplay::_create_window() : Can't open X11 display");
7626         cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display));
7627         if (cimg::X11attr().nb_bits!=8 && cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24 && cimg::X11attr().nb_bits!=32)
7628           throw CImgDisplayException("CImgDisplay::_create_window() : %u bits mode is not supported "
7629                                      "(only 8, 16, 24 and 32 bits modes are supported)",cimg::X11attr().nb_bits);
7630         cimg::X11attr().gc = new GC;
7631         *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
7632         Visual *visual = DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
7633         XVisualInfo vtemplate;
7634         vtemplate.visualid = XVisualIDFromVisual(visual);
7635         int nb_visuals;
7636         XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals);
7637         if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11attr().blue_first = true;
7638         cimg::X11attr().byte_order = ImageByteOrder(cimg::X11attr().display);
7639         XFree(vinfo);
7640         XLockDisplay(cimg::X11attr().display);
7641         cimg::X11attr().event_thread = new pthread_t;
7642         pthread_create(cimg::X11attr().event_thread,0,_events_thread,0);
7643       } else XLockDisplay(cimg::X11attr().display);
7644 
7645       // Set display variables
7646       width = cimg::min(dimw,(unsigned int)screen_dimx());
7647       height = cimg::min(dimh,(unsigned int)screen_dimy());
7648       normalization = normalization_type<4?normalization_type:3;
7649       is_fullscreen = fullscreen_flag;
7650       window_x = window_y = 0;
7651       is_closed = closed_flag;
7652       title = tmp_title;
7653       flush();
7654 
7655       // Create X11 window and palette (if 8bits display)
7656       if (is_fullscreen) {
7657         if (!is_closed) _init_fullscreen();
7658         const unsigned int sx = screen_dimx(), sy = screen_dimy();
7659         XSetWindowAttributes winattr;
7660         winattr.override_redirect = True;
7661         window = XCreateWindow(cimg::X11attr().display,
7662                                RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7663                                (sx-width)/2,(sy-height)/2,
7664                                width,height,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
7665       } else
7666         window = XCreateSimpleWindow(cimg::X11attr().display,
7667                                      RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7668                                      0,0,width,height,2,0,0x0L);
7669       XStoreName(cimg::X11attr().display,window,title?title:" ");
7670       if (cimg::X11attr().nb_bits==8) {
7671         colormap = XCreateColormap(cimg::X11attr().display,window,DefaultVisual(cimg::X11attr().display,
7672                                                                                 DefaultScreen(cimg::X11attr().display)),AllocAll);
7673         _set_colormap(colormap,3);
7674         XSetWindowColormap(cimg::X11attr().display,window,colormap);
7675       }
7676       window_width = width;
7677       window_height = height;
7678 
7679       // Create XImage
7680       const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
7681 #ifdef cimg_use_xshm
7682       shminfo = 0;
7683       if (XShmQueryExtension(cimg::X11attr().display)) {
7684         shminfo = new XShmSegmentInfo;
7685         image = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7686                                 cimg::X11attr().nb_bits,ZPixmap,0,shminfo,width,height);
7687         if (!image) {
7688           delete shminfo;
7689           shminfo = 0;
7690         } else {
7691           shminfo->shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777);
7692           if (shminfo->shmid==-1) {
7693             XDestroyImage(image);
7694             delete shminfo;
7695             shminfo = 0;
7696           } else {
7697             shminfo->shmaddr = image->data = (char*)(data = shmat(shminfo->shmid,0,0));
7698             if (shminfo->shmaddr==(char*)-1) {
7699               shmctl(shminfo->shmid,IPC_RMID,0);
7700               XDestroyImage(image);
7701               delete shminfo;
7702               shminfo = 0;
7703             } else {
7704               shminfo->readOnly = False;
7705               cimg::X11attr().shm_enabled = true;
7706               XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
7707               XShmAttach(cimg::X11attr().display, shminfo);
7708               XSync(cimg::X11attr().display, False);
7709               XSetErrorHandler(oldXErrorHandler);
7710               if (!cimg::X11attr().shm_enabled) {
7711                 shmdt(shminfo->shmaddr);
7712                 shmctl(shminfo->shmid,IPC_RMID,0);
7713                 XDestroyImage(image);
7714                 delete shminfo;
7715                 shminfo = 0;
7716               }
7717             }
7718           }
7719         }
7720       }
7721       if (!shminfo)
7722 #endif
7723         {
7724           data = cimg_std::malloc(bufsize);
7725           image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7726                                cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0);
7727         }
7728 
7729       wm_delete_window = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False);
7730       wm_delete_protocol = XInternAtom(cimg::X11attr().display, "WM_PROTOCOLS", False);
7731       XSetWMProtocols(cimg::X11attr().display, window, &wm_delete_window, 1);
7732       XSelectInput(cimg::X11attr().display,window,
7733                    ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask |
7734                    EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask);
7735       if (is_fullscreen) XGrabKeyboard(cimg::X11attr().display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
7736       cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this;
7737       if (!is_closed) _map_window(); else { window_x = window_y = cimg::type<int>::min(); }
7738       XUnlockDisplay(cimg::X11attr().display);
7739     }
7740 
7741     CImgDisplay& assign() {
7742       if (is_empty()) return *this;
7743       XLockDisplay(cimg::X11attr().display);
7744 
7745       // Remove display window from event thread list.
7746       unsigned int i;
7747       for (i = 0; i<cimg::X11attr().nb_wins && cimg::X11attr().wins[i]!=this; ++i) {}
7748       for (; i<cimg::X11attr().nb_wins-1; ++i) cimg::X11attr().wins[i] = cimg::X11attr().wins[i+1];
7749       --cimg::X11attr().nb_wins;
7750 
7751       // Destroy window, image, colormap and title.
7752       if (is_fullscreen && !is_closed) _desinit_fullscreen();
7753       XDestroyWindow(cimg::X11attr().display,window);
7754       window = 0;
7755 #ifdef cimg_use_xshm
7756       if (shminfo) {
7757         XShmDetach(cimg::X11attr().display, shminfo);
7758         XDestroyImage(image);
7759         shmdt(shminfo->shmaddr);
7760         shmctl(shminfo->shmid,IPC_RMID,0);
7761         delete shminfo;
7762         shminfo = 0;
7763       } else
7764 #endif
7765         XDestroyImage(image);
7766       data = 0; image = 0;
7767       if (cimg::X11attr().nb_bits==8) XFreeColormap(cimg::X11attr().display,colormap);
7768       colormap = 0;
7769       XSync(cimg::X11attr().display, False);
7770 
7771       // Reset display variables
7772       if (title) delete[] title;
7773       width = height = normalization = window_width = window_height = 0;
7774       window_x = window_y = 0;
7775       is_fullscreen = false;
7776       is_closed = true;
7777       min = max = 0;
7778       title = 0;
7779       flush();
7780 
7781       // End event thread and close display if necessary
7782       XUnlockDisplay(cimg::X11attr().display);
7783 
7784       /* The code below was used to close the X11 display when not used anymore,
7785          unfortunately, since the latest Xorg versions, it randomly hangs, so
7786          I prefer to remove it. A fix would be needed anyway.
7787 
7788          if (!cimg::X11attr().nb_wins) {
7789          // Kill event thread
7790          pthread_cancel(*cimg::X11attr().event_thread);
7791          XUnlockDisplay(cimg::X11attr().display);
7792          pthread_join(*cimg::X11attr().event_thread,0);
7793          delete cimg::X11attr().event_thread;
7794          cimg::X11attr().event_thread = 0;
7795          XCloseDisplay(cimg::X11attr().display);
7796          cimg::X11attr().display = 0;
7797          delete cimg::X11attr().gc;
7798          cimg::X11attr().gc = 0;
7799          } else XUnlockDisplay(cimg::X11attr().display);
7800       */
7801       return *this;
7802     }
7803 
7804     CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
7805                         const unsigned int normalization_type=3,
7806                         const bool fullscreen_flag=false, const bool closed_flag=false) {
7807       if (!dimw || !dimh) return assign();
7808       _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
7809       min = max = 0;
7810       cimg_std::memset(data,0,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
7811                           (cimg::X11attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*width*height);
7812       return paint();
7813     }
7814 
7815     template<typename T>
7816     CImgDisplay& assign(const CImg<T>& img, const char *title=0,
7817                         const unsigned int normalization_type=3,
7818                         const bool fullscreen_flag=false, const bool closed_flag=false) {
7819       if (!img) return assign();
7820       CImg<T> tmp;
7821       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
7822       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
7823       if (normalization==2) min = (float)nimg.minmax(max);
7824       return render(nimg).paint();
7825     }
7826 
7827     template<typename T>
7828     CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
7829                         const unsigned int normalization_type=3,
7830                         const bool fullscreen_flag=false, const bool closed_flag=false) {
7831       if (!list) return assign();
7832       CImg<T> tmp;
7833       const CImg<T> img = list.get_append('x','p'),
7834         &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
7835       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
7836       if (normalization==2) min = (float)nimg.minmax(max);
7837       return render(nimg).paint();
7838     }
7839 
7840     CImgDisplay& assign(const CImgDisplay& win) {
7841       if (!win) return assign();
7842       _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
7843       cimg_std::memcpy(data,win.data,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
7844                                  cimg::X11attr().nb_bits==16?sizeof(unsigned short):
7845                                  sizeof(unsigned int))*width*height);
7846       return paint();
7847     }
7848 
7849     CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
7850       if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
7851       if (is_empty()) return assign(nwidth,nheight);
7852       const unsigned int
7853         tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
7854         tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
7855         dimx = tmpdimx?tmpdimx:1,
7856         dimy = tmpdimy?tmpdimy:1;
7857       XLockDisplay(cimg::X11attr().display);
7858       if (window_width!=dimx || window_height!=dimy) XResizeWindow(cimg::X11attr().display,window,dimx,dimy);
7859       if (width!=dimx || height!=dimy) switch (cimg::X11attr().nb_bits) {
7860       case 8 :  { unsigned char foo = 0; _resize(foo,dimx,dimy,redraw); } break;
7861       case 16 : { unsigned short foo = 0; _resize(foo,dimx,dimy,redraw); } break;
7862       default : { unsigned int foo = 0; _resize(foo,dimx,dimy,redraw); }
7863       }
7864       window_width = width = dimx; window_height = height = dimy;
7865       is_resized = false;
7866       XUnlockDisplay(cimg::X11attr().display);
7867       if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
7868       if (redraw) return paint();
7869       return *this;
7870     }
7871 
7872     CImgDisplay& toggle_fullscreen(const bool redraw=true) {
7873       if (is_empty()) return *this;
7874       if (redraw) {
7875         const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
7876         void *odata = cimg_std::malloc(bufsize);
7877         cimg_std::memcpy(odata,data,bufsize);
7878         assign(width,height,title,normalization,!is_fullscreen,false);
7879         cimg_std::memcpy(data,odata,bufsize);
7880         cimg_std::free(odata);
7881         return paint(false);
7882       }
7883       return assign(width,height,title,normalization,!is_fullscreen,false);
7884     }
7885 
7886     CImgDisplay& show() {
7887       if (!is_empty() && is_closed) {
7888         XLockDisplay(cimg::X11attr().display);
7889         if (is_fullscreen) _init_fullscreen();
7890         _map_window();
7891         is_closed = false;
7892         XUnlockDisplay(cimg::X11attr().display);
7893         return paint();
7894       }
7895       return *this;
7896     }
7897 
7898     CImgDisplay& close() {
7899       if (!is_empty() && !is_closed) {
7900         XLockDisplay(cimg::X11attr().display);
7901         if (is_fullscreen) _desinit_fullscreen();
7902         XUnmapWindow(cimg::X11attr().display,window);
7903         window_x = window_y = -1;
7904         is_closed = true;
7905         XUnlockDisplay(cimg::X11attr().display);
7906       }
7907       return *this;
7908     }
7909 
7910     CImgDisplay& move(const int posx, const int posy) {
7911       if (is_empty()) return *this;
7912       show();
7913       XLockDisplay(cimg::X11attr().display);
7914       XMoveWindow(cimg::X11attr().display,window,posx,posy);
7915       window_x = posx; window_y = posy;
7916       is_moved = false;
7917       XUnlockDisplay(cimg::X11attr().display);
7918       return paint();
7919     }
7920 
7921     CImgDisplay& show_mouse() {
7922       if (is_empty()) return *this;
7923       XLockDisplay(cimg::X11attr().display);
7924       XDefineCursor(cimg::X11attr().display,window,None);
7925       XUnlockDisplay(cimg::X11attr().display);
7926       return *this;
7927     }
7928 
7929     CImgDisplay& hide_mouse() {
7930       if (is_empty()) return *this;
7931       XLockDisplay(cimg::X11attr().display);
7932       const char pix_data[8] = { 0 };
7933       XColor col;
7934       col.red = col.green = col.blue = 0;
7935       Pixmap pix = XCreateBitmapFromData(cimg::X11attr().display,window,pix_data,8,8);
7936       Cursor cur = XCreatePixmapCursor(cimg::X11attr().display,pix,pix,&col,&col,0,0);
7937       XFreePixmap(cimg::X11attr().display,pix);
7938       XDefineCursor(cimg::X11attr().display,window,cur);
7939       XUnlockDisplay(cimg::X11attr().display);
7940       return *this;
7941     }
7942 
7943     CImgDisplay& set_mouse(const int posx, const int posy) {
7944       if (is_empty() || is_closed) return *this;
7945       XLockDisplay(cimg::X11attr().display);
7946       XWarpPointer(cimg::X11attr().display,None,window,0,0,0,0,posx,posy);
7947       mouse_x = posx; mouse_y = posy;
7948       is_moved = false;
7949       XSync(cimg::X11attr().display, False);
7950       XUnlockDisplay(cimg::X11attr().display);
7951       return *this;
7952     }
7953 
7954     CImgDisplay& set_title(const char *format, ...) {
7955       if (is_empty()) return *this;
7956       char tmp[1024] = {0};
7957       va_list ap;
7958       va_start(ap, format);
7959       cimg_std::vsprintf(tmp,format,ap);
7960       va_end(ap);
7961       if (title) delete[] title;
7962       const int s = cimg::strlen(tmp)+1;
7963       title = new char[s];
7964       cimg_std::memcpy(title,tmp,s*sizeof(char));
7965       XLockDisplay(cimg::X11attr().display);
7966       XStoreName(cimg::X11attr().display,window,tmp);
7967       XUnlockDisplay(cimg::X11attr().display);
7968       return *this;
7969     }
7970 
7971     template<typename T>
7972     CImgDisplay& display(const CImg<T>& img) {
7973       if (img.is_empty())
7974         throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
7975       if (is_empty()) assign(img.width,img.height);
7976       return render(img).paint(false);
7977     }
7978 
7979     CImgDisplay& paint(const bool wait_expose=true) {
7980       if (is_empty()) return *this;
7981       XLockDisplay(cimg::X11attr().display);
7982       _paint(wait_expose);
7983       XUnlockDisplay(cimg::X11attr().display);
7984       return *this;
7985     }
7986 
7987     template<typename T>
7988     CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
7989       if (is_empty()) return *this;
7990       if (!img)
7991         throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
7992                                     img.width,img.height,img.depth,img.dim,img.data);
7993       if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
7994       if (cimg::X11attr().nb_bits==8 && (img.width!=width || img.height!=height)) return render(img.get_resize(width,height,1,-100,1));
7995       if (cimg::X11attr().nb_bits==8 && !flag8 && img.dim==3) return render(img.get_RGBtoLUT(true),true);
7996 
7997       const T
7998         *data1 = img.data,
7999         *data2 = (img.dim>1)?img.ptr(0,0,0,1):data1,
8000         *data3 = (img.dim>2)?img.ptr(0,0,0,2):data1;
8001 
8002       if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
8003       XLockDisplay(cimg::X11attr().display);
8004 
8005       if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
8006         min = max = 0;
8007         switch (cimg::X11attr().nb_bits) {
8008         case 8 : { // 256 color palette, no normalization
8009           _set_colormap(colormap,img.dim);
8010           unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
8011           unsigned char *ptrd = (unsigned char*)ndata;
8012           switch (img.dim) {
8013           case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) (*ptrd++) = (unsigned char)*(data1++);
8014             break;
8015           case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8016               const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++);
8017               (*ptrd++) = (R&0xf0) | (G>>4);
8018             } break;
8019           default : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8020               const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
8021               (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
8022             }
8023           }
8024           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
8025         } break;
8026         case 16 : { // 16 bits colors, no normalization
8027           unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
8028           unsigned char *ptrd = (unsigned char*)ndata;
8029           const unsigned int M = 248;
8030           switch (img.dim) {
8031           case 1 :
8032             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8033               const unsigned char val = (unsigned char)*(data1++), G = val>>2;
8034               *(ptrd++) = (val&M) | (G>>3);
8035               *(ptrd++) = (G<<5) | (G>>1);
8036             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8037               const unsigned char val = (unsigned char)*(data1++), G = val>>2;
8038               *(ptrd++) = (G<<5) | (G>>1);
8039               *(ptrd++) = (val&M) | (G>>3);
8040             }
8041             break;
8042           case 2 :
8043             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8044               const unsigned char G = (unsigned char)*(data2++)>>2;
8045               *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
8046               *(ptrd++) = (G<<5);
8047             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8048               const unsigned char G = (unsigned char)*(data2++)>>2;
8049               *(ptrd++) = (G<<5);
8050               *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
8051             }
8052             break;
8053           default :
8054             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8055               const unsigned char G = (unsigned char)*(data2++)>>2;
8056               *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
8057               *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
8058             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8059               const unsigned char G = (unsigned char)*(data2++)>>2;
8060               *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
8061               *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
8062             }
8063           }
8064           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
8065         } break;
8066         default : { // 24 bits colors, no normalization
8067           unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
8068           if (sizeof(int)==4) { // 32 bits int uses optimized version
8069             unsigned int *ptrd = ndata;
8070             switch (img.dim) {
8071             case 1 :
8072               if (cimg::X11attr().byte_order==cimg::endianness())
8073                 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8074                   const unsigned char val = (unsigned char)*(data1++);
8075                   *(ptrd++) = (val<<16) | (val<<8) | val;
8076                 }
8077               else
8078                for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8079                   const unsigned char val = (unsigned char)*(data1++)<<8;
8080                   *(ptrd++) = (val<<16) | (val<<8) | val;
8081                 }
8082               break;
8083             case 2 :
8084               if (cimg::X11attr().byte_order==cimg::endianness())
8085                for (unsigned int xy = img.width*img.height; xy>0; --xy)
8086                   *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
8087               else
8088                for (unsigned int xy = img.width*img.height; xy>0; --xy)
8089                   *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
8090               break;
8091             default :
8092               if (cimg::X11attr().byte_order==cimg::endianness())
8093                for (unsigned int xy = img.width*img.height; xy>0; --xy)
8094                   *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
8095               else
8096                for (unsigned int xy = img.width*img.height; xy>0; --xy)
8097                   *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
8098             }
8099           } else {
8100             unsigned char *ptrd = (unsigned char*)ndata;
8101             switch (img.dim) {
8102             case 1 :
8103               if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8104                 *(ptrd++) = 0;
8105                 *(ptrd++) = (unsigned char)*(data1++);
8106                 *(ptrd++) = 0;
8107                 *(ptrd++) = 0;
8108               } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8109                 *(ptrd++) = 0;
8110                 *(ptrd++) = 0;
8111                 *(ptrd++) = (unsigned char)*(data1++);
8112                 *(ptrd++) = 0;
8113               }
8114               break;
8115             case 2 :
8116               if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
8117               for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8118                 *(ptrd++) = 0;
8119                 *(ptrd++) = (unsigned char)*(data2++);
8120                 *(ptrd++) = (unsigned char)*(data1++);
8121                 *(ptrd++) = 0;
8122               }
8123               break;
8124             default :
8125               if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8126                 *(ptrd++) = 0;
8127                 *(ptrd++) = (unsigned char)*(data1++);
8128                 *(ptrd++) = (unsigned char)*(data2++);
8129                 *(ptrd++) = (unsigned char)*(data3++);
8130               } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8131                 *(ptrd++) = (unsigned char)*(data3++);
8132                 *(ptrd++) = (unsigned char)*(data2++);
8133                 *(ptrd++) = (unsigned char)*(data1++);
8134                 *(ptrd++) = 0;
8135               }
8136             }
8137           }
8138           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
8139         }
8140         };
8141       } else {
8142         if (normalization==3) {
8143           if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
8144           else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
8145         } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
8146         const float delta = max-min, mm = delta?delta:1.0f;
8147         switch (cimg::X11attr().nb_bits) {
8148         case 8 : { // 256 color palette, with normalization
8149           _set_colormap(colormap,img.dim);
8150           unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
8151           unsigned char *ptrd = (unsigned char*)ndata;
8152           switch (img.dim) {
8153           case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8154             const unsigned char R = (unsigned char)(255*(*(data1++)-min)/mm);
8155             *(ptrd++) = R;
8156           } break;
8157           case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8158             const unsigned char
8159               R = (unsigned char)(255*(*(data1++)-min)/mm),
8160               G = (unsigned char)(255*(*(data2++)-min)/mm);
8161             (*ptrd++) = (R&0xf0) | (G>>4);
8162           } break;
8163           default :
8164             for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8165               const unsigned char
8166                 R = (unsigned char)(255*(*(data1++)-min)/mm),
8167                 G = (unsigned char)(255*(*(data2++)-min)/mm),
8168                 B = (unsigned char)(255*(*(data3++)-min)/mm);
8169               *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
8170             }
8171           }
8172           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
8173         } break;
8174         case 16 : { // 16 bits colors, with normalization
8175           unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
8176           unsigned char *ptrd = (unsigned char*)ndata;
8177           const unsigned int M = 248;
8178           switch (img.dim) {
8179           case 1 :
8180             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8181               const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
8182               *(ptrd++) = (val&M) | (G>>3);
8183               *(ptrd++) = (G<<5) | (val>>3);
8184             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8185               const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
8186               *(ptrd++) = (G<<5) | (val>>3);
8187               *(ptrd++) = (val&M) | (G>>3);
8188             }
8189             break;
8190           case 2 :
8191             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8192               const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
8193               *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
8194               *(ptrd++) = (G<<5);
8195             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8196               const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
8197               *(ptrd++) = (G<<5);
8198               *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
8199             }
8200             break;
8201           default :
8202             if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8203               const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
8204               *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
8205               *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
8206             } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8207               const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
8208               *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
8209               *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
8210             }
8211           }
8212           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
8213         } break;
8214         default : { // 24 bits colors, with normalization
8215           unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
8216           if (sizeof(int)==4) { // 32 bits int uses optimized version
8217             unsigned int *ptrd = ndata;
8218             switch (img.dim) {
8219             case 1 :
8220               if (cimg::X11attr().byte_order==cimg::endianness())
8221                 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8222                   const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8223                   *(ptrd++) = (val<<16) | (val<<8) | val;
8224                 }
8225               else
8226                 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8227                   const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8228                   *(ptrd++) = (val<<24) | (val<<16) | (val<<8);
8229                 }
8230               break;
8231             case 2 :
8232               if (cimg::X11attr().byte_order==cimg::endianness())
8233                 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8234                   *(ptrd++) =
8235                     ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
8236                     ((unsigned char)(255*(*(data2++)-min)/mm)<<8);
8237               else
8238                 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8239                   *(ptrd++) =
8240                     ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
8241                     ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
8242               break;
8243             default :
8244               if (cimg::X11attr().byte_order==cimg::endianness())
8245                 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8246                   *(ptrd++) =
8247                     ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
8248                     ((unsigned char)(255*(*(data2++)-min)/mm)<<8) |
8249                     (unsigned char)(255*(*(data3++)-min)/mm);
8250               else
8251                 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8252                   *(ptrd++) =
8253                     ((unsigned char)(255*(*(data3++)-min)/mm)<<24) |
8254                     ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
8255                     ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
8256             }
8257           } else {
8258             unsigned char *ptrd = (unsigned char*)ndata;
8259             switch (img.dim) {
8260             case 1 :
8261               if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8262                 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8263                 (*ptrd++) = 0;
8264                 (*ptrd++) = val;
8265                 (*ptrd++) = val;
8266                 (*ptrd++) = val;
8267               } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8268                 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8269                 (*ptrd++) = val;
8270                 (*ptrd++) = val;
8271                 (*ptrd++) = val;
8272                 (*ptrd++) = 0;
8273               }
8274               break;
8275             case 2 :
8276               if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
8277               for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8278                 (*ptrd++) = 0;
8279                 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
8280                 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
8281                 (*ptrd++) = 0;
8282               }
8283               break;
8284             default :
8285               if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8286                 (*ptrd++) = 0;
8287                 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
8288                 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
8289                 (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
8290               } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8291                 (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
8292                 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
8293                 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
8294                 (*ptrd++) = 0;
8295               }
8296             }
8297           }
8298           if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
8299         }
8300         }
8301       }
8302       XUnlockDisplay(cimg::X11attr().display);
8303       return *this;
8304     }
8305 
8306     template<typename T>
8307     const CImgDisplay& snapshot(CImg<T>& img) const {
8308       if (is_empty()) img.assign();
8309       else {
8310         img.assign(width,height,1,3);
8311         T
8312           *data1 = img.ptr(0,0,0,0),
8313           *data2 = img.ptr(0,0,0,1),
8314           *data3 = img.ptr(0,0,0,2);
8315         if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
8316         switch (cimg::X11attr().nb_bits) {
8317         case 8 : {
8318           unsigned char *ptrs = (unsigned char*)data;
8319           for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8320             const unsigned char val = *(ptrs++);
8321             *(data1++) = val&0xe0;
8322             *(data2++) = (val&0x1c)<<3;
8323             *(data3++) = val<<6;
8324           }
8325         } break;
8326         case 16 : {
8327           unsigned char *ptrs = (unsigned char*)data;
8328           if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8329             const unsigned char val0 = *(ptrs++), val1 = *(ptrs++);
8330             *(data1++) = val0&0xf8;
8331             *(data2++) = (val0<<5) | ((val1&0xe0)>>5);
8332             *(data3++) = val1<<3;
8333           } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8334             const unsigned short val0 = *(ptrs++), val1 = *(ptrs++);
8335             *(data1++) = val1&0xf8;
8336             *(data2++) = (val1<<5) | ((val0&0xe0)>>5);
8337             *(data3++) = val0<<3;
8338           }
8339         } break;
8340         default : {
8341           unsigned char *ptrs = (unsigned char*)data;
8342           if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8343             ++ptrs;
8344             *(data1++) = *(ptrs++);
8345             *(data2++) = *(ptrs++);
8346             *(data3++) = *(ptrs++);
8347           } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8348             *(data3++) = *(ptrs++);
8349             *(data2++) = *(ptrs++);
8350             *(data1++) = *(ptrs++);
8351             ++ptrs;
8352           }
8353         }
8354         }
8355       }
8356       return *this;
8357     }
8358 
8359     // Windows-based display
8360     //-----------------------
8361 #elif cimg_display==2
8362     CLIENTCREATESTRUCT ccs;
8363     BITMAPINFO bmi;
8364     unsigned int *data;
8365     DEVMODE curr_mode;
8366     HWND window;
8367     HWND background_window;
8368     HDC hdc;
8369     HANDLE thread;
8370     HANDLE created;
8371     HANDLE mutex;
8372     bool mouse_tracking;
8373     bool visible_cursor;
8374 
8375     static int screen_dimx() {
8376       DEVMODE mode;
8377       mode.dmSize = sizeof(DEVMODE);
8378       mode.dmDriverExtra = 0;
8379       EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
8380       return mode.dmPelsWidth;
8381     }
8382 
8383     static int screen_dimy() {
8384       DEVMODE mode;
8385       mode.dmSize = sizeof(DEVMODE);
8386       mode.dmDriverExtra = 0;
8387       EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
8388       return mode.dmPelsHeight;
8389     }
8390 
8391     static void wait_all() {
8392       WaitForSingleObject(cimg::Win32attr().wait_event,INFINITE);
8393     }
8394 
8395     static LRESULT APIENTRY _handle_events(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
8396 #ifdef _WIN64
8397       CImgDisplay* disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA);
8398 #else
8399       CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
8400 #endif
8401       MSG st_msg;
8402 
8403       switch (msg) {
8404       case WM_CLOSE :
8405         disp->mouse_x = disp->mouse_y = -1;
8406         disp->window_x = disp->window_y = 0;
8407         if (disp->button) {
8408           cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8409           disp->button = 0;
8410         }
8411         if (disp->key) {
8412           cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
8413           disp->key = 0;
8414         }
8415         if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
8416         disp->is_closed = true;
8417         ReleaseMutex(disp->mutex);
8418         ShowWindow(disp->window,SW_HIDE);
8419         disp->is_event = true;
8420         SetEvent(cimg::Win32attr().wait_event);
8421         return 0;
8422       case WM_SIZE : {
8423         while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
8424         WaitForSingleObject(disp->mutex,INFINITE);
8425         const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);
8426         if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
8427           disp->window_width = nw;
8428           disp->window_height = nh;
8429           disp->mouse_x = disp->mouse_y = -1;
8430           disp->is_resized = disp->is_event = true;
8431           SetEvent(cimg::Win32attr().wait_event);
8432         }
8433         ReleaseMutex(disp->mutex);
8434       } break;
8435       case WM_MOVE : {
8436         while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
8437         WaitForSingleObject(disp->mutex,INFINITE);
8438         const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));
8439         if (nx!=disp->window_x || ny!=disp->window_y) {
8440           disp->window_x = nx;
8441           disp->window_y = ny;
8442           disp->is_moved = disp->is_event = true;
8443           SetEvent(cimg::Win32attr().wait_event);
8444         }
8445         ReleaseMutex(disp->mutex);
8446       } break;
8447       case WM_PAINT :
8448         disp->paint();
8449         break;
8450       case WM_KEYDOWN :
8451         disp->update_iskey((unsigned int)wParam,true);
8452         if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
8453         disp->key = (unsigned int)wParam;
8454         if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
8455         disp->is_event = true;
8456         SetEvent(cimg::Win32attr().wait_event);
8457         break;
8458       case WM_MOUSEMOVE : {
8459         while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {}
8460         disp->mouse_x = LOWORD(lParam);
8461         disp->mouse_y = HIWORD(lParam);
8462 #if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT)
8463         if (!disp->mouse_tracking) {
8464           TRACKMOUSEEVENT tme;
8465           tme.cbSize = sizeof(TRACKMOUSEEVENT);
8466           tme.dwFlags = TME_LEAVE;
8467           tme.hwndTrack = disp->window;
8468           if (TrackMouseEvent(&tme)) disp->mouse_tracking = true;
8469         }
8470 #endif
8471         if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
8472           disp->mouse_x = disp->mouse_y = -1;
8473         disp->is_event = true;
8474         SetEvent(cimg::Win32attr().wait_event);
8475       } break;
8476       case WM_MOUSELEAVE : {
8477         disp->mouse_x = disp->mouse_y = -1;
8478         disp->mouse_tracking = false;
8479       } break;
8480       case WM_LBUTTONDOWN :
8481         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8482         disp->button|=1U;
8483         disp->is_event = true;
8484         SetEvent(cimg::Win32attr().wait_event);
8485         break;
8486       case WM_RBUTTONDOWN :
8487         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8488         disp->button|=2U;
8489         disp->is_event = true;
8490         SetEvent(cimg::Win32attr().wait_event);
8491         break;
8492       case WM_MBUTTONDOWN :
8493         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8494         disp->button|=4U;
8495         disp->is_event = true;
8496         SetEvent(cimg::Win32attr().wait_event);
8497         break;
8498       case 0x020A : // WM_MOUSEWHEEL:
8499         disp->wheel+=(int)((short)HIWORD(wParam))/120;
8500         disp->is_event = true;
8501         SetEvent(cimg::Win32attr().wait_event);
8502       case WM_KEYUP :
8503         disp->update_iskey((unsigned int)wParam,false);
8504         if (disp->key) { cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
8505         if (disp->released_key) cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
8506         disp->released_key = (unsigned int)wParam;
8507         disp->is_event = true;
8508         SetEvent(cimg::Win32attr().wait_event);
8509         break;
8510       case WM_LBUTTONUP :
8511         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8512         disp->button&=~1U;
8513         disp->is_event = true;
8514         SetEvent(cimg::Win32attr().wait_event);
8515         break;
8516       case WM_RBUTTONUP :
8517         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8518         disp->button&=~2U;
8519         disp->is_event = true;
8520         SetEvent(cimg::Win32attr().wait_event);
8521         break;
8522       case WM_MBUTTONUP :
8523         cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8524         disp->button&=~4U;
8525         disp->is_event = true;
8526         SetEvent(cimg::Win32attr().wait_event);
8527         break;
8528       case WM_SETCURSOR :
8529         if (disp->visible_cursor) ShowCursor(TRUE);
8530         else ShowCursor(FALSE);
8531         break;
8532       }
8533       return DefWindowProc(window,msg,wParam,lParam);
8534     }
8535 
8536     static DWORD WINAPI _events_thread(void* arg) {
8537       CImgDisplay *disp = (CImgDisplay*)(((void**)arg)[0]);
8538       const char *title = (const char*)(((void**)arg)[1]);
8539       MSG msg;
8540       delete[] (void**)arg;
8541       disp->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
8542       disp->bmi.bmiHeader.biWidth = disp->width;
8543       disp->bmi.bmiHeader.biHeight = -(int)disp->height;
8544       disp->bmi.bmiHeader.biPlanes = 1;
8545       disp->bmi.bmiHeader.biBitCount = 32;
8546       disp->bmi.bmiHeader.biCompression = BI_RGB;
8547       disp->bmi.bmiHeader.biSizeImage = 0;
8548       disp->bmi.bmiHeader.biXPelsPerMeter = 1;
8549       disp->bmi.bmiHeader.biYPelsPerMeter = 1;
8550       disp->bmi.bmiHeader.biClrUsed = 0;
8551       disp->bmi.bmiHeader.biClrImportant = 0;
8552       disp->data = new unsigned int[disp->width*disp->height];
8553       if (!disp->is_fullscreen) { // Normal window
8554         RECT rect;
8555         rect.left = rect.top = 0; rect.right = disp->width-1; rect.bottom = disp->height-1;
8556         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8557         const int border1 = (rect.right-rect.left+1-disp->width)/2, border2 = rect.bottom-rect.top+1-disp->height-border1;
8558         disp->window = CreateWindowA("MDICLIENT",title?title:" ",
8559                                      WS_OVERLAPPEDWINDOW | (disp->is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
8560                                      disp->width + 2*border1, disp->height + border1 + border2,
8561                                      0,0,0,&(disp->ccs));
8562         if (!disp->is_closed) {
8563           GetWindowRect(disp->window,&rect);
8564           disp->window_x = rect.left + border1;
8565           disp->window_y = rect.top + border2;
8566         } else disp->window_x = disp->window_y = 0;
8567       } else { // Fullscreen window
8568         const unsigned int sx = screen_dimx(), sy = screen_dimy();
8569         disp->window = CreateWindowA("MDICLIENT",title?title:" ",
8570                                      WS_POPUP | (disp->is_closed?0:WS_VISIBLE), (sx-disp->width)/2, (sy-disp->height)/2,
8571                                      disp->width,disp->height,0,0,0,&(disp->ccs));
8572         disp->window_x = disp->window_y = 0;
8573       }
8574       SetForegroundWindow(disp->window);
8575       disp->hdc = GetDC(disp->window);
8576       disp->window_width = disp->width;
8577       disp->window_height = disp->height;
8578       disp->flush();
8579 #ifdef _WIN64
8580       SetWindowLongPtr(disp->window,GWLP_USERDATA,(LONG_PTR)disp);
8581       SetWindowLongPtr(disp->window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
8582 #else
8583       SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
8584       SetWindowLong(disp->window,GWL_WNDPROC,(LONG)_handle_events);
8585 #endif
8586       SetEvent(disp->created);
8587       while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
8588       return 0;
8589     }
8590 
8591     CImgDisplay& _update_window_pos() {
8592       if (!is_closed) {
8593         RECT rect;
8594         rect.left = rect.top = 0; rect.right = width-1; rect.bottom = height-1;
8595         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8596         const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
8597         GetWindowRect(window,&rect);
8598         window_x = rect.left + border1;
8599         window_y = rect.top + border2;
8600       } else window_x = window_y = -1;
8601       return *this;
8602     }
8603 
8604     void _init_fullscreen() {
8605       background_window = 0;
8606       if (is_fullscreen && !is_closed) {
8607         DEVMODE mode;
8608         unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U;
8609         for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) {
8610           const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight;
8611           if (nw>=width && nh>=height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) {
8612             bestbpp = mode.dmBitsPerPel;
8613             ibest = imode;
8614             bw = nw; bh = nh;
8615           }
8616         }
8617         if (bestbpp) {
8618           curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0;
8619           EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&curr_mode);
8620           EnumDisplaySettings(0,ibest,&mode);
8621           ChangeDisplaySettings(&mode,0);
8622         } else curr_mode.dmSize = 0;
8623 
8624         const unsigned int sx = screen_dimx(), sy = screen_dimy();
8625         if (sx!=width || sy!=height) {
8626           CLIENTCREATESTRUCT background_ccs;
8627           background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);
8628           SetForegroundWindow(background_window);
8629         }
8630       } else curr_mode.dmSize = 0;
8631     }
8632 
8633     void _desinit_fullscreen() {
8634       if (is_fullscreen) {
8635         if (background_window) DestroyWindow(background_window);
8636         background_window = 0;
8637         if (curr_mode.dmSize) ChangeDisplaySettings(&curr_mode,0);
8638         is_fullscreen = false;
8639       }
8640     }
8641 
8642     CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
8643                          const unsigned int normalization_type=3,
8644                          const bool fullscreen_flag=false, const bool closed_flag=false) {
8645 
8646       // Allocate space for window title
8647       const int s = cimg::strlen(ptitle)+1;
8648       char *tmp_title = s?new char[s]:0;
8649       if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
8650 
8651       // Destroy previous window if existing
8652       if (!is_empty()) assign();
8653 
8654       // Set display variables
8655       width = cimg::min(dimw,(unsigned int)screen_dimx());
8656       height = cimg::min(dimh,(unsigned int)screen_dimy());
8657       normalization = normalization_type<4?normalization_type:3;
8658       is_fullscreen = fullscreen_flag;
8659       window_x = window_y = 0;
8660       is_closed = closed_flag;
8661       visible_cursor = true;
8662       mouse_tracking = false;
8663       title = tmp_title;
8664       flush();
8665       if (is_fullscreen) _init_fullscreen();
8666 
8667       // Create event thread
8668       void *arg = (void*)(new void*[2]);
8669       ((void**)arg)[0]=(void*)this;
8670       ((void**)arg)[1]=(void*)title;
8671       unsigned long ThreadID = 0;
8672       mutex = CreateMutex(0,FALSE,0);
8673       created = CreateEvent(0,FALSE,FALSE,0);
8674       thread = CreateThread(0,0,_events_thread,arg,0,&ThreadID);
8675       WaitForSingleObject(created,INFINITE);
8676       return *this;
8677     }
8678 
8679     CImgDisplay& assign() {
8680       if (is_empty()) return *this;
8681       DestroyWindow(window);
8682       TerminateThread(thread,0);
8683       if (data) delete[] data;
8684       if (title) delete[] title;
8685       if (is_fullscreen) _desinit_fullscreen();
8686       width = height = normalization = window_width = window_height = 0;
8687       window_x = window_y = 0;
8688       is_fullscreen = false;
8689       is_closed = true;
8690       min = max = 0;
8691       title = 0;
8692       flush();
8693       return *this;
8694     }
8695 
8696     CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
8697                         const unsigned int normalization_type=3,
8698                         const bool fullscreen_flag=false, const bool closed_flag=false) {
8699       if (!dimw || !dimh) return assign();
8700       _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
8701       min = max = 0;
8702       cimg_std::memset(data,0,sizeof(unsigned int)*width*height);
8703       return paint();
8704     }
8705 
8706     template<typename T>
8707     CImgDisplay& assign(const CImg<T>& img, const char *title=0,
8708                         const unsigned int normalization_type=3,
8709                         const bool fullscreen_flag=false, const bool closed_flag=false) {
8710       if (!img) return assign();
8711       CImg<T> tmp;
8712       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
8713       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
8714       if (normalization==2) min = (float)nimg.minmax(max);
8715       return display(nimg);
8716     }
8717 
8718     template<typename T>
8719     CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
8720                         const unsigned int normalization_type=3,
8721                         const bool fullscreen_flag=false, const bool closed_flag=false) {
8722       if (!list) return assign();
8723       CImg<T> tmp;
8724       const CImg<T> img = list.get_append('x','p'),
8725         &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
8726       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
8727       if (normalization==2) min = (float)nimg.minmax(max);
8728       return display(nimg);
8729     }
8730 
8731     CImgDisplay& assign(const CImgDisplay& win) {
8732       if (!win) return assign();
8733       _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
8734       cimg_std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
8735       return paint();
8736     }
8737 
8738     CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
8739       if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
8740       if (is_empty()) return assign(nwidth,nheight);
8741       const unsigned int
8742         tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100),
8743         tmpdimy=(nheight>0)?nheight:(-nheight*height/100),
8744         dimx = tmpdimx?tmpdimx:1,
8745         dimy = tmpdimy?tmpdimy:1;
8746       if (window_width!=dimx || window_height!=dimy) {
8747         RECT rect; rect.left = rect.top = 0; rect.right = dimx-1; rect.bottom = dimy-1;
8748         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8749         const int cwidth = rect.right-rect.left+1, cheight = rect.bottom-rect.top+1;
8750         SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
8751       }
8752       if (width!=dimx || height!=dimy) {
8753         unsigned int *ndata = new unsigned int[dimx*dimy];
8754         if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
8755         else cimg_std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
8756         delete[] data;
8757         data = ndata;
8758         bmi.bmiHeader.biWidth = dimx;
8759         bmi.bmiHeader.biHeight = -(int)dimy;
8760         width = dimx;
8761         height = dimy;
8762       }
8763       window_width = dimx; window_height = dimy;
8764       is_resized = false;
8765       if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
8766       if (redraw) return paint();
8767       return *this;
8768     }
8769 
8770     CImgDisplay& toggle_fullscreen(const bool redraw=true) {
8771       if (is_empty()) return *this;
8772       if (redraw) {
8773         const unsigned int bufsize = width*height*4;
8774         void *odata = cimg_std::malloc(bufsize);
8775         cimg_std::memcpy(odata,data,bufsize);
8776         assign(width,height,title,normalization,!is_fullscreen,false);
8777         cimg_std::memcpy(data,odata,bufsize);
8778         cimg_std::free(odata);
8779         return paint();
8780       }
8781       return assign(width,height,title,normalization,!is_fullscreen,false);
8782     }
8783 
8784     CImgDisplay& show() {
8785       if (is_empty()) return *this;
8786       if (is_closed) {
8787         is_closed = false;
8788         if (is_fullscreen) _init_fullscreen();
8789         ShowWindow(window,SW_SHOW);
8790         _update_window_pos();
8791       }
8792       return paint();
8793     }
8794 
8795     CImgDisplay& close() {
8796       if (is_empty()) return *this;
8797       if (!is_closed && !is_fullscreen) {
8798         if (is_fullscreen) _desinit_fullscreen();
8799         ShowWindow(window,SW_HIDE);
8800         is_closed = true;
8801         window_x = window_y = 0;
8802       }
8803       return *this;
8804     }
8805 
8806     CImgDisplay& move(const int posx, const int posy) {
8807       if (is_empty()) return *this;
8808       if (!is_fullscreen) {
8809         RECT rect; rect.left = rect.top = 0; rect.right=window_width-1; rect.bottom=window_height-1;
8810         AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8811         const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
8812         SetWindowPos(window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
8813       } else SetWindowPos(window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
8814       window_x = posx;
8815       window_y = posy;
8816       is_moved = false;
8817       return show();
8818     }
8819 
8820     CImgDisplay& show_mouse() {
8821       if (is_empty()) return *this;
8822       visible_cursor = true;
8823       ShowCursor(TRUE);
8824       SendMessage(window,WM_SETCURSOR,0,0);
8825       return *this;
8826     }
8827 
8828     CImgDisplay& hide_mouse() {
8829       if (is_empty()) return *this;
8830       visible_cursor = false;
8831       ShowCursor(FALSE);
8832       SendMessage(window,WM_SETCURSOR,0,0);
8833       return *this;
8834     }
8835 
8836     CImgDisplay& set_mouse(const int posx, const int posy) {
8837       if (!is_closed && posx>=0 && posy>=0) {
8838         _update_window_pos();
8839         const int res = (int)SetCursorPos(window_x+posx,window_y+posy);
8840         if (res) { mouse_x = posx; mouse_y = posy; }
8841       }
8842       return *this;
8843     }
8844 
8845     CImgDisplay& set_title(const char *format, ...) {
8846       if (is_empty()) return *this;
8847       char tmp[1024] = {0};
8848       va_list ap;
8849       va_start(ap, format);
8850       cimg_std::vsprintf(tmp,format,ap);
8851       va_end(ap);
8852       if (title) delete[] title;
8853       const int s = cimg::strlen(tmp)+1;
8854       title = new char[s];
8855       cimg_std::memcpy(title,tmp,s*sizeof(char));
8856       SetWindowTextA(window, tmp);
8857       return *this;
8858     }
8859 
8860     template<typename T>
8861     CImgDisplay& display(const CImg<T>& img) {
8862       if (img.is_empty())
8863         throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
8864       if (is_empty()) assign(img.width,img.height);
8865       return render(img).paint();
8866     }
8867 
8868     CImgDisplay& paint() {
8869       if (!is_closed) {
8870         WaitForSingleObject(mutex,INFINITE);
8871         SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
8872         ReleaseMutex(mutex);
8873       }
8874       return *this;
8875     }
8876 
8877     template<typename T>
8878     CImgDisplay& render(const CImg<T>& img) {
8879       if (is_empty()) return *this;
8880       if (!img)
8881         throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
8882                                     img.width,img.height,img.depth,img.dim,img.data);
8883       if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
8884 
8885       const T
8886         *data1 = img.data,
8887         *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
8888         *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
8889 
8890       WaitForSingleObject(mutex,INFINITE);
8891       unsigned int
8892         *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
8893         *ptrd = ndata;
8894 
8895       if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
8896         min = max = 0;
8897         switch (img.dim) {
8898         case 1 : {
8899           for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8900             const unsigned char val = (unsigned char)*(data1++);
8901             *(ptrd++) = (val<<16) | (val<<8) | val;
8902           }} break;
8903         case 2 : {
8904           for (unsigned int xy = img.width*img.height; xy>0; --xy)
8905             *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
8906         } break;
8907         default : {
8908           for (unsigned int xy = img.width*img.height; xy>0; --xy)
8909             *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
8910         }
8911         }
8912       } else {
8913         if (normalization==3) {
8914           if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
8915           else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
8916         } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
8917         const float delta = max-min, mm = delta?delta:1.0f;
8918         switch (img.dim) {
8919         case 1 : {
8920           for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8921             const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8922             *(ptrd++) = (val<<16) | (val<<8) | val;
8923           }} break;
8924         case 2 : {
8925           for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8926             const unsigned char
8927               R = (unsigned char)(255*(*(data1++)-min)/mm),
8928               G = (unsigned char)(255*(*(data2++)-min)/mm);
8929             *(ptrd++) = (R<<16) | (G<<8);
8930           }} break;
8931         default : {
8932           for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8933             const unsigned char
8934               R = (unsigned char)(255*(*(data1++)-min)/mm),
8935               G = (unsigned char)(255*(*(data2++)-min)/mm),
8936               B = (unsigned char)(255*(*(data3++)-min)/mm);
8937             *(ptrd++) = (R<<16) | (G<<8) | B;
8938           }}
8939         }
8940       }
8941       if (ndata!=data) { _render_resize(ndata,img.width,img.height,data,width,height); delete[] ndata; }
8942       ReleaseMutex(mutex);
8943       return *this;
8944     }
8945 
8946     template<typename T>
8947     const CImgDisplay& snapshot(CImg<T>& img) const {
8948       if (is_empty()) img.assign();
8949       else {
8950         img.assign(width,height,1,3);
8951         T
8952           *data1 = img.ptr(0,0,0,0),
8953           *data2 = img.ptr(0,0,0,1),
8954           *data3 = img.ptr(0,0,0,2);
8955         unsigned int *ptrs = data;
8956          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8957           const unsigned int val = *(ptrs++);
8958           *(data1++) = (unsigned char)(val>>16);
8959           *(data2++) = (unsigned char)((val>>8)&0xFF);
8960           *(data3++) = (unsigned char)(val&0xFF);
8961         }
8962       }
8963       return *this;
8964     }
8965 
8966     // MacOSX - Carbon-based display
8967     //-------------------------------
8968     // (Code by Adrien Reboisson && Romain Blei, supervised by Jean-Marie Favreau)
8969     //
8970 #elif cimg_display==3
8971     unsigned int *data;                     // The bits of the picture
8972     WindowRef carbonWindow;                 // The opaque carbon window struct associated with the display
8973     MPCriticalRegionID paintCriticalRegion; // Critical section used when drawing
8974     CGColorSpaceRef csr;                    // Needed for painting
8975     CGDataProviderRef dataProvider;         // Needed for painting
8976     CGImageRef imageRef;                    // The image
8977     UInt32 lastKeyModifiers;                // Buffer storing modifiers state
8978 
8979     // Define the kind of the queries which can be serialized using the event thread.
8980     typedef enum {
8981       COM_CREATEWINDOW = 0, // Create window query
8982       COM_RELEASEWINDOW,    // Release window query
8983       COM_SHOWWINDOW,       // Show window query
8984       COM_HIDEWINDOW,       // Hide window query
8985       COM_SHOWMOUSE,        // Show mouse query
8986       COM_HIDEMOUSE,        // Hide mouse query
8987       COM_RESIZEWINDOW,     // Resize window query
8988       COM_MOVEWINDOW,       // Move window query
8989       COM_SETTITLE,         // Set window title query
8990       COM_SETMOUSEPOS       // Set cursor position query
8991     } CImgCarbonQueryKind;
8992 
8993     // The query destructor send to the event thread.
8994     struct CbSerializedQuery {
8995       CImgDisplay* sender;         // Query's sender
8996       CImgCarbonQueryKind kind;    // The kind of the query sent to the background thread
8997       short x, y;                  // X:Y values for move/resize operations
8998       char *c;                     // Char values for window title
8999       bool createFullScreenWindow; // Boolean value used for full-screen window creation
9000       bool createClosedWindow;     // Boolean value used for closed-window creation
9001       bool update;                 // Boolean value used for resize
9002       bool success;                // Success or failure of the message, used as return value
9003       CbSerializedQuery(CImgDisplay *s, CImgCarbonQueryKind k):sender(s),kind(k),success(false) {};
9004 
9005       inline static CbSerializedQuery BuildReleaseWindowQuery(CImgDisplay* sender) {
9006         return CbSerializedQuery(sender, COM_RELEASEWINDOW);
9007       }
9008       inline static CbSerializedQuery BuildCreateWindowQuery(CImgDisplay* sender, const bool fullscreen, const bool closed) {
9009         CbSerializedQuery q(sender, COM_CREATEWINDOW);
9010         q.createFullScreenWindow = fullscreen;
9011         q.createClosedWindow = closed;
9012         return q;
9013       }
9014       inline static CbSerializedQuery BuildShowWindowQuery(CImgDisplay* sender) {
9015         return CbSerializedQuery(sender, COM_SHOWWINDOW);
9016       }
9017       inline static CbSerializedQuery BuildHideWindowQuery(CImgDisplay* sender) {
9018         return CbSerializedQuery(sender, COM_HIDEWINDOW);
9019       }
9020       inline static CbSerializedQuery BuildShowMouseQuery(CImgDisplay* sender) {
9021         return CbSerializedQuery(sender, COM_SHOWMOUSE);
9022       }
9023       inline static CbSerializedQuery BuildHideMouseQuery(CImgDisplay* sender) {
9024         return CbSerializedQuery(sender, COM_HIDEMOUSE);
9025       }
9026       inline static CbSerializedQuery BuildResizeWindowQuery(CImgDisplay* sender, const int x, const int y, bool update) {
9027         CbSerializedQuery q(sender, COM_RESIZEWINDOW);
9028         q.x = x, q.y = y;
9029         q.update = update;
9030         return q;
9031       }
9032       inline static CbSerializedQuery BuildMoveWindowQuery(CImgDisplay* sender, const int x, const int y) {
9033         CbSerializedQuery q(sender, COM_MOVEWINDOW);
9034         q.x = x, q.y = y;
9035         return q;
9036       }
9037       inline static CbSerializedQuery BuildSetWindowTitleQuery(CImgDisplay* sender, char* c) {
9038         CbSerializedQuery q(sender, COM_SETTITLE);
9039         q.c = c;
9040         return q;
9041       }
9042       inline static CbSerializedQuery BuildSetWindowPosQuery(CImgDisplay* sender, const int x, const int y) {
9043         CbSerializedQuery q(sender, COM_SETMOUSEPOS);
9044         q.x = x, q.y = y;
9045         return q;
9046       }
9047     };
9048 
9049     // Send a serialized query in a synchronous way.
9050     // @param c Application Carbon global settings.
9051     // @param m The query to send.
9052     // @result Success/failure of the operation returned by the event thread.
9053     bool _CbSendMsg(cimg::CarbonInfo& c, CbSerializedQuery m) {
9054       MPNotifyQueue(c.com_queue,&m,0,0); // Send the given message
9055       MPWaitOnSemaphore(c.sync_event,kDurationForever); // Wait end of processing notification
9056       return m.success;
9057     }
9058 
9059     // Free the window attached to the current display.
9060     // @param c Application Carbon global settings.
9061     // @result Success/failure of the operation.
9062     bool _CbFreeAttachedWindow(cimg::CarbonInfo& c) {
9063       if (!_CbSendMsg(c, CbSerializedQuery::BuildReleaseWindowQuery(this))) // Ask the main thread to free the given window
9064         throw CImgDisplayException("Cannot release window associated with the current display.");
9065       // If a window existed, ask to release it
9066       MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
9067       --c.windowCount; //Decrement the window count
9068       MPExitCriticalRegion(c.windowListCR); // Unlock the list
9069       return c.windowCount == 0;
9070     }
9071 
9072     // Create the window attached to the current display.
9073     // @param c Application Carbon global settings.
9074     // @param title The window title, if any.
9075     // @param fullscreen Should we start in fullscreen mode ?
9076     // @param create_closed If true, the window is created but not displayed.
9077     // @result Success/failure of the operation.
9078     void _CbCreateAttachedWindow(cimg::CarbonInfo& c, const char* title, const bool fullscreen, const bool create_closed) {
9079       if (!_CbSendMsg(c,CbSerializedQuery::BuildCreateWindowQuery(this,fullscreen,create_closed))) // Ask the main thread to create the window
9080         throw CImgDisplayException("Cannot create the window associated with the current display.");
9081       if (title) set_title(title); // Set the title, if any
9082       // Now we can register the window
9083       MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
9084       ++c.windowCount; //Increment the window count
9085       MPExitCriticalRegion(c.windowListCR); // Unlock the list
9086     }
9087 
9088     // Destroy graphic objects previously allocated. We free the image, the data provider, then the colorspace.
9089     void _CbFinalizeGraphics() {
9090       CGImageRelease (imageRef); // Release the picture
9091       CGDataProviderRelease(dataProvider); // Release the DP
9092       CGColorSpaceRelease(csr); // Free the cs
9093     }
9094 
9095     // Create graphic objects associated to a display. We have to create a colormap, a data provider, and the image.
9096     void _CbInitializeGraphics() {
9097       csr = CGColorSpaceCreateDeviceRGB(); // Create the color space first
9098       if (!csr)
9099         throw CImgDisplayException("CGColorSpaceCreateDeviceRGB() failed.");
9100       // Create the DP
9101       dataProvider = CGDataProviderCreateWithData(0,data,height*width*sizeof(unsigned int),0);
9102       if (!dataProvider)
9103         throw CImgDisplayException("CGDataProviderCreateWithData() failed.");
9104       // ... and finally the image.
9105       if (cimg::endianness())
9106         imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
9107                                  kCGImageAlphaNoneSkipFirst,dataProvider,0,false,kCGRenderingIntentDefault);
9108       else
9109         imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
9110                                  kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,dataProvider,0,false,kCGRenderingIntentDefault);
9111       if (!imageRef)
9112         throw CImgDisplayException("CGImageCreate() failed.");
9113     }
9114 
9115     // Reinit graphic objects. Free them, then reallocate all.
9116     // This is used when image bounds are changed or when data source get invalid.
9117     void _CbReinitGraphics() {
9118       MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
9119       _CbFinalizeGraphics();
9120       _CbInitializeGraphics();
9121       MPExitCriticalRegion(paintCriticalRegion);
9122     }
9123 
9124     // Convert a point having global coordonates into the window coordonates.
9125     // We use this function to replace the deprecated GlobalToLocal QuickDraw API.
9126     // @param mouseEvent The mouse event which triggered the event handler.
9127     // @param window The window where the event occurred.
9128     // @param point The modified point struct.
9129     // @result True if the point struct has been converted successfully.
9130     static bool _CbToLocalPointFromMouseEvent(EventRef mouseEvent, WindowRef window, HIPoint* point) {
9131       Rect bounds;
9132       if (GetWindowBounds(window,kWindowStructureRgn,&bounds)==noErr) {
9133         point->x -= bounds.left;
9134         point->y -= bounds.top;
9135         HIViewRef view = NULL;
9136         if (HIViewGetViewForMouseEvent(HIViewGetRoot(window),mouseEvent,&view)==noErr)
9137           return HIViewConvertPoint(point, NULL, view) == noErr;
9138       }
9139       return false;
9140     }
9141 
9142     static int screen_dimx() {
9143       return CGDisplayPixelsWide(kCGDirectMainDisplay);
9144     }
9145 
9146     static int screen_dimy() {
9147       return CGDisplayPixelsHigh(kCGDirectMainDisplay);
9148     }
9149 
9150     CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
9151                         const unsigned int normalization_type=3,
9152                         const bool fullscreen_flag=false, const bool closed_flag=false) {
9153       if (!dimw || !dimh) return assign();
9154       _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
9155       min = max = 0;
9156       cimg_std::memset(data,0,sizeof(unsigned int)*width*height);
9157       return paint();
9158     }
9159 
9160     template<typename T>
9161     CImgDisplay& assign(const CImg<T>& img, const char *title=0,
9162                         const unsigned int normalization_type=3,
9163                         const bool fullscreen_flag=false, const bool closed_flag=false) {
9164       if (!img) return assign();
9165       CImg<T> tmp;
9166       const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
9167       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
9168       if (normalization==2) min = (float)nimg.minmax(max);
9169       return display(nimg);
9170     }
9171 
9172     template<typename T>
9173     CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
9174                         const unsigned int normalization_type=3,
9175                         const bool fullscreen_flag=false, const bool closed_flag=false) {
9176       if (!list) return assign();
9177       CImg<T> tmp;
9178       const CImg<T> img = list.get_append('x','p'),
9179         &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
9180       _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
9181       if (normalization==2) min = (float)nimg.minmax(max);
9182       return display(nimg);
9183     }
9184 
9185     CImgDisplay& assign(const CImgDisplay &win) {
9186       if (!win) return assign();
9187       _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
9188       cimg_std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
9189       return paint();
9190     }
9191 
9192     template<typename T>
9193     CImgDisplay& display(const CImg<T>& img) {
9194       if (is_empty()) assign(img.width,img.height);
9195       return render(img).paint();
9196     }
9197 
9198     CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
9199       if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
9200       if (is_empty()) return assign(nwidth,nheight);
9201       const unsigned int
9202         tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
9203         tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
9204         dimx = tmpdimx?tmpdimx:1,
9205         dimy = tmpdimy?tmpdimy:1;
9206       cimg::CarbonInfo& c = cimg::CarbonAttr();
9207 
9208       if ((window_width!=dimx || window_height!=dimy) &&
9209           !_CbSendMsg(c,CbSerializedQuery::BuildResizeWindowQuery(this,dimx,dimy,redraw)))
9210         throw CImgDisplayException("CImgDisplay::resize() : Cannot resize the window associated to the current display.");
9211 
9212       if (width!=dimx || height!=dimy) {
9213         unsigned int *ndata = new unsigned int[dimx*dimy];
9214         if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
9215         else cimg_std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
9216         unsigned int const* old_data = data;
9217         data = ndata;
9218         delete[] old_data;
9219         _CbReinitGraphics();
9220       }
9221       window_width = width = dimx; window_height = height = dimy;
9222       is_resized = false;
9223       if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
9224       if (redraw) return paint();
9225       return *this;
9226     }
9227 
9228     CImgDisplay& move(const int posx, const int posy) {
9229       if (is_empty()) return *this;
9230       if (!is_fullscreen) {
9231         // If the operation succeeds, window_x and window_y are updated by the event thread
9232         cimg::CarbonInfo& c = cimg::CarbonAttr();
9233         // Send the query
9234         if (!_CbSendMsg(c,CbSerializedQuery::BuildMoveWindowQuery(this,posx,posy)))
9235           throw CImgDisplayException("CImgDisplay::move() : Cannot move the window associated to the current display.");
9236       }
9237       return show();
9238     }
9239 
9240     CImgDisplay& set_mouse(const int posx, const int posy) {
9241       if (!is_closed && posx>=0 && posy>=0) {
9242         // If the operation succeeds, mouse_x and mouse_y are updated by the event thread
9243         cimg::CarbonInfo& c = cimg::CarbonAttr();
9244         // Send the query
9245         if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowPosQuery(this,posx,posy)))
9246           throw CImgDisplayException("CImgDisplay::set_mouse() : Cannot set the mouse position to the current display.");
9247       }
9248       return *this;
9249     }
9250 
9251     CImgDisplay& hide_mouse() {
9252       if (is_empty()) return *this;
9253       cimg::CarbonInfo& c = cimg::CarbonAttr();
9254       // Send the query
9255       if (!_CbSendMsg(c,CbSerializedQuery::BuildHideMouseQuery(this)))
9256         throw CImgDisplayException("CImgDisplay::hide_mouse() : Cannot hide the mouse associated to the current display.");
9257       return *this;
9258     }
9259 
9260     CImgDisplay& show_mouse() {
9261       if (is_empty()) return *this;
9262       cimg::CarbonInfo& c = cimg::CarbonAttr();
9263       // Send the query
9264       if (!_CbSendMsg(c,CbSerializedQuery::BuildShowMouseQuery(this)))
9265         throw CImgDisplayException("CImgDisplay::show_mouse() : Cannot show the mouse associated to the current display.");
9266       return *this;
9267     }
9268 
9269     static void wait_all() {
9270       cimg::CarbonInfo& c = cimg::CarbonAttr();
9271       MPWaitOnSemaphore(c.wait_event,kDurationForever);
9272     }
9273 
9274     CImgDisplay& show() {
9275       if (is_empty()) return *this;
9276       if (is_closed) {
9277         cimg::CarbonInfo& c = cimg::CarbonAttr();
9278         if (!_CbSendMsg(c,CbSerializedQuery::BuildShowWindowQuery(this)))
9279           throw CImgDisplayException("CImgDisplay::show() : Cannot show the window associated to the current display.");
9280       }
9281       return paint();
9282     }
9283 
9284     CImgDisplay& close() {
9285       if (is_empty()) return *this;
9286       if (!is_closed && !is_fullscreen) {
9287         cimg::CarbonInfo& c = cimg::CarbonAttr();
9288         // If the operation succeeds, window_x and window_y are updated on the event thread
9289         if (!_CbSendMsg(c,CbSerializedQuery::BuildHideWindowQuery(this)))
9290           throw CImgDisplayException("CImgDisplay::close() : Cannot hide the window associated to the current display.");
9291       }
9292       return *this;
9293     }
9294 
9295     CImgDisplay& set_title(const char *format, ...) {
9296       if (is_empty()) return *this;
9297       char tmp[1024] = {0};
9298       va_list ap;
9299       va_start(ap, format);
9300       cimg_std::vsprintf(tmp,format,ap);
9301       va_end(ap);
9302       if (title) delete[] title;
9303       const int s = cimg::strlen(tmp)+1;
9304       title = new char[s];
9305       cimg_std::memcpy(title,tmp,s*sizeof(char));
9306       cimg::CarbonInfo& c = cimg::CarbonAttr();
9307       if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowTitleQuery(this,tmp)))
9308         throw CImgDisplayException("CImgDisplay::set_title() : Cannot set the window title associated to the current display.");
9309       return *this;
9310     }
9311 
9312     CImgDisplay& paint() {
9313       if (!is_closed) {
9314         MPEnterCriticalRegion(paintCriticalRegion,kDurationForever);
9315         CGrafPtr portPtr = GetWindowPort(carbonWindow);
9316         CGContextRef currentContext = 0;
9317         QDBeginCGContext(portPtr,&currentContext);
9318         CGContextSetRGBFillColor(currentContext,255,255,255,255);
9319         CGContextFillRect(currentContext,CGRectMake(0,0,window_width,window_height));
9320         CGContextDrawImage(currentContext,CGRectMake(0,int(window_height-height)<0?0:window_height-height,width,height),imageRef);
9321         CGContextFlush(currentContext);
9322         QDEndCGContext(portPtr, &currentContext);
9323         MPExitCriticalRegion(paintCriticalRegion);
9324       }
9325       return *this;
9326     }
9327 
9328     template<typename T>
9329     CImgDisplay& render(const CImg<T>& img) {
9330       if (is_empty()) return *this;
9331       if (!img)
9332         throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
9333                                     img.width,img.height,img.depth,img.dim,img.data);
9334       if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
9335       const T
9336         *data1 = img.data,
9337         *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
9338         *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
9339       MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
9340       unsigned int
9341         *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
9342         *ptrd = ndata;
9343       if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
9344         min = max = 0;
9345         for (unsigned int xy = img.width*img.height; xy>0; --xy)
9346           *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
9347       } else {
9348         if (normalization==3) {
9349           if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
9350           else {
9351             min = (float)cimg::type<T>::min();
9352             max = (float)cimg::type<T>::max();
9353           }
9354         } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
9355         const float delta = max-min, mm = delta?delta:1.0f;
9356         for (unsigned int xy = img.width*img.height; xy>0; --xy) {
9357           const unsigned char
9358             R = (unsigned char)(255*(*(data1++)-min)/mm),
9359             G = (unsigned char)(255*(*(data2++)-min)/mm),
9360             B = (unsigned char)(255*(*(data3++)-min)/mm);
9361           *(ptrd++) = (R<<16) | (G<<8) | (B);
9362         }
9363       }
9364       if (ndata!=data) {
9365         _render_resize(ndata,img.width,img.height,data,width,height);
9366         delete[] ndata;
9367       }
9368       MPExitCriticalRegion(paintCriticalRegion);
9369       return *this;
9370     }
9371 
9372     template<typename T>
9373     const CImgDisplay& snapshot(CImg<T>& img) const {
9374       if (is_empty()) img.assign();
9375       else {
9376         img.assign(width,height,1,3);
9377         T
9378           *data1 = img.ptr(0,0,0,0),
9379           *data2 = img.ptr(0,0,0,1),
9380           *data3 = img.ptr(0,0,0,2);
9381         unsigned int *ptrs = data;
9382         for (unsigned int xy = img.width*img.height; xy>0; --xy) {
9383           const unsigned int val = *(ptrs++);
9384           *(data1++) = (unsigned char)(val>>16);
9385           *(data2++) = (unsigned char)((val>>8)&0xFF);
9386           *(data3++) = (unsigned char)(val&0xFF);
9387         }
9388       }
9389       return *this;
9390     }
9391 
9392     CImgDisplay& toggle_fullscreen(const bool redraw=true) {
9393       if (is_empty()) return *this;
9394       if (redraw) {
9395         const unsigned int bufsize = width*height*4;
9396         void *odata = cimg_std::malloc(bufsize);
9397         cimg_std::memcpy(odata,data,bufsize);
9398         assign(width,height,title,normalization,!is_fullscreen,false);
9399         cimg_std::memcpy(data,odata,bufsize);
9400         cimg_std::free(odata);
9401         return paint();
9402       }
9403       return assign(width,height,title,normalization,!is_fullscreen,false);
9404     }
9405 
9406     static OSStatus CarbonEventHandler(EventHandlerCallRef myHandler, EventRef theEvent, void* userData) {
9407       OSStatus result = eventNotHandledErr;
9408       CImgDisplay* disp = (CImgDisplay*) userData;
9409       (void)myHandler; // Avoid "unused parameter"
9410       cimg::CarbonInfo& c = cimg::CarbonAttr();
9411       // Gets the associated display
9412       if (disp) {
9413         // Window events are always handled
9414         if (GetEventClass(theEvent)==kEventClassWindow) switch (GetEventKind (theEvent)) {
9415         case kEventWindowClose :
9416           disp->mouse_x = disp->mouse_y = -1;
9417           disp->window_x = disp->window_y = 0;
9418           if (disp->button) {
9419             cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
9420             disp->button = 0;
9421           }
9422           if (disp->key) {
9423             cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
9424             disp->key = 0;
9425           }
9426           if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
9427           disp->is_closed = true;
9428           HideWindow(disp->carbonWindow);
9429           disp->is_event = true;
9430           MPSignalSemaphore(c.wait_event);
9431           result = noErr;
9432           break;
9433           // There is a lot of case where we have to redraw our window
9434         case kEventWindowBoundsChanging :
9435         case kEventWindowResizeStarted :
9436         case kEventWindowCollapsed : //Not sure it's really needed :-)
9437           break;
9438         case kEventWindowZoomed :
9439         case kEventWindowExpanded :
9440         case kEventWindowResizeCompleted : {
9441           MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
9442           // Now we retrieve the new size of the window
9443           Rect newContentRect;
9444           GetWindowBounds(disp->carbonWindow,kWindowContentRgn,&newContentRect);
9445           const unsigned int
9446             nw = (unsigned int)(newContentRect.right - newContentRect.left),
9447             nh = (unsigned int)(newContentRect.bottom - newContentRect.top);
9448 
9449           // Then we update CImg internal settings
9450           if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
9451             disp->window_width = nw;
9452             disp->window_height = nh;
9453             disp->mouse_x = disp->mouse_y = -1;
9454             disp->is_resized = true;
9455           }
9456           disp->is_event = true;
9457           MPExitCriticalRegion(disp->paintCriticalRegion);
9458           disp->paint(); // Coords changed, must update the screen
9459           MPSignalSemaphore(c.wait_event);
9460           result = noErr;
9461         } break;
9462         case kEventWindowDragStarted :
9463         case kEventWindowDragCompleted : {
9464           MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
9465           // Now we retrieve the new size of the window
9466           Rect newContentRect ;
9467           GetWindowBounds(disp->carbonWindow,kWindowStructureRgn,&newContentRect);
9468           const int nx = (int)(newContentRect.left), ny = (int)(newContentRect.top);
9469           // Then we update CImg internal settings
9470           if (nx!=disp->window_x || ny!=disp->window_y) {
9471             disp->window_x = nx;
9472             disp->window_y = ny;
9473             disp->is_moved = true;
9474           }
9475           disp->is_event = true;
9476           MPExitCriticalRegion(disp->paintCriticalRegion);
9477           disp->paint(); // Coords changed, must update the screen
9478           MPSignalSemaphore(c.wait_event);
9479           result = noErr;
9480         } break;
9481           case kEventWindowPaint :
9482           disp->paint();
9483           break;
9484           }
9485 
9486         switch (GetEventClass(theEvent)) {
9487         case kEventClassKeyboard : {
9488           if (GetEventKind(theEvent)==kEventRawKeyModifiersChanged) {
9489             // Apple has special keys named "notifiers", we have to convert this (exotic ?) key handling into the regular CImg processing.
9490             UInt32 newModifiers;
9491             if (GetEventParameter(theEvent,kEventParamKeyModifiers,typeUInt32,0,sizeof(UInt32),0,&newModifiers)==noErr) {
9492               int newKeyCode = -1;
9493               UInt32 changed = disp->lastKeyModifiers^newModifiers;
9494               // Find what changed here
9495               if ((changed & rightShiftKey)!=0) newKeyCode = cimg::keySHIFTRIGHT;
9496               if ((changed & shiftKey)!=0) newKeyCode = cimg::keySHIFTLEFT;
9497 
9498               // On the Mac, the "option" key = the ALT key
9499               if ((changed & (optionKey | rightOptionKey))!=0) newKeyCode = cimg::keyALTGR;
9500               if ((changed & controlKey)!=0) newKeyCode = cimg::keyCTRLLEFT;
9501               if ((changed & rightControlKey)!=0) newKeyCode = cimg::keyCTRLRIGHT;
9502               if ((changed & cmdKey)!=0) newKeyCode = cimg::keyAPPLEFT;
9503               if ((changed & alphaLock)!=0) newKeyCode = cimg::keyCAPSLOCK;
9504               if (newKeyCode != -1) { // Simulate keystroke
9505                 if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
9506                 disp->key = (int)newKeyCode;
9507               }
9508               disp->lastKeyModifiers = newModifiers; // Save current state
9509             }
9510             disp->is_event = true;
9511             MPSignalSemaphore(c.wait_event);
9512           }
9513           if (GetEventKind(theEvent)==kEventRawKeyDown || GetEventKind(theEvent)==kEventRawKeyRepeat) {
9514             char keyCode;
9515             if (GetEventParameter(theEvent,kEventParamKeyMacCharCodes,typeChar,0,sizeof(keyCode),0,&keyCode)==noErr) {
9516               disp->update_iskey((unsigned int)keyCode,true);
9517               if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
9518               disp->key = (unsigned int)keyCode;
9519               if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
9520             }
9521             disp->is_event = true;
9522             MPSignalSemaphore(c.wait_event);
9523           }
9524         } break;
9525 
9526         case kEventClassMouse :
9527           switch (GetEventKind(theEvent)) {
9528           case kEventMouseDragged :
9529             //  When you push the main button on the Apple mouse while moving it, you got NO kEventMouseMoved msg,
9530             //  but a kEventMouseDragged one. So we merge them here.
9531           case kEventMouseMoved :
9532             HIPoint point;
9533             if (GetEventParameter(theEvent,kEventParamMouseLocation,typeHIPoint,0,sizeof(point),0,&point)==noErr) {
9534               if (_CbToLocalPointFromMouseEvent(theEvent,disp->carbonWindow,&point)) {
9535                 disp->mouse_x = (int)point.x;
9536                 disp->mouse_y = (int)point.y;
9537                 if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
9538                   disp->mouse_x = disp->mouse_y = -1;
9539               } else disp->mouse_x = disp->mouse_y = -1;
9540             }
9541             disp->is_event = true;
9542             MPSignalSemaphore(c.wait_event);
9543             break;
9544           case kEventMouseDown :
9545             UInt16 btn;
9546             if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
9547               cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
9548               if (btn==kEventMouseButtonPrimary) disp->button|=1U;
9549               // For those who don't have a multi-mouse button (as me), I think it's better to allow the user
9550               // to emulate a right click by using the Control key
9551               if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
9552                 cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Down]");
9553               if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button|=2U;
9554               if (btn==kEventMouseButtonTertiary) disp->button|=4U;
9555             }
9556             disp->is_event = true;
9557             MPSignalSemaphore(c.wait_event);
9558             break;
9559           case kEventMouseWheelMoved :
9560             EventMouseWheelAxis wheelax;
9561             SInt32 delta;
9562             if (GetEventParameter(theEvent,kEventParamMouseWheelAxis,typeMouseWheelAxis,0,sizeof(wheelax),0,&wheelax)==noErr)
9563               if (wheelax==kEventMouseWheelAxisY) {
9564                 if (GetEventParameter(theEvent,kEventParamMouseWheelDelta,typeLongInteger,0,sizeof(delta),0,&delta)==noErr)
9565                   if (delta>0) disp->wheel+=delta/120; //FIXME: why 120 ?
9566                 disp->is_event = true;
9567                 MPSignalSemaphore(c.wait_event);
9568               }
9569             break;
9570           }
9571         }
9572 
9573         switch (GetEventClass(theEvent)) {
9574         case kEventClassKeyboard :
9575           if (GetEventKind(theEvent)==kEventRawKeyUp) {
9576             UInt32 keyCode;
9577             if (GetEventParameter(theEvent,kEventParamKeyCode,typeUInt32,0,sizeof(keyCode),0,&keyCode)==noErr) {
9578               disp->update_iskey((unsigned int)keyCode,false);
9579               if (disp->key) { cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
9580               if (disp->released_key) cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
9581               disp->released_key = (int)keyCode;
9582             }
9583             disp->is_event = true;
9584             MPSignalSemaphore(c.wait_event);
9585           }
9586           break;
9587 
9588         case kEventClassMouse :
9589           switch (GetEventKind(theEvent)) {
9590           case kEventMouseUp :
9591             UInt16 btn;
9592             if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
9593               cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
9594               if (btn==kEventMouseButtonPrimary) disp->button&=~1U;
9595               // See note in kEventMouseDown handler.
9596               if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
9597                 cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Up]");
9598               if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button&=~2U;
9599               if (btn==kEventMouseButtonTertiary) disp->button&=~2U;
9600             }
9601             disp->is_event = true;
9602             MPSignalSemaphore(c.wait_event);
9603             break;
9604           }
9605         }
9606       }
9607       return (result);
9608     }
9609 
9610     static void* _events_thread(void* args) {
9611       (void)args;      // Make the compiler happy
9612       cimg::CarbonInfo& c = cimg::CarbonAttr();
9613       pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
9614       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
9615       MPSignalSemaphore(c.sync_event);  // Notify the caller that all goes fine
9616       EventRef theEvent;
9617       EventTargetRef theTarget;
9618       OSStatus err;
9619       CbSerializedQuery* query;
9620       theTarget = GetEventDispatcherTarget();
9621 
9622       // Enter in the main loop
9623       while (true) {
9624         pthread_testcancel(); /* Check if cancelation happens */
9625         err = ReceiveNextEvent(0,0,kDurationImmediate,true,&theEvent); // Fetch new events
9626         if (err==noErr) { // Received a carbon event, so process it !
9627           SendEventToEventTarget (theEvent, theTarget);
9628           ReleaseEvent(theEvent);
9629         } else if (err == eventLoopTimedOutErr) { // There is no event to process, so check if there is new messages to process
9630           OSStatus r =MPWaitOnQueue(c.com_queue,(void**)&query,0,0,10*kDurationMillisecond);
9631           if (r!=noErr) continue; //nothing in the queue or an error.., bye
9632           // If we're here, we've something to do now.
9633           if (query) {
9634             switch (query->kind) {
9635             case COM_SETMOUSEPOS : { // change the cursor position
9636               query->success = CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,CGPointMake(query->sender->window_x+query->x,query->sender->window_y+query->y))
9637                 == kCGErrorSuccess;
9638               if (query->success) {
9639                 query->sender->mouse_x = query->x;
9640                 query->sender->mouse_y = query->y;
9641               } else cimg::warn("CImgDisplay::_events_thread() : CGDisplayMoveCursorToPoint failed.");
9642             } break;
9643             case COM_SETTITLE : { // change the title bar caption
9644               CFStringRef windowTitle = CFStringCreateWithCString(0,query->c,kCFStringEncodingMacRoman);
9645               query->success = SetWindowTitleWithCFString(query->sender->carbonWindow,windowTitle)==noErr;
9646               if (!query->success)
9647                 cimg::warn("CImgDisplay::_events_thread() : SetWindowTitleWithCFString failed.");
9648               CFRelease(windowTitle);
9649             } break;
9650             case COM_RESIZEWINDOW : { // Resize a window
9651               SizeWindow(query->sender->carbonWindow,query->x,query->y,query->update);
9652               // If the window has been resized successfully, update display informations
9653               query->sender->window_width = query->x;
9654               query->sender->window_height = query->y;
9655               query->success = true;
9656             } break;
9657             case COM_MOVEWINDOW : { // Move a window
9658               MoveWindow(query->sender->carbonWindow,query->x,query->y,false);
9659               query->sender->window_x = query->x;
9660               query->sender->window_y = query->y;
9661               query->sender->is_moved = false;
9662               query->success = true;
9663             } break;
9664             case COM_SHOWMOUSE : { // Show the mouse
9665               query->success = CGDisplayShowCursor(kCGDirectMainDisplay)==noErr;
9666               if (!query->success)
9667                 cimg::warn("CImgDisplay::_events_thread() : CGDisplayShowCursor failed.");
9668             } break;
9669             case COM_HIDEMOUSE : { // Hide the mouse
9670               query->success = CGDisplayHideCursor(kCGDirectMainDisplay)==noErr;
9671               if (!query->success)
9672                 cimg::warn("CImgDisplay::_events_thread() : CGDisplayHideCursor failed.");
9673             } break;
9674             case COM_SHOWWINDOW : { // We've to show a window
9675               ShowWindow(query->sender->carbonWindow);
9676               query->success = true;
9677               query->sender->is_closed = false;
9678             } break;
9679             case COM_HIDEWINDOW : { // We've to show a window
9680               HideWindow(query->sender->carbonWindow);
9681               query->sender->is_closed = true;
9682               query->sender->window_x = query->sender->window_y = 0;
9683               query->success = true;
9684             } break;
9685             case COM_RELEASEWINDOW : { // We have to release a given window handle
9686               query->success = true;
9687               CFRelease(query->sender->carbonWindow);
9688             } break;
9689             case COM_CREATEWINDOW : { // We have to create a window
9690               query->success = true;
9691               WindowAttributes  windowAttrs;
9692               Rect              contentRect;
9693               if (query->createFullScreenWindow) {
9694                 // To simulate a "true" full screen, we remove menus and close boxes
9695                 windowAttrs = (1L << 9); //Why ? kWindowNoTitleBarAttribute seems to be not defined on 10.3
9696                 // Define a full screen bound rect
9697                 SetRect(&contentRect,0,0,CGDisplayPixelsWide(kCGDirectMainDisplay),CGDisplayPixelsHigh(kCGDirectMainDisplay));
9698               } else { // Set the window size
9699                 SetRect(&contentRect,0,0,query->sender->width,query->sender->height); // Window will be centered with RepositionWindow.
9700                 // Use default attributes
9701                 windowAttrs = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute | kWindowLiveResizeAttribute;
9702               }
9703               // Update window position
9704               if (query->createClosedWindow) query->sender->window_x = query->sender->window_y = 0;
9705               else {
9706                 query->sender->window_x = contentRect.left;
9707                 query->sender->window_y = contentRect.top;
9708               }
9709               // Update window flags
9710               query->sender->window_width = query->sender->width;
9711               query->sender->window_height = query->sender->height;
9712               query->sender->flush();
9713               // Create the window
9714               if (CreateNewWindow(kDocumentWindowClass,windowAttrs,&contentRect,&query->sender->carbonWindow)!=noErr) {
9715                 query->success = false;
9716                 cimg::warn("CImgDisplay::_events_thread() : CreateNewWindow() failed.");
9717               }
9718               // Send it to the foreground
9719               if (RepositionWindow(query->sender->carbonWindow,0,kWindowCenterOnMainScreen)!=noErr) query->success = false;
9720               // Show it, if needed
9721               if (!query->createClosedWindow) ShowWindow(query->sender->carbonWindow);
9722 
9723               // Associate a valid event handler
9724               EventTypeSpec eventList[] = {
9725                 { kEventClassWindow, kEventWindowClose },
9726                 { kEventClassWindow, kEventWindowResizeStarted },
9727                 { kEventClassWindow, kEventWindowResizeCompleted },
9728                 { kEventClassWindow, kEventWindowDragStarted},
9729                 { kEventClassWindow, kEventWindowDragCompleted },
9730                 { kEventClassWindow, kEventWindowPaint },
9731                 { kEventClassWindow, kEventWindowBoundsChanging },
9732                 { kEventClassWindow, kEventWindowCollapsed },
9733                 { kEventClassWindow, kEventWindowExpanded },
9734                 { kEventClassWindow, kEventWindowZoomed },
9735                 { kEventClassKeyboard, kEventRawKeyDown },
9736                 { kEventClassKeyboard, kEventRawKeyUp },
9737                 { kEventClassKeyboard, kEventRawKeyRepeat },
9738                 { kEventClassKeyboard, kEventRawKeyModifiersChanged },
9739                 { kEventClassMouse, kEventMouseMoved },
9740                 { kEventClassMouse, kEventMouseDown },
9741                 { kEventClassMouse, kEventMouseUp },
9742                 { kEventClassMouse, kEventMouseDragged }
9743               };
9744 
9745               // Set up the handler
9746               if (InstallWindowEventHandler(query->sender->carbonWindow,NewEventHandlerUPP(CarbonEventHandler),GetEventTypeCount(eventList),
9747                                             eventList,(void*)query->sender,0)!=noErr) {
9748                 query->success = false;
9749                 cimg::warn("CImgDisplay::_events_thread() : InstallWindowEventHandler failed.");
9750               }
9751 
9752               // Paint
9753               query->sender->paint();
9754             } break;
9755             default :
9756               cimg::warn("CImgDisplay::_events_thread() : Received unknow code %d.",query->kind);
9757             }
9758             // Signal that the message has been processed
9759             MPSignalSemaphore(c.sync_event);
9760           }
9761         }
9762       }
9763       // If we are here, the application is now finished
9764       pthread_exit(0);
9765     }
9766 
9767     CImgDisplay& assign() {
9768       if (is_empty()) return *this;
9769       cimg::CarbonInfo& c = cimg::CarbonAttr();
9770       // Destroy the window associated to the display
9771       _CbFreeAttachedWindow(c);
9772       // Don't destroy the background thread here.
9773       // If you check whether _CbFreeAttachedWindow() returned true,
9774       //   - saying that there were no window left on screen - and
9775       //   you destroy the background thread here, ReceiveNextEvent won't
9776       //   work anymore if you create a new window after. So the
9777       //  background thread must be killed (pthread_cancel() + pthread_join())
9778       //   only on the application shutdown.
9779 
9780       // Finalize graphics
9781       _CbFinalizeGraphics();
9782 
9783       // Do some cleanup
9784       if (data) delete[] data;
9785       if (title) delete[] title;
9786       width = height = normalization = window_width = window_height = 0;
9787       window_x = window_y = 0;
9788       is_fullscreen = false;
9789       is_closed = true;
9790       min = max = 0;
9791       title = 0;
9792       flush();
9793       if (MPDeleteCriticalRegion(paintCriticalRegion)!=noErr)
9794         throw CImgDisplayException("CImgDisplay()::assign() : MPDeleteCriticalRegion failed.");
9795       return *this;
9796     }
9797 
9798     CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
9799                          const unsigned int normalization_type=3,
9800                          const bool fullscreen_flag=false, const bool closed_flag=false) {
9801       cimg::CarbonInfo& c = cimg::CarbonAttr();
9802 
9803       // Allocate space for window title
9804       const int s = cimg::strlen(ptitle)+1;
9805       char *tmp_title = s?new char[s]:0;
9806       if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
9807 
9808       // Destroy previous window if existing
9809       if (!is_empty()) assign();
9810 
9811       // Set display variables
9812       width = cimg::min(dimw,(unsigned int)screen_dimx());
9813       height = cimg::min(dimh,(unsigned int)screen_dimy());
9814       normalization = normalization_type<4?normalization_type:3;
9815       is_fullscreen = fullscreen_flag;
9816       is_closed = closed_flag;
9817       lastKeyModifiers = 0;
9818       title = tmp_title;
9819       flush();
9820 
9821       // Create the paint CR
9822       if (MPCreateCriticalRegion(&paintCriticalRegion) != noErr)
9823         throw CImgDisplayException("CImgDisplay::_assign() : MPCreateCriticalRegion() failed.");
9824 
9825       // Create the thread if it's not already created
9826       if (c.event_thread==0) {
9827         // Background thread does not exists, so create it !
9828         if (pthread_create(&c.event_thread,0,_events_thread,0)!=0)
9829           throw CImgDisplayException("CImgDisplay::_assign() : pthread_create() failed.");
9830         // Wait for thread initialization
9831         MPWaitOnSemaphore(c.sync_event, kDurationForever);
9832       }
9833 
9834       // Init disp. graphics
9835       data = new unsigned int[width*height];
9836       _CbInitializeGraphics();
9837 
9838       // Now ask the thread to create the window
9839       _CbCreateAttachedWindow(c,ptitle,fullscreen_flag,closed_flag);
9840       return *this;
9841     }
9842 
9843 #endif
9844 
9845   };
9846 
9847   /*
9848    #--------------------------------------
9849    #
9850    #
9851    #
9852    # Definition of the CImg<T> structure
9853    #
9854    #
9855    #
9856    #--------------------------------------
9857    */
9858 
9859   //! Class representing an image (up to 4 dimensions wide), each pixel being of type \c T.
9860   /**
9861      This is the main class of the %CImg Library. It declares and constructs
9862      an image, allows access to its pixel values, and is able to perform various image operations.
9863 
9864      \par Image representation
9865 
9866      A %CImg image is defined as an instance of the container \ref CImg<\c T>, which contains a regular grid of pixels,
9867      each pixel value being of type \c T. The image grid can have up to 4 dimensions : width, height, depth
9868      and number of channels.
9869      Usually, the three first dimensions are used to describe spatial coordinates <tt>(x,y,z)</tt>, while the number of channels
9870      is rather used as a vector-valued dimension (it may describe the R,G,B color channels for instance).
9871      If you need a fifth dimension, you can use image lists \ref CImgList<\c T> rather than simple images \ref CImg<\c T>.
9872 
9873      Thus, the \ref CImg<\c T> class is able to represent volumetric images of vector-valued pixels,
9874      as well as images with less dimensions (1D scalar signal, 2D color images, ...).
9875      Most member functions of the class CImg<\c T> are designed to handle this maximum case of (3+1) dimensions.
9876 
9877      Concerning the pixel value type \c T :
9878      fully supported template types are the basic C++ types : <tt>unsigned char, char, short, unsigned int, int,
9879      unsigned long, long, float, double, ... </tt>.
9880      Typically, fast image display can be done using <tt>CImg<unsigned char></tt> images,
9881      while complex image processing algorithms may be rather coded using <tt>CImg<float></tt> or <tt>CImg<double></tt>
9882      images that have floating-point pixel values. The default value for the template T is \c float.
9883      Using your own template types may be possible. However, you will certainly have to define the complete set
9884      of arithmetic and logical operators for your class.
9885 
9886      \par Image structure
9887 
9888      The \ref CImg<\c T> structure contains \a six fields :
9889      - \ref width defines the number of \a columns of the image (size along the X-axis).
9890      - \ref height defines the number of \a rows of the image (size along the Y-axis).
9891      - \ref depth defines the number of \a slices of the image (size along the Z-axis).
9892      - \ref dim defines the number of \a channels of the image (size along the V-axis).
9893      - \ref data defines a \a pointer to the \a pixel \a data (of type \c T).
9894      - \ref is_shared is a boolean that tells if the memory buffer \ref data is shared with
9895        another image.
9896 
9897      You can access these fields publicly although it is recommended to use the dedicated functions
9898      dimx(), dimy(), dimz(), dimv() and ptr() to do so.
9899      Image dimensions are not limited to a specific range (as long as you got enough available memory).
9900      A value of \e 1 usually means that the corresponding dimension is \a flat.
9901      If one of the dimensions is \e 0, or if the data pointer is null, the image is considered as \e empty.
9902      Empty images should not contain any pixel data and thus, will not be processed by CImg member functions
9903      (a CImgInstanceException will be thrown instead).
9904      Pixel data are stored in memory, in a non interlaced mode (See \ref cimg_storage).
9905 
9906      \par Image declaration and construction
9907 
9908      Declaring an image can be done by using one of the several available constructors.
9909      Here is a list of the most used :
9910 
9911      - Construct images from arbitrary dimensions :
9912          - <tt>CImg<char> img;</tt> declares an empty image.
9913          - <tt>CImg<unsigned char> img(128,128);</tt> declares a 128x128 greyscale image with
9914          \c unsigned \c char pixel values.
9915          - <tt>CImg<double> img(3,3);</tt> declares a 3x3 matrix with \c double coefficients.
9916          - <tt>CImg<unsigned char> img(256,256,1,3);</tt> declares a 256x256x1x3 (color) image
9917          (colors are stored as an image with three channels).
9918          - <tt>CImg<double> img(128,128,128);</tt> declares a 128x128x128 volumetric and greyscale image
9919          (with \c double pixel values).
9920          - <tt>CImg<> img(128,128,128,3);</tt> declares a 128x128x128 volumetric color image
9921          (with \c float pixels, which is the default value of the template parameter \c T).
9922          - \b Note : images pixels are <b>not automatically initialized to 0</b>. You may use the function \ref fill() to
9923          do it, or use the specific constructor taking 5 parameters like this :
9924          <tt>CImg<> img(128,128,128,3,0);</tt> declares a 128x128x128 volumetric color image with all pixel values to 0.
9925 
9926      - Construct images from filenames :
9927          - <tt>CImg<unsigned char> img("image.jpg");</tt> reads a JPEG color image from the file "image.jpg".
9928          - <tt>CImg<float> img("analyze.hdr");</tt> reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr".
9929          - \b Note : You need to install <a href="http://www.imagemagick.org">ImageMagick</a>
9930          to be able to read common compressed image formats (JPG,PNG, ...) (See \ref cimg_files_io).
9931 
9932      - Construct images from C-style arrays :
9933          - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer
9934          \c data_buffer (of size 256x256=65536).
9935          - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,false);</tt> constructs a 256x256 color image
9936          from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others).
9937          - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,true);</tt> constructs a 256x256 color image
9938          from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels are multiplexed).
9939 
9940          The complete list of constructors can be found <a href="#constructors">here</a>.
9941 
9942      \par Most useful functions
9943 
9944      The \ref CImg<\c T> class contains a lot of functions that operates on images.
9945      Some of the most useful are :
9946 
9947      - operator()(), operator[]() : allows to access or write pixel values.
9948      - display() : displays the image in a new window.
9949   **/
9950   template<typename T>
9951   struct CImg {
9952 
9953     //! Variable representing the width of the instance image (i.e. dimensions along the X-axis).
9954     /**
9955        \remark
9956        - Prefer using the function CImg<T>::dimx() to get information about the width of an image.
9957        - Use function CImg<T>::resize() to set a new width for an image. Setting directly the variable \c width would probably
9958        result in a library crash.
9959        - Empty images have \c width defined to \c 0.
9960     **/
9961     unsigned int width;
9962 
9963     //! Variable representing the height of the instance image (i.e. dimensions along the Y-axis).
9964     /**
9965        \remark
9966        - Prefer using the function CImg<T>::dimy() to get information about the height of an image.
9967        - Use function CImg<T>::resize() to set a new height for an image. Setting directly the variable \c height would probably
9968        result in a library crash.
9969        - 1D signals have \c height defined to \c 1.
9970        - Empty images have \c height defined to \c 0.
9971     **/
9972     unsigned int height;
9973 
9974     //! Variable representing the depth of the instance image (i.e. dimensions along the Z-axis).
9975     /**
9976        \remark
9977        - Prefer using the function CImg<T>::dimz() to get information about the depth of an image.
9978        - Use function CImg<T>::resize() to set a new depth for an image. Setting directly the variable \c depth would probably
9979        result in a library crash.
9980        - Classical 2D images have \c depth defined to \c 1.
9981        - Empty images have \c depth defined to \c 0.
9982     **/
9983     unsigned int depth;
9984 
9985     //! Variable representing the number of channels of the instance image (i.e. dimensions along the V-axis).
9986     /**
9987        \remark
9988        - Prefer using the function CImg<T>::dimv() to get information about the depth of an image.
9989        - Use function CImg<T>::resize() to set a new vector dimension for an image. Setting directly the variable \c dim would probably
9990        result in a library crash.
9991        - Scalar-valued images (one value per pixel) have \c dim defined to \c 1.
9992        - Empty images have \c depth defined to \c 0.
9993     **/
9994     unsigned int dim;
9995 
9996     //! Variable telling if pixel buffer of the instance image is shared with another one.
9997     bool is_shared;
9998 
9999     //! Pointer to the first pixel of the pixel buffer.
10000     T *data;
10001 
10002     //! Iterator type for CImg<T>.
10003     /**
10004        \remark
10005        - An \p iterator is a <tt>T*</tt> pointer (address of a pixel value in the pixel buffer).
10006        - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL.
10007     **/
10008     typedef T* iterator;
10009 
10010     //! Const iterator type for CImg<T>.
10011     /**
10012        \remark
10013        - A \p const_iterator is a <tt>const T*</tt> pointer (address of a pixel value in the pixel buffer).
10014        - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL.
10015     **/
10016     typedef const T* const_iterator;
10017 
10018     //! Get value type
10019     typedef T value_type;
10020 
10021     // Define common T-dependent types.
10022     typedef typename cimg::superset<T,bool>::type Tbool;
10023     typedef typename cimg::superset<T,unsigned char>::type Tuchar;
10024     typedef typename cimg::superset<T,char>::type Tchar;
10025     typedef typename cimg::superset<T,unsigned short>::type Tushort;
10026     typedef typename cimg::superset<T,short>::type Tshort;
10027     typedef typename cimg::superset<T,unsigned int>::type Tuint;
10028     typedef typename cimg::superset<T,int>::type Tint;
10029     typedef typename cimg::superset<T,unsigned long>::type Tulong;
10030     typedef typename cimg::superset<T,long>::type Tlong;
10031     typedef typename cimg::superset<T,float>::type Tfloat;
10032     typedef typename cimg::superset<T,double>::type Tdouble;
10033     typedef typename cimg::last<T,bool>::type boolT;
10034     typedef typename cimg::last<T,unsigned char>::type ucharT;
10035     typedef typename cimg::last<T,char>::type charT;
10036     typedef typename cimg::last<T,unsigned short>::type ushortT;
10037     typedef typename cimg::last<T,short>::type shortT;
10038     typedef typename cimg::last<T,unsigned int>::type uintT;
10039     typedef typename cimg::last<T,int>::type intT;
10040     typedef typename cimg::last<T,unsigned long>::type ulongT;
10041     typedef typename cimg::last<T,long>::type longT;
10042     typedef typename cimg::last<T,float>::type floatT;
10043     typedef typename cimg::last<T,double>::type doubleT;
10044 
10045     //@}
10046     //---------------------------
10047     //
10048     //! \name Plugins
10049     //@{
10050     //---------------------------
10051 #ifdef cimg_plugin
10052 #include cimg_plugin
10053 #endif
10054 #ifdef cimg_plugin1
10055 #include cimg_plugin1
10056 #endif
10057 #ifdef cimg_plugin2
10058 #include cimg_plugin2
10059 #endif
10060 #ifdef cimg_plugin3
10061 #include cimg_plugin3
10062 #endif
10063 #ifdef cimg_plugin4
10064 #include cimg_plugin4
10065 #endif
10066 #ifdef cimg_plugin5
10067 #include cimg_plugin5
10068 #endif
10069 #ifdef cimg_plugin6
10070 #include cimg_plugin6
10071 #endif
10072 #ifdef cimg_plugin7
10073 #include cimg_plugin7
10074 #endif
10075 #ifdef cimg_plugin8
10076 #include cimg_plugin8
10077 #endif
10078 #ifndef cimg_plugin_greycstoration
10079 #define cimg_plugin_greycstoration_count
10080 #endif
10081 #ifndef cimg_plugin_greycstoration_lock
10082 #define cimg_plugin_greycstoration_lock
10083 #endif
10084 #ifndef cimg_plugin_greycstoration_unlock
10085 #define cimg_plugin_greycstoration_unlock
10086 #endif
10087 
10088     //@}
10089 
10090     //--------------------------------------
10091     //
10092     //! \name Constructors-Destructor-Copy
10093     //@{
10094     //--------------------------------------
10095 
10096     //! Destructor.
10097     /**
10098        The destructor destroys the instance image.
10099        \remark
10100        - Destructing an empty or shared image does nothing.
10101        - Otherwise, all memory used to store the pixel data of the instance image is freed.
10102        - When destroying a non-shared image, be sure that every shared instances of the same image are
10103        also destroyed to avoid further access to desallocated memory buffers.
10104     **/
10105     ~CImg() {
10106       if (data && !is_shared) delete[] data;
10107     }
10108 
10109     //! Default constructor.
10110     /**
10111        The default constructor creates an empty instance image.
10112        \remark
10113        - An empty image does not contain any data and has all of its dimensions \ref width, \ref height, \ref depth, \ref dim
10114        set to 0 as well as its pointer to the pixel buffer \ref data.
10115        - An empty image is non-shared.
10116     **/
10117     CImg():
10118       width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {}
10119 
10120     //! Constructs a new image with given size (\p dx,\p dy,\p dz,\p dv).
10121     /**
10122        This constructors create an instance image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T.
10123        \param dx Desired size along the X-axis, i.e. the \ref width of the image.
10124        \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
10125        \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
10126        \param dv Desired size along the V-axis, i.e. the number of image channels \ref dim.
10127        \remark
10128        - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the created image is empty
10129        and all has its dimensions set to 0. No memory for pixel data is then allocated.
10130        - This constructor creates only non-shared images.
10131        - Image pixels allocated by this constructor are \b not \b initialized.
10132        Use the constructor CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
10133        to get an image of desired size with pixels set to a particular value.
10134     **/
10135     explicit CImg(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1):
10136       is_shared(false) {
10137       const unsigned long siz = dx*dy*dz*dv;
10138       if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; }
10139       else { width = height = depth = dim = 0; data = 0; }
10140     }
10141 
10142     //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with pixel having a default value \p val.
10143     /**
10144        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
10145        values of the created instance image to \p val.
10146        \param dx Desired size along the X-axis, i.e. the \ref width of the image.
10147        \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
10148        \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
10149        \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
10150        \param val Default value for image pixels.
10151        \remark
10152        - This constructor has the same properties as CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
10153     **/
10154     CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val):
10155       is_shared(false) {
10156       const unsigned long siz = dx*dy*dz*dv;
10157       if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(val); }
10158       else { width = height = depth = dim = 0; data = 0; }
10159     }
10160 
10161     //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (int version).
10162     CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10163          const int val0, const int val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10164 #define _CImg_stdarg(img,a0,a1,N,t) { \
10165         unsigned int _siz = (unsigned int)N; \
10166         if (_siz--) { \
10167           va_list ap; \
10168           va_start(ap,a1); \
10169           T *ptrd = (img).data; \
10170           *(ptrd++) = (T)a0; \
10171           if (_siz--) { \
10172             *(ptrd++) = (T)a1; \
10173             for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \
10174           } \
10175           va_end(ap); \
10176         }}
10177       assign(dx,dy,dz,dv);
10178       _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
10179     }
10180 
10181     //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (double version).
10182     CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10183          const double val0, const double val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10184       assign(dx,dy,dz,dv);
10185       _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
10186     }
10187 
10188     //! Construct an image with given size and with specified values given in a string.
10189     CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10190          const char *const values, const bool repeat_pattern):is_shared(false) {
10191       const unsigned long siz = dx*dy*dz*dv;
10192       if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(values,repeat_pattern); }
10193       else { width = height = depth = dim = 0; data = 0; }
10194     }
10195 
10196     //! Construct an image from a raw memory buffer.
10197     /**
10198        This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dv) and fill its pixel buffer by
10199        copying data values from the input raw pixel buffer \p data_buffer.
10200     **/
10201     template<typename t>
10202     CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
10203          const unsigned int dz=1, const unsigned int dv=1, const bool shared=false):is_shared(false) {
10204       if (shared)
10205         throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a (%s*) buffer "
10206                                     "(different pixel types).",
10207                                     pixel_type(),CImg<t>::pixel_type());
10208       const unsigned long siz = dx*dy*dz*dv;
10209       if (data_buffer && siz) {
10210         width = dx; height = dy; depth = dz; dim = dv; data = new T[siz];
10211         const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
10212       } else { width = height = depth = dim = 0; data = 0; }
10213     }
10214 
10215 #ifndef cimg_use_visualcpp6
10216     CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
10217          const unsigned int dz=1, const unsigned int dv=1, const bool shared=false)
10218 #else
10219     CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
10220          const unsigned int dz, const unsigned int dv, const bool shared)
10221 #endif
10222     {
10223       const unsigned long siz = dx*dy*dz*dv;
10224       if (data_buffer && siz) {
10225         width = dx; height = dy; depth = dz; dim = dv; is_shared = shared;
10226         if (is_shared) data = const_cast<T*>(data_buffer);
10227         else { data = new T[siz]; cimg_std::memcpy(data,data_buffer,siz*sizeof(T)); }
10228       } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
10229     }
10230 
10231    //! Default copy constructor.
10232     /**
10233        The default copy constructor creates a new instance image having same dimensions
10234        (\ref width, \ref height, \ref depth, \ref dim) and same pixel values as the input image \p img.
10235        \param img The input image to copy.
10236        \remark
10237        - If the input image \p img is non-shared or have a different template type \p t != \p T,
10238        the default copy constructor allocates a new pixel buffer and copy the pixel data
10239        of \p img into it. In this case, the pointers \ref data to the pixel buffers of the two images are different
10240        and the resulting instance image is non-shared.
10241        - If the input image \p img is shared and has the same template type \p t == \p T,
10242        the default copy constructor does not allocate a new pixel buffer and the resulting instance image
10243        shares its pixel buffer with the input image \p img, which means that modifying pixels of \p img also modifies
10244        the created instance image.
10245        - Copying an image having a different template type \p t != \p T performs a crude static cast conversion of each pixel value from
10246        type \p t to type \p T.
10247        - Copying an image having the same template type \p t == \p T is significantly faster.
10248     **/
10249     template<typename t>
10250     CImg(const CImg<t>& img):is_shared(false) {
10251       const unsigned int siz = img.size();
10252       if (img.data && siz) {
10253         width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
10254         const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
10255       } else { width = height = depth = dim = 0; data = 0; }
10256     }
10257 
10258     CImg(const CImg<T>& img) {
10259       const unsigned int siz = img.size();
10260       if (img.data && siz) {
10261         width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = img.is_shared;
10262         if (is_shared) data = const_cast<T*>(img.data);
10263         else { data = new T[siz]; cimg_std::memcpy(data,img.data,siz*sizeof(T)); }
10264       } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
10265     }
10266 
10267    //! Advanced copy constructor.
10268     /**
10269        The advanced copy constructor - as the default constructor CImg(const CImg< t >&) - creates a new instance image having same dimensions
10270        \ref width, \ref height, \ref depth, \ref dim and same pixel values as the input image \p img.
10271        But it also decides if the created instance image shares its memory with the input image \p img (if the input parameter
10272        \p shared is set to \p true) or not (if the input parameter \p shared is set to \p false).
10273        \param img The input image to copy.
10274        \param shared Boolean flag that decides if the copy is shared on non-shared.
10275        \remark
10276        - 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.
10277        - If a non-shared copy of the input image \p img is created, a new memory buffer is allocated for pixel data.
10278        - If a shared copy of the input image \p img is created, no extra memory is allocated and the pixel buffer of the instance
10279        image is the same as the one used by the input image \p img.
10280     **/
10281     template<typename t>
10282     CImg(const CImg<t>& img, const bool shared):is_shared(false) {
10283       if (shared)
10284         throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a CImg<%s> instance "
10285                                     "(different pixel types).",
10286                                     pixel_type(),CImg<t>::pixel_type());
10287       const unsigned int siz = img.size();
10288       if (img.data && siz) {
10289         width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
10290         const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
10291       } else { width = height = depth = dim = 0; data = 0; }
10292     }
10293 
10294     CImg(const CImg<T>& img, const bool shared) {
10295       const unsigned int siz = img.size();
10296       if (img.data && siz) {
10297         width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = shared;
10298         if (is_shared) data = const_cast<T*>(img.data);
10299         else { data = new T[siz]; cimg_std::memcpy(data,img.data,siz*sizeof(T)); }
10300       } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
10301     }
10302 
10303     //! Construct an image using dimensions of another image
10304     template<typename t>
10305     CImg(const CImg<t>& img, const char *const dimensions):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10306       assign(img,dimensions);
10307     }
10308 
10309     //! Construct an image using dimensions of another image, and fill it with a default value
10310     template<typename t>
10311     CImg(const CImg<t>& img, const char *const dimensions, const T val):
10312       width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10313       assign(img,dimensions).fill(val);
10314     }
10315 
10316    //! Construct an image from an image file.
10317     /**
10318        This constructor creates an instance image by reading it from a file.
10319        \param filename Filename of the image file.
10320        \remark
10321        - The image format is deduced from the filename only by looking for the filename extension i.e. without
10322        analyzing the file itself.
10323        - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
10324        More informations on this topic can be found in cimg_files_io.
10325        - If the filename is not found, a CImgIOException is thrown by this constructor.
10326     **/
10327     explicit CImg(const char *const filename):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10328       assign(filename);
10329     }
10330 
10331     //! Construct an image from the content of a CImgDisplay instance.
10332     explicit CImg(const CImgDisplay &disp):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10333       disp.snapshot(*this);
10334     }
10335 
10336     //! In-place version of the default constructor/destructor.
10337     /**
10338        This function replaces the instance image by an empty image.
10339        \remark
10340        - Memory used by the previous content of the instance image is freed if necessary.
10341        - If the instance image was initially shared, it is replaced by a (non-shared) empty image.
10342        - This function is useful to free memory used by an image that is not of use, but which
10343        has been created in the current code scope (i.e. not destroyed yet).
10344     **/
10345     CImg<T>& assign() {
10346       if (data && !is_shared) delete[] data;
10347       width = height = depth = dim = 0; is_shared = false; data = 0;
10348       return *this;
10349     }
10350 
10351     //! In-place version of the default constructor.
10352     /**
10353        This function is strictly equivalent to \ref assign() and has been
10354        introduced for having a STL-compliant function name.
10355     **/
10356     CImg<T>& clear() {
10357       return assign();
10358     }
10359 
10360     //! In-place version of the previous constructor.
10361     /**
10362        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.
10363        \param dx Desired size along the X-axis, i.e. the \ref width of the image.
10364        \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
10365        \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
10366        \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
10367        - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the instance image becomes empty
10368        and all has its dimensions set to 0. No memory for pixel data is then allocated.
10369        - Memory buffer used to store previous pixel values is freed if necessary.
10370        - If the instance image is shared, this constructor actually does nothing more than verifying
10371        that new and old image dimensions fit.
10372        - Image pixels allocated by this function are \b not \b initialized.
10373        Use the function assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
10374        to assign an image of desired size with pixels set to a particular value.
10375     **/
10376     CImg<T>& assign(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1) {
10377       const unsigned long siz = dx*dy*dz*dv;
10378       if (!siz) return assign();
10379       const unsigned long curr_siz = size();
10380       if (siz!=curr_siz) {
10381         if (is_shared)
10382           throw CImgArgumentException("CImg<%s>::assign() : Cannot assign image (%u,%u,%u,%u) to shared instance image (%u,%u,%u,%u,%p).",
10383                                       pixel_type(),dx,dy,dz,dv,width,height,depth,dim,data);
10384         else { if (data) delete[] data; data = new T[siz]; }
10385       }
10386       width = dx; height = dy; depth = dz; dim = dv;
10387       return *this;
10388     }
10389 
10390     //! In-place version of the previous constructor.
10391     /**
10392        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
10393        and sets all pixel values of the instance image to \p val.
10394        \param dx Desired size along the X-axis, i.e. the \ref width of the image.
10395        \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
10396        \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
10397        \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
10398        \param val Default value for image pixels.
10399        \remark
10400        - This function has the same properties as assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
10401     **/
10402     CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val) {
10403       return assign(dx,dy,dz,dv).fill(val);
10404     }
10405 
10406     //! In-place version of the previous constructor.
10407     CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10408                     const int val0, const int val1, ...) {
10409       assign(dx,dy,dz,dv);
10410       _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
10411       return *this;
10412     }
10413 
10414     //! In-place version of the previous constructor.
10415     CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10416                     const double val0, const double val1, ...) {
10417       assign(dx,dy,dz,dv);
10418       _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
10419       return *this;
10420     }
10421 
10422     //! In-place version of the previous constructor.
10423     template<typename t>
10424     CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
10425                     const unsigned int dz=1, const unsigned int dv=1) {
10426       const unsigned long siz = dx*dy*dz*dv;
10427       if (!data_buffer || !siz) return assign();
10428       assign(dx,dy,dz,dv);
10429       const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
10430       return *this;
10431     }
10432 
10433 #ifndef cimg_use_visualcpp6
10434     CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
10435                     const unsigned int dz=1, const unsigned int dv=1)
10436 #else
10437     CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
10438                     const unsigned int dz, const unsigned int dv)
10439 #endif
10440     {
10441       const unsigned long siz = dx*dy*dz*dv;
10442       if (!data_buffer || !siz) return assign();
10443       const unsigned long curr_siz = size();
10444       if (data_buffer==data && siz==curr_siz) return assign(dx,dy,dz,dv);
10445       if (is_shared || data_buffer+siz<data || data_buffer>=data+size()) {
10446         assign(dx,dy,dz,dv);
10447         if (is_shared) cimg_std::memmove(data,data_buffer,siz*sizeof(T));
10448         else cimg_std::memcpy(data,data_buffer,siz*sizeof(T));
10449       } else {
10450         T *new_data = new T[siz];
10451         cimg_std::memcpy(new_data,data_buffer,siz*sizeof(T));
10452         delete[] data; data = new_data; width = dx; height = dy; depth = dz; dim = dv;
10453       }
10454       return *this;
10455     }
10456 
10457     //! In-place version of the previous constructor, allowing to force the shared state of the instance image.
10458     template<typename t>
10459     CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy,
10460                     const unsigned int dz, const unsigned int dv, const bool shared) {
10461       if (shared)
10462         throw CImgArgumentException("CImg<%s>::assign() : Cannot assign buffer (%s*) to shared instance image (%u,%u,%u,%u,%p)"
10463                                     "(different pixel types).",
10464                                     pixel_type(),CImg<t>::pixel_type(),width,height,depth,dim,data);
10465       return assign(data_buffer,dx,dy,dz,dv);
10466     }
10467 
10468     CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
10469                     const unsigned int dz, const unsigned int dv, const bool shared) {
10470       const unsigned long siz = dx*dy*dz*dv;
10471       if (!data_buffer || !siz) return assign();
10472       if (!shared) { if (is_shared) assign(); assign(data_buffer,dx,dy,dz,dv); }
10473       else {
10474         if (!is_shared) {
10475           if (data_buffer+siz<data || data_buffer>=data+size()) assign();
10476           else cimg::warn("CImg<%s>::assign() : Shared instance image has overlapping memory !",
10477                           pixel_type());
10478         }
10479         width = dx; height = dy; depth = dz; dim = dv; is_shared = true;
10480         data = const_cast<T*>(data_buffer);
10481       }
10482       return *this;
10483     }
10484 
10485     //! In-place version of the default copy constructor.
10486     /**
10487        This function assigns a copy of the input image \p img to the current instance image.
10488        \param img The input image to copy.
10489        \remark
10490        - If the instance image is not shared, the content of the input image \p img is copied into a new buffer
10491        becoming the new pixel buffer of the instance image, while the old pixel buffer is freed if necessary.
10492        - If the instance image is shared, the content of the input image \p img is copied into the current (shared) pixel buffer
10493        of the instance image, modifying then the image referenced by the shared instance image. The instance image still remains shared.
10494     **/
10495     template<typename t>
10496     CImg<T>& assign(const CImg<t>& img) {
10497       return assign(img.data,img.width,img.height,img.depth,img.dim);
10498     }
10499 
10500     //! In-place version of the advanced constructor.
10501     /**
10502        This function - as the simpler function assign(const CImg< t >&) - assigns a copy of the input image \p img to the
10503        current instance image. But it also decides if the copy is shared (if the input parameter \p shared is set to \c true)
10504        or non-shared (if the input parameter \p shared is set to \c false).
10505        \param img The input image to copy.
10506        \param shared Boolean flag that decides if the copy is shared or non-shared.
10507        \remark
10508        - 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.
10509        - If a non-shared copy of the input image \p img is assigned, a new memory buffer is allocated for pixel data.
10510        - If a shared copy of the input image \p img is assigned, no extra memory is allocated and the pixel buffer of the instance
10511        image is the same as the one used by the input image \p img.
10512     **/
10513     template<typename t>
10514     CImg<T>& assign(const CImg<t>& img, const bool shared) {
10515       return assign(img.data,img.width,img.height,img.depth,img.dim,shared);
10516     }
10517 
10518     //! In-place version of the previous constructor.
10519     template<typename t>
10520     CImg<T>& assign(const CImg<t>& img, const char *const dimensions) {
10521       if (dimensions) {
10522         unsigned int siz[4] = { 0,1,1,1 };
10523         const char *s = dimensions;
10524         char tmp[256] = { 0 }, c = 0;
10525         int val = 0;
10526         for (unsigned int k=0; k<4; ++k) {
10527           const int err = cimg_std::sscanf(s,"%[-0-9]%c",tmp,&c);
10528           if (err>=1) {
10529             const int err = cimg_std::sscanf(s,"%d",&val);
10530             if (err==1) {
10531               int val2 = val<0?-val:(c=='%'?val:-1);
10532               if (val2>=0) {
10533                 val = (int)((k==0?img.width:(k==1?img.height:(k==2?img.depth:img.dim)))*val2/100);
10534                 if (c!='%' && !val) val = 1;
10535               }
10536               siz[k] = val;
10537             }
10538             s+=cimg::strlen(tmp);
10539             if (c=='%') ++s;
10540           }
10541           if (!err) {
10542             if (!cimg::strncasecmp(s,"x",1)) { ++s; siz[k] = img.width; }
10543             else if (!cimg::strncasecmp(s,"y",1)) { ++s; siz[k] = img.height; }
10544             else if (!cimg::strncasecmp(s,"z",1)) { ++s; siz[k] = img.depth; }
10545             else if (!cimg::strncasecmp(s,"v",1)) { ++s; siz[k] = img.dim; }
10546             else if (!cimg::strncasecmp(s,"dx",2)) { s+=2; siz[k] = img.width; }
10547             else if (!cimg::strncasecmp(s,"dy",2)) { s+=2; siz[k] = img.height; }
10548             else if (!cimg::strncasecmp(s,"dz",2)) { s+=2; siz[k] = img.depth; }
10549             else if (!cimg::strncasecmp(s,"dv",2)) { s+=2; siz[k] = img.dim; }
10550             else if (!cimg::strncasecmp(s,"dimx",4)) { s+=4; siz[k] = img.width; }
10551             else if (!cimg::strncasecmp(s,"dimy",4)) { s+=4; siz[k] = img.height; }
10552             else if (!cimg::strncasecmp(s,"dimz",4)) { s+=4; siz[k] = img.depth; }
10553             else if (!cimg::strncasecmp(s,"dimv",4)) { s+=4; siz[k] = img.dim; }
10554             else if (!cimg::strncasecmp(s,"width",5)) { s+=5; siz[k] = img.width; }
10555             else if (!cimg::strncasecmp(s,"height",6)) { s+=6; siz[k] = img.height; }
10556             else if (!cimg::strncasecmp(s,"depth",5)) { s+=5; siz[k] = img.depth; }
10557             else if (!cimg::strncasecmp(s,"dim",3)) { s+=3; siz[k] = img.dim; }
10558             else { ++s; --k; }
10559           }
10560         }
10561         return assign(siz[0],siz[1],siz[2],siz[3]);
10562       }
10563       return assign();
10564     }
10565 
10566     //! In-place version of the previous constructor.
10567     template<typename t>
10568     CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T val) {
10569       return assign(img,dimensions).fill(val);
10570     }
10571 
10572     //! In-place version of the previous constructor.
10573     /**
10574        This function replaces the instance image by the one that have been read from the given file.
10575        \param filename Filename of the image file.
10576        - The image format is deduced from the filename only by looking for the filename extension i.e. without
10577        analyzing the file itself.
10578        - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
10579        More informations on this topic can be found in cimg_files_io.
10580        - If the filename is not found, a CImgIOException is thrown by this constructor.
10581     **/
10582     CImg<T>& assign(const char *const filename) {
10583       return load(filename);
10584     }
10585 
10586     //! In-place version of the previous constructor.
10587     CImg<T>& assign(const CImgDisplay &disp) {
10588       disp.snapshot(*this);
10589       return *this;
10590     }
10591 
10592     //! Transfer the content of the instance image into another one in a way that memory copies are avoided if possible.
10593     /**
10594        The instance image is always empty after a call to this function.
10595     **/
10596     template<typename t>
10597     CImg<t>& transfer_to(CImg<t>& img) {
10598       img.assign(*this);
10599       assign();
10600       return img;
10601     }
10602 
10603     CImg<T>& transfer_to(CImg<T>& img) {
10604       if (is_shared || img.is_shared) { img.assign(*this); assign(); } else { img.assign(); swap(img); }
10605       return img;
10606     }
10607 
10608     //! Swap all fields of two images. Use with care !
10609     CImg<T>& swap(CImg<T>& img) {
10610       cimg::swap(width,img.width);
10611       cimg::swap(height,img.height);
10612       cimg::swap(depth,img.depth);
10613       cimg::swap(dim,img.dim);
10614       cimg::swap(data,img.data);
10615       cimg::swap(is_shared,img.is_shared);
10616       return img;
10617     }
10618 
10619     //@}
10620     //-------------------------------------
10621     //
10622     //! \name Image Informations
10623     //@{
10624     //-------------------------------------
10625 
10626     //! Return the type of the pixel values.
10627     /**
10628        \return a string describing the type of the image pixels (template parameter \p T).
10629        - The string returned may contains spaces (<tt>"unsigned char"</tt>).
10630        - If the template parameter T does not correspond to a registered type, the string <tt>"unknown"</tt> is returned.
10631     **/
10632     static const char* pixel_type() {
10633       return cimg::type<T>::string();
10634     }
10635 
10636     //! Return the total number of pixel values in an image.
10637     /**
10638        - Equivalent to : dimx() * dimy() * dimz() * dimv().
10639 
10640        \par example:
10641        \code
10642        CImg<> img(100,100,1,3);
10643        if (img.size()==100*100*3) std::fprintf(stderr,"This statement is true");
10644        \endcode
10645     **/
10646     unsigned long size() const {
10647       return width*height*depth*dim;
10648     }
10649 
10650     //! Return the number of columns of the instance image (size along the X-axis, i.e image width).
10651     int dimx() const {
10652       return (int)width;
10653     }
10654 
10655     //! Return the number of rows of the instance image (size along the Y-axis, i.e image height).
10656     int dimy() const {
10657       return (int)height;
10658     }
10659 
10660     //! Return the number of slices of the instance image (size along the Z-axis).
10661     int dimz() const {
10662       return (int)depth;
10663     }
10664 
10665     //! Return the number of vector channels of the instance image (size along the V-axis).
10666     int dimv() const {
10667       return (int)dim;
10668     }
10669 
10670     //! Return \c true if image (*this) has the specified width.
10671     bool is_sameX(const unsigned int dx) const {
10672       return (width==dx);
10673     }
10674 
10675     //! Return \c true if images \c (*this) and \c img have same width.
10676     template<typename t>
10677     bool is_sameX(const CImg<t>& img) const {
10678       return is_sameX(img.width);
10679     }
10680 
10681     //! Return \c true if images \c (*this) and the display \c disp have same width.
10682     bool is_sameX(const CImgDisplay& disp) const {
10683       return is_sameX(disp.width);
10684     }
10685 
10686     //! Return \c true if image (*this) has the specified height.
10687     bool is_sameY(const unsigned int dy) const {
10688       return (height==dy);
10689     }
10690 
10691     //! Return \c true if images \c (*this) and \c img have same height.
10692     template<typename t>
10693     bool is_sameY(const CImg<t>& img) const {
10694       return is_sameY(img.height);
10695     }
10696 
10697     //! Return \c true if images \c (*this) and the display \c disp have same height.
10698     bool is_sameY(const CImgDisplay& disp) const {
10699       return is_sameY(disp.height);
10700     }
10701 
10702     //! Return \c true if image (*this) has the specified depth.
10703     bool is_sameZ(const unsigned int dz) const {
10704       return (depth==dz);
10705     }
10706 
10707     //! Return \c true if images \c (*this) and \c img have same depth.
10708     template<typename t>
10709     bool is_sameZ(const CImg<t>& img) const {
10710       return is_sameZ(img.depth);
10711     }
10712 
10713     //! Return \c true if image (*this) has the specified number of channels.
10714     bool is_sameV(const unsigned int dv) const {
10715       return (dim==dv);
10716     }
10717 
10718     //! Return \c true if images \c (*this) and \c img have same dim.
10719     template<typename t>
10720     bool is_sameV(const CImg<t>& img) const {
10721       return is_sameV(img.dim);
10722     }
10723 
10724     //! Return \c true if image (*this) has the specified width and height.
10725     bool is_sameXY(const unsigned int dx, const unsigned int dy) const {
10726       return (is_sameX(dx) && is_sameY(dy));
10727     }
10728 
10729     //! Return \c true if images have same width and same height.
10730     template<typename t>
10731     bool is_sameXY(const CImg<t>& img) const {
10732       return (is_sameX(img) && is_sameY(img));
10733     }
10734 
10735     //! Return \c true if image \c (*this) and the display \c disp have same width and same height.
10736     bool is_sameXY(const CImgDisplay& disp) const {
10737       return (is_sameX(disp) && is_sameY(disp));
10738     }
10739 
10740     //! Return \c true if image (*this) has the specified width and depth.
10741     bool is_sameXZ(const unsigned int dx, const unsigned int dz) const {
10742       return (is_sameX(dx) && is_sameZ(dz));
10743     }
10744 
10745     //! Return \c true if images have same width and same depth.
10746     template<typename t>
10747     bool is_sameXZ(const CImg<t>& img) const {
10748       return (is_sameX(img) && is_sameZ(img));
10749     }
10750 
10751     //! Return \c true if image (*this) has the specified width and number of channels.
10752     bool is_sameXV(const unsigned int dx, const unsigned int dv) const {
10753       return (is_sameX(dx) && is_sameV(dv));
10754     }
10755 
10756     //! Return \c true if images have same width and same number of channels.
10757     template<typename t>
10758     bool is_sameXV(const CImg<t>& img) const {
10759       return (is_sameX(img) && is_sameV(img));
10760     }
10761 
10762     //! Return \c true if image (*this) has the specified height and depth.
10763     bool is_sameYZ(const unsigned int dy, const unsigned int dz) const {
10764       return (is_sameY(dy) && is_sameZ(dz));
10765     }
10766 
10767     //! Return \c true if images have same height and same depth.
10768     template<typename t>
10769     bool is_sameYZ(const CImg<t>& img) const {
10770       return (is_sameY(img) && is_sameZ(img));
10771     }
10772 
10773     //! Return \c true if image (*this) has the specified height and number of channels.
10774     bool is_sameYV(const unsigned int dy, const unsigned int dv) const {
10775       return (is_sameY(dy) && is_sameV(dv));
10776     }
10777 
10778     //! Return \c true if images have same height and same number of channels.
10779     template<typename t>
10780     bool is_sameYV(const CImg<t>& img) const {
10781       return (is_sameY(img) && is_sameV(img));
10782     }
10783 
10784     //! Return \c true if image (*this) has the specified depth and number of channels.
10785     bool is_sameZV(const unsigned int dz, const unsigned int dv) const {
10786       return (is_sameZ(dz) && is_sameV(dv));
10787     }
10788 
10789     //! Return \c true if images have same depth and same number of channels.
10790     template<typename t>
10791     bool is_sameZV(const CImg<t>& img) const {
10792       return (is_sameZ(img) && is_sameV(img));
10793     }
10794 
10795     //! Return \c true if image (*this) has the specified width, height and depth.
10796     bool is_sameXYZ(const unsigned int dx, const unsigned int dy, const unsigned int dz) const {
10797       return (is_sameXY(dx,dy) && is_sameZ(dz));
10798     }
10799 
10800     //! Return \c true if images have same width, same height and same depth.
10801     template<typename t>
10802     bool is_sameXYZ(const CImg<t>& img) const {
10803       return (is_sameXY(img) && is_sameZ(img));
10804     }
10805 
10806     //! Return \c true if image (*this) has the specified width, height and depth.
10807     bool is_sameXYV(const unsigned int dx, const unsigned int dy, const unsigned int dv) const {
10808       return (is_sameXY(dx,dy) && is_sameV(dv));
10809     }
10810 
10811     //! Return \c true if images have same width, same height and same number of channels.
10812     template<typename t>
10813     bool is_sameXYV(const CImg<t>& img) const {
10814       return (is_sameXY(img) && is_sameV(img));
10815     }
10816 
10817     //! Return \c true if image (*this) has the specified width, height and number of channels.
10818     bool is_sameXZV(const unsigned int dx, const unsigned int dz, const unsigned int dv) const {
10819       return (is_sameXZ(dx,dz) && is_sameV(dv));
10820     }
10821 
10822     //! Return \c true if images have same width, same depth and same number of channels.
10823     template<typename t>
10824     bool is_sameXZV(const CImg<t>& img) const {
10825       return (is_sameXZ(img) && is_sameV(img));
10826     }
10827 
10828     //! Return \c true if image (*this) has the specified height, depth and number of channels.
10829     bool is_sameYZV(const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
10830       return (is_sameYZ(dy,dz) && is_sameV(dv));
10831     }
10832 
10833     //! Return \c true if images have same heigth, same depth and same number of channels.
10834     template<typename t>
10835     bool is_sameYZV(const CImg<t>& img) const {
10836       return (is_sameYZ(img) && is_sameV(img));
10837     }
10838 
10839     //! Return \c true if image (*this) has the specified width, height, depth and number of channels.
10840     bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
10841       return (is_sameXYZ(dx,dy,dz) && is_sameV(dv));
10842     }
10843 
10844     //! Return \c true if images \c (*this) and \c img have same width, same height, same depth and same number of channels.
10845     template<typename t>
10846     bool is_sameXYZV(const CImg<t>& img) const {
10847       return (is_sameXYZ(img) && is_sameV(img));
10848     }
10849 
10850     //! Return \c true if current image is empty.
10851     bool is_empty() const {
10852       return !(data && width && height && depth && dim);
10853     }
10854 
10855     //! Return \p true if image is not empty.
10856     operator bool() const {
10857       return !is_empty();
10858     }
10859 
10860     //! Return an iterator to the first image pixel
10861     iterator begin() {
10862       return data;
10863     }
10864 
10865     const_iterator begin() const {
10866       return data;
10867     }
10868 
10869     //! Return reference to the first image pixel
10870     const T& first() const {
10871       return *data;
10872     }
10873 
10874     T& first() {
10875        return *data;
10876     }
10877 
10878     //! Return an iterator pointing after the last image pixel
10879     iterator end() {
10880       return data + size();
10881     }
10882 
10883     const_iterator end() const {
10884       return data + size();
10885     }
10886 
10887     //! Return a reference to the last image pixel
10888     const T& last() const {
10889        return data[size() - 1];
10890     }
10891 
10892     T& last() {
10893        return data[size() - 1];
10894     }
10895 
10896     //! Return a pointer to the pixel buffer.
10897     T* ptr() {
10898       return data;
10899     }
10900 
10901     const T* ptr() const {
10902       return data;
10903     }
10904 
10905     //! Return a pointer to the pixel value located at (\p x,\p y,\p z,\p v).
10906     /**
10907        \param x X-coordinate of the pixel.
10908        \param y Y-coordinate of the pixel.
10909        \param z Z-coordinate of the pixel.
10910        \param v V-coordinate of the pixel.
10911 
10912        - When called without parameters, ptr() returns a pointer to the beginning of the pixel buffer.
10913        - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear if
10914        given coordinates are outside the image range (but function performances decrease).
10915 
10916        \par example:
10917        \code
10918        CImg<float> img(100,100,1,1,0);   // Define a 100x100 greyscale image with float-valued pixels.
10919        float *ptr = ptr(10,10);          // Get a pointer to the pixel located at (10,10).
10920        float val = *ptr;                 // Get the pixel value.
10921        \endcode
10922     **/
10923 #if cimg_debug>=3
10924     T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
10925       const long off = offset(x,y,z,v);
10926       if (off<0 || off>=(long)size()) {
10927         cimg::warn("CImg<%s>::ptr() : Asked for a pointer at coordinates (%u,%u,%u,%u) (offset=%ld), "
10928                    "outside image range (%u,%u,%u,%u) (size=%lu)",
10929                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
10930         return data;
10931       }
10932       return data + off;
10933     }
10934 
10935     const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
10936       return const_cast<CImg<T>*>(this)->ptr(x,y,z,v);
10937     }
10938 #else
10939     T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
10940       return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
10941     }
10942 
10943     const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
10944       return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
10945     }
10946 #endif
10947 
10948     //! Return \c true if the memory buffers of the two images overlaps.
10949     /**
10950        May happen when using shared images.
10951     **/
10952     template<typename t>
10953     bool is_overlapped(const CImg<t>& img) const {
10954       const unsigned long csiz = size(), isiz = img.size();
10955       return !((void*)(data+csiz)<=(void*)img.data || (void*)data>=(void*)(img.data+isiz));
10956     }
10957 
10958     //! Return the offset of the pixel coordinates (\p x,\p y,\p z,\p v) with respect to the data pointer \c data.
10959     /**
10960        \param x X-coordinate of the pixel.
10961        \param y Y-coordinate of the pixel.
10962        \param z Z-coordinate of the pixel.
10963        \param v V-coordinate of the pixel.
10964 
10965        - No checking is done on the validity of the given coordinates.
10966 
10967        \par Example:
10968        \code
10969        CImg<float> img(100,100,1,3,0);         // Define a 100x100 color image with float-valued black pixels.
10970        long off = img.offset(10,10,0,2);       // Get the offset of the blue value of the pixel located at (10,10).
10971        float val = img[off];                   // Get the blue value of the pixel.
10972        \endcode
10973     **/
10974     long offset(const int x, const int y=0, const int z=0, const int v=0) const {
10975       return (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
10976     }
10977 
10978     //! Fast access to pixel value for reading or writing.
10979     /**
10980        \param x X-coordinate of the pixel.
10981        \param y Y-coordinate of the pixel.
10982        \param z Z-coordinate of the pixel.
10983        \param v V-coordinate of the pixel.
10984 
10985        - If one image dimension is equal to 1, it can be omitted in the coordinate list (see example below).
10986        - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
10987        (but function performances decrease).
10988 
10989        \par example:
10990        \code
10991        CImg<float> img(100,100,1,3,0);                       // Define a 100x100 color image with float-valued black pixels.
10992        const float valR = img(10,10,0,0);                    // Read the red component at coordinates (10,10).
10993        const float valG = img(10,10,0,1);                    // Read the green component at coordinates (10,10)
10994        const float valB = img(10,10,2);                      // Read the blue component at coordinates (10,10) (Z-coordinate omitted here).
10995        const float avg = (valR + valG + valB)/3;             // Compute average pixel value.
10996        img(10,10,0) = img(10,10,1) = img(10,10,2) = avg;     // Replace the pixel (10,10) by the average grey value.
10997        \endcode
10998     **/
10999 #if cimg_debug>=3
11000     T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
11001       const long off = offset(x,y,z,v);
11002       if (!data || off>=(long)size()) {
11003         cimg::warn("CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%ld) "
11004                    "outside the image range (%u,%u,%u,%u) (size=%lu)",
11005                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
11006         return *data;
11007       }
11008       else return data[off];
11009     }
11010 
11011     const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
11012       return const_cast<CImg<T>*>(this)->operator()(x,y,z,v);
11013     }
11014 #else
11015     T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
11016       return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
11017     }
11018 
11019     const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
11020       return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
11021     }
11022 #endif
11023 
11024     //! Fast access to pixel value for reading or writing, using an offset to the image pixel.
11025     /**
11026        \param off Offset of the pixel according to the beginning of the pixel buffer, given by ptr().
11027 
11028        - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
11029        (but function performances decrease).
11030        - As pixel values are aligned in memory, this operator can sometime useful to access values easier than
11031        with operator()() (see example below).
11032 
11033        \par example:
11034        \code
11035        CImg<float> vec(1,10);        // Define a vector of float values (10 lines, 1 row).
11036        const float val1 = vec(0,4);  // Get the fifth element using operator()().
11037        const float val2 = vec[4];    // Get the fifth element using operator[]. Here, val2==val1.
11038        \endcode
11039     **/
11040 #if cimg_debug>=3
11041     T& operator[](const unsigned long off) {
11042       if (!data || off>=size()) {
11043         cimg::warn("CImg<%s>::operator[] : Pixel access requested at offset=%lu "
11044                    "outside the image range (%u,%u,%u,%u) (size=%lu)",
11045                    pixel_type(),off,width,height,depth,dim,size());
11046         return *data;
11047       }
11048       else return data[off];
11049     }
11050 
11051     const T& operator[](const unsigned long off) const {
11052       return const_cast<CImg<T>*>(this)->operator[](off);
11053     }
11054 #else
11055     T& operator[](const unsigned long off) {
11056       return data[off];
11057     }
11058 
11059     const T& operator[](const unsigned long off) const {
11060       return data[off];
11061     }
11062 #endif
11063 
11064     //! Return a reference to the last image value
11065     T& back() {
11066       return operator()(size()-1);
11067     }
11068 
11069     const T& back() const {
11070       return operator()(size()-1);
11071     }
11072 
11073     //! Return a reference to the first image value
11074     T& front() {
11075       return *data;
11076     }
11077 
11078     const T& front() const {
11079       return *data;
11080     }
11081 
11082     //! Return \c true if pixel (x,y,z,v) is inside image boundaries.
11083     bool containsXYZV(const int x, const int y=0, const int z=0, const int v=0) const {
11084       return !is_empty() && x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz() && v>=0 && v<dimv();
11085     }
11086 
11087     //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z,v).
11088     template<typename t>
11089     bool contains(const T& pixel, t& x, t& y, t& z, t& v) const {
11090       const unsigned long wh = width*height, whz = wh*depth, siz = whz*dim;
11091       const T *const ppixel = &pixel;
11092       if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
11093       unsigned long off = (unsigned long)(ppixel - data);
11094       const unsigned long nv = off/whz;
11095       off%=whz;
11096       const unsigned long nz = off/wh;
11097       off%=wh;
11098       const unsigned long ny = off/width, nx = off%width;
11099       x = (t)nx; y = (t)ny; z = (t)nz; v = (t)nv;
11100       return true;
11101     }
11102 
11103     //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z).
11104     template<typename t>
11105     bool contains(const T& pixel, t& x, t& y, t& z) const {
11106       const unsigned long wh = width*height, whz = wh*depth, siz = whz*dim;
11107       const T *const ppixel = &pixel;
11108       if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
11109       unsigned long off = ((unsigned long)(ppixel - data))%whz;
11110       const unsigned long nz = off/wh;
11111       off%=wh;
11112       const unsigned long ny = off/width, nx = off%width;
11113       x = (t)nx; y = (t)ny; z = (t)nz;
11114       return true;
11115     }
11116 
11117     //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y).
11118     template<typename t>
11119     bool contains(const T& pixel, t& x, t& y) const {
11120       const unsigned long wh = width*height, siz = wh*depth*dim;
11121       const T *const ppixel = &pixel;
11122       if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
11123       unsigned long off = ((unsigned long)(ppixel - data))%wh;
11124       const unsigned long ny = off/width, nx = off%width;
11125       x = (t)nx; y = (t)ny;
11126       return true;
11127     }
11128 
11129     //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x).
11130     template<typename t>
11131     bool contains(const T& pixel, t& x) const {
11132       const T *const ppixel = &pixel;
11133       if (is_empty() || ppixel<data || ppixel>=data+size()) return false;
11134       x = (t)(((unsigned long)(ppixel - data))%width);
11135       return true;
11136     }
11137 
11138     //! Return \c true if specified referenced value is inside the image boundaries.
11139     bool contains(const T& pixel) const {
11140       const T *const ppixel = &pixel;
11141       return !is_empty() && ppixel>=data && ppixel<data+size();
11142     }
11143 
11144     //! Read a pixel value with Dirichlet boundary conditions.
11145     T& at(const int off, const T out_val) {
11146       return (off<0 || off>=(int)size())?(cimg::temporary(out_val)=out_val):(*this)[off];
11147     }
11148 
11149     T at(const int off, const T out_val) const {
11150       return (off<0 || off>=(int)size())?out_val:(*this)[off];
11151     }
11152 
11153     //! Read a pixel value with Neumann boundary conditions.
11154     T& at(const int off) {
11155       if (!size())
11156         throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
11157                                     pixel_type());
11158       return _at(off);
11159     }
11160 
11161     T at(const int off) const {
11162       if (!size())
11163         throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
11164                                     pixel_type());
11165       return _at(off);
11166     }
11167 
11168     T& _at(const int off) {
11169       const unsigned int siz = (unsigned int)size();
11170       return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
11171     }
11172 
11173     T _at(const int off) const {
11174       const unsigned int siz = (unsigned int)size();
11175       return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
11176     }
11177 
11178     //! Read a pixel value with Dirichlet boundary conditions.
11179     T& atXYZV(const int x, const int y, const int z, const int v, const T out_val) {
11180       return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?
11181         (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11182     }
11183 
11184     T atXYZV(const int x, const int y, const int z, const int v, const T out_val) const {
11185       return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v);
11186     }
11187 
11188     //! Read a pixel value with Neumann boundary conditions.
11189     T& atXYZV(const int x, const int y, const int z, const int v) {
11190       if (is_empty())
11191         throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
11192                                     pixel_type());
11193       return _atXYZV(x,y,z,v);
11194     }
11195 
11196     T atXYZV(const int x, const int y, const int z, const int v) const {
11197       if (is_empty())
11198         throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
11199                                     pixel_type());
11200       return _atXYZV(x,y,z,v);
11201     }
11202 
11203     T& _atXYZV(const int x, const int y, const int z, const int v) {
11204       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
11205                      z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
11206     }
11207 
11208     T _atXYZV(const int x, const int y, const int z, const int v) const {
11209       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
11210                      z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
11211     }
11212 
11213     //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c x,\c y,\c z).
11214     T& atXYZ(const int x, const int y, const int z, const int v, const T out_val) {
11215       return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?
11216         (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11217     }
11218 
11219     T atXYZ(const int x, const int y, const int z, const int v, const T out_val) const {
11220       return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v);
11221     }
11222 
11223     //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c x,\c y,\c z).
11224     T& atXYZ(const int x, const int y, const int z, const int v=0) {
11225       if (is_empty())
11226         throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
11227                                     pixel_type());
11228       return _atXYZ(x,y,z,v);
11229     }
11230 
11231     T atXYZ(const int x, const int y, const int z, const int v=0) const {
11232       if (is_empty())
11233         throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
11234                                     pixel_type());
11235       return _atXYZ(x,y,z,v);
11236     }
11237 
11238     T& _atXYZ(const int x, const int y, const int z, const int v=0) {
11239       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
11240                      z<0?0:(z>=dimz()?dimz()-1:z),v);
11241     }
11242 
11243     T _atXYZ(const int x, const int y, const int z, const int v=0) const {
11244       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
11245                      z<0?0:(z>=dimz()?dimz()-1:z),v);
11246     }
11247 
11248     //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c x,\c y).
11249     T& atXY(const int x, const int y, const int z, const int v, const T out_val) {
11250       return (x<0 || y<0 || x>=dimx() || y>=dimy())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11251     }
11252 
11253     T atXY(const int x, const int y, const int z, const int v, const T out_val) const {
11254       return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v);
11255     }
11256 
11257     //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c x,\c y).
11258     T& atXY(const int x, const int y, const int z=0, const int v=0) {
11259       if (is_empty())
11260         throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
11261                                     pixel_type());
11262       return _atXY(x,y,z,v);
11263     }
11264 
11265     T atXY(const int x, const int y, const int z=0, const int v=0) const {
11266       if (is_empty())
11267         throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
11268                                     pixel_type());
11269       return _atXY(x,y,z,v);
11270     }
11271 
11272     T& _atXY(const int x, const int y, const int z=0, const int v=0) {
11273       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
11274     }
11275 
11276     T _atXY(const int x, const int y, const int z=0, const int v=0) const {
11277       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
11278     }
11279 
11280     //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c x).
11281     T& atX(const int x, const int y, const int z, const int v, const T out_val) {
11282       return (x<0 || x>=dimx())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11283     }
11284 
11285     T atX(const int x, const int y, const int z, const int v, const T out_val) const {
11286       return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v);
11287     }
11288 
11289     //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c x).
11290     T& atX(const int x, const int y=0, const int z=0, const int v=0) {
11291       if (is_empty())
11292         throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
11293                                     pixel_type());
11294       return _atX(x,y,z,v);
11295     }
11296 
11297     T atX(const int x, const int y=0, const int z=0, const int v=0) const {
11298       if (is_empty())
11299         throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
11300                                     pixel_type());
11301       return _atX(x,y,z,v);
11302     }
11303 
11304     T& _atX(const int x, const int y=0, const int z=0, const int v=0) {
11305       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
11306     }
11307 
11308     T _atX(const int x, const int y=0, const int z=0, const int v=0) const {
11309       return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
11310     }
11311 
11312     //! Read a pixel value using linear interpolation and Dirichlet boundary conditions.
11313     Tfloat linear_atXYZV(const float fx, const float fy, const float fz, const float fv, const T out_val) const {
11314       const int
11315         x = (int)fx-(fx>=0?0:1), nx = x+1,
11316         y = (int)fy-(fy>=0?0:1), ny = y+1,
11317         z = (int)fz-(fz>=0?0:1), nz = z+1,
11318         v = (int)fv-(fv>=0?0:1), nv = v+1;
11319       const float
11320         dx = fx-x,
11321         dy = fy-y,
11322         dz = fz-z,
11323         dv = fv-v;
11324       const Tfloat
11325         Icccc = (Tfloat)atXYZV(x,y,z,v,out_val), Inccc = (Tfloat)atXYZV(nx,y,z,v,out_val),
11326         Icncc = (Tfloat)atXYZV(x,ny,z,v,out_val), Inncc = (Tfloat)atXYZV(nx,ny,z,v,out_val),
11327         Iccnc = (Tfloat)atXYZV(x,y,nz,v,out_val), Incnc = (Tfloat)atXYZV(nx,y,nz,v,out_val),
11328         Icnnc = (Tfloat)atXYZV(x,ny,nz,v,out_val), Innnc = (Tfloat)atXYZV(nx,ny,nz,v,out_val),
11329         Icccn = (Tfloat)atXYZV(x,y,z,nv,out_val), Inccn = (Tfloat)atXYZV(nx,y,z,nv,out_val),
11330         Icncn = (Tfloat)atXYZV(x,ny,z,nv,out_val), Inncn = (Tfloat)atXYZV(nx,ny,z,nv,out_val),
11331         Iccnn = (Tfloat)atXYZV(x,y,nz,nv,out_val), Incnn = (Tfloat)atXYZV(nx,y,nz,nv,out_val),
11332         Icnnn = (Tfloat)atXYZV(x,ny,nz,nv,out_val), Innnn = (Tfloat)atXYZV(nx,ny,nz,nv,out_val);
11333       return Icccc +
11334         dx*(Inccc-Icccc +
11335             dy*(Icccc+Inncc-Icncc-Inccc +
11336                 dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
11337                     dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
11338                 dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
11339             dz*(Icccc+Incnc-Iccnc-Inccc +
11340                 dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
11341             dv*(Icccc+Inccn-Inccc-Icccn)) +
11342         dy*(Icncc-Icccc +
11343             dz*(Icccc+Icnnc-Iccnc-Icncc +
11344                 dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
11345             dv*(Icccc+Icncn-Icncc-Icccn)) +
11346         dz*(Iccnc-Icccc +
11347             dv*(Icccc+Iccnn-Iccnc-Icccn)) +
11348         dv*(Icccn-Icccc);
11349     }
11350 
11351     //! Read a pixel value using linear interpolation and Neumann boundary conditions.
11352     Tfloat linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
11353       if (is_empty())
11354         throw CImgInstanceException("CImg<%s>::linear_atXYZV() : Instance image is empty.",
11355                                     pixel_type());
11356       return _linear_atXYZV(fx,fy,fz,fv);
11357     }
11358 
11359     Tfloat _linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
11360       const float
11361         nfx = fx<0?0:(fx>width-1?width-1:fx),
11362         nfy = fy<0?0:(fy>height-1?height-1:fy),
11363         nfz = fz<0?0:(fz>depth-1?depth-1:fz),
11364         nfv = fv<0?0:(fv>dim-1?dim-1:fv);
11365       const unsigned int
11366         x = (unsigned int)nfx,
11367         y = (unsigned int)nfy,
11368         z = (unsigned int)nfz,
11369         v = (unsigned int)nfv;
11370       const float
11371         dx = nfx-x,
11372         dy = nfy-y,
11373         dz = nfz-z,
11374         dv = nfv-v;
11375       const unsigned int
11376         nx = dx>0?x+1:x,
11377         ny = dy>0?y+1:y,
11378         nz = dz>0?z+1:z,
11379         nv = dv>0?v+1:v;
11380       const Tfloat
11381         Icccc = (Tfloat)(*this)(x,y,z,v), Inccc = (Tfloat)(*this)(nx,y,z,v),
11382         Icncc = (Tfloat)(*this)(x,ny,z,v), Inncc = (Tfloat)(*this)(nx,ny,z,v),
11383         Iccnc = (Tfloat)(*this)(x,y,nz,v), Incnc = (Tfloat)(*this)(nx,y,nz,v),
11384         Icnnc = (Tfloat)(*this)(x,ny,nz,v), Innnc = (Tfloat)(*this)(nx,ny,nz,v),
11385         Icccn = (Tfloat)(*this)(x,y,z,nv), Inccn = (Tfloat)(*this)(nx,y,z,nv),
11386         Icncn = (Tfloat)(*this)(x,ny,z,nv), Inncn = (Tfloat)(*this)(nx,ny,z,nv),
11387         Iccnn = (Tfloat)(*this)(x,y,nz,nv), Incnn = (Tfloat)(*this)(nx,y,nz,nv),
11388         Icnnn = (Tfloat)(*this)(x,ny,nz,nv), Innnn = (Tfloat)(*this)(nx,ny,nz,nv);
11389       return Icccc +
11390         dx*(Inccc-Icccc +
11391             dy*(Icccc+Inncc-Icncc-Inccc +
11392                 dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
11393                     dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
11394                 dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
11395             dz*(Icccc+Incnc-Iccnc-Inccc +
11396                 dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
11397             dv*(Icccc+Inccn-Inccc-Icccn)) +
11398         dy*(Icncc-Icccc +
11399             dz*(Icccc+Icnnc-Iccnc-Icncc +
11400                 dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
11401             dv*(Icccc+Icncn-Icncc-Icccn)) +
11402         dz*(Iccnc-Icccc +
11403             dv*(Icccc+Iccnn-Iccnc-Icccn)) +
11404         dv*(Icccn-Icccc);
11405     }
11406 
11407     //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first three coordinates).
11408     Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int v, const T out_val) const {
11409       const int
11410         x = (int)fx-(fx>=0?0:1), nx = x+1,
11411         y = (int)fy-(fy>=0?0:1), ny = y+1,
11412         z = (int)fz-(fz>=0?0:1), nz = z+1;
11413       const float
11414         dx = fx-x,
11415         dy = fy-y,
11416         dz = fz-z;
11417       const Tfloat
11418         Iccc = (Tfloat)atXYZ(x,y,z,v,out_val), Incc = (Tfloat)atXYZ(nx,y,z,v,out_val),
11419         Icnc = (Tfloat)atXYZ(x,ny,z,v,out_val), Innc = (Tfloat)atXYZ(nx,ny,z,v,out_val),
11420         Iccn = (Tfloat)atXYZ(x,y,nz,v,out_val), Incn = (Tfloat)atXYZ(nx,y,nz,v,out_val),
11421         Icnn = (Tfloat)atXYZ(x,ny,nz,v,out_val), Innn = (Tfloat)atXYZ(nx,ny,nz,v,out_val);
11422       return Iccc +
11423         dx*(Incc-Iccc +
11424             dy*(Iccc+Innc-Icnc-Incc +
11425                 dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
11426             dz*(Iccc+Incn-Iccn-Incc)) +
11427         dy*(Icnc-Iccc +
11428             dz*(Iccc+Icnn-Iccn-Icnc)) +
11429         dz*(Iccn-Iccc);
11430     }
11431 
11432     //! Read a pixel value using linear interpolation and Neumann boundary conditions (first three coordinates).
11433     Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
11434       if (is_empty())
11435         throw CImgInstanceException("CImg<%s>::linear_atXYZ() : Instance image is empty.",
11436                                     pixel_type());
11437       return _linear_atXYZ(fx,fy,fz,v);
11438     }
11439 
11440     Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
11441       const float
11442         nfx = fx<0?0:(fx>width-1?width-1:fx),
11443         nfy = fy<0?0:(fy>height-1?height-1:fy),
11444         nfz = fz<0?0:(fz>depth-1?depth-1:fz);
11445       const unsigned int
11446         x = (unsigned int)nfx,
11447         y = (unsigned int)nfy,
11448         z = (unsigned int)nfz;
11449       const float
11450         dx = nfx-x,
11451         dy = nfy-y,
11452         dz = nfz-z;
11453       const unsigned int
11454         nx = dx>0?x+1:x,
11455         ny = dy>0?y+1:y,
11456         nz = dz>0?z+1:z;
11457       const Tfloat
11458         Iccc = (Tfloat)(*this)(x,y,z,v), Incc = (Tfloat)(*this)(nx,y,z,v),
11459         Icnc = (Tfloat)(*this)(x,ny,z,v), Innc = (Tfloat)(*this)(nx,ny,z,v),
11460         Iccn = (Tfloat)(*this)(x,y,nz,v), Incn = (Tfloat)(*this)(nx,y,nz,v),
11461         Icnn = (Tfloat)(*this)(x,ny,nz,v), Innn = (Tfloat)(*this)(nx,ny,nz,v);
11462       return Iccc +
11463         dx*(Incc-Iccc +
11464             dy*(Iccc+Innc-Icnc-Incc +
11465                 dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
11466             dz*(Iccc+Incn-Iccn-Incc)) +
11467         dy*(Icnc-Iccc +
11468             dz*(Iccc+Icnn-Iccn-Icnc)) +
11469         dz*(Iccn-Iccc);
11470     }
11471 
11472     //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first two coordinates).
11473     Tfloat linear_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
11474       const int
11475         x = (int)fx-(fx>=0?0:1), nx = x+1,
11476         y = (int)fy-(fy>=0?0:1), ny = y+1;
11477       const float
11478         dx = fx-x,
11479         dy = fy-y;
11480       const Tfloat
11481         Icc = (Tfloat)atXY(x,y,z,v,out_val),  Inc = (Tfloat)atXY(nx,y,z,v,out_val),
11482         Icn = (Tfloat)atXY(x,ny,z,v,out_val), Inn = (Tfloat)atXY(nx,ny,z,v,out_val);
11483       return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
11484     }
11485 
11486     //! Read a pixel value using linear interpolation and Neumann boundary conditions (first two coordinates).
11487     Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11488       if (is_empty())
11489         throw CImgInstanceException("CImg<%s>::linear_atXY() : Instance image is empty.",
11490                                     pixel_type());
11491       return _linear_atXY(fx,fy,z,v);
11492     }
11493 
11494     Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11495       const float
11496         nfx = fx<0?0:(fx>width-1?width-1:fx),
11497         nfy = fy<0?0:(fy>height-1?height-1:fy);
11498       const unsigned int
11499         x = (unsigned int)nfx,
11500         y = (unsigned int)nfy;
11501       const float
11502         dx = nfx-x,
11503         dy = nfy-y;
11504       const unsigned int
11505         nx = dx>0?x+1:x,
11506         ny = dy>0?y+1:y;
11507       const Tfloat
11508         Icc = (Tfloat)(*this)(x,y,z,v),  Inc = (Tfloat)(*this)(nx,y,z,v),
11509         Icn = (Tfloat)(*this)(x,ny,z,v), Inn = (Tfloat)(*this)(nx,ny,z,v);
11510       return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
11511     }
11512 
11513     //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first coordinate).
11514     Tfloat linear_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
11515       const int
11516         x = (int)fx-(fx>=0?0:1), nx = x+1;
11517       const float
11518         dx = fx-x;
11519       const Tfloat
11520         Ic = (Tfloat)atX(x,y,z,v,out_val), In = (Tfloat)atXY(nx,y,z,v,out_val);
11521       return Ic + dx*(In-Ic);
11522     }
11523 
11524     //! Read a pixel value using linear interpolation and Neumann boundary conditions (first coordinate).
11525     Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11526       if (is_empty())
11527         throw CImgInstanceException("CImg<%s>::linear_atX() : Instance image is empty.",
11528                                     pixel_type());
11529       return _linear_atX(fx,y,z,v);
11530     }
11531 
11532     Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11533       const float
11534         nfx = fx<0?0:(fx>width-1?width-1:fx);
11535       const unsigned int
11536         x = (unsigned int)nfx;
11537       const float
11538         dx = nfx-x;
11539       const unsigned int
11540         nx = dx>0?x+1:x;
11541       const Tfloat
11542         Ic = (Tfloat)(*this)(x,y,z,v), In = (Tfloat)(*this)(nx,y,z,v);
11543       return Ic + dx*(In-Ic);
11544     }
11545 
11546     //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions.
11547     Tfloat cubic_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
11548       const int
11549         x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2,
11550         y = (int)fy-(fy>=0?0:1), py = y-1, ny = y+1, ay = y+2;
11551       const float
11552         dx = fx-x, dx2 = dx*dx, dx3 = dx2*dx,
11553         dy = fy-y;
11554       const Tfloat
11555         Ipp = (Tfloat)atXY(px,py,z,v,out_val), Icp = (Tfloat)atXY(x,py,z,v,out_val),
11556         Inp = (Tfloat)atXY(nx,py,z,v,out_val), Iap = (Tfloat)atXY(ax,py,z,v,out_val),
11557         Ipc = (Tfloat)atXY(px,y,z,v,out_val),  Icc = (Tfloat)atXY(x,y,z,v,out_val),
11558         Inc = (Tfloat)atXY(nx,y,z,v,out_val),  Iac = (Tfloat)atXY(ax,y,z,v,out_val),
11559         Ipn = (Tfloat)atXY(px,ny,z,v,out_val), Icn = (Tfloat)atXY(x,ny,z,v,out_val),
11560         Inn = (Tfloat)atXY(nx,ny,z,v,out_val), Ian = (Tfloat)atXY(ax,ny,z,v,out_val),
11561         Ipa = (Tfloat)atXY(px,ay,z,v,out_val), Ica = (Tfloat)atXY(x,ay,z,v,out_val),
11562         Ina = (Tfloat)atXY(nx,ay,z,v,out_val), Iaa = (Tfloat)atXY(ax,ay,z,v,out_val),
11563         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)),
11564         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)),
11565         u0p = Icp - Ipp,
11566         u1p = Iap - Inp,
11567         ap = 2*(Icp-Inp) + u0p + u1p,
11568         bp = 3*(Inp-Icp) - 2*u0p - u1p,
11569         u0c = Icc - Ipc,
11570         u1c = Iac - Inc,
11571         ac = 2*(Icc-Inc) + u0c + u1c,
11572         bc = 3*(Inc-Icc) - 2*u0c - u1c,
11573         u0n = Icn - Ipn,
11574         u1n = Ian - Inn,
11575         an = 2*(Icn-Inn) + u0n + u1n,
11576         bn = 3*(Inn-Icn) - 2*u0n - u1n,
11577         u0a = Ica - Ipa,
11578         u1a = Iaa - Ina,
11579         aa = 2*(Ica-Ina) + u0a + u1a,
11580         ba = 3*(Ina-Ica) - 2*u0a - u1a,
11581         valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
11582         valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
11583         valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
11584         vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
11585         u0 = valc - valp,
11586         u1 = vala - valn,
11587         a = 2*(valc-valn) + u0 + u1,
11588         b = 3*(valn-valc) - 2*u0 - u1,
11589         val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
11590       return val<valm?valm:(val>valM?valM:val);
11591     }
11592 
11593     //! Read a pixel value using cubic interpolation and Neumann boundary conditions.
11594     Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11595       if (is_empty())
11596         throw CImgInstanceException("CImg<%s>::cubic_atXY() : Instance image is empty.",
11597                                     pixel_type());
11598       return _cubic_atXY(fx,fy,z,v);
11599     }
11600 
11601     Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11602       const float
11603         nfx = fx<0?0:(fx>width-1?width-1:fx),
11604         nfy = fy<0?0:(fy>height-1?height-1:fy);
11605       const int
11606         x = (int)nfx,
11607         y = (int)nfy;
11608       const float
11609         dx = nfx-x, dx2 = dx*dx, dx3 = dx2*dx,
11610         dy = nfy-y;
11611       const int
11612         px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2,
11613         py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=dimy()?dimy()-1:y+2;
11614       const Tfloat
11615         Ipp = (Tfloat)(*this)(px,py,z,v), Icp = (Tfloat)(*this)(x,py,z,v),
11616         Inp = (Tfloat)(*this)(nx,py,z,v), Iap = (Tfloat)(*this)(ax,py,z,v),
11617         Ipc = (Tfloat)(*this)(px,y,z,v),  Icc = (Tfloat)(*this)(x,y,z,v),
11618         Inc = (Tfloat)(*this)(nx,y,z,v),  Iac = (Tfloat)(*this)(ax,y,z,v),
11619         Ipn = (Tfloat)(*this)(px,ny,z,v), Icn = (Tfloat)(*this)(x,ny,z,v),
11620         Inn = (Tfloat)(*this)(nx,ny,z,v), Ian = (Tfloat)(*this)(ax,ny,z,v),
11621         Ipa = (Tfloat)(*this)(px,ay,z,v), Ica = (Tfloat)(*this)(x,ay,z,v),
11622         Ina = (Tfloat)(*this)(nx,ay,z,v), Iaa = (Tfloat)(*this)(ax,ay,z,v),
11623         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)),
11624         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)),
11625         u0p = Icp - Ipp,
11626         u1p = Iap - Inp,
11627         ap = 2*(Icp-Inp) + u0p + u1p,
11628         bp = 3*(Inp-Icp) - 2*u0p - u1p,
11629         u0c = Icc - Ipc,
11630         u1c = Iac - Inc,
11631         ac = 2*(Icc-Inc) + u0c + u1c,
11632         bc = 3*(Inc-Icc) - 2*u0c - u1c,
11633         u0n = Icn - Ipn,
11634         u1n = Ian - Inn,
11635         an = 2*(Icn-Inn) + u0n + u1n,
11636         bn = 3*(Inn-Icn) - 2*u0n - u1n,
11637         u0a = Ica - Ipa,
11638         u1a = Iaa - Ina,
11639         aa = 2*(Ica-Ina) + u0a + u1a,
11640         ba = 3*(Ina-Ica) - 2*u0a - u1a,
11641         valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
11642         valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
11643         valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
11644         vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
11645         u0 = valc - valp,
11646         u1 = vala - valn,
11647         a = 2*(valc-valn) + u0 + u1,
11648         b = 3*(valn-valc) - 2*u0 - u1,
11649         val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
11650       return val<valm?valm:(val>valM?valM:val);
11651     }
11652 
11653     //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions (first coordinates).
11654     Tfloat cubic_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
11655       const int
11656         x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2;
11657       const float
11658         dx = fx-x;
11659       const Tfloat
11660         Ip = (Tfloat)atX(px,y,z,v,out_val), Ic = (Tfloat)atX(x,y,z,v,out_val),
11661         In = (Tfloat)atX(nx,y,z,v,out_val), Ia = (Tfloat)atX(ax,y,z,v,out_val),
11662         valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
11663         u0 = Ic - Ip,
11664         u1 = Ia - In,
11665         a = 2*(Ic-In) + u0 + u1,
11666         b = 3*(In-Ic) - 2*u0 - u1,
11667         val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
11668       return val<valm?valm:(val>valM?valM:val);
11669     }
11670 
11671     //! Read a pixel value using cubic interpolation and Neumann boundary conditions (first coordinates).
11672     Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11673       if (is_empty())
11674         throw CImgInstanceException("CImg<%s>::cubic_atX() : Instance image is empty.",
11675                                     pixel_type());
11676       return _cubic_atX(fx,y,z,v);
11677     }
11678 
11679     Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11680       const float
11681         nfx = fx<0?0:(fx>width-1?width-1:fx);
11682       const int
11683         x = (int)nfx;
11684       const float
11685         dx = nfx-x;
11686       const int
11687         px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2;
11688       const Tfloat
11689         Ip = (Tfloat)(*this)(px,y,z,v), Ic = (Tfloat)(*this)(x,y,z,v),
11690         In = (Tfloat)(*this)(nx,y,z,v), Ia = (Tfloat)(*this)(ax,y,z,v),
11691         valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
11692         u0 = Ic - Ip,
11693         u1 = Ia - In,
11694         a = 2*(Ic-In) + u0 + u1,
11695         b = 3*(In-Ic) - 2*u0 - u1,
11696         val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
11697       return val<valm?valm:(val>valM?valM:val);
11698     }
11699 
11700     //! Set a pixel value, with 3D float coordinates, using linear interpolation.
11701     CImg& set_linear_atXYZ(const T& val, const float fx, const float fy=0, const float fz=0, const int v=0,
11702                            const bool add=false) {
11703       const int
11704         x = (int)fx-(fx>=0?0:1), nx = x+1,
11705         y = (int)fy-(fy>=0?0:1), ny = y+1,
11706         z = (int)fz-(fz>=0?0:1), nz = z+1;
11707       const float
11708         dx = fx-x,
11709         dy = fy-y,
11710         dz = fz-z;
11711       if (v>=0 && v<dimv()) {
11712         if (z>=0 && z<dimz()) {
11713           if (y>=0 && y<dimy()) {
11714             if (x>=0 && x<dimx()) {
11715               const float w1 = (1-dx)*(1-dy)*(1-dz), w2 = add?1:(1-w1);
11716               (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
11717             }
11718             if (nx>=0 && nx<dimx()) {
11719               const float w1 = dx*(1-dy)*(1-dz), w2 = add?1:(1-w1);
11720               (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
11721             }
11722           }
11723           if (ny>=0 && ny<dimy()) {
11724             if (x>=0 && x<dimx()) {
11725               const float w1 = (1-dx)*dy*(1-dz), w2 = add?1:(1-w1);
11726               (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
11727             }
11728             if (nx>=0 && nx<dimx()) {
11729               const float w1 = dx*dy*(1-dz), w2 = add?1:(1-w1);
11730               (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
11731             }
11732           }
11733         }
11734         if (nz>=0 && nz<dimz()) {
11735           if (y>=0 && y<dimy()) {
11736             if (x>=0 && x<dimx()) {
11737               const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
11738               (*this)(x,y,nz,v) = (T)(w1*val + w2*(*this)(x,y,nz,v));
11739             }
11740             if (nx>=0 && nx<dimx()) {
11741               const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
11742               (*this)(nx,y,nz,v) = (T)(w1*val + w2*(*this)(nx,y,nz,v));
11743             }
11744           }
11745           if (ny>=0 && ny<dimy()) {
11746             if (x>=0 && x<dimx()) {
11747               const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
11748               (*this)(x,ny,nz,v) = (T)(w1*val + w2*(*this)(x,ny,nz,v));
11749             }
11750             if (nx>=0 && nx<dimx()) {
11751               const float w1 = dx*dy, w2 = add?1:(1-w1);
11752               (*this)(nx,ny,nz,v) = (T)(w1*val + w2*(*this)(nx,ny,nz,v));
11753             }
11754           }
11755         }
11756       }
11757       return *this;
11758     }
11759 
11760     //! Set a pixel value, with 2D float coordinates, using linear interpolation.
11761     CImg& set_linear_atXY(const T& val, const float fx, const float fy=0, const int z=0, const int v=0,
11762                           const bool add=false) {
11763       const int
11764         x = (int)fx-(fx>=0?0:1), nx = x+1,
11765         y = (int)fy-(fy>=0?0:1), ny = y+1;
11766       const float
11767         dx = fx-x,
11768         dy = fy-y;
11769       if (z>=0 && z<dimz() && v>=0 && v<dimv()) {
11770         if (y>=0 && y<dimy()) {
11771           if (x>=0 && x<dimx()) {
11772             const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
11773             (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
11774           }
11775           if (nx>=0 && nx<dimx()) {
11776             const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
11777             (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
11778           }
11779         }
11780         if (ny>=0 && ny<dimy()) {
11781           if (x>=0 && x<dimx()) {
11782             const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
11783             (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
11784           }
11785           if (nx>=0 && nx<dimx()) {
11786             const float w1 = dx*dy, w2 = add?1:(1-w1);
11787             (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
11788           }
11789         }
11790       }
11791       return *this;
11792     }
11793 
11794     //! Return a reference to the minimum pixel value of the instance image
11795     const T& min() const {
11796       if (is_empty())
11797         throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",
11798                                     pixel_type());
11799       const T *ptrmin = data;
11800       T min_value = *ptrmin;
11801       cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
11802       return *ptrmin;
11803     }
11804 
11805     //! Return a reference to the minimum pixel value of the instance image
11806     T& min() {
11807       if (is_empty())
11808         throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",
11809                                     pixel_type());
11810       T *ptrmin = data;
11811       T min_value = *ptrmin;
11812       cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
11813       return *ptrmin;
11814     }
11815 
11816     //! Return a reference to the maximum pixel value of the instance image
11817     const T& max() const {
11818       if (is_empty())
11819         throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",
11820                                     pixel_type());
11821       const T *ptrmax = data;
11822       T max_value = *ptrmax;
11823       cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
11824       return *ptrmax;
11825     }
11826 
11827     //! Return a reference to the maximum pixel value of the instance image
11828     T& max() {
11829       if (is_empty())
11830         throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",
11831                                     pixel_type());
11832       T *ptrmax = data;
11833       T max_value = *ptrmax;
11834       cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
11835       return *ptrmax;
11836     }
11837 
11838     //! Return a reference to the minimum pixel value and return also the maximum pixel value.
11839     template<typename t>
11840     const T& minmax(t& max_val) const {
11841       if (is_empty())
11842         throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",
11843                                     pixel_type());
11844       const T *ptrmin = data;
11845       T min_value = *ptrmin, max_value = min_value;
11846       cimg_for(*this,ptr,T) {
11847         const T val = *ptr;
11848         if (val<min_value) { min_value = val; ptrmin = ptr; }
11849         if (val>max_value) max_value = val;
11850       }
11851       max_val = (t)max_value;
11852       return *ptrmin;
11853     }
11854 
11855     //! Return a reference to the minimum pixel value and return also the maximum pixel value.
11856     template<typename t>
11857     T& minmax(t& max_val) {
11858       if (is_empty())
11859         throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",
11860                                     pixel_type());
11861       T *ptrmin = data;
11862       T min_value = *ptrmin, max_value = min_value;
11863       cimg_for(*this,ptr,T) {
11864         const T val = *ptr;
11865         if (val<min_value) { min_value = val; ptrmin = ptr; }
11866         if (val>max_value) max_value = val;
11867       }
11868       max_val = (t)max_value;
11869       return *ptrmin;
11870     }
11871 
11872     //! Return a reference to the maximum pixel value and return also the minimum pixel value.
11873     template<typename t>
11874     const T& maxmin(t& min_val) const {
11875       if (is_empty())
11876         throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",
11877                                     pixel_type());
11878       const T *ptrmax = data;
11879       T max_value = *ptrmax, min_value = max_value;
11880       cimg_for(*this,ptr,T) {
11881         const T val = *ptr;
11882         if (val>max_value) { max_value = val; ptrmax = ptr; }
11883         if (val<min_value) min_value = val;
11884       }
11885       min_val = (t)min_value;
11886       return *ptrmax;
11887     }
11888 
11889     //! Return a reference to the maximum pixel value and return also the minimum pixel value.
11890     template<typename t>
11891     T& maxmin(t& min_val) {
11892       if (is_empty())
11893         throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",
11894                                     pixel_type());
11895       T *ptrmax = data;
11896       T max_value = *ptrmax, min_value = max_value;
11897       cimg_for(*this,ptr,T) {
11898         const T val = *ptr;
11899         if (val>max_value) { max_value = val; ptrmax = ptr; }
11900         if (val<min_value) min_value = val;
11901       }
11902       min_val = (t)min_value;
11903       return *ptrmax;
11904     }
11905 
11906     //! Return the sum of all the pixel values in an image.
11907     Tfloat sum() const {
11908       if (is_empty())
11909         throw CImgInstanceException("CImg<%s>::sum() : Instance image (%u,%u,%u,%u,%p) is empty.",
11910                                                   pixel_type(),width,height,depth,dim,data);
11911       Tfloat res = 0;
11912       cimg_for(*this,ptr,T) res+=*ptr;
11913       return res;
11914     }
11915 
11916     //! Return the mean pixel value of the instance image.
11917     Tfloat mean() const {
11918       if (is_empty())
11919         throw CImgInstanceException("CImg<%s>::mean() : Instance image is empty.",
11920                                     pixel_type());
11921       Tfloat val = 0;
11922       cimg_for(*this,ptr,T) val+=*ptr;
11923       return val/size();
11924     }
11925 
11926     //! Return the variance of the image.
11927     /**
11928        @param variance_method Determines how to calculate the variance
11929        <table border="0">
11930        <tr><td>0</td>
11931        <td>Second moment:
11932        @f$ v = 1/N \sum\limits_{k=1}^{N} (x_k - \bar x)^2
11933        = 1/N \left( \sum\limits_{k=1}^N x_k^2 - \left( \sum\limits_{k=1}^N x_k \right)^2 / N \right) @f$
11934        with @f$ \bar x = 1/N \sum\limits_{k=1}^N x_k \f$</td></tr>
11935        <tr><td>1</td>
11936        <td>Best unbiased estimator: @f$ v = \frac{1}{N-1} \sum\limits_{k=1}^{N} (x_k - \bar x)^2 @f$</td></tr>
11937        <tr><td>2</td>
11938        <td>Least median of squares</td></tr>
11939        <tr><td>3</td>
11940        <td>Least trimmed of squares</td></tr>
11941        </table>
11942     */
11943     Tfloat variance(const unsigned int variance_method=1) const {
11944       Tfloat foo;
11945       return variancemean(variance_method,foo);
11946     }
11947 
11948     //! Return the variance and the mean of the image.
11949     template<typename t>
11950     Tfloat variancemean(const unsigned int variance_method, t& mean) const {
11951       if (is_empty())
11952         throw CImgInstanceException("CImg<%s>::variance() : Instance image is empty.",
11953                                     pixel_type());
11954       Tfloat variance = 0, average = 0;
11955       const unsigned int siz = size();
11956       switch (variance_method) {
11957       case 3 : { // Least trimmed of Squares
11958         CImg<Tfloat> buf(*this);
11959         const unsigned int siz2 = siz>>1;
11960         { cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; (*ptrs)*=val; average+=val; }}
11961         buf.sort();
11962         Tfloat a = 0;
11963         const Tfloat *ptrs = buf.ptr();
11964         for (unsigned int j = 0; j<siz2; ++j) a+=*(ptrs++);
11965         const Tfloat sig = (Tfloat)(2.6477*cimg_std::sqrt(a/siz2));
11966         variance = sig*sig;
11967       } break;
11968       case 2 : { // Least Median of Squares (MAD)
11969         CImg<Tfloat> buf(*this);
11970         buf.sort();
11971         const unsigned int siz2 = siz>>1;
11972         const Tfloat med_i = buf[siz2];
11973         cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; *ptrs = cimg::abs(val - med_i); average+=val; }
11974         buf.sort();
11975         const Tfloat sig = (Tfloat)(1.4828*buf[siz2]);
11976         variance = sig*sig;
11977       } break;
11978       case 1 : { // Least mean square (robust definition)
11979         Tfloat S = 0, S2 = 0;
11980         cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val;  S2+=val*val; }
11981         variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;
11982         average = S;
11983       } break;
11984       case 0 :{ // Least mean square (standard definition)
11985         Tfloat S = 0, S2 = 0;
11986         cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val;  S2+=val*val; }
11987         variance = (S2 - S*S/siz)/siz;
11988         average = S;
11989       } break;
11990       default :
11991         throw CImgArgumentException("CImg<%s>::variancemean() : Incorrect parameter 'variance_method = %d' (correct values are 0,1,2 or 3).",
11992                                     pixel_type(),variance_method);
11993       }
11994       mean = (t)(average/siz);
11995       return variance>0?variance:0;
11996     }
11997 
11998     //! Return the kth smallest element of the image.
11999     // (Adapted from the numerical recipes for CImg)
12000     T kth_smallest(const unsigned int k) const {
12001       if (is_empty())
12002         throw CImgInstanceException("CImg<%s>::kth_smallest() : Instance image (%u,%u,%u,%u,%p) is empty.",
12003                                     pixel_type(),width,height,depth,dim,data);
12004       CImg<T> arr(*this);
12005       unsigned long l = 0, ir = size()-1;
12006       for (;;) {
12007         if (ir<=l+1) {
12008           if (ir==l+1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
12009           return arr[k];
12010         } else {
12011           const unsigned long mid = (l+ir)>>1;
12012           cimg::swap(arr[mid],arr[l+1]);
12013           if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);
12014           if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]);
12015           if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]);
12016           unsigned long i = l+1, j = ir;
12017           const T pivot = arr[l+1];
12018           for (;;) {
12019             do ++i; while (arr[i]<pivot);
12020             do --j; while (arr[j]>pivot);
12021             if (j<i) break;
12022             cimg::swap(arr[i],arr[j]);
12023           }
12024           arr[l+1] = arr[j];
12025           arr[j] = pivot;
12026           if (j>=k) ir=j-1;
12027           if (j<=k) l=i;
12028         }
12029       }
12030       return 0;
12031     }
12032 
12033     //! Compute a statistics vector (min,max,mean,variance,xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax).
12034     CImg<T>& stats(const unsigned int variance_method=1) {
12035       return get_stats(variance_method).transfer_to(*this);
12036     }
12037 
12038     CImg<Tfloat> get_stats(const unsigned int variance_method=1) const {
12039       if (is_empty()) return CImg<Tfloat>();
12040       const unsigned long siz = size();
12041       const T *const odata = data;
12042       const T *pm = odata, *pM = odata;
12043       Tfloat S = 0, S2 = 0;
12044       T m = *pm, M = m;
12045       cimg_for(*this,ptr,T) {
12046         const T val = *ptr;
12047         const Tfloat fval = (Tfloat)val;
12048         if (val<m) { m = val; pm = ptr; }
12049         if (val>M) { M = val; pM = ptr; }
12050         S+=fval;
12051         S2+=fval*fval;
12052       }
12053       const Tfloat
12054         mean_value = S/siz,
12055         _variance_value = variance_method==0?(S2 - S*S/siz)/siz:
12056         (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0):
12057          variance(variance_method)),
12058         variance_value = _variance_value>0?_variance_value:0;
12059       int
12060         xm = 0, ym = 0, zm = 0, vm = 0,
12061         xM = 0, yM = 0, zM = 0, vM = 0;
12062       contains(*pm,xm,ym,zm,vm);
12063       contains(*pM,xM,yM,zM,vM);
12064       return CImg<Tfloat>(1,12).fill((Tfloat)m,(Tfloat)M,mean_value,variance_value,
12065                                      (Tfloat)xm,(Tfloat)ym,(Tfloat)zm,(Tfloat)vm,
12066                                      (Tfloat)xM,(Tfloat)yM,(Tfloat)zM,(Tfloat)vM);
12067     }
12068 
12069     //! Return the median value of the image.
12070     T median() const {
12071       const unsigned int s = size();
12072       const T res = kth_smallest(s>>1);
12073       return (s%2)?res:((res+kth_smallest((s>>1)-1))/2);
12074     }
12075 
12076     //! Compute the MSE (Mean-Squared Error) between two images.
12077     template<typename t>
12078     Tfloat MSE(const CImg<t>& img) const {
12079       if (img.size()!=size())
12080         throw CImgArgumentException("CImg<%s>::MSE() : Instance image (%u,%u,%u,%u) and given image (%u,%u,%u,%u) have different dimensions.",
12081                                     pixel_type(),width,height,depth,dim,img.width,img.height,img.depth,img.dim);
12082 
12083       Tfloat vMSE = 0;
12084       const t* ptr2 = img.end();
12085       cimg_for(*this,ptr1,T) {
12086         const Tfloat diff = (Tfloat)*ptr1 - (Tfloat)*(--ptr2);
12087         vMSE += diff*diff;
12088       }
12089       vMSE/=img.size();
12090       return vMSE;
12091     }
12092 
12093     //! Compute the PSNR between two images.
12094     template<typename t>
12095     Tfloat PSNR(const CImg<t>& img, const Tfloat valmax=(Tfloat)255) const {
12096       const Tfloat vMSE = (Tfloat)cimg_std::sqrt(MSE(img));
12097       return (vMSE!=0)?(Tfloat)(20*cimg_std::log10(valmax/vMSE)):(Tfloat)(cimg::type<Tfloat>::max());
12098     }
12099 
12100     //! Return the trace of the image, viewed as a matrix.
12101     Tfloat trace() const {
12102       if (is_empty())
12103         throw CImgInstanceException("CImg<%s>::trace() : Instance matrix (%u,%u,%u,%u,%p) is empty.",
12104                                     pixel_type(),width,height,depth,dim,data);
12105       Tfloat res = 0;
12106       cimg_forX(*this,k) res+=(*this)(k,k);
12107       return res;
12108     }
12109 
12110     //! Return the dot product of the current vector/matrix with the vector/matrix \p img.
12111     template<typename t>
12112     Tfloat dot(const CImg<t>& img) const {
12113       if (is_empty())
12114         throw CImgInstanceException("CImg<%s>::dot() : Instance object (%u,%u,%u,%u,%p) is empty.",
12115                                     pixel_type(),width,height,depth,dim,data);
12116       if (!img)
12117         throw CImgArgumentException("CImg<%s>::trace() : Specified argument (%u,%u,%u,%u,%p) is empty.",
12118                                     pixel_type(),img.width,img.height,img.depth,img.dim,img.data);
12119       const unsigned long nb = cimg::min(size(),img.size());
12120       Tfloat res = 0;
12121       for (unsigned long off = 0; off<nb; ++off) res+=(Tfloat)data[off]*(Tfloat)img[off];
12122       return res;
12123     }
12124 
12125     //! Return the determinant of the image, viewed as a matrix.
12126     Tfloat det() const {
12127       if (is_empty() || width!=height || depth!=1 || dim!=1)
12128         throw CImgInstanceException("CImg<%s>::det() : Instance matrix (%u,%u,%u,%u,%p) is not square or is empty.",
12129                                     pixel_type(),width,height,depth,dim,data);
12130       switch (width) {
12131       case 1 : return (Tfloat)((*this)(0,0));
12132       case 2 : return (Tfloat)((*this)(0,0))*(Tfloat)((*this)(1,1)) - (Tfloat)((*this)(0,1))*(Tfloat)((*this)(1,0));
12133       case 3 : {
12134         const Tfloat
12135           a = (Tfloat)data[0], d = (Tfloat)data[1], g = (Tfloat)data[2],
12136           b = (Tfloat)data[3], e = (Tfloat)data[4], h = (Tfloat)data[5],
12137           c = (Tfloat)data[6], f = (Tfloat)data[7], i = (Tfloat)data[8];
12138         return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e;
12139       }
12140       default : {
12141         CImg<Tfloat> lu(*this);
12142         CImg<uintT> indx;
12143         bool d;
12144         lu._LU(indx,d);
12145         Tfloat res = d?(Tfloat)1:(Tfloat)-1;
12146         cimg_forX(lu,i) res*=lu(i,i);
12147         return res;
12148       }
12149       }
12150       return 0;
12151     }
12152 
12153     //! Return the norm of the current vector/matrix. \p ntype = norm type (0=L2, 1=L1, -1=Linf).
12154     Tfloat norm(const int norm_type=2) const {
12155       if (is_empty())
12156         throw CImgInstanceException("CImg<%s>::norm() : Instance object (%u,%u,%u,%u,%p) is empty.",
12157                                     pixel_type(),width,height,depth,dim,data);
12158       Tfloat res = 0;
12159       switch (norm_type) {
12160       case -1 : {
12161         cimg_foroff(*this,off) {
12162           const Tfloat tmp = cimg::abs((Tfloat)data[off]);
12163           if (tmp>res) res = tmp;
12164         }
12165         return res;
12166       } break;
12167       case 1 : {
12168         cimg_foroff(*this,off) res+=cimg::abs((Tfloat)data[off]);
12169         return res;
12170       } break;
12171       case 2 : return (Tfloat)cimg_std::sqrt(dot(*this)); break;
12172       default :
12173         throw CImgArgumentException("CImg<%s>::norm() : Incorrect parameter 'norm_type=%d' (correct values are -1,1 or 2).",
12174                                     pixel_type(),norm_type);
12175       }
12176       return 0;
12177     }
12178 
12179     //! Return a C-string containing the values of the instance image.
12180     CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
12181       if (is_empty()) return CImg<charT>(1,1,1,1,0);
12182       const unsigned int siz = (unsigned int)size();
12183       CImgList<charT> items;
12184       char item[256] = { 0 };
12185       const T *ptrs = ptr();
12186       for (unsigned int off = 0; off<siz-1; ++off) {
12187         cimg_std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*(ptrs++)));
12188         const int l = cimg::strlen(item);
12189         items.insert(CImg<charT>(item,l+1));
12190         items[items.size-1](l) = separator;
12191       }
12192       cimg_std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*ptrs));
12193       items.insert(CImg<charT>(item,cimg::strlen(item)+1));
12194       CImg<ucharT> res = items.get_append('x');
12195       if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
12196       return res;
12197     }
12198 
12199     //! Display informations about the image on the standard error output.
12200     /**
12201        \param title Name for the considered image (optional).
12202        \param display_stats Compute and display image statistics (optional).
12203     **/
12204     const CImg<T>& print(const char *title=0, const bool display_stats=true) const {
12205       int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0;
12206       static CImg<doubleT> st;
12207       if (!is_empty() && display_stats) {
12208         st = get_stats();
12209         xm = (int)st[4]; ym = (int)st[5], zm = (int)st[6], vm = (int)st[7];
12210         xM = (int)st[8]; yM = (int)st[9], zM = (int)st[10], vM = (int)st[11];
12211       }
12212       const unsigned long siz = size(), msiz = siz*sizeof(T), siz1 = siz-1;
12213       const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2), width1 = width-1;
12214       char ntitle[64] = { 0 };
12215       if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
12216       cimg_std::fprintf(cimg_stdout,"%s: this = %p, size = (%u,%u,%u,%u) [%lu %s], data = (%s*)%p (%s) = [ ",
12217                    title?title:ntitle,(void*)this,width,height,depth,dim,
12218                    mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
12219                    mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
12220                    pixel_type(),(void*)data,is_shared?"shared":"not shared");
12221       if (!is_empty()) cimg_foroff(*this,off) {
12222         cimg_std::fprintf(cimg_stdout,cimg::type<T>::format(),cimg::type<T>::format(data[off]));
12223         if (off!=siz1) cimg_std::fprintf(cimg_stdout,"%s",off%width==width1?" ; ":" ");
12224         if (off==7 && siz>16) { off = siz1-8; if (off!=7) cimg_std::fprintf(cimg_stdout,"... "); }
12225       }
12226       if (!is_empty() && display_stats)
12227         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",
12228                      st[0],st[1],st[2],cimg_std::sqrt(st[3]),xm,ym,zm,vm,xM,yM,zM,vM);
12229       else cimg_std::fprintf(cimg_stdout,"%s].\n",is_empty()?"":" ");
12230       return *this;
12231     }
12232 
12233     //@}
12234     //------------------------------------------
12235     //
12236     //! \name Arithmetic and Boolean Operators
12237     //@{
12238     //------------------------------------------
12239 
12240     //! Assignment operator.
12241     /**
12242        This operator assigns a copy of the input image \p img to the current instance image.
12243        \param img The input image to copy.
12244        \remark
12245        - This operator is strictly equivalent to the function assign(const CImg< t >&) and has exactly the same properties.
12246     **/
12247     template<typename t>
12248     CImg<T>& operator=(const CImg<t>& img) {
12249       return assign(img);
12250     }
12251 
12252     CImg<T>& operator=(const CImg<T>& img) {
12253       return assign(img);
12254     }
12255 
12256     //! Assign values of a C-array to the instance image.
12257     /**
12258        \param buf Pointer to a C-style array having a size of (at least) <tt>this->size()</tt>.
12259 
12260        - Replace pixel values by the content of the array \c buf.
12261        - Warning : the value types in the array and in the image must be the same.
12262 
12263        \par example:
12264        \code
12265        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.
12266        CImg<float> matrice(4,4);                                        // Define a 4x4 greyscale image.
12267        matrice = tab;                                                   // Fill the image by the values in tab.
12268        \endcode
12269     **/
12270     CImg<T>& operator=(const T *buf) {
12271       return assign(buf,width,height,depth,dim);
12272     }
12273 
12274     //! Assign a value to each image pixel of the instance image.
12275     CImg<T>& operator=(const T val) {
12276       return fill(val);
12277     }
12278 
12279     //! Operator+
12280     /**
12281        \remark
12282        - This operator can be used to get a non-shared copy of an image.
12283     **/
12284     CImg<T> operator+() const {
12285       return CImg<T>(*this,false);
12286     }
12287 
12288     //! Operator+=;
12289 #ifdef cimg_use_visualcpp6
12290     CImg<T>& operator+=(const T val)
12291 #else
12292     template<typename t>
12293     CImg<T>& operator+=(const t val)
12294 #endif
12295     {
12296       cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)+val);
12297       return *this;
12298     }
12299 
12300     //! Operator+=
12301     template<typename t>
12302     CImg<T>& operator+=(const CImg<t>& img) {
12303       if (is_overlapped(img)) return *this+=+img;
12304       const unsigned int smin = cimg::min(size(),img.size());
12305       t *ptrs = img.data + smin;
12306       for (T *ptrd = data + smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs)))) {}
12307       return *this;
12308     }
12309 
12310     //! Operator++ (prefix)
12311     CImg<T>& operator++() {
12312       cimg_for(*this,ptr,T) ++(*ptr);
12313       return *this;
12314     }
12315 
12316     //! Operator++ (postfix)
12317     CImg<T> operator++(int) {
12318       const CImg<T> copy(*this,false);
12319       ++*this;
12320       return copy;
12321     }
12322 
12323     //! Operator-.
12324     CImg<T> operator-() const {
12325       return CImg<T>(width,height,depth,dim,0)-=*this;
12326     }
12327 
12328     //! Operator-=.
12329 #ifdef cimg_use_visualcpp6
12330     CImg<T>& operator-=(const T val)
12331 #else
12332     template<typename t>
12333     CImg<T>& operator-=(const t val)
12334 #endif
12335     {
12336       cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)-val);
12337       return *this;
12338     }
12339 
12340     //! Operator-=.
12341     template<typename t>
12342     CImg<T>& operator-=(const CImg<t>& img) {
12343       if (is_overlapped(img)) return *this-=+img;
12344       const unsigned int smin = cimg::min(size(),img.size());
12345       t *ptrs = img.data+smin;
12346       for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd) = (T)((*ptrd)-(*(--ptrs)))) {}
12347       return *this;
12348     }
12349 
12350     //! Operator-- (prefix).
12351     CImg<T>& operator--() {
12352       cimg_for(*this,ptr,T) *ptr = *ptr-(T)1;
12353       return *this;
12354     }
12355 
12356     //! Operator-- (postfix).
12357     CImg<T> operator--(int) {
12358       CImg<T> copy(*this,false);
12359       --*this;
12360       return copy;
12361     }
12362 
12363     //! Operator*=.
12364 #ifdef cimg_use_visualcpp6
12365     CImg<T>& operator*=(const double val)
12366 #else
12367     template<typename t>
12368     CImg<T>& operator*=(const t val)
12369 #endif
12370     {
12371       cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)*val);
12372       return *this;
12373     }
12374 
12375     //! Operator*=.
12376     template<typename t>
12377     CImg<T>& operator*=(const CImg<t>& img) {
12378       return ((*this)*img).transfer_to(*this);
12379     }
12380 
12381     //! Operator/=.
12382 #ifdef cimg_use_visualcpp6
12383     CImg<T>& operator/=(const double val)
12384 #else
12385     template<typename t>
12386     CImg<T>& operator/=(const t val)
12387 #endif
12388     {
12389       cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)/val);
12390       return *this;
12391     }
12392 
12393     //! Operator/=.
12394     template<typename t>
12395     CImg<T>& operator/=(const CImg<t>& img) {
12396       return assign(*this*img.get_invert());
12397     }
12398 
12399     //! Modulo.
12400     template<typename t>
12401     CImg<typename cimg::superset<T,t>::type> operator%(const CImg<t>& img) const {
12402       typedef typename cimg::superset<T,t>::type Tt;
12403       return CImg<Tt>(*this,false)%=img;
12404     }
12405 
12406     //! Modulo.
12407     CImg<T> operator%(const T val) const {
12408       return (+*this)%=val;
12409     }
12410 
12411     //! In-place modulo.
12412     CImg<T>& operator%=(const T val) {
12413       cimg_for(*this,ptr,T) (*ptr) = (T)cimg::mod(*ptr,val);
12414       return *this;
12415     }
12416 
12417     //! In-place modulo.
12418     template<typename t>
12419     CImg<T>& operator%=(const CImg<t>& img) {
12420       if (is_overlapped(img)) return *this%=+img;
12421       typedef typename cimg::superset<T,t>::type Tt;
12422       const unsigned int smin = cimg::min(size(),img.size());
12423       const t *ptrs = img.data + smin;
12424       for (T *ptrd = data + smin; ptrd>data; ) {
12425         T& val = *(--ptrd);
12426         val = (T)cimg::mod((Tt)val,(Tt)*(--ptrs));
12427       }
12428       return *this;
12429     }
12430 
12431     //! Bitwise AND.
12432     template<typename t>
12433     CImg<typename cimg::superset<T,t>::type> operator&(const CImg<t>& img) const {
12434       typedef typename cimg::superset<T,t>::type Tt;
12435       return CImg<Tt>(*this,false)&=img;
12436     }
12437 
12438     //! Bitwise AND.
12439     CImg<T> operator&(const T val) const {
12440       return (+*this)&=val;
12441     }
12442 
12443     //! In-place bitwise AND.
12444     template<typename t>
12445     CImg<T>& operator&=(const CImg<t>& img) {
12446       if (is_overlapped(img)) return *this&=+img;
12447       const unsigned int smin = cimg::min(size(),img.size());
12448       const t *ptrs = img.data + smin;
12449       for (T *ptrd = data + smin; ptrd>data; ) {
12450         T& val = *(--ptrd);
12451         val = (T)((unsigned long)val & (unsigned long)*(--ptrs));
12452       }
12453       return *this;
12454     }
12455 
12456     //! In-place bitwise AND.
12457     CImg<T>& operator&=(const T val) {
12458       cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr & (unsigned long)val);
12459       return *this;
12460     }
12461 
12462     //! Bitwise OR.
12463     template<typename t>
12464     CImg<typename cimg::superset<T,t>::type> operator|(const CImg<t>& img) const {
12465       typedef typename cimg::superset<T,t>::type Tt;
12466       return CImg<Tt>(*this,false)|=img;
12467     }
12468 
12469     //! Bitwise OR.
12470     CImg<T> operator|(const T val) const {
12471       return (+*this)|=val;
12472     }
12473 
12474     //! In-place bitwise OR.
12475     template<typename t>
12476     CImg<T>& operator|=(const CImg<t>& img) {
12477       if (is_overlapped(img)) return *this|=+img;
12478       const unsigned int smin = cimg::min(size(),img.size());
12479       const t *ptrs = img.data + smin;
12480       for (T *ptrd = data + smin; ptrd>data; ) {
12481         T& val = *(--ptrd);
12482         val = (T)((unsigned long)val | (unsigned long)*(--ptrs));
12483       }
12484       return *this;
12485     }
12486 
12487     //! In-place bitwise OR.
12488     CImg<T>& operator|=(const T val) {
12489       cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr | (unsigned long)val);
12490       return *this;
12491     }
12492 
12493     //! Bitwise XOR.
12494     template<typename t>
12495     CImg<typename cimg::superset<T,t>::type> operator^(const CImg<t>& img) const {
12496       typedef typename cimg::superset<T,t>::type Tt;
12497       return CImg<Tt>(*this,false)^=img;
12498     }
12499 
12500     //! Bitwise XOR.
12501     CImg<T> operator^(const T val) const {
12502       return (+*this)^=val;
12503     }
12504 
12505     //! In-place bitwise XOR.
12506     template<typename t>
12507     CImg<T>& operator^=(const CImg<t>& img) {
12508       if (is_overlapped(img)) return *this^=+img;
12509       const unsigned int smin = cimg::min(size(),img.size());
12510       const t *ptrs = img.data + smin;
12511       for (T *ptrd = data+smin; ptrd>data; ) {
12512         T& val = *(--ptrd);
12513         val =(T)((unsigned long)val ^ (unsigned long)*(--ptrs));
12514       }
12515       return *this;
12516     }
12517 
12518     //! In-place bitwise XOR.
12519     CImg<T>& operator^=(const T val) {
12520       cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr ^ (unsigned long)val);
12521       return *this;
12522     }
12523 
12524     //! Bitwise NOT.
12525     CImg<T> operator~() const {
12526       CImg<T> res(width,height,depth,dim);
12527       const T *ptrs = end();
12528       cimg_for(res,ptrd,T) { const unsigned long val = (unsigned long)*(--ptrs); *ptrd = (T)~val; }
12529       return res;
12530     }
12531 
12532     //! Bitwise left shift.
12533     CImg<T>& operator<<=(const int n) {
12534       cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)<<n);
12535       return *this;
12536     }
12537 
12538     //! Bitwise left shift.
12539     CImg<T> operator<<(const int n) const {
12540       return (+*this)<<=n;
12541     }
12542 
12543     //! Bitwise right shift.
12544     CImg<T>& operator>>=(const int n) {
12545       cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)>>n);
12546       return *this;
12547     }
12548 
12549     //! Bitwise right shift.
12550     CImg<T> operator>>(const int n) const {
12551       return (+*this)>>=n;
12552     }
12553 
12554     //! Boolean equality.
12555     template<typename t>
12556     bool operator==(const CImg<t>& img) const {
12557       const unsigned int siz = size();
12558       bool vequal = true;
12559       if (siz!=img.size()) return false;
12560       t *ptrs = img.data + siz;
12561       for (T *ptrd = data + siz; vequal && ptrd>data; vequal = vequal && ((*(--ptrd))==(*(--ptrs)))) {}
12562       return vequal;
12563     }
12564 
12565     //! Boolean difference.
12566     template<typename t>
12567     bool operator!=(const CImg<t>& img) const {
12568       return !((*this)==img);
12569     }
12570 
12571     //! Return a list of two images { *this, img }.
12572     template<typename t>
12573     CImgList<typename cimg::superset<T,t>::type> operator<<(const CImg<t>& img) const {
12574       typedef typename cimg::superset<T,t>::type Tt;
12575       return CImgList<Tt>(*this,img);
12576     }
12577 
12578     //! Return a copy of \p list, where image *this has been inserted at first position.
12579     template<typename t>
12580     CImgList<typename cimg::superset<T,t>::type> operator<<(const CImgList<t>& list) const {
12581       typedef typename cimg::superset<T,t>::type Tt;
12582       return CImgList<Tt>(list).insert(*this,0);
12583     }
12584 
12585     //! Return a list of two images { *this, img }.
12586     template<typename t>
12587     CImgList<typename cimg::superset<T,t>::type> operator>>(const CImg<t>& img) const {
12588       return (*this)<<img;
12589     }
12590 
12591     //! Insert an image into the beginning of an image list.
12592     template<typename t>
12593     CImgList<t>& operator>>(const CImgList<t>& list) const {
12594       return list.insert(*this,0);
12595     }
12596 
12597     //! Display an image into a CImgDisplay.
12598     const CImg<T>& operator>>(CImgDisplay& disp) const {
12599       return display(disp);
12600     }
12601 
12602     //@}
12603     //---------------------------------------
12604     //
12605     //! \name Usual Mathematics Functions
12606     //@{
12607     //---------------------------------------
12608 
12609     //! Apply a R->R function on all pixel values.
12610     template<typename t>
12611     CImg<T>& apply(t& func) {
12612       cimg_for(*this,ptr,T) *ptr = func(*ptr);
12613       return *this;
12614     }
12615 
12616     template<typename t>
12617     CImg<T> get_apply(t& func) const {
12618       return (+*this).apply(func);
12619     }
12620 
12621     //! Pointwise multiplication between two images.
12622     template<typename t>
12623     CImg<T>& mul(const CImg<t>& img) {
12624       if (is_overlapped(img)) return mul(+img);
12625       t *ptrs = img.data;
12626       T *ptrf = data + cimg::min(size(),img.size());
12627       for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd*(*(ptrs++)));
12628       return *this;
12629     }
12630 
12631     template<typename t>
12632     CImg<typename cimg::superset<T,t>::type> get_mul(const CImg<t>& img) const {
12633       typedef typename cimg::superset<T,t>::type Tt;
12634       return CImg<Tt>(*this,false).mul(img);
12635     }
12636 
12637     //! Pointwise division between two images.
12638     template<typename t>
12639     CImg<T>& div(const CImg<t>& img) {
12640       if (is_overlapped(img)) return div(+img);
12641       t *ptrs = img.data;
12642       T *ptrf = data + cimg::min(size(),img.size());
12643       for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd/(*(ptrs++)));
12644       return *this;
12645     }
12646 
12647     template<typename t>
12648     CImg<typename cimg::superset<T,t>::type> get_div(const CImg<t>& img) const {
12649       typedef typename cimg::superset<T,t>::type Tt;
12650       return CImg<Tt>(*this,false).div(img);
12651     }
12652 
12653     //! Pointwise max operator between two images.
12654     template<typename t>
12655     CImg<T>& max(const CImg<t>& img) {
12656       if (is_overlapped(img)) return max(+img);
12657       t *ptrs = img.data;
12658       T *ptrf = data + cimg::min(size(),img.size());
12659       for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::max((T)*(ptrs++),*ptrd);
12660       return *this;
12661     }
12662 
12663     template<typename t>
12664     CImg<typename cimg::superset<T,t>::type> get_max(const CImg<t>& img) const {
12665       typedef typename cimg::superset<T,t>::type Tt;
12666       return CImg<Tt>(*this,false).max(img);
12667     }
12668 
12669     //! Pointwise max operator between an image and a value.
12670     CImg<T>& max(const T val) {
12671       cimg_for(*this,ptr,T) (*ptr) = cimg::max(*ptr,val);
12672       return *this;
12673     }
12674 
12675     CImg<T> get_max(const T val) const {
12676       return (+*this).max(val);
12677     }
12678 
12679     //! Pointwise min operator between two images.
12680     template<typename t>
12681     CImg<T>& min(const CImg<t>& img) {
12682       if (is_overlapped(img)) return min(+img);
12683       t *ptrs = img.data;
12684       T *ptrf = data + cimg::min(size(),img.size());
12685       for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::min((T)*(ptrs++),*ptrd);
12686       return *this;
12687     }
12688 
12689     template<typename t>
12690     CImg<typename cimg::superset<T,t>::type> get_min(const CImg<t>& img) const {
12691       typedef typename cimg::superset<T,t>::type Tt;
12692       return CImg<Tt>(*this,false).min(img);
12693     }
12694 
12695     //! Pointwise min operator between an image and a value.
12696     CImg<T>& min(const T val) {
12697       cimg_for(*this,ptr,T) (*ptr) = cimg::min(*ptr,val);
12698       return *this;
12699     }
12700 
12701     CImg<T> get_min(const T val) const {
12702       return (+*this).min(val);
12703     }
12704 
12705     //! Compute the square value of each pixel.
12706     CImg<T>& sqr() {
12707       cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)(val*val); };
12708       return *this;
12709     }
12710 
12711     CImg<Tfloat> get_sqr() const {
12712       return CImg<Tfloat>(*this,false).sqr();
12713     }
12714 
12715     //! Compute the square root of each pixel value.
12716     CImg<T>& sqrt() {
12717       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::sqrt((double)(*ptr));
12718       return *this;
12719     }
12720 
12721     CImg<Tfloat> get_sqrt() const {
12722       return CImg<Tfloat>(*this,false).sqrt();
12723     }
12724 
12725     //! Compute the exponential of each pixel value.
12726     CImg<T>& exp() {
12727       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::exp((double)(*ptr));
12728       return *this;
12729     }
12730 
12731     CImg<Tfloat> get_exp() const {
12732       return CImg<Tfloat>(*this,false).exp();
12733     }
12734 
12735     //! Compute the log of each pixel value.
12736     CImg<T>& log() {
12737       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::log((double)(*ptr));
12738       return *this;
12739     }
12740 
12741     CImg<Tfloat> get_log() const {
12742       return CImg<Tfloat>(*this,false).log();
12743     }
12744 
12745     //! Compute the log10 of each pixel value.
12746     CImg<T>& log10() {
12747       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::log10((double)(*ptr));
12748       return *this;
12749     }
12750 
12751     CImg<Tfloat> get_log10() const {
12752       return CImg<Tfloat>(*this,false).log10();
12753     }
12754 
12755     //! Compute the power by p of each pixel value.
12756     CImg<T>& pow(const double p) {
12757       if (p==0) return fill(1);
12758       if (p==0.5) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)cimg_std::sqrt((double)val); } return *this; }
12759       if (p==1) return *this;
12760       if (p==2) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val; } return *this; }
12761       if (p==3) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val; } return *this; }
12762       if (p==4) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val*val; } return *this; }
12763       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::pow((double)(*ptr),p);
12764       return *this;
12765     }
12766 
12767     CImg<Tfloat> get_pow(const double p) const {
12768       return CImg<Tfloat>(*this,false).pow(p);
12769     }
12770 
12771     //! Compute the power of each pixel value.
12772     template<typename t>
12773     CImg<T>& pow(const CImg<t>& img) {
12774       if (is_overlapped(img)) return pow(+img);
12775       t *ptrs = img.data;
12776       T *ptrf = data + cimg::min(size(),img.size());
12777       for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)cimg_std::pow((double)*ptrd,(double)(*(ptrs++)));
12778       return *this;
12779     }
12780 
12781     template<typename t>
12782     CImg<Tfloat> get_pow(const CImg<t>& img) const {
12783       return CImg<Tfloat>(*this,false).pow(img);
12784     }
12785 
12786     //! Compute the absolute value of each pixel value.
12787     CImg<T>& abs() {
12788       cimg_for(*this,ptr,T) (*ptr) = cimg::abs(*ptr);
12789       return *this;
12790     }
12791 
12792     CImg<Tfloat> get_abs() const {
12793       return CImg<Tfloat>(*this,false).abs();
12794     }
12795 
12796     //! Compute the cosinus of each pixel value.
12797     CImg<T>& cos() {
12798       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::cos((double)(*ptr));
12799       return *this;
12800     }
12801 
12802     CImg<Tfloat> get_cos() const {
12803       return CImg<Tfloat>(*this,false).cos();
12804     }
12805 
12806     //! Compute the sinus of each pixel value.
12807     CImg<T>& sin() {
12808       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::sin((double)(*ptr));
12809       return *this;
12810     }
12811 
12812     CImg<Tfloat> get_sin() const {
12813       return CImg<Tfloat>(*this,false).sin();
12814     }
12815 
12816     //! Compute the tangent of each pixel.
12817     CImg<T>& tan() {
12818       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::tan((double)(*ptr));
12819       return *this;
12820     }
12821 
12822     CImg<Tfloat> get_tan() const {
12823       return CImg<Tfloat>(*this,false).tan();
12824     }
12825 
12826     //! Compute the arc-cosine of each pixel value.
12827     CImg<T>& acos() {
12828       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::acos((double)(*ptr));
12829       return *this;
12830     }
12831 
12832     CImg<Tfloat> get_acos() const {
12833       return CImg<Tfloat>(*this,false).acos();
12834     }
12835 
12836     //! Compute the arc-sinus of each pixel value.
12837     CImg<T>& asin() {
12838       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::asin((double)(*ptr));
12839       return *this;
12840     }
12841 
12842     CImg<Tfloat> get_asin() const {
12843       return CImg<Tfloat>(*this,false).asin();
12844     }
12845 
12846     //! Compute the arc-tangent of each pixel.
12847     CImg<T>& atan() {
12848       cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::atan((double)(*ptr));
12849       return *this;
12850     }
12851 
12852     CImg<Tfloat> get_atan() const {
12853       return CImg<Tfloat>(*this,false).atan();
12854     }
12855 
12856     //! Compute image with rounded pixel values.
12857     /**
12858        \param x Rounding precision.
12859        \param rounding_type Roundin type, can be 0 (nearest), 1 (forward), -1(backward).
12860     **/
12861     CImg<T>& round(const float x, const int rounding_type=0) {
12862       cimg_for(*this,ptr,T) (*ptr) = (T)cimg::round(*ptr,x,rounding_type);
12863       return *this;
12864     }
12865 
12866     CImg<T> get_round(const float x, const unsigned int rounding_type=0) const {
12867       return (+*this).round(x,rounding_type);
12868     }
12869 
12870     //! Fill the instance image with random values between specified range.
12871     CImg<T>& rand(const T val_min, const T val_max) {
12872       const float delta = (float)val_max - (float)val_min;
12873       cimg_for(*this,ptr,T) *ptr = (T)(val_min + cimg::rand()*delta);
12874       return *this;
12875     }
12876 
12877     CImg<T> get_rand(const T val_min, const T val_max) const {
12878       return (+*this).rand(val_min,val_max);
12879     }
12880 
12881     //@}
12882     //-----------------------------------
12883     //
12884     //! \name Usual Image Transformations
12885     //@{
12886     //-----------------------------------
12887 
12888     //! Fill an image by a value \p val.
12889     /**
12890        \param val = fill value
12891        \note All pixel values of the instance image will be initialized by \p val.
12892     **/
12893     CImg<T>& fill(const T val) {
12894       if (is_empty()) return *this;
12895       if (val && sizeof(T)!=1) cimg_for(*this,ptr,T) *ptr = val;
12896       else cimg_std::memset(data,(int)val,size()*sizeof(T));
12897       return *this;
12898     }
12899 
12900     CImg<T> get_fill(const T val) const {
12901       return CImg<T>(width,height,depth,dim).fill(val);
12902     }
12903 
12904     //! Fill sequentially all pixel values with values \a val0 and \a val1 respectively.
12905     CImg<T>& fill(const T val0, const T val1) {
12906       if (is_empty()) return *this;
12907       T *ptr, *ptr_end = end()-1;
12908       for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; }
12909       if (ptr!=ptr_end+1) *(ptr++) = val0;
12910       return *this;
12911     }
12912 
12913     CImg<T> get_fill(const T val0, const T val1) const {
12914       return CImg<T>(width,height,depth,dim).fill(val0,val1);
12915     }
12916 
12917     //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2.
12918     CImg<T>& fill(const T val0, const T val1, const T val2) {
12919       if (is_empty()) return *this;
12920       T *ptr, *ptr_end = end()-2;
12921       for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; }
12922       ptr_end+=2;
12923       switch (ptr_end-ptr) {
12924       case 2 : *(--ptr_end) = val1;
12925       case 1 : *(--ptr_end) = val0;
12926       }
12927       return *this;
12928     }
12929 
12930     CImg<T> get_fill(const T val0, const T val1, const T val2) const {
12931       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2);
12932     }
12933 
12934     //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3.
12935     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3) {
12936       if (is_empty()) return *this;
12937       T *ptr, *ptr_end = end()-3;
12938       for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; }
12939       ptr_end+=3;
12940       switch (ptr_end-ptr) {
12941       case 3 : *(--ptr_end) = val2;
12942       case 2 : *(--ptr_end) = val1;
12943       case 1 : *(--ptr_end) = val0;
12944       }
12945       return *this;
12946     }
12947 
12948     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3) const {
12949       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3);
12950     }
12951 
12952     //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4.
12953     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4) {
12954       if (is_empty()) return *this;
12955       T *ptr, *ptr_end = end()-4;
12956       for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; }
12957       ptr_end+=4;
12958       switch (ptr_end-ptr) {
12959       case 4 : *(--ptr_end) = val3;
12960       case 3 : *(--ptr_end) = val2;
12961       case 2 : *(--ptr_end) = val1;
12962       case 1 : *(--ptr_end) = val0;
12963       }
12964       return *this;
12965     }
12966 
12967     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4) const {
12968       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4);
12969     }
12970 
12971     //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5.
12972     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) {
12973       if (is_empty()) return *this;
12974       T *ptr, *ptr_end = end()-5;
12975       for (ptr = data; ptr<ptr_end; ) {
12976         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
12977       }
12978       ptr_end+=5;
12979       switch (ptr_end-ptr) {
12980       case 5 : *(--ptr_end) = val4;
12981       case 4 : *(--ptr_end) = val3;
12982       case 3 : *(--ptr_end) = val2;
12983       case 2 : *(--ptr_end) = val1;
12984       case 1 : *(--ptr_end) = val0;
12985       }
12986       return *this;
12987     }
12988 
12989     CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) const {
12990       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5);
12991     }
12992 
12993     //! Fill sequentially pixel values.
12994     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) {
12995       if (is_empty()) return *this;
12996       T *ptr, *ptr_end = end()-6;
12997       for (ptr = data; ptr<ptr_end; ) {
12998         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6;
12999       }
13000       ptr_end+=6;
13001       switch (ptr_end-ptr) {
13002       case 6 : *(--ptr_end) = val5;
13003       case 5 : *(--ptr_end) = val4;
13004       case 4 : *(--ptr_end) = val3;
13005       case 3 : *(--ptr_end) = val2;
13006       case 2 : *(--ptr_end) = val1;
13007       case 1 : *(--ptr_end) = val0;
13008       }
13009       return *this;
13010     }
13011 
13012     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 {
13013       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6);
13014     }
13015 
13016     //! Fill sequentially pixel values.
13017     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13018                   const T val7) {
13019       if (is_empty()) return *this;
13020       T *ptr, *ptr_end = end()-7;
13021       for (ptr = data; ptr<ptr_end; ) {
13022         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3;
13023         *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7;
13024       }
13025       ptr_end+=7;
13026       switch (ptr_end-ptr) {
13027       case 7 : *(--ptr_end) = val6;
13028       case 6 : *(--ptr_end) = val5;
13029       case 5 : *(--ptr_end) = val4;
13030       case 4 : *(--ptr_end) = val3;
13031       case 3 : *(--ptr_end) = val2;
13032       case 2 : *(--ptr_end) = val1;
13033       case 1 : *(--ptr_end) = val0;
13034       }
13035       return *this;
13036     }
13037 
13038     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,
13039                      const T val7) const {
13040       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7);
13041     }
13042 
13043     //! Fill sequentially pixel values.
13044     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13045                   const T val7, const T val8) {
13046       if (is_empty()) return *this;
13047       T *ptr, *ptr_end = end()-8;
13048       for (ptr = data; ptr<ptr_end; ) {
13049         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2;
13050         *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13051         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8;
13052       }
13053       ptr_end+=8;
13054       switch (ptr_end-ptr) {
13055       case 8 : *(--ptr_end) = val7;
13056       case 7 : *(--ptr_end) = val6;
13057       case 6 : *(--ptr_end) = val5;
13058       case 5 : *(--ptr_end) = val4;
13059       case 4 : *(--ptr_end) = val3;
13060       case 3 : *(--ptr_end) = val2;
13061       case 2 : *(--ptr_end) = val1;
13062       case 1 : *(--ptr_end) = val0;
13063       }
13064       return *this;
13065     }
13066 
13067     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,
13068                      const T val7, const T val8) const {
13069       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);
13070     }
13071 
13072     //! Fill sequentially pixel values.
13073     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13074                   const T val7, const T val8, const T val9) {
13075       if (is_empty()) return *this;
13076       T *ptr, *ptr_end = end()-9;
13077       for (ptr = data; ptr<ptr_end; ) {
13078         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
13079         *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
13080       }
13081       ptr_end+=9;
13082       switch (ptr_end-ptr) {
13083       case 9 : *(--ptr_end) = val8;
13084       case 8 : *(--ptr_end) = val7;
13085       case 7 : *(--ptr_end) = val6;
13086       case 6 : *(--ptr_end) = val5;
13087       case 5 : *(--ptr_end) = val4;
13088       case 4 : *(--ptr_end) = val3;
13089       case 3 : *(--ptr_end) = val2;
13090       case 2 : *(--ptr_end) = val1;
13091       case 1 : *(--ptr_end) = val0;
13092       }
13093       return *this;
13094     }
13095 
13096     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,
13097                      const T val7, const T val8, const T val9) const {
13098       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);
13099     }
13100 
13101     //! Fill sequentially pixel values.
13102     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13103                   const T val7, const T val8, const T val9, const T val10) {
13104       if (is_empty()) return *this;
13105       T *ptr, *ptr_end = end()-10;
13106       for (ptr = data; ptr<ptr_end; ) {
13107         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
13108         *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
13109         *(ptr++) = val10;
13110       }
13111       ptr_end+=10;
13112       switch (ptr_end-ptr) {
13113       case 10 : *(--ptr_end) = val9;
13114       case 9 : *(--ptr_end) = val8;
13115       case 8 : *(--ptr_end) = val7;
13116       case 7 : *(--ptr_end) = val6;
13117       case 6 : *(--ptr_end) = val5;
13118       case 5 : *(--ptr_end) = val4;
13119       case 4 : *(--ptr_end) = val3;
13120       case 3 : *(--ptr_end) = val2;
13121       case 2 : *(--ptr_end) = val1;
13122       case 1 : *(--ptr_end) = val0;
13123       }
13124       return *this;
13125     }
13126 
13127     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,
13128                      const T val7, const T val8, const T val9, const T val10) const {
13129       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10);
13130     }
13131 
13132     //! Fill sequentially pixel values.
13133     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13134                   const T val7, const T val8, const T val9, const T val10, const T val11) {
13135       if (is_empty()) return *this;
13136       T *ptr, *ptr_end = end()-11;
13137       for (ptr = data; ptr<ptr_end; ) {
13138         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13139         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
13140       }
13141       ptr_end+=11;
13142       switch (ptr_end-ptr) {
13143       case 11 : *(--ptr_end) = val10;
13144       case 10 : *(--ptr_end) = val9;
13145       case 9 : *(--ptr_end) = val8;
13146       case 8 : *(--ptr_end) = val7;
13147       case 7 : *(--ptr_end) = val6;
13148       case 6 : *(--ptr_end) = val5;
13149       case 5 : *(--ptr_end) = val4;
13150       case 4 : *(--ptr_end) = val3;
13151       case 3 : *(--ptr_end) = val2;
13152       case 2 : *(--ptr_end) = val1;
13153       case 1 : *(--ptr_end) = val0;
13154       }
13155       return *this;
13156     }
13157 
13158     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,
13159                      const T val7, const T val8, const T val9, const T val10, const T val11) const {
13160       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11);
13161     }
13162 
13163     //! Fill sequentially pixel values.
13164     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13165                   const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) {
13166       if (is_empty()) return *this;
13167       T *ptr, *ptr_end = end()-12;
13168       for (ptr = data; ptr<ptr_end; ) {
13169         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13170         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
13171         *(ptr++) = val12;
13172       }
13173       ptr_end+=12;
13174       switch (ptr_end-ptr) {
13175       case 12 : *(--ptr_end) = val11;
13176       case 11 : *(--ptr_end) = val10;
13177       case 10 : *(--ptr_end) = val9;
13178       case 9 : *(--ptr_end) = val8;
13179       case 8 : *(--ptr_end) = val7;
13180       case 7 : *(--ptr_end) = val6;
13181       case 6 : *(--ptr_end) = val5;
13182       case 5 : *(--ptr_end) = val4;
13183       case 4 : *(--ptr_end) = val3;
13184       case 3 : *(--ptr_end) = val2;
13185       case 2 : *(--ptr_end) = val1;
13186       case 1 : *(--ptr_end) = val0;
13187       }
13188       return *this;
13189     }
13190 
13191     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,
13192                      const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) const {
13193       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12);
13194     }
13195 
13196     //! Fill sequentially pixel values.
13197     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13198                   const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13199                   const T val13) {
13200       if (is_empty()) return *this;
13201       T *ptr, *ptr_end = end()-13;
13202       for (ptr = data; ptr<ptr_end; ) {
13203         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13204         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
13205         *(ptr++) = val12; *(ptr++) = val13;
13206       }
13207       ptr_end+=13;
13208       switch (ptr_end-ptr) {
13209       case 13 : *(--ptr_end) = val12;
13210       case 12 : *(--ptr_end) = val11;
13211       case 11 : *(--ptr_end) = val10;
13212       case 10 : *(--ptr_end) = val9;
13213       case 9 : *(--ptr_end) = val8;
13214       case 8 : *(--ptr_end) = val7;
13215       case 7 : *(--ptr_end) = val6;
13216       case 6 : *(--ptr_end) = val5;
13217       case 5 : *(--ptr_end) = val4;
13218       case 4 : *(--ptr_end) = val3;
13219       case 3 : *(--ptr_end) = val2;
13220       case 2 : *(--ptr_end) = val1;
13221       case 1 : *(--ptr_end) = val0;
13222       }
13223       return *this;
13224     }
13225 
13226     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,
13227                      const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13228                      const T val13) const {
13229       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
13230                                                   val13);
13231     }
13232 
13233     //! Fill sequentially pixel values.
13234     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13235                   const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13236                   const T val13, const T val14) {
13237       if (is_empty()) return *this;
13238       T *ptr, *ptr_end = end()-14;
13239       for (ptr = data; ptr<ptr_end; ) {
13240         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13241         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
13242         *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14;
13243       }
13244       ptr_end+=14;
13245       switch (ptr_end-ptr) {
13246       case 14 : *(--ptr_end) = val13;
13247       case 13 : *(--ptr_end) = val12;
13248       case 12 : *(--ptr_end) = val11;
13249       case 11 : *(--ptr_end) = val10;
13250       case 10 : *(--ptr_end) = val9;
13251       case 9 : *(--ptr_end) = val8;
13252       case 8 : *(--ptr_end) = val7;
13253       case 7 : *(--ptr_end) = val6;
13254       case 6 : *(--ptr_end) = val5;
13255       case 5 : *(--ptr_end) = val4;
13256       case 4 : *(--ptr_end) = val3;
13257       case 3 : *(--ptr_end) = val2;
13258       case 2 : *(--ptr_end) = val1;
13259       case 1 : *(--ptr_end) = val0;
13260       }
13261       return *this;
13262     }
13263 
13264     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,
13265                      const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13266                      const T val13, const T val14) const {
13267       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
13268                                                   val13,val14);
13269     }
13270 
13271     //! Fill sequentially pixel values.
13272     CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13273                   const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13274                   const T val13, const T val14, const T val15) {
13275       if (is_empty()) return *this;
13276       T *ptr, *ptr_end = end()-15;
13277       for (ptr = data; ptr<ptr_end; ) {
13278         *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13279         *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
13280         *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14; *(ptr++) = val15;
13281       }
13282       ptr_end+=15;
13283       switch (ptr_end-ptr) {
13284       case 15 : *(--ptr_end) = val14;
13285       case 14 : *(--ptr_end) = val13;
13286       case 13 : *(--ptr_end) = val12;
13287       case 12 : *(--ptr_end) = val11;
13288       case 11 : *(--ptr_end) = val10;
13289       case 10 : *(--ptr_end) = val9;
13290       case 9 : *(--ptr_end) = val8;
13291       case 8 : *(--ptr_end) = val7;
13292       case 7 : *(--ptr_end) = val6;
13293       case 6 : *(--ptr_end) = val5;
13294       case 5 : *(--ptr_end) = val4;
13295       case 4 : *(--ptr_end) = val3;
13296       case 3 : *(--ptr_end) = val2;
13297       case 2 : *(--ptr_end) = val1;
13298       case 1 : *(--ptr_end) = val0;
13299       }
13300       return *this;
13301     }
13302 
13303     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,
13304                      const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13305                      const T val13, const T val14, const T val15) const {
13306       return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
13307                                                   val13,val14,val15);
13308     }
13309 
13310     //! Fill image values according to the values found in the specified string.
13311     CImg<T>& fill(const char *const values, const bool repeat_pattern) {
13312       if (is_empty() || !values) return *this;
13313       T *ptrd = data, *ptr_end = data + size();
13314       const char *nvalues = values;
13315       const unsigned int siz = size();
13316       char cval[64] = { 0 },  sep = 0;
13317       int err = 0; double val = 0; unsigned int nb = 0;
13318       while ((err=cimg_std::sscanf(nvalues,"%63[ \n\t0-9e.+-]%c",cval,&sep))>0 &&
13319              cimg_std::sscanf(cval,"%lf",&val)>0 && nb<siz) {
13320         nvalues += cimg::strlen(cval);
13321         *(ptrd++) = (T)val;
13322         ++nb;
13323         if (err!=2) break; else ++nvalues;
13324       }
13325       if (repeat_pattern && nb) for (T *ptrs = data; ptrd<ptr_end; ++ptrs) *(ptrd++) = *ptrs;
13326       return *this;
13327     }
13328 
13329     CImg<T> get_fill(const char *const values, const bool repeat_pattern) const {
13330       return repeat_pattern?CImg<T>(width,height,depth,dim).fill(values,repeat_pattern):(+*this).fill(values,repeat_pattern);
13331     }
13332 
13333     //! Fill image values according to the values found in the specified image.
13334     template<typename t>
13335     CImg<T>& fill(const CImg<t>& values, const bool repeat_pattern=true) {
13336       if (is_empty() || !values) return *this;
13337       T *ptrd = data, *ptrd_end = ptrd + size();
13338       for (t *ptrs = values.data, *ptrs_end = ptrs + values.size(); ptrs<ptrs_end && ptrd<ptrd_end; ++ptrs) *(ptrd++) = (T)*ptrs;
13339       if (repeat_pattern && ptrd<ptrd_end) for (T *ptrs = data; ptrd<ptrd_end; ++ptrs) *(ptrd++) = *ptrs;
13340       return *this;
13341     }
13342 
13343     template<typename t>
13344     CImg<T> get_fill(const CImg<t>& values, const bool repeat_pattern=true) const {
13345       return repeat_pattern?CImg<T>(width,height,depth,dim).fill(values,repeat_pattern):(+*this).fill(values,repeat_pattern);
13346     }
13347 
13348     //! Fill image values along the X-axis at the specified pixel position (y,z,v).
13349     CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const int a0, ...) {
13350 #define _cimg_fill1(x,y,z,v,off,siz,t) { \
13351     va_list ap; va_start(ap,a0); T *ptrd = ptr(x,y,z,v); *ptrd = (T)a0; \
13352     for (unsigned int k = 1; k<siz; ++k) { ptrd+=off; *ptrd = (T)va_arg(ap,t); } \
13353     va_end(ap); }
13354       if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,int);
13355       return *this;
13356     }
13357 
13358     CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const double a0, ...) {
13359       if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,double);
13360       return *this;
13361     }
13362 
13363     //! Fill image values along the Y-axis at the specified pixel position (x,z,v).
13364     CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const int a0, ...) {
13365       if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,int);
13366       return *this;
13367     }
13368 
13369     CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const double a0, ...) {
13370       if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,double);
13371       return *this;
13372     }
13373 
13374     //! Fill image values along the Z-axis at the specified pixel position (x,y,v).
13375     CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const int a0, ...) {
13376       const unsigned int wh = width*height;
13377       if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,int);
13378       return *this;
13379     }
13380 
13381     CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const double a0, ...) {
13382       const unsigned int wh = width*height;
13383       if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,double);
13384       return *this;
13385     }
13386 
13387     //! Fill image values along the V-axis at the specified pixel position (x,y,z).
13388     CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) {
13389       const unsigned int whz = width*height*depth;
13390       if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,int);
13391       return *this;
13392     }
13393 
13394     CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) {
13395       const unsigned int whz = width*height*depth;
13396       if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,double);
13397       return *this;
13398     }
13399 
13400     //! Linear normalization of the pixel values between \a a and \a b.
13401     CImg<T>& normalize(const T a, const T b) {
13402       if (is_empty()) return *this;
13403       const T na = a<b?a:b, nb = a<b?b:a;
13404       T m, M = maxmin(m);
13405       const Tfloat fm = (Tfloat)m, fM = (Tfloat)M;
13406       if (m==M) return fill(0);
13407       if (m!=na || M!=nb) cimg_for(*this,ptr,T) *ptr = (T)((*ptr-fm)/(fM-fm)*(nb-na)+na);
13408       return *this;
13409     }
13410 
13411     CImg<T> get_normalize(const T a, const T b) const {
13412       return (+*this).normalize(a,b);
13413     }
13414 
13415     //! Cut pixel values between \a a and \a b.
13416     CImg<T>& cut(const T a, const T b) {
13417       if (is_empty()) return *this;
13418       const T na = a<b?a:b, nb = a<b?b:a;
13419       cimg_for(*this,ptr,T) *ptr = (*ptr<na)?na:((*ptr>nb)?nb:*ptr);
13420       return *this;
13421     }
13422 
13423     CImg<T> get_cut(const T a, const T b) const {
13424       return (+*this).cut(a,b);
13425     }
13426 
13427     //! Quantize pixel values into \n levels.
13428     CImg<T>& quantize(const unsigned int n, const bool keep_range=true) {
13429       if (is_empty()) return *this;
13430       if (!n)
13431         throw CImgArgumentException("CImg<%s>::quantize() : Cannot quantize image to 0 values.",
13432                                     pixel_type());
13433       Tfloat m, M = (Tfloat)maxmin(m), range = M - m;
13434       if (range>0) {
13435         if (keep_range) cimg_for(*this,ptr,T) {
13436           const unsigned int val = (unsigned int)((*ptr-m)*n/range);
13437           *ptr = (T)(m + cimg::min(val,n-1)*range/n);
13438         } else cimg_for(*this,ptr,T) {
13439           const unsigned int val = (unsigned int)((*ptr-m)*n/range);
13440           *ptr = (T)cimg::min(val,n-1);
13441         }
13442       }
13443       return *this;
13444     }
13445 
13446     CImg<T> get_quantize(const unsigned int n, const bool keep_range=true) const {
13447       return (+*this).quantize(n,keep_range);
13448     }
13449 
13450     //! Threshold the image.
13451     /**
13452        \param value Threshold value.
13453        \param soft Enable soft thresholding.
13454        \param strict Tells if the threshold is strict.
13455     **/
13456     CImg<T>& threshold(const T value, const bool soft=false, const bool strict=false) {
13457       if (is_empty()) return *this;
13458       if (strict) {
13459         if (soft) cimg_for(*this,ptr,T) { const T v = *ptr; *ptr = v>value?(T)(v-value):v<-value?(T)(v+value):(T)0; }
13460         else cimg_for(*this,ptr,T) *ptr = *ptr>value?(T)1:(T)0;
13461       } else {
13462         if (soft) cimg_for(*this,ptr,T) { const T v = *ptr; *ptr = v>=value?(T)(v-value):v<=-value?(T)(v+value):(T)0; }
13463         else cimg_for(*this,ptr,T) *ptr = *ptr>=value?(T)1:(T)0;
13464       }
13465       return *this;
13466     }
13467 
13468     CImg<T> get_threshold(const T value, const bool soft=false, const bool strict=false) const {
13469       return (+*this).threshold(value,soft,strict);
13470     }
13471 
13472     //! Rotate an image.
13473     /**
13474        \param angle = rotation angle (in degrees).
13475        \param cond = rotation type. can be :
13476        - 0 = zero-value at borders
13477        - 1 = nearest pixel.
13478        - 2 = Fourier style.
13479        \note Returned image will probably have a different size than the instance image *this.
13480     **/
13481     CImg<T>& rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) {
13482       return get_rotate(angle,border_conditions,interpolation).transfer_to(*this);
13483     }
13484 
13485     CImg<T> get_rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
13486       if (is_empty()) return *this;
13487       CImg<T> dest;
13488       const float nangle = cimg::mod(angle,360.0f);
13489       if (border_conditions!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
13490         const int wm1 = dimx()-1, hm1 = dimy()-1;
13491         const int iangle = (int)nangle/90;
13492         switch (iangle) {
13493         case 1 : {
13494           dest.assign(height,width,depth,dim);
13495           cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,hm1-x,z,v);
13496         } break;
13497         case 2 : {
13498           dest.assign(width,height,depth,dim);
13499           cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-x,hm1-y,z,v);
13500         } break;
13501         case 3 : {
13502           dest.assign(height,width,depth,dim);
13503           cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-y,x,z,v);
13504         } break;
13505         default :
13506           return *this;
13507         }
13508       } else { // generic version
13509         const float
13510           rad = (float)(nangle*cimg::valuePI/180.0),
13511           ca = (float)cimg_std::cos(rad),
13512           sa = (float)cimg_std::sin(rad),
13513           ux = cimg::abs(width*ca), uy = cimg::abs(width*sa),
13514           vx = cimg::abs(height*sa), vy = cimg::abs(height*ca),
13515           w2 = 0.5f*width, h2 = 0.5f*height,
13516           dw2 = 0.5f*(ux+vx), dh2 = 0.5f*(uy+vy);
13517         dest.assign((int)(ux+vx), (int)(uy+vy),depth,dim);
13518         switch (border_conditions) {
13519         case 0 : {
13520           switch (interpolation) {
13521           case 2 : {
13522             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13523               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);
13524           } break;
13525           case 1 : {
13526             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13527               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);
13528           } break;
13529           default : {
13530             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13531               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);
13532           }
13533           }
13534         } break;
13535         case 1 : {
13536           switch (interpolation) {
13537           case 2 :
13538             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13539               dest(x,y,z,v) = (T)cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
13540             break;
13541           case 1 :
13542             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13543               dest(x,y,z,v) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
13544             break;
13545           default :
13546             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13547               dest(x,y,z,v) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v);
13548           }
13549         } break;
13550         case 2 : {
13551           switch (interpolation) {
13552           case 2 :
13553             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13554               dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
13555                                             cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
13556             break;
13557           case 1 :
13558             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13559               dest(x,y,z,v) = (T)linear_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
13560                                              cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
13561             break;
13562           default :
13563             cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13564               dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),dimx()),
13565                                       cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),dimy()),z,v);
13566           }
13567         } break;
13568         default :
13569           throw CImgArgumentException("CImg<%s>::get_rotate() : Invalid border conditions %d (should be 0,1 or 2).",
13570                                       pixel_type(),border_conditions);
13571         }
13572       }
13573       return dest;
13574     }
13575 
13576     //! Rotate an image around a center point (\c cx,\c cy).
13577     /**
13578        \param angle = rotation angle (in degrees).
13579        \param cx = X-coordinate of the rotation center.
13580        \param cy = Y-coordinate of the rotation center.
13581        \param zoom = zoom.
13582        \param cond = rotation type. can be :
13583        - 0 = zero-value at borders
13584        - 1 = repeat image at borders
13585        - 2 = zero-value at borders and linear interpolation
13586     **/
13587     CImg<T>& rotate(const float angle, const float cx, const float cy, const float zoom,
13588                     const unsigned int border_conditions=3, const unsigned int interpolation=1) {
13589       return get_rotate(angle,cx,cy,zoom,border_conditions,interpolation).transfer_to(*this);
13590     }
13591 
13592     CImg<T> get_rotate(const float angle, const float cx, const float cy, const float zoom,
13593                        const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
13594       if (interpolation>2)
13595         throw CImgArgumentException("CImg<%s>::get_rotate() : Invalid interpolation parameter %d (should be {0=none, 1=linear or 2=cubic}).",
13596                                     pixel_type(),interpolation);
13597       if (is_empty()) return *this;
13598       CImg<T> dest(width,height,depth,dim);
13599       const float nangle = cimg::mod(angle,360.0f);
13600       if (border_conditions!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
13601         const int iangle = (int)nangle/90;
13602         switch (iangle) {
13603         case 1 : {
13604           dest.fill(0);
13605           const unsigned int
13606             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
13607             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
13608             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
13609             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
13610           cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
13611             dest(x,y,z,v) = (*this)(y-yoff,height-1-x+xoff,z,v);
13612         } break;
13613         case 2 : {
13614           cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v);
13615         } break;
13616         case 3 : {
13617           dest.fill(0);
13618           const unsigned int
13619             xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
13620             ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
13621             xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
13622             yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
13623           cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
13624             dest(x,y,z,v) = (*this)(width-1-y+yoff,x-xoff,z,v);
13625         } break;
13626         default :
13627           return *this;
13628         }
13629       } else {
13630         const float
13631           rad = (float)((nangle*cimg::valuePI)/180.0),
13632           ca = (float)cimg_std::cos(rad)/zoom,
13633           sa = (float)cimg_std::sin(rad)/zoom;
13634         switch (border_conditions) { // generic version
13635         case 0 : {
13636           switch (interpolation) {
13637           case 2 : {
13638             cimg_forXY(dest,x,y)
13639               cimg_forZV(*this,z,v)
13640               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);
13641           } break;
13642           case 1 : {
13643             cimg_forXY(dest,x,y)
13644               cimg_forZV(*this,z,v)
13645               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);
13646           } break;
13647           default : {
13648             cimg_forXY(dest,x,y)
13649               cimg_forZV(*this,z,v)
13650               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);
13651           }
13652           }
13653         } break;
13654         case 1 : {
13655           switch (interpolation) {
13656           case 2 : {
13657             cimg_forXY(dest,x,y)
13658               cimg_forZV(*this,z,v)
13659               dest(x,y,z,v) = (T)cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
13660             } break;
13661           case 1 : {
13662             cimg_forXY(dest,x,y)
13663               cimg_forZV(*this,z,v)
13664               dest(x,y,z,v) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
13665           } break;
13666           default : {
13667             cimg_forXY(dest,x,y)
13668               cimg_forZV(*this,z,v)
13669               dest(x,y,z,v) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v);
13670           }
13671           }
13672         } break;
13673         case 2 : {
13674           switch (interpolation) {
13675           case 2 : {
13676             cimg_forXY(dest,x,y)
13677               cimg_forZV(*this,z,v)
13678               dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
13679                                             cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
13680             } break;
13681           case 1 : {
13682             cimg_forXY(dest,x,y)
13683               cimg_forZV(*this,z,v)
13684               dest(x,y,z,v) = (T)linear_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
13685                                              cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
13686           } break;
13687           default : {
13688             cimg_forXY(dest,x,y)
13689               cimg_forZV(*this,z,v)
13690               dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),dimx()),
13691                                       cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),dimy()),z,v);
13692           }
13693           }
13694         } break;
13695         default :
13696           throw CImgArgumentException("CImg<%s>::get_rotate() : Incorrect border conditions %d (should be 0,1 or 2).",
13697                                       pixel_type(),border_conditions);
13698         }
13699       }
13700       return dest;
13701     }
13702 
13703     //! Resize an image.
13704     /**
13705        \param pdx Number of columns (new size along the X-axis).
13706        \param pdy Number of rows (new size along the Y-axis).
13707        \param pdz Number of slices (new size along the Z-axis).
13708        \param pdv Number of vector-channels (new size along the V-axis).
13709        \param interpolation_type Method of interpolation :
13710        - -1 = no interpolation : raw memory resizing.
13711        - 0 = no interpolation : additional space is filled according to \p border_condition.
13712        - 1 = bloc interpolation (nearest point).
13713        - 2 = moving average interpolation.
13714        - 3 = linear interpolation.
13715        - 4 = grid interpolation.
13716        - 5 = bi-cubic interpolation.
13717        \param border_condition Border condition type.
13718        \param center Set centering type (only if \p interpolation_type=0).
13719        \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
13720     **/
13721     CImg<T>& resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
13722                     const int interpolation_type=1, const int border_condition=-1, const bool center=false) {
13723       if (!pdx || !pdy || !pdz || !pdv) return assign();
13724       const unsigned int
13725         tdx = pdx<0?-pdx*width/100:pdx,
13726         tdy = pdy<0?-pdy*height/100:pdy,
13727         tdz = pdz<0?-pdz*depth/100:pdz,
13728         tdv = pdv<0?-pdv*dim/100:pdv,
13729         dx = tdx?tdx:1,
13730         dy = tdy?tdy:1,
13731         dz = tdz?tdz:1,
13732         dv = tdv?tdv:1;
13733       if (width==dx && height==dy && depth==dz && dim==dv) return *this;
13734       if (interpolation_type==-1 && dx*dy*dz*dv==size()) {
13735         width = dx; height = dy; depth = dz; dim = dv;
13736         return *this;
13737       }
13738       return get_resize(dx,dy,dz,dv,interpolation_type,border_condition,center).transfer_to(*this);
13739     }
13740 
13741     CImg<T> get_resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
13742                        const int interpolation_type=1, const int border_condition=-1, const bool center=false) const {
13743       if (!pdx || !pdy || !pdz || !pdv) return CImg<T>();
13744       const unsigned int
13745         tdx = pdx<0?-pdx*width/100:pdx,
13746         tdy = pdy<0?-pdy*height/100:pdy,
13747         tdz = pdz<0?-pdz*depth/100:pdz,
13748         tdv = pdv<0?-pdv*dim/100:pdv,
13749         dx = tdx?tdx:1,
13750         dy = tdy?tdy:1,
13751         dz = tdz?tdz:1,
13752         dv = tdv?tdv:1;
13753       if (width==dx && height==dy && depth==dz && dim==dv) return +*this;
13754       if (is_empty()) return CImg<T>(dx,dy,dz,dv,0);
13755 
13756       CImg<T> res;
13757 
13758       switch (interpolation_type) {
13759       case -1 : // Raw resizing
13760         cimg_std::memcpy(res.assign(dx,dy,dz,dv,0).data,data,sizeof(T)*cimg::min(size(),(long unsigned int)dx*dy*dz*dv));
13761         break;
13762 
13763       case 0 :  { // No interpolation
13764         const unsigned int bx = width-1, by = height-1, bz = depth-1, bv = dim-1;
13765         res.assign(dx,dy,dz,dv);
13766         switch (border_condition) {
13767         case 1 : {
13768           if (center) {
13769             const int
13770               x0 = (res.dimx()-dimx())/2,
13771               y0 = (res.dimy()-dimy())/2,
13772               z0 = (res.dimz()-dimz())/2,
13773               v0 = (res.dimv()-dimv())/2,
13774               x1 = x0 + (int)bx,
13775               y1 = y0 + (int)by,
13776               z1 = z0 + (int)bz,
13777               v1 = v0 + (int)bv;
13778             res.draw_image(x0,y0,z0,v0,*this);
13779             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);
13780           } else {
13781             res.draw_image(*this);
13782             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);
13783           }
13784           } break;
13785         case 2 : {
13786           int nx0 = 0, ny0 = 0, nz0 = 0, nv0 = 0;
13787           if (center) {
13788             const int
13789               x0 = (res.dimx()-dimx())/2,
13790               y0 = (res.dimy()-dimy())/2,
13791               z0 = (res.dimz()-dimz())/2,
13792               v0 = (res.dimv()-dimv())/2;
13793             nx0 = x0>0?x0-(1+x0/width)*width:x0;
13794             ny0 = y0>0?y0-(1+y0/height)*height:y0;
13795             nz0 = z0>0?z0-(1+z0/depth)*depth:z0;
13796             nv0 = v0>0?v0-(1+v0/dim)*dim:v0;
13797           }
13798           for (int k = nv0; k<(int)dv; k+=dimv())
13799             for (int z = nz0; z<(int)dz; z+=dimz())
13800               for (int y = ny0; y<(int)dy; y+=dimy())
13801                 for (int x = nx0; x<(int)dx; x+=dimx()) res.draw_image(x,y,z,k,*this);
13802           } break;
13803         default : {
13804           res.fill(0);
13805           if (center) res.draw_image((res.dimx()-dimx())/2,(res.dimy()-dimy())/2,(res.dimz()-dimz())/2,(res.dimv()-dimv())/2,*this);
13806           else res.draw_image(*this);
13807         }
13808         }
13809       } break;
13810 
13811       case 1 : { // Nearest-neighbor interpolation
13812         res.assign(dx,dy,dz,dv);
13813         unsigned int
13814           *const offx = new unsigned int[dx],
13815           *const offy = new unsigned int[dy+1],
13816           *const offz = new unsigned int[dz+1],
13817           *const offv = new unsigned int[dv+1],
13818           *poffx, *poffy, *poffz, *poffv,
13819           curr, old;
13820         const unsigned int wh = width*height, whd = width*height*depth, rwh = dx*dy, rwhd = dx*dy*dz;
13821         poffx = offx; curr = 0; { cimg_forX(res,x) { old=curr; curr=(x+1)*width/dx; *(poffx++) = (unsigned int)curr-(unsigned int)old; }}
13822         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;
13823         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;
13824         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;
13825         T *ptrd = res.data;
13826         const T* ptrv = data;
13827         poffv = offv;
13828         for (unsigned int k=0; k<dv; ) {
13829           const T *ptrz = ptrv;
13830           poffz = offz;
13831           for (unsigned int z=0; z<dz; ) {
13832             const T *ptry = ptrz;
13833             poffy = offy;
13834             for (unsigned int y=0; y<dy; ) {
13835               const T *ptrx = ptry;
13836               poffx = offx;
13837               cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poffx++); }
13838               ++y;
13839               unsigned int dy = *(poffy++);
13840               for (;!dy && y<dy; cimg_std::memcpy(ptrd, ptrd-dx, sizeof(T)*dx), ++y, ptrd+=dx, dy=*(poffy++)) {}
13841               ptry+=dy;
13842             }
13843             ++z;
13844             unsigned int dz = *(poffz++);
13845             for (;!dz && z<dz; cimg_std::memcpy(ptrd, ptrd-rwh, sizeof(T)*rwh), ++z, ptrd+=rwh, dz=*(poffz++)) {}
13846             ptrz+=dz;
13847           }
13848           ++k;
13849           unsigned int dv = *(poffv++);
13850           for (;!dv && k<dv; cimg_std::memcpy(ptrd, ptrd-rwhd, sizeof(T)*rwhd), ++k, ptrd+=rwhd, dv=*(poffv++)) {}
13851           ptrv+=dv;
13852         }
13853         delete[] offx; delete[] offy; delete[] offz; delete[] offv;
13854       } break;
13855 
13856       case 2 : { // Moving average
13857         bool instance_first = true;
13858         if (dx!=width) {
13859           CImg<Tfloat> tmp(dx,height,depth,dim,0);
13860           for (unsigned int a = width*dx, b = width, c = dx, s = 0, t = 0; a; ) {
13861             const unsigned int d = cimg::min(b,c);
13862             a-=d; b-=d; c-=d;
13863             cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d;
13864             if (!b) { cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)/=width; ++t; b = width; }
13865             if (!c) { ++s; c = dx; }
13866           }
13867           tmp.transfer_to(res);
13868           instance_first = false;
13869         }
13870         if (dy!=height) {
13871           CImg<Tfloat> tmp(dx,dy,depth,dim,0);
13872           for (unsigned int a = height*dy, b = height, c = dy, s = 0, t = 0; a; ) {
13873             const unsigned int d = cimg::min(b,c);
13874             a-=d; b-=d; c-=d;
13875             if (instance_first) cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d;
13876             else cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d;
13877             if (!b) { cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)/=height; ++t; b = height; }
13878             if (!c) { ++s; c = dy; }
13879           }
13880           tmp.transfer_to(res);
13881           instance_first = false;
13882         }
13883         if (dz!=depth) {
13884           CImg<Tfloat> tmp(dx,dy,dz,dim,0);
13885           for (unsigned int a = depth*dz, b = depth, c = dz, s = 0, t = 0; a; ) {
13886             const unsigned int d = cimg::min(b,c);
13887             a-=d; b-=d; c-=d;
13888             if (instance_first) cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d;
13889             else cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d;
13890             if (!b) { cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)/=depth; ++t; b = depth; }
13891             if (!c) { ++s; c = dz; }
13892           }
13893           tmp.transfer_to(res);
13894           instance_first = false;
13895         }
13896         if (dv!=dim) {
13897           CImg<Tfloat> tmp(dx,dy,dz,dv,0);
13898           for (unsigned int a = dim*dv, b = dim, c = dv, s = 0, t = 0; a; ) {
13899             const unsigned int d = cimg::min(b,c);
13900             a-=d; b-=d; c-=d;
13901             if (instance_first) cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d;
13902             else cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d;
13903             if (!b) { cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)/=dim; ++t; b = dim; }
13904             if (!c) { ++s; c = dv; }
13905           }
13906           tmp.transfer_to(res);
13907           instance_first = false;
13908         }
13909       } break;
13910 
13911       case 3 : { // Linear interpolation
13912         const unsigned int dimmax = cimg::max(dx,dy,dz,dv);
13913         const float
13914           sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
13915           sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
13916           sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
13917           sv = (border_condition<0 && dv>dim   )?(dv>1?(dim-1.0f)/(dv-1)   :0):(float)dim/dv;
13918 
13919         unsigned int *const off = new unsigned int[dimmax], *poff;
13920         float *const foff = new float[dimmax], *pfoff, old, curr;
13921         CImg<T> resx, resy, resz, resv;
13922         T *ptrd;
13923 
13924         if (dx!=width) {
13925           if (width==1) resx = get_resize(dx,height,depth,dim,1,0);
13926           else {
13927             resx.assign(dx,height,depth,dim);
13928             curr = old = 0; poff = off; pfoff = foff;
13929             cimg_forX(resx,x) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sx; *(poff++) = (unsigned int)curr-(unsigned int)old; }
13930             ptrd = resx.data;
13931             const T *ptrs0 = data;
13932             cimg_forYZV(resx,y,z,k) {
13933               poff = off; pfoff = foff;
13934               const T *ptrs = ptrs0, *const ptrsmax = ptrs0 + (width-1);
13935               cimg_forX(resx,x) {
13936                 const float alpha = *(pfoff++);
13937                 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+1):(border_condition?val1:(T)0);
13938                 *(ptrd++) = (T)((1-alpha)*val1 + alpha*val2);
13939                 ptrs+=*(poff++);
13940               }
13941               ptrs0+=width;
13942             }
13943           }
13944         } else resx.assign(*this,true);
13945 
13946         if (dy!=height) {
13947           if (height==1) resy = resx.get_resize(dx,dy,depth,dim,1,0);
13948           else {
13949             resy.assign(dx,dy,depth,dim);
13950             curr = old = 0; poff = off; pfoff = foff;
13951             cimg_forY(resy,y) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sy; *(poff++) = dx*((unsigned int)curr-(unsigned int)old); }
13952             cimg_forXZV(resy,x,z,k) {
13953               ptrd = resy.ptr(x,0,z,k);
13954               const T *ptrs = resx.ptr(x,0,z,k), *const ptrsmax = ptrs + (height-1)*dx;
13955               poff = off; pfoff = foff;
13956               cimg_forY(resy,y) {
13957                 const float alpha = *(pfoff++);
13958                 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+dx):(border_condition?val1:(T)0);
13959                 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
13960                 ptrd+=dx;
13961                 ptrs+=*(poff++);
13962               }
13963             }
13964           }
13965           resx.assign();
13966         } else resy.assign(resx,true);
13967 
13968         if (dz!=depth) {
13969           if (depth==1) resz = resy.get_resize(dx,dy,dz,dim,1,0);
13970           else {
13971             const unsigned int wh = dx*dy;
13972             resz.assign(dx,dy,dz,dim);
13973             curr = old = 0; poff = off; pfoff = foff;
13974             cimg_forZ(resz,z) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sz; *(poff++) = wh*((unsigned int)curr-(unsigned int)old); }
13975             cimg_forXYV(resz,x,y,k) {
13976               ptrd = resz.ptr(x,y,0,k);
13977               const T *ptrs = resy.ptr(x,y,0,k), *const ptrsmax = ptrs + (depth-1)*wh;
13978               poff = off; pfoff = foff;
13979               cimg_forZ(resz,z) {
13980                 const float alpha = *(pfoff++);
13981                 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+wh):(border_condition?val1:(T)0);
13982                 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
13983                 ptrd+=wh;
13984                 ptrs+=*(poff++);
13985               }
13986             }
13987           }
13988           resy.assign();
13989         } else resz.assign(resy,true);
13990 
13991         if (dv!=dim) {
13992           if (dim==1) resv = resz.get_resize(dx,dy,dz,dv,1,0);
13993           else {
13994             const unsigned int whd = dx*dy*dz;
13995             resv.assign(dx,dy,dz,dv);
13996             curr = old = 0; poff = off; pfoff = foff;
13997             cimg_forV(resv,k) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sv; *(poff++) = whd*((unsigned int)curr-(unsigned int)old); }
13998             cimg_forXYZ(resv,x,y,z) {
13999               ptrd = resv.ptr(x,y,z,0);
14000               const T *ptrs = resz.ptr(x,y,z,0), *const ptrsmax = ptrs + (dim-1)*whd;
14001               poff = off; pfoff = foff;
14002               cimg_forV(resv,k) {
14003                 const float alpha = *(pfoff++);
14004                 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+whd):(border_condition?val1:(T)0);
14005                 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
14006                 ptrd+=whd;
14007                 ptrs+=*(poff++);
14008               }
14009             }
14010           }
14011           resz.assign();
14012         } else resv.assign(resz,true);
14013 
14014         delete[] off; delete[] foff;
14015         return resv.is_shared?(resz.is_shared?(resy.is_shared?(resx.is_shared?(+(*this)):resx):resy):resz):resv;
14016       } break;
14017 
14018       case 4 : { // Grid filling
14019         res.assign(dx,dy,dz,dv,0);
14020         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);
14021       } break;
14022 
14023       case 5 : { // Cubic interpolation
14024         const float
14025           sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
14026           sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
14027           sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
14028           sv = (border_condition<0 && dv>dim   )?(dv>1?(dim-1.0f)/(dv-1)   :0):(float)dim/dv;
14029         res.assign(dx,dy,dz,dv);
14030         T *ptrd = res.ptr();
14031         float cx, cy, cz, ck = 0;
14032         cimg_forV(res,k) { cz = 0;
14033         cimg_forZ(res,z) { cy = 0;
14034         cimg_forY(res,y) { cx = 0;
14035         cimg_forX(res,x) {
14036           *(ptrd++) = (T)(border_condition?_cubic_atXY(cx,cy,(int)cz,(int)ck):cubic_atXY(cx,cy,(int)cz,(int)ck,0));
14037           cx+=sx;
14038         } cy+=sy;
14039         } cz+=sz;
14040         } ck+=sv;
14041         }
14042       } break;
14043 
14044       default : // Invalid interpolation method
14045         throw CImgArgumentException("CImg<%s>::resize() : Invalid interpolation_type %d "
14046                                     "(should be { -1=raw, 0=zero, 1=nearest, 2=average, 3=linear, 4=grid, 5=bicubic}).",
14047                                     pixel_type(),interpolation_type);
14048       }
14049       return res;
14050     }
14051 
14052     //! Resize an image.
14053     /**
14054        \param src  Image giving the geometry of the resize.
14055        \param interpolation_type  Interpolation method :
14056        - 1 = raw memory
14057        - 0 = no interpolation : additional space is filled with 0.
14058        - 1 = bloc interpolation (nearest point).
14059        - 2 = mosaic : image is repeated if necessary.
14060        - 3 = linear interpolation.
14061        - 4 = grid interpolation.
14062        - 5 = bi-cubic interpolation.
14063        \param border_condition Border condition type.
14064        \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
14065     **/
14066     template<typename t>
14067     CImg<T>& resize(const CImg<t>& src, const int interpolation_type=1,
14068                     const int border_condition=-1, const bool center=false) {
14069       return resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
14070     }
14071 
14072     template<typename t>
14073     CImg<T> get_resize(const CImg<t>& src, const int interpolation_type=1,
14074                        const int border_condition=-1, const bool center=false) const {
14075       return get_resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
14076     }
14077 
14078     //! Resize an image.
14079     /**
14080        \param disp = Display giving the geometry of the resize.
14081        \param interpolation_type = Resizing type :
14082        - 0 = no interpolation : additional space is filled with 0.
14083        - 1 = bloc interpolation (nearest point).
14084        - 2 = mosaic : image is repeated if necessary.
14085        - 3 = linear interpolation.
14086        - 4 = grid interpolation.
14087        - 5 = bi-cubic interpolation.
14088        - 6 = moving average (best quality for photographs)
14089        \param border_condition Border condition type.
14090        \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
14091     **/
14092     CImg<T>& resize(const CImgDisplay& disp, const int interpolation_type=1,
14093                     const int border_condition=-1, const bool center=false) {
14094       return resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
14095     }
14096 
14097     CImg<T> get_resize(const CImgDisplay& disp, const int interpolation_type=1,
14098                        const int border_condition=-1, const bool center=false) const {
14099       return get_resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
14100     }
14101 
14102     //! Half-resize an image, using a special optimized filter.
14103     CImg<T>& resize_halfXY() {
14104       return get_resize_halfXY().transfer_to(*this);
14105     }
14106 
14107     CImg<T> get_resize_halfXY() const {
14108       if (is_empty()) return *this;
14109       const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f,
14110                               0.1231940459f,  0.1935127547f, 0.1231940459f,
14111                               0.07842776544f, 0.1231940459f, 0.07842776544f };
14112       T I[9] = { 0 };
14113       CImg<T> dest(width/2,height/2,depth,dim);
14114       cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I)
14115         if (x%2 && y%2) dest(x/2,y/2,z,k) = (T)
14116                           (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
14117                            I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
14118                            I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
14119       return dest;
14120     }
14121 
14122     //! Upscale an image by a factor 2x.
14123     /**
14124        Use anisotropic upscaling algorithm described at
14125        http://scale2x.sourceforge.net/algorithm.html
14126     **/
14127     CImg<T>& resize_doubleXY() {
14128       return get_resize_doubleXY().transfer_to(*this);
14129     }
14130 
14131     CImg<T> get_resize_doubleXY() const {
14132 #define _cimg_gs2x_for3(bound,i) \
14133  for (int i = 0, _p1##i = 0, \
14134       _n1##i = 1>=(bound)?(int)(bound)-1:1; \
14135       _n1##i<(int)(bound) || i==--_n1##i; \
14136       _p1##i = i++, ++_n1##i, ptrd1+=(res).width, ptrd2+=(res).width)
14137 
14138 #define _cimg_gs2x_for3x3(img,x,y,z,v,I) \
14139   _cimg_gs2x_for3((img).height,y) for (int x = 0, \
14140    _p1##x = 0, \
14141    _n1##x = (int)( \
14142    (I[1] = (img)(0,_p1##y,z,v)), \
14143    (I[3] = I[4] = (img)(0,y,z,v)), \
14144    (I[7] = (img)(0,_n1##y,z,v)),        \
14145    1>=(img).width?(int)((img).width)-1:1); \
14146    (_n1##x<(int)((img).width) && ( \
14147    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
14148    (I[5] = (img)(_n1##x,y,z,v)), \
14149    (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
14150    x==--_n1##x; \
14151    I[1] = I[2], \
14152    I[3] = I[4], I[4] = I[5], \
14153    I[7] = I[8], \
14154    _p1##x = x++, ++_n1##x)
14155 
14156       if (is_empty()) return *this;
14157       CImg<T> res(2*width,2*height,depth,dim);
14158       CImg_3x3(I,T);
14159       cimg_forZV(*this,z,k) {
14160         T
14161           *ptrd1 = res.ptr(0,0,0,k),
14162           *ptrd2 = ptrd1 + res.width;
14163         _cimg_gs2x_for3x3(*this,x,y,0,k,I) {
14164           if (Icp!=Icn && Ipc!=Inc) {
14165             *(ptrd1++) = Ipc==Icp?Ipc:Icc;
14166             *(ptrd1++) = Icp==Inc?Inc:Icc;
14167             *(ptrd2++) = Ipc==Icn?Ipc:Icc;
14168             *(ptrd2++) = Icn==Inc?Inc:Icc;
14169           } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; }
14170         }
14171       }
14172       return res;
14173     }
14174 
14175     //! Upscale an image by a factor 3x.
14176     /**
14177        Use anisotropic upscaling algorithm described at
14178        http://scale2x.sourceforge.net/algorithm.html
14179     **/
14180     CImg<T>& resize_tripleXY() {
14181       return get_resize_tripleXY().transfer_to(*this);
14182     }
14183 
14184     CImg<T> get_resize_tripleXY() const {
14185 #define _cimg_gs3x_for3(bound,i) \
14186  for (int i = 0, _p1##i = 0, \
14187       _n1##i = 1>=(bound)?(int)(bound)-1:1; \
14188       _n1##i<(int)(bound) || i==--_n1##i; \
14189       _p1##i = i++, ++_n1##i, ptrd1+=2*(res).width, ptrd2+=2*(res).width, ptrd3+=2*(res).width)
14190 
14191 #define _cimg_gs3x_for3x3(img,x,y,z,v,I) \
14192   _cimg_gs3x_for3((img).height,y) for (int x = 0, \
14193    _p1##x = 0, \
14194    _n1##x = (int)( \
14195    (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
14196    (I[3] = I[4] = (img)(0,y,z,v)), \
14197    (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
14198    1>=(img).width?(int)((img).width)-1:1); \
14199    (_n1##x<(int)((img).width) && ( \
14200    (I[2] = (img)(_n1##x,_p1##y,z,v)), \
14201    (I[5] = (img)(_n1##x,y,z,v)), \
14202    (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
14203    x==--_n1##x; \
14204    I[0] = I[1], I[1] = I[2], \
14205    I[3] = I[4], I[4] = I[5], \
14206    I[6] = I[7], I[7] = I[8], \
14207    _p1##x = x++, ++_n1##x)
14208 
14209       if (is_empty()) return *this;
14210       CImg<T> res(3*width,3*height,depth,dim);
14211       CImg_3x3(I,T);
14212       cimg_forZV(*this,z,k) {
14213         T
14214           *ptrd1 = res.ptr(0,0,0,k),
14215           *ptrd2 = ptrd1 + res.width,
14216           *ptrd3 = ptrd2 + res.width;
14217         _cimg_gs3x_for3x3(*this,x,y,0,k,I) {
14218           if (Icp != Icn && Ipc != Inc) {
14219             *(ptrd1++) = Ipc==Icp?Ipc:Icc;
14220             *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc;
14221             *(ptrd1++) = Icp==Inc?Inc:Icc;
14222             *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc;
14223             *(ptrd2++) = Icc;
14224             *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc;
14225             *(ptrd3++) = Ipc==Icn?Ipc:Icc;
14226             *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc;
14227             *(ptrd3++) = Icn==Inc?Inc:Icc;
14228           } else {
14229             *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc;
14230             *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc;
14231             *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc;
14232           }
14233         }
14234       }
14235       return res;
14236     }
14237 
14238     // Warp an image.
14239     template<typename t>
14240     CImg<T>& warp(const CImg<t>& warp, const bool relative=false,
14241                   const bool interpolation=true, const unsigned int border_conditions=0) {
14242       return get_warp(warp,relative,interpolation,border_conditions).transfer_to(*this);
14243     }
14244 
14245     template<typename t>
14246     CImg<T> get_warp(const CImg<t>& warp, const bool relative=false,
14247                      const bool interpolation=true, const unsigned int border_conditions=0) const {
14248       if (is_empty() || !warp) return *this;
14249       if (!is_sameXYZ(warp))
14250         throw CImgArgumentException("CImg<%s>::warp() : Instance image (%u,%u,%u,%u,%p) and warping field (%u,%u,%u,%u,%p) "
14251                                     "have different XYZ dimensions.",
14252                                     pixel_type(),width,height,depth,dim,data,
14253                                     warp.width,warp.height,warp.depth,warp.dim,warp.data);
14254       CImg<T> res(width,height,depth,dim);
14255       switch (warp.dim) {
14256       case 1 : // 1D warping.
14257         if (relative) { // Relative warp coordinates
14258           if (interpolation) switch (border_conditions) {
14259           case 2 : {
14260             cimg_forXYZV(*this,x,y,z,v)
14261               res(x,y,z,v) = (T)_linear_atX(cimg::mod(x-(float)warp(x,y,z,0),(float)width),y,z,v);
14262           } break;
14263           case 1 : {
14264             cimg_forXYZV(*this,x,y,z,v)
14265               res(x,y,z,v) = (T)_linear_atX(x-(float)warp(x,y,z,0),y,z,v);
14266           } break;
14267           default : {
14268             cimg_forXYZV(*this,x,y,z,v)
14269               res(x,y,z,v) = (T)linear_atX(x-(float)warp(x,y,z,0),y,z,v,0);
14270           }
14271           } else switch (border_conditions) {
14272           case 2 : {
14273             cimg_forXYZV(*this,x,y,z,v)
14274               res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),y,z,v);
14275           } break;
14276           case 1 : {
14277             cimg_forXYZV(*this,x,y,z,v)
14278               res(x,y,z,v) = _atX(x-(int)warp(x,y,z,0),y,z,v);
14279           } break;
14280           default : {
14281             cimg_forXYZV(*this,x,y,z,v)
14282               res(x,y,z,v) = atX(x-(int)warp(x,y,z,0),y,z,v,0);
14283           }
14284           }
14285         } else { // Absolute warp coordinates
14286           if (interpolation) switch (border_conditions) {
14287           case 2 : {
14288             cimg_forXYZV(*this,x,y,z,v)
14289               res(x,y,z,v) = (T)_linear_atX(cimg::mod((float)warp(x,y,z,0),(float)width),y,z,v);
14290           } break;
14291           case 1 : {
14292             cimg_forXYZV(*this,x,y,z,v)
14293               res(x,y,z,v) = (T)_linear_atX((float)warp(x,y,z,0),y,z,v);
14294           } break;
14295           default : {
14296             cimg_forXYZV(*this,x,y,z,v)
14297               res(x,y,z,v) = (T)linear_atX((float)warp(x,y,z,0),y,z,v,0);
14298           }
14299           } else switch (border_conditions) {
14300           case 2 : {
14301             cimg_forXYZV(*this,x,y,z,v)
14302               res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),y,z,v);
14303           } break;
14304           case 1 : {
14305             cimg_forXYZV(*this,x,y,z,v)
14306               res(x,y,z,v) = _atX((int)warp(x,y,z,0),y,z,v);
14307           } break;
14308           default : {
14309             cimg_forXYZV(*this,x,y,z,v)
14310               res(x,y,z,v) = atX((int)warp(x,y,z,0),y,z,v,0);
14311           }
14312           }
14313         }
14314         break;
14315 
14316       case 2 : // 2D warping
14317         if (relative) { // Relative warp coordinates
14318           if (interpolation) switch (border_conditions) {
14319           case 2 : {
14320             cimg_forXYZV(*this,x,y,z,v)
14321               res(x,y,z,v) = (T)_linear_atXY(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
14322                                              cimg::mod(y-(float)warp(x,y,z,1),(float)height),z,v);
14323           } break;
14324           case 1 : {
14325             cimg_forXYZV(*this,x,y,z,v)
14326               res(x,y,z,v) = (T)_linear_atXY(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z,v);
14327           } break;
14328           default : {
14329             cimg_forXYZV(*this,x,y,z,v)
14330               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);
14331           }
14332           } else switch (border_conditions) {
14333           case 2 : {
14334             cimg_forXYZV(*this,x,y,z,v)
14335               res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
14336                                      cimg::mod(y-(int)warp(x,y,z,1),(int)height),z,v);
14337           } break;
14338           case 1 : {
14339             cimg_forXYZV(*this,x,y,z,v)
14340               res(x,y,z,v) = _atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v);
14341           } break;
14342           default : {
14343             cimg_forXYZV(*this,x,y,z,v)
14344               res(x,y,z,v) = atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v,0);
14345           }
14346           }
14347         } else { // Absolute warp coordinates
14348           if (interpolation) switch (border_conditions) {
14349           case 2 : {
14350             cimg_forXYZV(*this,x,y,z,v)
14351               res(x,y,z,v) = (T)_linear_atXY(cimg::mod((float)warp(x,y,z,0),(float)width),
14352                                              cimg::mod((float)warp(x,y,z,1),(float)height),z,v);
14353           } break;
14354           case 1 : {
14355             cimg_forXYZV(*this,x,y,z,v)
14356               res(x,y,z,v) = (T)_linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v);
14357           } break;
14358           default : {
14359             cimg_forXYZV(*this,x,y,z,v)
14360               res(x,y,z,v) = (T)linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v,0);
14361           }
14362           } else switch (border_conditions) {
14363           case 2 : {
14364             cimg_forXYZV(*this,x,y,z,v)
14365               res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
14366                                      cimg::mod((int)warp(x,y,z,1),(int)depth),z,v);
14367           } break;
14368           case 1 : {
14369             cimg_forXYZV(*this,x,y,z,v)
14370               res(x,y,z,v) = _atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v);
14371           } break;
14372           default : {
14373             cimg_forXYZV(*this,x,y,z,v)
14374               res(x,y,z,v) = atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v,0);
14375           }
14376           }
14377         }
14378         break;
14379 
14380       case 3 : // 3D warping
14381         if (relative) { // Relative warp coordinates
14382           if (interpolation) switch (border_conditions) {
14383           case 2 : {
14384             cimg_forXYZV(*this,x,y,z,v)
14385               res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
14386                                               cimg::mod(y-(float)warp(x,y,z,1),(float)height),
14387                                               cimg::mod(z-(float)warp(x,y,z,2),(float)depth),v);
14388           } break;
14389           case 1 : {
14390             cimg_forXYZV(*this,x,y,z,v)
14391               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);
14392           } break;
14393           default : {
14394             cimg_forXYZV(*this,x,y,z,v)
14395               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);
14396           }
14397           } else switch (border_conditions) {
14398           case 2 : {
14399             cimg_forXYZV(*this,x,y,z,v)
14400               res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
14401                                      cimg::mod(y-(int)warp(x,y,z,1),(int)height),
14402                                      cimg::mod(z-(int)warp(x,y,z,2),(int)depth),v);
14403           } break;
14404           case 1 : {
14405             cimg_forXYZV(*this,x,y,z,v)
14406               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);
14407           } break;
14408           default : {
14409             cimg_forXYZV(*this,x,y,z,v)
14410               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);
14411           }
14412           }
14413         } else { // Absolute warp coordinates
14414           if (interpolation) switch (border_conditions) {
14415           case 2 : {
14416             cimg_forXYZV(*this,x,y,z,v)
14417               res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod((float)warp(x,y,z,0),(float)width),
14418                                               cimg::mod((float)warp(x,y,z,1),(float)height),
14419                                               cimg::mod((float)warp(x,y,z,2),(float)depth),v);
14420           } break;
14421           case 1 : {
14422             cimg_forXYZV(*this,x,y,z,v)
14423               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);
14424           } break;
14425           default : {
14426             cimg_forXYZV(*this,x,y,z,v)
14427               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);
14428           }
14429           } else switch (border_conditions) {
14430           case 2 : {
14431             cimg_forXYZV(*this,x,y,z,v)
14432               res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
14433                                      cimg::mod((int)warp(x,y,z,1),(int)height),
14434                                      cimg::mod((int)warp(x,y,z,2),(int)depth),v);
14435           } break;
14436           case 1 : {
14437             cimg_forXYZV(*this,x,y,z,v)
14438               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);
14439           } break;
14440           default : {
14441             cimg_forXYZV(*this,x,y,z,v)
14442               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);
14443           }
14444           }
14445         }
14446         break;
14447 
14448       default : // 4D warping
14449         if (relative) { // Relative warp coordinates
14450           if (interpolation) switch (border_conditions) {
14451           case 2 : {
14452             cimg_forXYZV(*this,x,y,z,v)
14453               res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
14454                                                cimg::mod(y-(float)warp(x,y,z,1),(float)height),
14455                                                cimg::mod(z-(float)warp(x,y,z,2),(float)depth),
14456                                                cimg::mod(z-(float)warp(x,y,z,3),(float)dim));
14457           } break;
14458           case 1 : {
14459             cimg_forXYZV(*this,x,y,z,v)
14460               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));
14461           } break;
14462           default : {
14463             cimg_forXYZV(*this,x,y,z,v)
14464               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);
14465           }
14466           } else switch (border_conditions) {
14467           case 2 : {
14468             cimg_forXYZV(*this,x,y,z,v)
14469               res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
14470                                      cimg::mod(y-(int)warp(x,y,z,1),(int)height),
14471                                      cimg::mod(z-(int)warp(x,y,z,2),(int)depth),
14472                                      cimg::mod(v-(int)warp(x,y,z,3),(int)dim));
14473           } break;
14474           case 1 : {
14475             cimg_forXYZV(*this,x,y,z,v)
14476               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));
14477           } break;
14478           default : {
14479             cimg_forXYZV(*this,x,y,z,v)
14480               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);
14481           }
14482           }
14483         } else { // Absolute warp coordinates
14484           if (interpolation) switch (border_conditions) {
14485           case 2 : {
14486             cimg_forXYZV(*this,x,y,z,v)
14487               res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod((float)warp(x,y,z,0),(float)width),
14488                                                cimg::mod((float)warp(x,y,z,1),(float)height),
14489                                                cimg::mod((float)warp(x,y,z,2),(float)depth),
14490                                                cimg::mod((float)warp(x,y,z,3),(float)dim));
14491           } break;
14492           case 1 : {
14493             cimg_forXYZV(*this,x,y,z,v)
14494               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));
14495           } break;
14496           default : {
14497             cimg_forXYZV(*this,x,y,z,v)
14498               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);
14499           }
14500           } else switch (border_conditions) {
14501           case 2 : {
14502             cimg_forXYZV(*this,x,y,z,v)
14503               res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
14504                                      cimg::mod((int)warp(x,y,z,1),(int)height),
14505                                      cimg::mod((int)warp(x,y,z,2),(int)depth),
14506                                      cimg::mod((int)warp(x,y,z,3),(int)dim));
14507           } break;
14508           case 1 : {
14509             cimg_forXYZV(*this,x,y,z,v)
14510               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));
14511           } break;
14512           default : {
14513             cimg_forXYZV(*this,x,y,z,v)
14514               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);
14515           }
14516           }
14517         }
14518       }
14519       return res;
14520     }
14521 
14522     // Permute axes order (internal).
14523     template<typename t>
14524     CImg<t> _get_permute_axes(const char *permut, const t&) const {
14525       if (is_empty() || !permut) return CImg<t>(*this,false);
14526       CImg<t> res;
14527       const T* ptrs = data;
14528       if (!cimg::strncasecmp(permut,"xyzv",4)) return (+*this);
14529       if (!cimg::strncasecmp(permut,"xyvz",4)) {
14530         res.assign(width,height,dim,depth);
14531         cimg_forXYZV(*this,x,y,z,v) res(x,y,v,z) = (t)*(ptrs++);
14532       }
14533       if (!cimg::strncasecmp(permut,"xzyv",4)) {
14534         res.assign(width,depth,height,dim);
14535         cimg_forXYZV(*this,x,y,z,v) res(x,z,y,v) = (t)*(ptrs++);
14536       }
14537       if (!cimg::strncasecmp(permut,"xzvy",4)) {
14538         res.assign(width,depth,dim,height);
14539         cimg_forXYZV(*this,x,y,z,v) res(x,z,v,y) = (t)*(ptrs++);
14540       }
14541       if (!cimg::strncasecmp(permut,"xvyz",4)) {
14542         res.assign(width,dim,height,depth);
14543         cimg_forXYZV(*this,x,y,z,v) res(x,v,y,z) = (t)*(ptrs++);
14544       }
14545       if (!cimg::strncasecmp(permut,"xvzy",4)) {
14546         res.assign(width,dim,depth,height);
14547         cimg_forXYZV(*this,x,y,z,v) res(x,v,z,y) = (t)*(ptrs++);
14548       }
14549       if (!cimg::strncasecmp(permut,"yxzv",4)) {
14550         res.assign(height,width,depth,dim);
14551         cimg_forXYZV(*this,x,y,z,v) res(y,x,z,v) = (t)*(ptrs++);
14552       }
14553       if (!cimg::strncasecmp(permut,"yxvz",4)) {
14554         res.assign(height,width,dim,depth);
14555         cimg_forXYZV(*this,x,y,z,v) res(y,x,v,z) = (t)*(ptrs++);
14556       }
14557       if (!cimg::strncasecmp(permut,"yzxv",4)) {
14558         res.assign(height,depth,width,dim);
14559         cimg_forXYZV(*this,x,y,z,v) res(y,z,x,v) = (t)*(ptrs++);
14560       }
14561       if (!cimg::strncasecmp(permut,"yzvx",4)) {
14562         res.assign(height,depth,dim,width);
14563         switch (width) {
14564         case 1 : {
14565           t *ptrR = res.ptr(0,0,0,0);
14566           for (unsigned long siz = height*depth*dim; siz; --siz) {
14567             *(ptrR++) = (t)*(ptrs++);
14568           }
14569         } break;
14570         case 2 : {
14571           t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1);
14572           for (unsigned long siz = height*depth*dim; siz; --siz) {
14573             *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++);
14574           }
14575         } break;
14576         case 3 : { // Optimization for the classical conversion from interleaved RGB to planar RGB
14577           t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1), *ptrB = res.ptr(0,0,0,2);
14578           for (unsigned long siz = height*depth*dim; siz; --siz) {
14579             *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++);
14580           }
14581         } break;
14582         case 4 : { // Optimization for the classical conversion from interleaved RGBA to planar RGBA
14583           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);
14584           for (unsigned long siz = height*depth*dim; siz; --siz) {
14585             *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++); *(ptrA++) = (t)*(ptrs++);
14586           }
14587         } break;
14588         default : {
14589           cimg_forXYZV(*this,x,y,z,v) res(y,z,v,x) = *(ptrs++);
14590           return res;
14591         }
14592         }
14593       }
14594       if (!cimg::strncasecmp(permut,"yvxz",4)) {
14595         res.assign(height,dim,width,depth);
14596         cimg_forXYZV(*this,x,y,z,v) res(y,v,x,z) = (t)*(ptrs++);
14597       }
14598       if (!cimg::strncasecmp(permut,"yvzx",4)) {
14599         res.assign(height,dim,depth,width);
14600         cimg_forXYZV(*this,x,y,z,v) res(y,v,z,x) = (t)*(ptrs++);
14601       }
14602       if (!cimg::strncasecmp(permut,"zxyv",4)) {
14603         res.assign(depth,width,height,dim);
14604         cimg_forXYZV(*this,x,y,z,v) res(z,x,y,v) = (t)*(ptrs++);
14605       }
14606       if (!cimg::strncasecmp(permut,"zxvy",4)) {
14607         res.assign(depth,width,dim,height);
14608         cimg_forXYZV(*this,x,y,z,v) res(z,x,v,y) = (t)*(ptrs++);
14609       }
14610       if (!cimg::strncasecmp(permut,"zyxv",4)) {
14611         res.assign(depth,height,width,dim);
14612         cimg_forXYZV(*this,x,y,z,v) res(z,y,x,v) = (t)*(ptrs++);
14613       }
14614       if (!cimg::strncasecmp(permut,"zyvx",4)) {
14615         res.assign(depth,height,dim,width);
14616         cimg_forXYZV(*this,x,y,z,v) res(z,y,v,x) = (t)*(ptrs++);
14617       }
14618       if (!cimg::strncasecmp(permut,"zvxy",4)) {
14619         res.assign(depth,dim,width,height);
14620         cimg_forXYZV(*this,x,y,z,v) res(z,v,x,y) = (t)*(ptrs++);
14621       }
14622       if (!cimg::strncasecmp(permut,"zvyx",4)) {
14623         res.assign(depth,dim,height,width);
14624         cimg_forXYZV(*this,x,y,z,v) res(z,v,y,x) = (t)*(ptrs++);
14625       }
14626       if (!cimg::strncasecmp(permut,"vxyz",4)) {
14627         res.assign(dim,width,height,depth);
14628         switch (dim) {
14629         case 1 : {
14630           const T *ptrR = ptr(0,0,0,0);
14631           t *ptrd = res.ptr();
14632           for (unsigned long siz = width*height*depth; siz; --siz) {
14633             *(ptrd++) = (t)*(ptrR++);
14634           }
14635         } break;
14636         case 2 : {
14637           const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1);
14638           t *ptrd = res.ptr();
14639           for (unsigned long siz = width*height*depth; siz; --siz) {
14640             *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++);
14641           }
14642         } break;
14643         case 3 : { // Optimization for the classical conversion from planar RGB to interleaved RGB
14644           const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1), *ptrB = ptr(0,0,0,2);
14645           t *ptrd = res.ptr();
14646           for (unsigned long siz = width*height*depth; siz; --siz) {
14647             *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++);
14648           }
14649         } break;
14650         case 4 : { // Optimization for the classical conversion from planar RGBA to interleaved RGBA
14651           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);
14652           t *ptrd = res.ptr();
14653           for (unsigned long siz = width*height*depth; siz; --siz) {
14654             *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++); *(ptrd++) = (t)*(ptrA++);
14655           }
14656         } break;
14657         default : {
14658           cimg_forXYZV(*this,x,y,z,v) res(v,x,y,z) = (t)*(ptrs++);
14659         }
14660         }
14661       }
14662       if (!cimg::strncasecmp(permut,"vxzy",4)) {
14663         res.assign(dim,width,depth,height);
14664         cimg_forXYZV(*this,x,y,z,v) res(v,x,z,y) = (t)*(ptrs++);
14665       }
14666       if (!cimg::strncasecmp(permut,"vyxz",4)) {
14667         res.assign(dim,height,width,depth);
14668         cimg_forXYZV(*this,x,y,z,v) res(v,y,x,z) = (t)*(ptrs++);
14669       }
14670       if (!cimg::strncasecmp(permut,"vyzx",4)) {
14671         res.assign(dim,height,depth,width);
14672         cimg_forXYZV(*this,x,y,z,v) res(v,y,z,x) = (t)*(ptrs++);
14673       }
14674       if (!cimg::strncasecmp(permut,"vzxy",4)) {
14675         res.assign(dim,depth,width,height);
14676         cimg_forXYZV(*this,x,y,z,v) res(v,z,x,y) = (t)*(ptrs++);
14677       }
14678       if (!cimg::strncasecmp(permut,"vzyx",4)) {
14679         res.assign(dim,depth,height,width);
14680         cimg_forXYZV(*this,x,y,z,v) res(v,z,y,x) = (t)*(ptrs++);
14681       }
14682       if (!res)
14683         throw CImgArgumentException("CImg<%s>::permute_axes() : Invalid input permutation '%s'.",
14684                                     pixel_type(),permut);
14685       return res;
14686     }
14687 
14688     //! Permute axes order.
14689     /**
14690        This function permutes image axes.
14691        \param permut = String describing the permutation (4 characters).
14692     **/
14693     CImg<T>& permute_axes(const char *order) {
14694       return get_permute_axes(order).transfer_to(*this);
14695     }
14696 
14697     CImg<T> get_permute_axes(const char *order) const {
14698       const T foo = (T)0;
14699       return _get_permute_axes(order,foo);
14700     }
14701 
14702     //! Invert endianness.
14703     CImg<T>& invert_endianness() {
14704       cimg::invert_endianness(data,size());
14705       return *this;
14706     }
14707 
14708     CImg<T> get_invert_endianness() const {
14709       return (+*this).invert_endianness();
14710     }
14711 
14712     //! Mirror an image along the specified axis.
14713     CImg<T>& mirror(const char axis) {
14714       if (is_empty()) return *this;
14715       T *pf, *pb, *buf = 0;
14716       switch (cimg::uncase(axis)) {
14717       case 'x' : {
14718         pf = data; pb = ptr(width-1);
14719         const unsigned int width2 = width/2;
14720         for (unsigned int yzv = 0; yzv<height*depth*dim; ++yzv) {
14721           for (unsigned int x = 0; x<width2; ++x) { const T val = *pf; *(pf++) = *pb; *(pb--) = val; }
14722           pf+=width - width2;
14723           pb+=width + width2;
14724         }
14725       } break;
14726       case 'y' : {
14727         buf = new T[width];
14728         pf = data; pb = ptr(0,height-1);
14729         const unsigned int height2 = height/2;
14730         for (unsigned int zv=0; zv<depth*dim; ++zv) {
14731           for (unsigned int y=0; y<height2; ++y) {
14732             cimg_std::memcpy(buf,pf,width*sizeof(T));
14733             cimg_std::memcpy(pf,pb,width*sizeof(T));
14734             cimg_std::memcpy(pb,buf,width*sizeof(T));
14735             pf+=width;
14736             pb-=width;
14737           }
14738           pf+=width*(height - height2);
14739           pb+=width*(height + height2);
14740         }
14741       } break;
14742       case 'z' : {
14743         buf = new T[width*height];
14744         pf = data; pb = ptr(0,0,depth-1);
14745         const unsigned int depth2 = depth/2;
14746         cimg_forV(*this,v) {
14747           for (unsigned int z=0; z<depth2; ++z) {
14748             cimg_std::memcpy(buf,pf,width*height*sizeof(T));
14749             cimg_std::memcpy(pf,pb,width*height*sizeof(T));
14750             cimg_std::memcpy(pb,buf,width*height*sizeof(T));
14751             pf+=width*height;
14752             pb-=width*height;
14753           }
14754           pf+=width*height*(depth - depth2);
14755           pb+=width*height*(depth + depth2);
14756         }
14757       } break;
14758       case 'v' : {
14759         buf = new T[width*height*depth];
14760         pf = data; pb = ptr(0,0,0,dim-1);
14761         const unsigned int dim2 = dim/2;
14762         for (unsigned int v=0; v<dim2; ++v) {
14763           cimg_std::memcpy(buf,pf,width*height*depth*sizeof(T));
14764           cimg_std::memcpy(pf,pb,width*height*depth*sizeof(T));
14765           cimg_std::memcpy(pb,buf,width*height*depth*sizeof(T));
14766           pf+=width*height*depth;
14767           pb-=width*height*depth;
14768         }
14769       } break;
14770       default :
14771         throw CImgArgumentException("CImg<%s>::mirror() : unknow axis '%c', must be 'x','y','z' or 'v'.",
14772                                     pixel_type(),axis);
14773       }
14774       if (buf) delete[] buf;
14775       return *this;
14776     }
14777 
14778     CImg<T> get_mirror(const char axis) const {
14779       return (+*this).mirror(axis);
14780     }
14781 
14782     //! Translate the image.
14783     /**
14784        \param deltax Amount of displacement along the X-axis.
14785        \param deltay Amount of displacement along the Y-axis.
14786        \param deltaz Amount of displacement along the Z-axis.
14787        \param deltav Amount of displacement along the V-axis.
14788        \param border_condition Border condition.
14789 
14790        - \c border_condition can be :
14791           - 0 : Zero border condition (Dirichlet).
14792           - 1 : Nearest neighbors (Neumann).
14793           - 2 : Repeat Pattern (Fourier style).
14794     **/
14795     CImg<T>& translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
14796                        const int border_condition=0) {
14797       if (is_empty()) return *this;
14798       if (deltax) // Translate along X-axis
14799         switch (border_condition) {
14800         case 0 :
14801           if (cimg::abs(deltax)>=dimx()) return fill(0);
14802           if (deltax>0) cimg_forYZV(*this,y,z,k) {
14803             cimg_std::memmove(ptr(0,y,z,k),ptr(deltax,y,z,k),(width-deltax)*sizeof(T));
14804             cimg_std::memset(ptr(width-deltax,y,z,k),0,deltax*sizeof(T));
14805           } else cimg_forYZV(*this,y,z,k) {
14806             cimg_std::memmove(ptr(-deltax,y,z,k),ptr(0,y,z,k),(width+deltax)*sizeof(T));
14807             cimg_std::memset(ptr(0,y,z,k),0,-deltax*sizeof(T));
14808           }
14809           break;
14810         case 1 :
14811           if (deltax>0) {
14812             const int ndeltax = (deltax>=dimx())?width-1:deltax;
14813             if (!ndeltax) return *this;
14814             cimg_forYZV(*this,y,z,k) {
14815               cimg_std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
14816               T *ptrd = ptr(width-1,y,z,k);
14817               const T val = *ptrd;
14818               for (int l = 0; l<ndeltax-1; ++l) *(--ptrd) = val;
14819             }
14820           } else {
14821             const int ndeltax = (-deltax>=dimx())?width-1:-deltax;
14822             if (!ndeltax) return *this;
14823             cimg_forYZV(*this,y,z,k) {
14824               cimg_std::memmove(ptr(ndeltax,y,z,k),ptr(0,y,z,k),(width-ndeltax)*sizeof(T));
14825               T *ptrd = ptr(0,y,z,k);
14826               const T val = *ptrd;
14827               for (int l = 0; l<ndeltax-1; ++l) *(++ptrd) = val;
14828             }
14829           }
14830           break;
14831         case 2 : {
14832           const int ml = cimg::mod(deltax,dimx()), ndeltax = (ml<=dimx()/2)?ml:(ml-dimx());
14833           if (!ndeltax) return *this;
14834           T* buf = new T[cimg::abs(ndeltax)];
14835           if (ndeltax>0) cimg_forYZV(*this,y,z,k) {
14836             cimg_std::memcpy(buf,ptr(0,y,z,k),ndeltax*sizeof(T));
14837             cimg_std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
14838             cimg_std::memcpy(ptr(width-ndeltax,y,z,k),buf,ndeltax*sizeof(T));
14839           } else cimg_forYZV(*this,y,z,k) {
14840             cimg_std::memcpy(buf,ptr(width+ndeltax,y,z,k),-ndeltax*sizeof(T));
14841             cimg_std::memmove(ptr(-ndeltax,y,z,k),ptr(0,y,z,k),(width+ndeltax)*sizeof(T));
14842             cimg_std::memcpy(ptr(0,y,z,k),buf,-ndeltax*sizeof(T));
14843           }
14844           delete[] buf;
14845         } break;
14846         }
14847 
14848       if (deltay) // Translate along Y-axis
14849         switch (border_condition) {
14850         case 0 :
14851           if (cimg::abs(deltay)>=dimy()) return fill(0);
14852           if (deltay>0) cimg_forZV(*this,z,k) {
14853             cimg_std::memmove(ptr(0,0,z,k),ptr(0,deltay,z,k),width*(height-deltay)*sizeof(T));
14854             cimg_std::memset(ptr(0,height-deltay,z,k),0,width*deltay*sizeof(T));
14855           } else cimg_forZV(*this,z,k) {
14856             cimg_std::memmove(ptr(0,-deltay,z,k),ptr(0,0,z,k),width*(height+deltay)*sizeof(T));
14857             cimg_std::memset(ptr(0,0,z,k),0,-deltay*width*sizeof(T));
14858           }
14859           break;
14860         case 1 :
14861           if (deltay>0) {
14862             const int ndeltay = (deltay>=dimy())?height-1:deltay;
14863             if (!ndeltay) return *this;
14864             cimg_forZV(*this,z,k) {
14865               cimg_std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
14866               T *ptrd = ptr(0,height-ndeltay,z,k), *ptrs = ptr(0,height-1,z,k);
14867               for (int l = 0; l<ndeltay-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
14868             }
14869           } else {
14870             const int ndeltay = (-deltay>=dimy())?height-1:-deltay;
14871             if (!ndeltay) return *this;
14872             cimg_forZV(*this,z,k) {
14873               cimg_std::memmove(ptr(0,ndeltay,z,k),ptr(0,0,z,k),width*(height-ndeltay)*sizeof(T));
14874               T *ptrd = ptr(0,1,z,k), *ptrs = ptr(0,0,z,k);
14875               for (int l = 0; l<ndeltay-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
14876             }
14877           }
14878           break;
14879         case 2 : {
14880           const int ml = cimg::mod(deltay,dimy()), ndeltay = (ml<=dimy()/2)?ml:(ml-dimy());
14881           if (!ndeltay) return *this;
14882           T* buf = new T[width*cimg::abs(ndeltay)];
14883           if (ndeltay>0) cimg_forZV(*this,z,k) {
14884             cimg_std::memcpy(buf,ptr(0,0,z,k),width*ndeltay*sizeof(T));
14885             cimg_std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
14886             cimg_std::memcpy(ptr(0,height-ndeltay,z,k),buf,width*ndeltay*sizeof(T));
14887           } else cimg_forZV(*this,z,k) {
14888             cimg_std::memcpy(buf,ptr(0,height+ndeltay,z,k),-ndeltay*width*sizeof(T));
14889             cimg_std::memmove(ptr(0,-ndeltay,z,k),ptr(0,0,z,k),width*(height+ndeltay)*sizeof(T));
14890             cimg_std::memcpy(ptr(0,0,z,k),buf,-ndeltay*width*sizeof(T));
14891           }
14892           delete[] buf;
14893         } break;
14894         }
14895 
14896       if (deltaz) // Translate along Z-axis
14897         switch (border_condition) {
14898         case 0 :
14899           if (cimg::abs(deltaz)>=dimz()) return fill(0);
14900           if (deltaz>0) cimg_forV(*this,k) {
14901             cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,deltaz,k),width*height*(depth-deltaz)*sizeof(T));
14902             cimg_std::memset(ptr(0,0,depth-deltaz,k),0,width*height*deltaz*sizeof(T));
14903           } else cimg_forV(*this,k) {
14904             cimg_std::memmove(ptr(0,0,-deltaz,k),ptr(0,0,0,k),width*height*(depth+deltaz)*sizeof(T));
14905             cimg_std::memset(ptr(0,0,0,k),0,-deltaz*width*height*sizeof(T));
14906           }
14907           break;
14908         case 1 :
14909           if (deltaz>0) {
14910             const int ndeltaz = (deltaz>=dimz())?depth-1:deltaz;
14911             if (!ndeltaz) return *this;
14912             cimg_forV(*this,k) {
14913               cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
14914               T *ptrd = ptr(0,0,depth-ndeltaz,k), *ptrs = ptr(0,0,depth-1,k);
14915               for (int l = 0; l<ndeltaz-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
14916             }
14917           } else {
14918             const int ndeltaz = (-deltaz>=dimz())?depth-1:-deltaz;
14919             if (!ndeltaz) return *this;
14920             cimg_forV(*this,k) {
14921               cimg_std::memmove(ptr(0,0,ndeltaz,k),ptr(0,0,0,k),width*height*(depth-ndeltaz)*sizeof(T));
14922               T *ptrd = ptr(0,0,1,k), *ptrs = ptr(0,0,0,k);
14923               for (int l = 0; l<ndeltaz-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
14924             }
14925           }
14926           break;
14927         case 2 : {
14928           const int ml = cimg::mod(deltaz,dimz()), ndeltaz = (ml<=dimz()/2)?ml:(ml-dimz());
14929           if (!ndeltaz) return *this;
14930           T* buf = new T[width*height*cimg::abs(ndeltaz)];
14931           if (ndeltaz>0) cimg_forV(*this,k) {
14932             cimg_std::memcpy(buf,ptr(0,0,0,k),width*height*ndeltaz*sizeof(T));
14933             cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
14934             cimg_std::memcpy(ptr(0,0,depth-ndeltaz,k),buf,width*height*ndeltaz*sizeof(T));
14935           } else cimg_forV(*this,k) {
14936             cimg_std::memcpy(buf,ptr(0,0,depth+ndeltaz,k),-ndeltaz*width*height*sizeof(T));
14937             cimg_std::memmove(ptr(0,0,-ndeltaz,k),ptr(0,0,0,k),width*height*(depth+ndeltaz)*sizeof(T));
14938             cimg_std::memcpy(ptr(0,0,0,k),buf,-ndeltaz*width*height*sizeof(T));
14939           }
14940           delete[] buf;
14941         } break;
14942         }
14943 
14944       if (deltav) // Translate along V-axis
14945         switch (border_condition) {
14946         case 0 :
14947           if (cimg::abs(deltav)>=dimv()) return fill(0);
14948           if (deltav>0) {
14949             cimg_std::memmove(data,ptr(0,0,0,deltav),width*height*depth*(dim-deltav)*sizeof(T));
14950             cimg_std::memset(ptr(0,0,0,dim-deltav),0,width*height*depth*deltav*sizeof(T));
14951           } else cimg_forV(*this,k) {
14952             cimg_std::memmove(ptr(0,0,0,-deltav),data,width*height*depth*(dim+deltav)*sizeof(T));
14953             cimg_std::memset(data,0,-deltav*width*height*depth*sizeof(T));
14954           }
14955           break;
14956         case 1 :
14957           if (deltav>0) {
14958             const int ndeltav = (deltav>=dimv())?dim-1:deltav;
14959             if (!ndeltav) return *this;
14960             cimg_std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
14961             T *ptrd = ptr(0,0,0,dim-ndeltav), *ptrs = ptr(0,0,0,dim-1);
14962             for (int l = 0; l<ndeltav-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
14963           } else {
14964             const int ndeltav = (-deltav>=dimv())?dim-1:-deltav;
14965             if (!ndeltav) return *this;
14966             cimg_std::memmove(ptr(0,0,0,ndeltav),data,width*height*depth*(dim-ndeltav)*sizeof(T));
14967             T *ptrd = ptr(0,0,0,1);
14968             for (int l = 0; l<ndeltav-1; ++l) { cimg_std::memcpy(ptrd,data,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
14969           }
14970           break;
14971         case 2 : {
14972           const int ml = cimg::mod(deltav,dimv()), ndeltav = (ml<=dimv()/2)?ml:(ml-dimv());
14973           if (!ndeltav) return *this;
14974           T* buf = new T[width*height*depth*cimg::abs(ndeltav)];
14975           if (ndeltav>0) {
14976             cimg_std::memcpy(buf,data,width*height*depth*ndeltav*sizeof(T));
14977             cimg_std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
14978             cimg_std::memcpy(ptr(0,0,0,dim-ndeltav),buf,width*height*depth*ndeltav*sizeof(T));
14979           } else {
14980             cimg_std::memcpy(buf,ptr(0,0,0,dim+ndeltav),-ndeltav*width*height*depth*sizeof(T));
14981             cimg_std::memmove(ptr(0,0,0,-ndeltav),data,width*height*depth*(dim+ndeltav)*sizeof(T));
14982             cimg_std::memcpy(data,buf,-ndeltav*width*height*depth*sizeof(T));
14983           }
14984           delete[] buf;
14985         } break;
14986         }
14987       return *this;
14988     }
14989 
14990     CImg<T> get_translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
14991                           const int border_condition=0) const {
14992       return (+*this).translate(deltax,deltay,deltaz,deltav,border_condition);
14993     }
14994 
14995     //! Get a square region of the image.
14996     /**
14997        \param x0 = X-coordinate of the upper-left crop rectangle corner.
14998        \param y0 = Y-coordinate of the upper-left crop rectangle corner.
14999        \param z0 = Z-coordinate of the upper-left crop rectangle corner.
15000        \param v0 = V-coordinate of the upper-left crop rectangle corner.
15001        \param x1 = X-coordinate of the lower-right crop rectangle corner.
15002        \param y1 = Y-coordinate of the lower-right crop rectangle corner.
15003        \param z1 = Z-coordinate of the lower-right crop rectangle corner.
15004        \param v1 = V-coordinate of the lower-right crop rectangle corner.
15005        \param border_condition = Dirichlet (false) or Neumann border conditions.
15006     **/
15007     CImg<T>& crop(const int x0, const int y0, const int z0, const int v0,
15008                   const int x1, const int y1, const int z1, const int v1,
15009                   const bool border_condition=false) {
15010       return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).transfer_to(*this);
15011     }
15012 
15013     CImg<T> get_crop(const int x0, const int y0, const int z0, const int v0,
15014                      const int x1, const int y1, const int z1, const int v1,
15015                      const bool border_condition=false) const {
15016       if (is_empty()) return *this;
15017       const int
15018         nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
15019         ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0,
15020         nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0,
15021         nv0 = v0<v1?v0:v1, nv1 = v0^v1^nv0;
15022       CImg<T> dest(1U+nx1-nx0,1U+ny1-ny0,1U+nz1-nz0,1U+nv1-nv0);
15023       if (nx0<0 || nx1>=dimx() || ny0<0 || ny1>=dimy() || nz0<0 || nz1>=dimz() || nv0<0 || nv1>=dimv()) {
15024         if (border_condition) cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = _atXYZV(nx0+x,ny0+y,nz0+z,nv0+v);
15025         else dest.fill(0).draw_image(-nx0,-ny0,-nz0,-nv0,*this);
15026       } else dest.draw_image(-nx0,-ny0,-nz0,-nv0,*this);
15027       return dest;
15028     }
15029 
15030     //! Get a rectangular part of the instance image.
15031     /**
15032        \param x0 = X-coordinate of the upper-left crop rectangle corner.
15033        \param y0 = Y-coordinate of the upper-left crop rectangle corner.
15034        \param z0 = Z-coordinate of the upper-left crop rectangle corner.
15035        \param x1 = X-coordinate of the lower-right crop rectangle corner.
15036        \param y1 = Y-coordinate of the lower-right crop rectangle corner.
15037        \param z1 = Z-coordinate of the lower-right crop rectangle corner.
15038        \param border_condition = determine the type of border condition if
15039        some of the desired region is outside the image.
15040     **/
15041     CImg<T>& crop(const int x0, const int y0, const int z0,
15042                   const int x1, const int y1, const int z1,
15043                   const bool border_condition=false) {
15044       return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
15045     }
15046 
15047     CImg<T> get_crop(const int x0, const int y0, const int z0,
15048                      const int x1, const int y1, const int z1,
15049                      const bool border_condition=false) const {
15050       return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
15051     }
15052 
15053     //! Get a rectangular part of the instance image.
15054     /**
15055        \param x0 = X-coordinate of the upper-left crop rectangle corner.
15056        \param y0 = Y-coordinate of the upper-left crop rectangle corner.
15057        \param x1 = X-coordinate of the lower-right crop rectangle corner.
15058        \param y1 = Y-coordinate of the lower-right crop rectangle corner.
15059        \param border_condition = determine the type of border condition if
15060        some of the desired region is outside the image.
15061     **/
15062     CImg<T>& crop(const int x0, const int y0,
15063                   const int x1, const int y1,
15064                   const bool border_condition=false) {
15065       return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
15066     }
15067 
15068     CImg<T> get_crop(const int x0, const int y0,
15069                      const int x1, const int y1,
15070                      const bool border_condition=false) const {
15071       return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
15072     }
15073 
15074     //! Get a rectangular part of the instance image.
15075     /**
15076        \param x0 = X-coordinate of the upper-left crop rectangle corner.
15077        \param x1 = X-coordinate of the lower-right crop rectangle corner.
15078        \param border_condition = determine the type of border condition if
15079        some of the desired region is outside the image.
15080     **/
15081     CImg<T>& crop(const int x0, const int x1, const bool border_condition=false) {
15082       return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
15083     }
15084 
15085     CImg<T> get_crop(const int x0, const int x1, const bool border_condition=false) const {
15086       return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
15087     }
15088 
15089     //! Autocrop an image, regarding of the specified backround value.
15090     CImg<T>& autocrop(const T value, const char *const axes="vzyx") {
15091       if (is_empty()) return *this;
15092       const int lmax = cimg::strlen(axes);
15093       for (int l = 0; l<lmax; ++l) autocrop(value,axes[l]);
15094       return *this;
15095     }
15096 
15097     CImg<T> get_autocrop(const T value, const char *const axes="vzyx") const {
15098       return (+*this).autocrop(value,axes);
15099     }
15100 
15101     //! Autocrop an image, regarding of the specified backround color.
15102     CImg<T>& autocrop(const T *const color, const char *const axes="zyx") {
15103       if (is_empty()) return *this;
15104       const int lmax = cimg::strlen(axes);
15105       for (int l = 0; l<lmax; ++l) autocrop(color,axes[l]);
15106       return *this;
15107     }
15108 
15109     CImg<T> get_autocrop(const T *const color, const char *const axes="zyx") const {
15110       return (+*this).autocrop(color,axes);
15111     }
15112 
15113     //! Autocrop an image, regarding of the specified backround color.
15114     template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char *const axes="zyx") {
15115       return get_autocrop(color,axes).transfer_to(*this);
15116     }
15117 
15118     template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char *const axes="zyx") const {
15119       return get_autocrop(color.data,axes);
15120     }
15121 
15122     //! Autocrop an image along specified axis, regarding of the specified backround value.
15123     CImg<T>& autocrop(const T value, const char axis) {
15124       return get_autocrop(value,axis).transfer_to(*this);
15125     }
15126 
15127     CImg<T> get_autocrop(const T value, const char axis) const {
15128       if (is_empty()) return *this;
15129       CImg<T> res;
15130       const CImg<intT> coords = _get_autocrop(value,axis);
15131       switch (cimg::uncase(axis)) {
15132         case 'x' : {
15133           const int x0 = coords[0], x1 = coords[1];
15134           if (x0>=0 && x1>=0) res = get_crop(x0,x1);
15135         } break;
15136         case 'y' : {
15137           const int y0 = coords[0], y1 = coords[1];
15138           if (y0>=0 && y1>=0) res = get_crop(0,y0,width-1,y1);
15139         } break;
15140         case 'z' : {
15141           const int z0 = coords[0], z1 = coords[1];
15142           if (z0>=0 && z1>=0) res = get_crop(0,0,z0,width-1,height-1,z1);
15143         } break;
15144         case 'v' : {
15145           const int v0 = coords[0], v1 = coords[1];
15146           if (v0>=0 && v1>=0) res = get_crop(0,0,0,v0,width-1,height-1,depth-1,v1);
15147         } break;
15148       }
15149       return res;
15150     }
15151 
15152     //! Autocrop an image along specified axis, regarding of the specified backround color.
15153     CImg<T>& autocrop(const T *const color, const char axis) {
15154       return get_autocrop(color,axis).transfer_to(*this);
15155     }
15156 
15157     CImg<T> get_autocrop(const T *const color, const char axis) const {
15158       if (is_empty()) return *this;
15159       CImg<T> res;
15160       switch (cimg::uncase(axis)) {
15161         case 'x' : {
15162           int x0 = width, x1 = -1;
15163           cimg_forV(*this,k) {
15164             const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
15165             const int nx0 = coords[0], nx1 = coords[1];
15166             if (nx0>=0 && nx1>=0) { x0 = cimg::min(x0,nx0); x1 = cimg::max(x1,nx1); }
15167           }
15168           if (x0<=x1) res = get_crop(x0,x1);
15169         } break;
15170         case 'y' : {
15171           int y0 = height, y1 = -1;
15172           cimg_forV(*this,k) {
15173             const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
15174             const int ny0 = coords[0], ny1 = coords[1];
15175             if (ny0>=0 && ny1>=0) { y0 = cimg::min(y0,ny0); y1 = cimg::max(y1,ny1); }
15176           }
15177           if (y0<=y1) res = get_crop(0,y0,width-1,y1);
15178         } break;
15179         case 'z' : {
15180           int z0 = depth, z1 = -1;
15181           cimg_forV(*this,k) {
15182             const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
15183             const int nz0 = coords[0], nz1 = coords[1];
15184             if (nz0>=0 && nz1>=0) { z0 = cimg::min(z0,nz0); z1 = cimg::max(z1,nz1); }
15185           }
15186           if (z0<=z1) res = get_crop(0,0,z0,width-1,height-1,z1);
15187         } break;
15188       default :
15189           throw CImgArgumentException("CImg<%s>::autocrop() : Invalid axis '%c', must be 'x','y' or 'z'.",
15190                                       pixel_type(),axis);
15191       }
15192       return res;
15193     }
15194 
15195     //! Autocrop an image along specified axis, regarding of the specified backround color.
15196     template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char axis) {
15197       return get_autocrop(color,axis).transfer_to(*this);
15198     }
15199 
15200     template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char axis) const {
15201       return get_autocrop(color.data,axis);
15202     }
15203 
15204     CImg<intT> _get_autocrop(const T value, const char axis) const {
15205       CImg<intT> res;
15206       int x0 = -1, y0 = -1, z0 = -1, v0 = -1, x1 = -1, y1 = -1, z1 = -1, v1 = -1;
15207       switch (cimg::uncase(axis)) {
15208       case 'x' : {
15209         cimg_forX(*this,x) cimg_forYZV(*this,y,z,v)
15210           if ((*this)(x,y,z,v)!=value) { x0 = x; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
15211         if (x0>=0) {
15212           for (int x = dimx()-1; x>=0; --x) cimg_forYZV(*this,y,z,v)
15213             if ((*this)(x,y,z,v)!=value) { x1 = x; x = 0; y = dimy(); z = dimz(); v = dimv(); }
15214         }
15215         res = CImg<intT>::vector(x0,x1);
15216       } break;
15217       case 'y' : {
15218         cimg_forY(*this,y) cimg_forXZV(*this,x,z,v)
15219           if ((*this)(x,y,z,v)!=value) { y0 = y; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
15220         if (y0>=0) {
15221           for (int y = dimy()-1; y>=0; --y) cimg_forXZV(*this,x,z,v)
15222             if ((*this)(x,y,z,v)!=value) { y1 = y; x = dimx(); y = 0; z = dimz(); v = dimv(); }
15223         }
15224         res = CImg<intT>::vector(y0,y1);
15225       } break;
15226       case 'z' : {
15227         cimg_forZ(*this,z) cimg_forXYV(*this,x,y,v)
15228           if ((*this)(x,y,z,v)!=value) { z0 = z; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
15229         if (z0>=0) {
15230           for (int z = dimz()-1; z>=0; --z) cimg_forXYV(*this,x,y,v)
15231             if ((*this)(x,y,z,v)!=value) { z1 = z; x = dimx(); y = dimy(); z = 0; v = dimv(); }
15232         }
15233         res = CImg<intT>::vector(z0,z1);
15234       } break;
15235       case 'v' : {
15236         cimg_forV(*this,v) cimg_forXYZ(*this,x,y,z)
15237           if ((*this)(x,y,z,v)!=value) { v0 = v; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
15238         if (v0>=0) {
15239           for (int v = dimv()-1; v>=0; --v) cimg_forXYZ(*this,x,y,z)
15240             if ((*this)(x,y,z,v)!=value) { v1 = v; x = dimx(); y = dimy(); z = dimz(); v = 0; }
15241         }
15242         res = CImg<intT>::vector(v0,v1);
15243       } break;
15244       default :
15245         throw CImgArgumentException("CImg<%s>::autocrop() : unknow axis '%c', must be 'x','y','z' or 'v'",
15246                                     pixel_type(),axis);
15247       }
15248       return res;
15249     }
15250 
15251     //! Get a set of columns.
15252     CImg<T>& columns(const unsigned int x0, const unsigned int x1) {
15253       return get_columns(x0,x1).transfer_to(*this);
15254     }
15255 
15256     CImg<T> get_columns(const unsigned int x0, const unsigned int x1) const {
15257       return get_crop((int)x0,0,0,0,(int)x1,dimy()-1,dimz()-1,dimv()-1);
15258     }
15259 
15260     //! Get one column.
15261     CImg<T>& column(const unsigned int x0) {
15262       return columns(x0,x0);
15263     }
15264 
15265     CImg<T> get_column(const unsigned int x0) const {
15266       return get_columns(x0,x0);
15267     }
15268 
15269     //! Get a set of lines.
15270     CImg<T>& lines(const unsigned int y0, const unsigned int y1) {
15271       return get_lines(y0,y1).transfer_to(*this);
15272     }
15273 
15274     CImg<T> get_lines(const unsigned int y0, const unsigned int y1) const {
15275       return get_crop(0,(int)y0,0,0,dimx()-1,(int)y1,dimz()-1,dimv()-1);
15276     }
15277 
15278     //! Get a line.
15279     CImg<T>& line(const unsigned int y0) {
15280       return lines(y0,y0);
15281     }
15282 
15283     CImg<T> get_line(const unsigned int y0) const {
15284       return get_lines(y0,y0);
15285     }
15286 
15287     //! Get a set of slices.
15288     CImg<T>& slices(const unsigned int z0, const unsigned int z1) {
15289       return get_slices(z0,z1).transfer_to(*this);
15290     }
15291 
15292     CImg<T> get_slices(const unsigned int z0, const unsigned int z1) const {
15293       return get_crop(0,0,(int)z0,0,dimx()-1,dimy()-1,(int)z1,dimv()-1);
15294     }
15295 
15296     //! Get a slice.
15297     CImg<T>& slice(const unsigned int z0) {
15298       return slices(z0,z0);
15299     }
15300 
15301     CImg<T> get_slice(const unsigned int z0) const {
15302       return get_slices(z0,z0);
15303     }
15304 
15305     //! Get a set of channels.
15306     CImg<T>& channels(const unsigned int v0, const unsigned int v1) {
15307       return get_channels(v0,v1).transfer_to(*this);
15308     }
15309 
15310     CImg<T> get_channels(const unsigned int v0, const unsigned int v1) const {
15311       return get_crop(0,0,0,(int)v0,dimx()-1,dimy()-1,dimz()-1,(int)v1);
15312     }
15313 
15314     //! Get a channel.
15315     CImg<T>& channel(const unsigned int v0) {
15316       return channels(v0,v0);
15317     }
15318 
15319     CImg<T> get_channel(const unsigned int v0) const {
15320       return get_channels(v0,v0);
15321     }
15322 
15323     //! Get a shared-memory image referencing a set of points of the instance image.
15324     CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
15325                               const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) {
15326       const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
15327       if (beg>end || beg>=size() || end>=size())
15328         throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
15329                                     "a (%u,%u,%u,%u) image.",
15330                                     pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
15331       return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
15332     }
15333 
15334     const CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
15335                                     const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const {
15336       const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
15337       if (beg>end || beg>=size() || end>=size())
15338         throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
15339                                     "a (%u,%u,%u,%u) image.",
15340                                     pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
15341       return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
15342     }
15343 
15344     //! Return a shared-memory image referencing a set of lines of the instance image.
15345     CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
15346                              const unsigned int z0=0, const unsigned int v0=0) {
15347       const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
15348       if (beg>end || beg>=size() || end>=size())
15349         throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
15350                                     "a (%u,%u,%u,%u) image.",
15351                                     pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
15352       return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
15353     }
15354 
15355     const CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
15356                                    const unsigned int z0=0, const unsigned int v0=0) const {
15357       const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
15358       if (beg>end || beg>=size() || end>=size())
15359         throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
15360                                     "a (%u,%u,%u,%u) image.",
15361                                     pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
15362       return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
15363     }
15364 
15365     //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image.
15366     CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) {
15367       return get_shared_lines(y0,y0,z0,v0);
15368     }
15369 
15370     const CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) const {
15371       return get_shared_lines(y0,y0,z0,v0);
15372     }
15373 
15374     //! Return a shared memory image referencing a set of planes (z0->z1,v0) of the instance image.
15375     CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) {
15376       const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
15377       if (beg>end || beg>=size() || end>=size())
15378         throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
15379                                     "a (%u,%u,%u,%u) image.",
15380                                     pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
15381       return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
15382     }
15383 
15384     const CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const {
15385       const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
15386       if (beg>end || beg>=size() || end>=size())
15387         throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
15388                                     "a (%u,%u,%u,%u) image.",
15389                                     pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
15390       return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
15391     }
15392 
15393     //! Return a shared-memory image referencing one plane (z0,v0) of the instance image.
15394     CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) {
15395       return get_shared_planes(z0,z0,v0);
15396     }
15397 
15398     const CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) const {
15399       return get_shared_planes(z0,z0,v0);
15400     }
15401 
15402     //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image.
15403     CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) {
15404       const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
15405       if (beg>end || beg>=size() || end>=size())
15406         throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
15407                                     "a (%u,%u,%u,%u) image.",
15408                                     pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
15409       return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
15410     }
15411 
15412     const CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) const {
15413       const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
15414       if (beg>end || beg>=size() || end>=size())
15415         throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
15416                                     "a (%u,%u,%u,%u) image.",
15417                                     pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
15418       return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
15419     }
15420 
15421     //! Return a shared-memory image referencing one channel v0 of the instance image.
15422     CImg<T> get_shared_channel(const unsigned int v0) {
15423       return get_shared_channels(v0,v0);
15424     }
15425 
15426     const CImg<T> get_shared_channel(const unsigned int v0) const {
15427       return get_shared_channels(v0,v0);
15428     }
15429 
15430     //! Return a shared version of the instance image.
15431     CImg<T> get_shared() {
15432       return CImg<T>(data,width,height,depth,dim,true);
15433     }
15434 
15435     const CImg<T> get_shared() const {
15436       return CImg<T>(data,width,height,depth,dim,true);
15437     }
15438 
15439     //! Return a 2D representation of a 3D image, with three slices.
15440     CImg<T>& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
15441                            const int dx=-100, const int dy=-100, const int dz=-100) {
15442       return get_projections2d(x0,y0,z0,dx,dy,dz).transfer_to(*this);
15443     }
15444 
15445     CImg<T> get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
15446                               const int dx=-100, const int dy=-100, const int dz=-100) const {
15447       if (is_empty()) return *this;
15448       const unsigned int
15449         nx0 = (x0>=width)?width-1:x0,
15450         ny0 = (y0>=height)?height-1:y0,
15451         nz0 = (z0>=depth)?depth-1:z0;
15452       CImg<T>
15453         imgxy(width,height,1,dim),
15454         imgzy(depth,height,1,dim),
15455         imgxz(width,depth,1,dim);
15456       { cimg_forXYV(*this,x,y,k) imgxy(x,y,k) = (*this)(x,y,nz0,k); }
15457       { cimg_forYZV(*this,y,z,k) imgzy(z,y,k) = (*this)(nx0,y,z,k); }
15458       { cimg_forXZV(*this,x,z,k) imgxz(x,z,k) = (*this)(x,ny0,z,k); }
15459       imgxy.resize(dx,dy,1,dim,1);
15460       imgzy.resize(dz,dy,1,dim,1);
15461       imgxz.resize(dx,dz,1,dim,1);
15462       return CImg<T>(imgxy.width+imgzy.width,imgxy.height+imgxz.height,1,dim,0).
15463         draw_image(imgxy).draw_image(imgxy.width,imgzy).draw_image(0,imgxy.height,imgxz);
15464     }
15465 
15466     //! Compute the image histogram.
15467     /**
15468        The histogram H of an image I is a 1D-function where H(x) is the number of
15469        occurrences of the value x in I.
15470        \param nblevels = Number of different levels of the computed histogram.
15471        For classical images, this value is 256. You should specify more levels
15472        if you are working with CImg<float> or images with high range of pixel values.
15473        \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
15474        won't be counted.
15475        \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
15476        won't be counted.
15477        \note If val_min==val_max==0 (default values), the function first estimates the minimum and maximum
15478        pixel values of the current image, then uses these values for the histogram computation.
15479        \result The histogram is returned as a 1D CImg<float> image H, having a size of (nblevels,1,1,1) such that
15480        H(0) and H(nblevels-1) are respectively equal to the number of occurrences of the values val_min and val_max in I.
15481        \note Histogram computation always returns a 1D function. Histogram of multi-valued (such as color) images
15482        are not multi-dimensional.
15483     **/
15484     CImg<T>& histogram(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) {
15485       return get_histogram(nblevels,val_min,val_max).transfer_to(*this);
15486     }
15487 
15488     CImg<floatT> get_histogram(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const {
15489       if (is_empty()) return CImg<floatT>();
15490       if (!nblevels)
15491         throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with 0 levels",
15492                                     pixel_type());
15493       T vmin = val_min, vmax = val_max;
15494       CImg<floatT> res(nblevels,1,1,1,0);
15495       if (vmin>=vmax && vmin==0) vmin = minmax(vmax);
15496       if (vmin<vmax) cimg_for(*this,ptr,T) {
15497         const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin));
15498         if (pos>=0 && pos<(int)nblevels) ++res[pos];
15499       } else res[0]+=size();
15500       return res;
15501     }
15502 
15503     //! Compute the histogram-equalized version of the instance image.
15504     /**
15505        The histogram equalization is a classical image processing algorithm that enhances the image contrast
15506        by expanding its histogram.
15507        \param nblevels = Number of different levels of the computed histogram.
15508        For classical images, this value is 256. You should specify more levels
15509        if you are working with CImg<float> or images with high range of pixel values.
15510        \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
15511        won't be changed.
15512        \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
15513        won't be changed.
15514        \note If val_min==val_max==0 (default values), the function acts on all pixel values of the image.
15515        \return A new image with same size is returned, where pixels have been equalized.
15516     **/
15517     CImg<T>& equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) {
15518       if (is_empty()) return *this;
15519       T vmin = val_min, vmax = val_max;
15520       if (vmin==vmax && vmin==0) vmin = minmax(vmax);
15521       if (vmin<vmax) {
15522         CImg<floatT> hist = get_histogram(nblevels,vmin,vmax);
15523         float cumul = 0;
15524         cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos]=cumul; }
15525         cimg_for(*this,ptr,T) {
15526           const int pos = (unsigned int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin));
15527           if (pos>=0 && pos<(int)nblevels) *ptr = (T)(vmin + (vmax-vmin)*hist[pos]/size());
15528         }
15529       }
15530       return *this;
15531     }
15532 
15533     CImg<T> get_equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const {
15534       return (+*this).equalize(nblevels,val_min,val_max);
15535     }
15536 
15537     //! Get a label map of disconnected regions with same intensities.
15538     CImg<T>& label_regions() {
15539       return get_label_regions().transfer_to(*this);
15540     }
15541 
15542     CImg<uintT> get_label_regions() const {
15543 #define _cimg_get_label_test(p,q) { \
15544   flag = true; \
15545   const T *ptr1 = ptr(x,y) + siz, *ptr2 = ptr(p,q) + siz; \
15546   for (unsigned int i = dim; flag && i; --i) { ptr1-=wh; ptr2-=wh; flag = (*ptr1==*ptr2); } \
15547 }
15548       if (depth>1)
15549         throw CImgInstanceException("CImg<%s>::label_regions() : Instance image must be a 2D image");
15550       CImg<uintT> res(width,height,depth,1,0);
15551       unsigned int label = 1;
15552       const unsigned int wh = width*height, siz = width*height*dim;
15553       const int W1 = dimx()-1, H1 = dimy()-1;
15554       bool flag;
15555       cimg_forXY(*this,x,y) {
15556         bool done = false;
15557         if (y) {
15558           _cimg_get_label_test(x,y-1);
15559           if (flag) {
15560             const unsigned int lab = (res(x,y) = res(x,y-1));
15561             done = true;
15562             if (x && res(x-1,y)!=lab) {
15563               _cimg_get_label_test(x-1,y);
15564               if (flag) {
15565                 const unsigned int lold = res(x-1,y), *const cptr = res.ptr(x,y);
15566                 for (unsigned int *ptr = res.ptr(); ptr<cptr; ++ptr) if (*ptr==lold) *ptr = lab;
15567               }
15568             }
15569           }
15570         }
15571         if (x && !done) { _cimg_get_label_test(x-1,y); if (flag) { res(x,y) = res(x-1,y); done = true; }}
15572         if (!done) res(x,y) = label++;
15573       }
15574       { for (int y = H1; y>=0; --y) for (int x=W1; x>=0; --x) {
15575         bool done = false;
15576         if (y<H1) {
15577           _cimg_get_label_test(x,y+1);
15578           if (flag) {
15579             const unsigned int lab = (res(x,y) = res(x,y+1));
15580             done = true;
15581             if (x<W1 && res(x+1,y)!=lab) {
15582               _cimg_get_label_test(x+1,y);
15583               if (flag) {
15584                 const unsigned int lold = res(x+1,y), *const cptr = res.ptr(x,y);
15585                 for (unsigned int *ptr = res.ptr()+res.size()-1; ptr>cptr; --ptr) if (*ptr==lold) *ptr = lab;
15586               }
15587             }
15588           }
15589         }
15590         if (x<W1 && !done) { _cimg_get_label_test(x+1,y); if (flag) res(x,y) = res(x+1,y); done = true; }
15591       }}
15592       const unsigned int lab0 = res.max()+1;
15593       label = lab0;
15594       cimg_foroff(res,off) { // Relabel regions
15595         const unsigned int lab = res[off];
15596         if (lab<lab0) { cimg_for(res,ptr,unsigned int) if (*ptr==lab) *ptr = label; ++label; }
15597       }
15598       return (res-=lab0);
15599     }
15600 
15601     //! Compute the scalar image of vector norms.
15602     /**
15603        When dealing with vector-valued images (i.e images with dimv()>1), this function computes the L1,L2 or Linf norm of each
15604        vector-valued pixel.
15605        \param norm_type = Type of the norm being computed (1 = L1, 2 = L2, -1 = Linf).
15606        \return A scalar-valued image CImg<float> with size (dimx(),dimy(),dimz(),1), where each pixel is the norm
15607        of the corresponding pixels in the original vector-valued image.
15608     **/
15609     CImg<T>& pointwise_norm(int norm_type=2) {
15610       return get_pointwise_norm(norm_type).transfer_to(*this);
15611     }
15612 
15613     CImg<Tfloat> get_pointwise_norm(int norm_type=2) const {
15614       if (is_empty()) return *this;
15615       if (dim==1) return get_abs();
15616       CImg<Tfloat> res(width,height,depth);
15617       switch (norm_type) {
15618       case -1 : {             // Linf norm
15619         cimg_forXYZ(*this,x,y,z) {
15620           Tfloat n = 0; cimg_forV(*this,v) {
15621             const Tfloat tmp = (Tfloat)cimg::abs((*this)(x,y,z,v));
15622             if (tmp>n) n=tmp; res(x,y,z) = n;
15623           }
15624         }
15625       } break;
15626       case 1 : {              // L1 norm
15627         cimg_forXYZ(*this,x,y,z) {
15628           Tfloat n = 0; cimg_forV(*this,v) n+=cimg::abs((*this)(x,y,z,v)); res(x,y,z) = n;
15629         }
15630       } break;
15631       default : {             // L2 norm
15632         cimg_forXYZ(*this,x,y,z) {
15633           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);
15634         }
15635       }
15636       }
15637       return res;
15638     }
15639 
15640     //! Compute the image of normalized vectors.
15641     /**
15642        When dealing with vector-valued images (i.e images with dimv()>1), this function return the image of normalized vectors
15643        (unit vectors). Null vectors are unchanged. The L2-norm is computed for the normalization.
15644        \return A new vector-valued image with same size, where each vector-valued pixels have been normalized.
15645     **/
15646     CImg<T>& pointwise_orientation() {
15647       cimg_forXYZ(*this,x,y,z) {
15648         float n = 0;
15649         cimg_forV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v));
15650         n = (float)cimg_std::sqrt(n);
15651         if (n>0) cimg_forV(*this,v) (*this)(x,y,z,v) = (T)((*this)(x,y,z,v)/n);
15652         else cimg_forV(*this,v) (*this)(x,y,z,v) = 0;
15653       }
15654       return *this;
15655     }
15656 
15657     CImg<Tfloat> get_pointwise_orientation() const {
15658       if (is_empty()) return *this;
15659       return CImg<Tfloat>(*this,false).pointwise_orientation();
15660     }
15661 
15662     //! Split image into a list.
15663     CImgList<T> get_split(const char axis, const unsigned int nb=0) const {
15664       if (is_empty()) return CImgList<T>();
15665       CImgList<T> res;
15666       switch (cimg::uncase(axis)) {
15667       case 'x' : {
15668         if (nb>width)
15669           throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'x' into %u images.",
15670                                       pixel_type(),width,height,depth,dim,data,nb);
15671         res.assign(nb?nb:width);
15672         const unsigned int delta = (unsigned int)cimg::round((float)width/res.size,1);
15673         unsigned int l, x;
15674         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);
15675         res[res.size-1] = get_crop(x,0,0,0,width-1,height-1,depth-1,dim-1);
15676       } break;
15677       case 'y' : {
15678         if (nb>height)
15679           throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'y' into %u images.",
15680                                       pixel_type(),width,height,depth,dim,data,nb);
15681         res.assign(nb?nb:height);
15682         const unsigned int delta = (unsigned int)cimg::round((float)height/res.size,1);
15683         unsigned int l, y;
15684         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);
15685         res[res.size-1] = get_crop(0,y,0,0,width-1,height-1,depth-1,dim-1);
15686       } break;
15687       case 'z' : {
15688         if (nb>depth)
15689           throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'z' into %u images.",
15690                                       pixel_type(),width,height,depth,dim,data,nb);
15691         res.assign(nb?nb:depth);
15692         const unsigned int delta = (unsigned int)cimg::round((float)depth/res.size,1);
15693         unsigned int l, z;
15694         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);
15695         res[res.size-1] = get_crop(0,0,z,0,width-1,height-1,depth-1,dim-1);
15696       } break;
15697       case 'v' : {
15698         if (nb>dim)
15699           throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'v' into %u images.",
15700                                       pixel_type(),width,height,depth,dim,data,nb);
15701         res.assign(nb?nb:dim);
15702         const unsigned int delta = (unsigned int)cimg::round((float)dim/res.size,1);
15703         unsigned int l, v;
15704         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);
15705         res[res.size-1] = get_crop(0,0,0,v,width-1,height-1,depth-1,dim-1);
15706       } break;
15707       default :
15708         throw CImgArgumentException("CImg<%s>::get_split() : Unknow axis '%c', must be 'x','y','z' or 'v'",
15709                                     pixel_type(),axis);
15710       }
15711       return res;
15712     }
15713 
15714     // Split image into a list of vectors, according to a given splitting value.
15715     CImgList<T> get_split(const T value, const bool keep_values, const bool shared) const {
15716       CImgList<T> res;
15717       const T *ptr0 = data, *const ptr_end = data + size();
15718       while (ptr0<ptr_end) {
15719         const T *ptr1 = ptr0;
15720         while (ptr1<ptr_end && *ptr1==value) ++ptr1;
15721         const unsigned int siz0 = ptr1 - ptr0;
15722         if (siz0 && keep_values) res.insert(CImg<T>(ptr0,1,siz0,1,1,shared));
15723         ptr0 = ptr1;
15724         while (ptr1<ptr_end && *ptr1!=value) ++ptr1;
15725         const unsigned int siz1 = ptr1 - ptr0;
15726         if (siz1) res.insert(CImg<T>(ptr0,1,siz1,1,1,shared),~0U,shared);
15727         ptr0 = ptr1;
15728       }
15729       return res;
15730     }
15731 
15732     //! Append an image to another one.
15733     CImg<T>& append(const CImg<T>& img, const char axis, const char align='p') {
15734       if (!img) return *this;
15735       if (is_empty()) return (*this=img);
15736       return get_append(img,axis,align).transfer_to(*this);
15737     }
15738 
15739     CImg<T> get_append(const CImg<T>& img, const char axis, const char align='p') const {
15740       if (!img) return *this;
15741       if (is_empty()) return img;
15742       CImgList<T> temp(2);
15743       temp[0].width = width; temp[0].height = height; temp[0].depth = depth;
15744       temp[0].dim = dim; temp[0].data = data;
15745       temp[1].width = img.width; temp[1].height = img.height; temp[1].depth = img.depth;
15746       temp[1].dim = img.dim; temp[1].data = img.data;
15747       const CImg<T> res = temp.get_append(axis,align);
15748       temp[0].width = temp[0].height = temp[0].depth = temp[0].dim = 0; temp[0].data = 0;
15749       temp[1].width = temp[1].height = temp[1].depth = temp[1].dim = 0; temp[1].data = 0;
15750       return res;
15751     }
15752 
15753     //! Compute the list of images, corresponding to the XY-gradients of an image.
15754     /**
15755        \param scheme = Numerical scheme used for the gradient computation :
15756        - -1 = Backward finite differences
15757        - 0 = Centered finite differences
15758        - 1 = Forward finite differences
15759        - 2 = Using Sobel masks
15760        - 3 = Using rotation invariant masks
15761        - 4 = Using Deriche recusrsive filter.
15762     **/
15763     CImgList<Tfloat> get_gradient(const char *const axes=0, const int scheme=3) const {
15764       CImgList<Tfloat> grad(2,width,height,depth,dim);
15765       bool threed = false;
15766       if (axes) {
15767         for (unsigned int a = 0; axes[a]; ++a) {
15768           const char axis = cimg::uncase(axes[a]);
15769           switch (axis) {
15770           case 'x' : case 'y' : break;
15771           case 'z' : threed = true; break;
15772           default :
15773             throw CImgArgumentException("CImg<%s>::get_gradient() : Unknown specified axis '%c'.",
15774                                         pixel_type(),axis);
15775           }
15776         }
15777       } else threed = (depth>1);
15778       if (threed) {
15779         grad.insert(1); grad[2].assign(width,height,depth,dim);
15780         switch (scheme) { // Compute 3D gradient
15781         case -1 : { // backward finite differences
15782           CImg_3x3x3(I,T);
15783           cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
15784             grad[0](x,y,z,k) = (Tfloat)Iccc - Ipcc;
15785             grad[1](x,y,z,k) = (Tfloat)Iccc - Icpc;
15786             grad[2](x,y,z,k) = (Tfloat)Iccc - Iccp;
15787           }
15788         } break;
15789         case 1 : { // forward finite differences
15790           CImg_2x2x2(I,T);
15791           cimg_forV(*this,k) cimg_for2x2x2(*this,x,y,z,k,I) {
15792             grad[0](x,y,z,k) = (Tfloat)Incc - Iccc;
15793             grad[1](x,y,z,k) = (Tfloat)Icnc - Iccc;
15794             grad[2](x,y,z,k) = (Tfloat)Iccn - Iccc;
15795           }
15796         } break;
15797         case 4 : { // using Deriche filter with low standard variation
15798           grad[0] = get_deriche(0,1,'x');
15799           grad[1] = get_deriche(0,1,'y');
15800           grad[2] = get_deriche(0,1,'z');
15801         } break;
15802         default : { // central finite differences
15803           CImg_3x3x3(I,T);
15804           cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
15805             grad[0](x,y,z,k) = 0.5f*((Tfloat)Incc - Ipcc);
15806             grad[1](x,y,z,k) = 0.5f*((Tfloat)Icnc - Icpc);
15807             grad[2](x,y,z,k) = 0.5f*((Tfloat)Iccn - Iccp);
15808           }
15809         }
15810         }
15811       } else switch (scheme) { // Compute 2D-gradient
15812       case -1 : { // backward finite differences
15813         CImg_3x3(I,T);
15814         cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
15815           grad[0](x,y,z,k) = (Tfloat)Icc - Ipc;
15816           grad[1](x,y,z,k) = (Tfloat)Icc - Icp;
15817         }
15818       } break;
15819       case 1 : { // forward finite differences
15820         CImg_2x2(I,T);
15821         cimg_forZV(*this,z,k) cimg_for2x2(*this,x,y,z,k,I) {
15822           grad[0](x,y,0,k) = (Tfloat)Inc - Icc;
15823           grad[1](x,y,z,k) = (Tfloat)Icn - Icc;
15824         }
15825       } break;
15826       case 2 : { // using Sobel mask
15827         CImg_3x3(I,T);
15828         const Tfloat a = 1, b = 2;
15829         cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
15830           grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
15831           grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
15832         }
15833       } break;
15834       case 3 : { // using rotation invariant mask
15835         CImg_3x3(I,T);
15836         const Tfloat a = (Tfloat)(0.25f*(2-cimg_std::sqrt(2.0f))), b = (Tfloat)(0.5f*(cimg_std::sqrt(2.0f)-1));
15837         cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
15838           grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
15839           grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
15840         }
15841       } break;
15842       case 4 : { // using Deriche filter with low standard variation
15843         grad[0] = get_deriche(0,1,'x');
15844         grad[1] = get_deriche(0,1,'y');
15845       } break;
15846       default : { // central finite differences
15847         CImg_3x3(I,T);
15848         cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
15849           grad[0](x,y,z,k) = 0.5f*((Tfloat)Inc - Ipc);
15850           grad[1](x,y,z,k) = 0.5f*((Tfloat)Icn - Icp);
15851         }
15852       }
15853       }
15854       if (!axes) return grad;
15855       CImgList<Tfloat> res;
15856       for (unsigned int l = 0; axes[l]; ++l) {
15857         const char axis = cimg::uncase(axes[l]);
15858         switch (axis) {
15859         case 'x' : res.insert(grad[0]); break;
15860         case 'y' : res.insert(grad[1]); break;
15861         case 'z' : res.insert(grad[2]); break;
15862         }
15863       }
15864       grad.assign();
15865       return res;
15866     }
15867 
15868     //! Compute the structure tensor field of an image.
15869     CImg<T>& structure_tensor(const bool central_scheme=false) {
15870       return get_structure_tensor(central_scheme).transfer_to(*this);
15871     }
15872 
15873     CImg<Tfloat> get_structure_tensor(const bool central_scheme=false) const {
15874       if (is_empty()) return *this;
15875       CImg<Tfloat> res;
15876       if (depth>1) { // 3D version
15877         res.assign(width,height,depth,6,0);
15878         CImg_3x3x3(I,T);
15879         if (central_scheme) cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { // classical central finite differences
15880           const Tfloat
15881             ix = 0.5f*((Tfloat)Incc - Ipcc),
15882             iy = 0.5f*((Tfloat)Icnc - Icpc),
15883             iz = 0.5f*((Tfloat)Iccn - Iccp);
15884           res(x,y,z,0)+=ix*ix;
15885           res(x,y,z,1)+=ix*iy;
15886           res(x,y,z,2)+=ix*iz;
15887           res(x,y,z,3)+=iy*iy;
15888           res(x,y,z,4)+=iy*iz;
15889           res(x,y,z,5)+=iz*iz;
15890         } else cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { // Precise forward/backward finite differences
15891           const Tfloat
15892             ixf = (Tfloat)Incc - Iccc, ixb = (Tfloat)Iccc - Ipcc,
15893             iyf = (Tfloat)Icnc - Iccc, iyb = (Tfloat)Iccc - Icpc,
15894             izf = (Tfloat)Iccn - Iccc, izb = (Tfloat)Iccc - Iccp;
15895           res(x,y,z,0) += 0.5f*(ixf*ixf + ixb*ixb);
15896           res(x,y,z,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb);
15897           res(x,y,z,2) += 0.25f*(ixf*izf + ixf*izb + ixb*izf + ixb*izb);
15898           res(x,y,z,3) += 0.5f*(iyf*iyf + iyb*iyb);
15899           res(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb);
15900           res(x,y,z,5) += 0.5f*(izf*izf + izb*izb);
15901         }
15902       } else { // 2D version
15903         res.assign(width,height,depth,3,0);
15904         CImg_3x3(I,T);
15905         if (central_scheme) cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { // classical central finite differences
15906           const Tfloat
15907             ix = 0.5f*((Tfloat)Inc - Ipc),
15908             iy = 0.5f*((Tfloat)Icn - Icp);
15909           res(x,y,0,0)+=ix*ix;
15910           res(x,y,0,1)+=ix*iy;
15911           res(x,y,0,2)+=iy*iy;
15912         } else cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { // Precise forward/backward finite differences
15913           const Tfloat
15914             ixf = (Tfloat)Inc - Icc, ixb = (Tfloat)Icc - Ipc,
15915             iyf = (Tfloat)Icn - Icc, iyb = (Tfloat)Icc - Icp;
15916           res(x,y,0,0) += 0.5f*(ixf*ixf+ixb*ixb);
15917           res(x,y,0,1) += 0.25f*(ixf*iyf+ixf*iyb+ixb*iyf+ixb*iyb);
15918           res(x,y,0,2) += 0.5f*(iyf*iyf+iyb*iyb);
15919         }
15920       }
15921       return res;
15922     }
15923 
15924     //! Get components of the Hessian matrix of an image.
15925     CImgList<Tfloat> get_hessian(const char *const axes=0) const {
15926       const char *naxes = axes, *const def_axes2d = "xxxyyy", *const def_axes3d = "xxxyxzyyyzzz";
15927       if (!axes) naxes = depth>1?def_axes3d:def_axes2d;
15928       CImgList<Tfloat> res;
15929       const int lmax = cimg::strlen(naxes);
15930       if (lmax%2)
15931         throw CImgArgumentException("CImg<%s>::get_hessian() : Incomplete parameter axes = '%s'.",
15932                                     pixel_type(),naxes);
15933       res.assign(lmax/2,width,height,depth,dim);
15934       if (!cimg::strcasecmp(naxes,def_axes3d)) { // Default 3D version
15935         CImg_3x3x3(I,T);
15936         cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
15937           res[0](x,y,z,k) = (Tfloat)Ipcc + Incc - 2*Iccc;              // Ixx
15938           res[1](x,y,z,k) = 0.25f*((Tfloat)Ippc + Innc - Ipnc - Inpc); // Ixy
15939           res[2](x,y,z,k) = 0.25f*((Tfloat)Ipcp + Incn - Ipcn - Incp); // Ixz
15940           res[3](x,y,z,k) = (Tfloat)Icpc + Icnc - 2*Iccc;              // Iyy
15941           res[4](x,y,z,k) = 0.25f*((Tfloat)Icpp + Icnn - Icpn - Icnp); // Iyz
15942           res[5](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc;              // Izz
15943         }
15944       } else if (!cimg::strcasecmp(naxes,def_axes2d)) { // Default 2D version
15945         CImg_3x3(I,T);
15946         cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
15947           res[0](x,y,0,k) = (Tfloat)Ipc + Inc - 2*Icc;             // Ixx
15948           res[1](x,y,0,k) = 0.25f*((Tfloat)Ipp + Inn - Ipn - Inp); // Ixy
15949           res[2](x,y,0,k) = (Tfloat)Icp + Icn - 2*Icc;             // Iyy
15950         }
15951       } else for (int l = 0; l<lmax; ) { // Version with custom axes.
15952           const int l2 = l/2;
15953           char axis1 = naxes[l++], axis2 = naxes[l++];
15954           if (axis1>axis2) cimg::swap(axis1,axis2);
15955           bool valid_axis = false;
15956           if (axis1=='x' && axis2=='x') { // Ixx
15957             valid_axis = true; CImg_3x3(I,T);
15958             cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Ipc + Inc - 2*Icc;
15959           }
15960           else if (axis1=='x' && axis2=='y') { // Ixy
15961             valid_axis = true; CImg_3x3(I,T);
15962             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);
15963           }
15964           else if (axis1=='x' && axis2=='z') { // Ixz
15965             valid_axis = true; CImg_3x3x3(I,T);
15966             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);
15967           }
15968           else if (axis1=='y' && axis2=='y') { // Iyy
15969             valid_axis = true; CImg_3x3(I,T);
15970             cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Icp + Icn - 2*Icc;
15971           }
15972           else if (axis1=='y' && axis2=='z') { // Iyz
15973             valid_axis = true; CImg_3x3x3(I,T);
15974             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);
15975           }
15976           else if (axis1=='z' && axis2=='z') { // Izz
15977             valid_axis = true; CImg_3x3x3(I,T);
15978             cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc;
15979           }
15980           else if (!valid_axis) throw CImgArgumentException("CImg<%s>::get_hessian() : Invalid parameter axes = '%s'.",
15981                                                             pixel_type(),naxes);
15982       }
15983       return res;
15984     }
15985 
15986     //! Compute distance function from 0-valued isophotes by the application of an Hamilton-Jacobi PDE.
15987     CImg<T>& distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) {
15988       if (is_empty()) return *this;
15989       CImg<Tfloat> veloc(*this);
15990       for (unsigned int iter = 0; iter<nb_iter; ++iter) {
15991         veloc.fill(0);
15992         if (depth>1) { // 3D version
15993           CImg_3x3x3(I,T);
15994           cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) if (band_size<=0 || cimg::abs(Iccc)<band_size) {
15995             const Tfloat
15996               gx = 0.5f*((Tfloat)Incc - Ipcc),
15997               gy = 0.5f*((Tfloat)Icnc - Icpc),
15998               gz = 0.5f*((Tfloat)Iccn - Iccp),
15999               sgn = -cimg::sign((Tfloat)Iccc),
16000               ix = gx*sgn>0?(Tfloat)Incc - Iccc:(Tfloat)Iccc - Ipcc,
16001               iy = gy*sgn>0?(Tfloat)Icnc - Iccc:(Tfloat)Iccc - Icpc,
16002               iz = gz*sgn>0?(Tfloat)Iccn - Iccc:(Tfloat)Iccc - Iccp,
16003               ng = 1e-5f + (Tfloat)cimg_std::sqrt(gx*gx + gy*gy + gz*gz),
16004               ngx = gx/ng,
16005               ngy = gy/ng,
16006               ngz = gz/ng;
16007             veloc(x,y,z,k) = sgn*(ngx*ix + ngy*iy + ngz*iz - 1);
16008           }
16009         } else { // 2D version
16010           CImg_3x3(I,T);
16011           cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) if (band_size<=0 || cimg::abs(Icc)<band_size) {
16012             const Tfloat
16013               gx = 0.5f*((Tfloat)Inc - Ipc),
16014               gy = 0.5f*((Tfloat)Icn - Icp),
16015               sgn = -cimg::sign((Tfloat)Icc),
16016               ix = gx*sgn>0?(Tfloat)Inc - Icc:(Tfloat)Icc - Ipc,
16017               iy = gy*sgn>0?(Tfloat)Icn - Icc:(Tfloat)Icc - Icp,
16018               ng = 1e-5f + (Tfloat)cimg_std::sqrt(gx*gx + gy*gy),
16019               ngx = gx/ng,
16020               ngy = gy/ng;
16021             veloc(x,y,k) = sgn*(ngx*ix + ngy*iy - 1);
16022           }
16023         }
16024         float m, M = (float)veloc.maxmin(m), xdt = precision/(float)cimg::max(cimg::abs(m),cimg::abs(M));
16025         *this+=(veloc*=xdt);
16026       }
16027       return *this;
16028     }
16029 
16030     CImg<Tfloat> get_distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) const {
16031       return CImg<Tfloat>(*this,false).distance_hamilton(nb_iter,band_size,precision);
16032     }
16033 
16034     //! Compute the Euclidean distance map to a shape of specified isovalue.
16035     CImg<T>& distance(const T isovalue,
16036                       const float sizex=1, const float sizey=1, const float sizez=1,
16037                       const bool compute_sqrt=true) {
16038       return get_distance(isovalue,sizex,sizey,sizez,compute_sqrt).transfer_to(*this);
16039     }
16040 
16041     CImg<floatT> get_distance(const T isovalue,
16042                               const float sizex=1, const float sizey=1, const float sizez=1,
16043                               const bool compute_sqrt=true) const {
16044       if (is_empty()) return *this;
16045       const int dx = dimx(), dy = dimy(), dz = dimz();
16046       CImg<floatT> res(dx,dy,dz,dim);
16047       const float maxdist = (float)cimg_std::sqrt((float)dx*dx + dy*dy + dz*dz);
16048       cimg_forV(*this,k) {
16049         bool is_isophote = false;
16050 
16051         if (depth>1) { // 3D version
16052           { cimg_forYZ(*this,y,z) {
16053             if ((*this)(0,y,z,k)==isovalue) { is_isophote = true; res(0,y,z,k) = 0; } else res(0,y,z,k) = maxdist;
16054             for (int x = 1; x<dx; ++x) if ((*this)(x,y,z,k)==isovalue) { is_isophote = true; res(x,y,z,k) = 0; }
16055             else res(x,y,z,k) = res(x-1,y,z,k) + sizex;
16056             { 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; }
16057           }}
16058           if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<float>::max()); continue; }
16059           CImg<floatT> tmp(cimg::max(dy,dz));
16060           CImg<intT> s(tmp.width), t(s.width);
16061           { cimg_forXZ(*this,x,z) {
16062             { cimg_forY(*this,y) tmp[y] = res(x,y,z,k); }
16063             int q = s[0] = t[0] = 0;
16064             { for (int y = 1; y<dy; ++y) {
16065               const float val = tmp[y], val2 = val*val;
16066               while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizey)>_distance_f(t[q],y,val2,sizey)) --q;
16067               if (q<0) { q = 0; s[0] = y; }
16068               else {
16069                 const int w = 1 + _distance_sep(s[q],y,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizey);
16070                 if (w<dy) { s[++q] = y; t[q] = w; }
16071               }
16072             }}
16073             { for (int y = dy - 1; y>=0; --y) {
16074               res(x,y,z,k) = _distance_f(y,s[q],cimg::sqr(tmp[s[q]]),sizey);
16075               if (y==t[q]) --q;
16076             }}
16077           }}
16078           { cimg_forXY(*this,x,y) {
16079             { cimg_forZ(*this,z) tmp[z] = res(x,y,z,k); }
16080             int q = s[0] = t[0] = 0;
16081             { for (int z = 1; z<dz; ++z) {
16082               const float val = tmp[z];
16083               while (q>=0 && _distance_f(t(q),s[q],tmp[s[q]],sizez)>_distance_f(t[q],z,tmp[z],sizez)) --q;
16084               if (q<0) { q = 0; s[0] = z; }
16085               else {
16086                 const int w = 1 + _distance_sep(s[q],z,(int)tmp[s[q]],(int)val,sizez);
16087                 if (w<dz) { s[++q] = z; t[q] = w; }
16088               }
16089             }}
16090             { for (int z = dz - 1; z>=0; --z) {
16091               const float val = _distance_f(z,s[q],tmp[s[q]],sizez);
16092               res(x,y,z,k) = compute_sqrt?(float)cimg_std::sqrt(val):val;
16093               if (z==t[q]) --q;
16094             }}
16095           }}
16096         } else { // 2D version (with small optimizations)
16097           cimg_forX(*this,x) {
16098             const T *ptrs = ptr(x,0,0,k);
16099             float *ptrd = res.ptr(x,0,0,k), d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:maxdist;
16100             for (int y = 1; y<dy; ++y) { ptrs+=width; ptrd+=width; d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:d+sizey; }
16101             { for (int y = dy - 2; y>=0; --y) { ptrd-=width; if (d<*ptrd) *ptrd = (d+=sizey); else d = *ptrd; }}
16102           }
16103           if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<float>::max()); continue; }
16104           CImg<floatT> tmp(dx);
16105           CImg<intT> s(dx), t(dx);
16106           cimg_forY(*this,y) {
16107             float *ptmp = tmp.ptr();
16108             cimg_std::memcpy(ptmp,res.ptr(0,y,0,k),sizeof(float)*dx);
16109             int q = s[0] = t[0] = 0;
16110             for (int x = 1; x<dx; ++x) {
16111               const float val = *(++ptmp), val2 = val*val;
16112               while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizex)>_distance_f(t[q],x,val2,sizex)) --q;
16113               if (q<0) { q = 0; s[0] = x; }
16114               else {
16115                 const int w = 1 + _distance_sep(s[q],x,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizex);
16116                 if (w<dx) { q++; s[q] = x; t[q] = w; }
16117               }
16118             }
16119             float *pres = res.ptr(0,y,0,k) + width;
16120             { for (int x = dx - 1; x>=0; --x) {
16121               const float val = _distance_f(x,s[q],cimg::sqr(tmp[s[q]]),sizex);
16122               *(--pres) = compute_sqrt?(float)cimg_std::sqrt(val):val;
16123               if (x==t[q]) --q;
16124             }}
16125           }
16126         }
16127       }
16128       return res;
16129     }
16130 
16131     static float _distance_f(const int x, const int i, const float gi2, const float fact) {
16132       const float xmi = fact*((float)x - i);
16133       return xmi*xmi + gi2;
16134     }
16135     static int _distance_sep(const int i, const int u, const int gi2, const int gu2, const float fact) {
16136       const float fact2 = fact*fact;
16137       return (int)(fact2*(u*u - i*i) + gu2 - gi2)/(int)(2*fact2*(u - i));
16138     }
16139 
16140     //! Compute minimal path in a graph, using the Dijkstra algorithm.
16141     /**
16142        \param distance An object having operator()(unsigned int i, unsigned int j) which returns distance between two nodes (i,j).
16143        \param nb_nodes Number of graph nodes.
16144        \param starting_node Indice of the starting node.
16145        \param ending_node Indice of the ending node (set to ~0U to ignore ending node).
16146        \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
16147        \return Array of distances of each node to the starting node.
16148     **/
16149     template<typename tf, typename t>
16150     static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
16151                             const unsigned int starting_node, const unsigned int ending_node,
16152                             CImg<t>& previous) {
16153 
16154       CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max());
16155       dist(starting_node) = 0;
16156       previous.assign(1,nb_nodes,1,1,(t)-1);
16157       previous(starting_node) = (t)starting_node;
16158       CImg<uintT> Q(nb_nodes);
16159       cimg_forX(Q,u) Q(u) = u;
16160       cimg::swap(Q(starting_node),Q(0));
16161       unsigned int sizeQ = nb_nodes;
16162       while (sizeQ) {
16163         // Update neighbors from minimal vertex
16164         const unsigned int umin = Q(0);
16165         if (umin==ending_node) sizeQ = 0;
16166         else {
16167           const T dmin = dist(umin);
16168           const T infty = cimg::type<T>::max();
16169           for (unsigned int q=1; q<sizeQ; ++q) {
16170             const unsigned int v = Q(q);
16171             const T d = (T)distance(v,umin);
16172             if (d<infty) {
16173               const T alt = dmin + d;
16174               if (alt<dist(v)) {
16175                 dist(v) = alt;
16176                 previous(v) = (t)umin;
16177                 const T distpos = dist(Q(q));
16178                 for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos+1)/2-1)); pos=par) cimg::swap(Q(pos),Q(par));
16179               }
16180             }
16181           }
16182           // Remove minimal vertex from queue
16183           Q(0) = Q(--sizeQ);
16184           const T distpos = dist(Q(0));
16185           for (unsigned int pos = 0, left = 0, right = 0;
16186                ((right=2*(pos+1),(left=right-1))<sizeQ && distpos>dist(Q(left))) || (right<sizeQ && distpos>dist(Q(right)));) {
16187             if (right<sizeQ) {
16188               if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; }
16189               else { cimg::swap(Q(pos),Q(right)); pos = right; }
16190             } else { cimg::swap(Q(pos),Q(left)); pos = left; }
16191           }
16192         }
16193       }
16194       return dist;
16195     }
16196 
16197     //! Return minimal path in a graph, using the Dijkstra algorithm.
16198     template<typename tf, typename t>
16199     static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
16200                             const unsigned int starting_node, const unsigned int ending_node=~0U) {
16201       CImg<uintT> foo;
16202       return dijkstra(distance,nb_nodes,starting_node,ending_node,foo);
16203     }
16204 
16205     //! Return minimal path in a graph, using the Dijkstra algorithm.
16206     /**
16207        Instance image corresponds to the adjacency matrix of the graph.
16208        \param starting_node Indice of the starting node.
16209        \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
16210        \return Array of distances of each node to the starting node.
16211     **/
16212     template<typename t>
16213     CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) {
16214       return get_dijkstra(starting_node,ending_node,previous).transfer_to(*this);
16215     }
16216 
16217     template<typename t>
16218     CImg<T> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) const {
16219       if (width!=height || depth!=1 || dim!=1)
16220         throw CImgInstanceException("CImg<%s>::dijkstra() : Instance image (%u,%u,%u,%u,%p) is not a graph adjacency matrix",
16221                                     pixel_type(),width,height,depth,dim,data);
16222       return dijkstra(*this,width,starting_node,ending_node,previous);
16223     }
16224 
16225     //! Return minimal path in a graph, using the Dijkstra algorithm.
16226     CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) {
16227       return get_dijkstra(starting_node,ending_node).transfer_to(*this);
16228     }
16229 
16230     CImg<Tfloat> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const {
16231       CImg<uintT> foo;
16232       return get_dijkstra(starting_node,ending_node,foo);
16233     }
16234 
16235     //@}
16236     //-------------------------------------
16237     //
16238     //! \name Meshes and Triangulations
16239     //@{
16240     //-------------------------------------
16241 
16242     //! Return a 3D centered cube.
16243     template<typename tf>
16244     static CImg<floatT> cube3d(CImgList<tf>& primitives, const float size=100) {
16245       const double s = size/2.0;
16246       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);
16247       return CImg<floatT>(8,3,1,1,
16248                           -s,s,s,-s,-s,s,s,-s,
16249                           -s,-s,s,s,-s,-s,s,s,
16250                           -s,-s,-s,-s,s,s,s,s);
16251     }
16252 
16253     //! Return a 3D centered cuboid.
16254     template<typename tf>
16255     static CImg<floatT> cuboid3d(CImgList<tf>& primitives, const float sizex=200,
16256                                  const float sizey=100, const float sizez=100) {
16257       const double sx = sizex/2.0, sy = sizey/2.0, sz = sizez/2.0;
16258       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);
16259       return CImg<floatT>(8,3,1,1,
16260                           -sx,sx,sx,-sx,-sx,sx,sx,-sx,
16261                           -sy,-sy,sy,sy,-sy,-sy,sy,sy,
16262                           -sz,-sz,-sz,-sz,sz,sz,sz,sz);
16263     }
16264 
16265     //! Return a 3D centered cone.
16266     template<typename tf>
16267     static CImg<floatT> cone3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
16268                                const unsigned int subdivisions=24, const bool symetrize=false) {
16269       primitives.assign();
16270       if (!subdivisions) return CImg<floatT>();
16271       const double r = (double)radius, h = (double)height/2;
16272       CImgList<floatT> points(2,1,3,1,1,
16273                               0.0,0.0,h,
16274                               0.0,0.0,-h);
16275       const float delta = 360.0f/subdivisions, nh = symetrize?0:-(float)h;
16276       for (float angle = 0; angle<360; angle+=delta) {
16277         const float a = (float)(angle*cimg::valuePI/180);
16278         points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),nh));
16279       }
16280       const unsigned int nbr = points.size-2;
16281       for (unsigned int p = 0; p<nbr; ++p) {
16282         const unsigned int curr = 2+p, next = 2+((p+1)%nbr);
16283         primitives.insert(CImg<tf>::vector(1,next,curr)).
16284           insert(CImg<tf>::vector(0,curr,next));
16285       }
16286       return points.get_append('x');
16287     }
16288 
16289     //! Return a 3D centered cylinder.
16290     template<typename tf>
16291     static CImg<floatT> cylinder3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
16292                                    const unsigned int subdivisions=24) {
16293       primitives.assign();
16294       if (!subdivisions) return CImg<floatT>();
16295       const double r = (double)radius, h = (double)height/2;
16296       CImgList<floatT> points(2,1,3,1,1,
16297                               0.0,0.0,-h,
16298                               0.0,0.0,h);
16299 
16300       const float delta = 360.0f/subdivisions;
16301       for (float angle = 0; angle<360; angle+=delta) {
16302         const float a = (float)(angle*cimg::valuePI/180);
16303         points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),-(float)h));
16304         points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),(float)h));
16305       }
16306       const unsigned int nbr = (points.size-2)/2;
16307       for (unsigned int p = 0; p<nbr; ++p) {
16308         const unsigned int curr = 2+2*p, next = 2+(2*((p+1)%nbr));
16309         primitives.insert(CImg<tf>::vector(0,next,curr)).
16310           insert(CImg<tf>::vector(1,curr+1,next+1)).
16311           insert(CImg<tf>::vector(curr,next,next+1,curr+1));
16312       }
16313       return points.get_append('x');
16314     }
16315 
16316     //! Return a 3D centered torus.
16317     template<typename tf>
16318     static CImg<floatT> torus3d(CImgList<tf>& primitives, const float radius1=100, const float radius2=30,
16319                                 const unsigned int subdivisions1=24, const unsigned int subdivisions2=12) {
16320       primitives.assign();
16321       if (!subdivisions1 || !subdivisions2) return CImg<floatT>();
16322       CImgList<floatT> points;
16323       for (unsigned int v = 0; v<subdivisions1; ++v) {
16324         const float
16325           beta = (float)(v*2*cimg::valuePI/subdivisions1),
16326           xc = radius1*(float)cimg_std::cos(beta),
16327           yc = radius1*(float)cimg_std::sin(beta);
16328         for (unsigned int u=0; u<subdivisions2; ++u) {
16329           const float
16330             alpha = (float)(u*2*cimg::valuePI/subdivisions2),
16331             x = xc + radius2*(float)(cimg_std::cos(alpha)*cimg_std::cos(beta)),
16332             y = yc + radius2*(float)(cimg_std::cos(alpha)*cimg_std::sin(beta)),
16333             z = radius2*(float)cimg_std::sin(alpha);
16334           points.insert(CImg<floatT>::vector(x,y,z));
16335         }
16336       }
16337       for (unsigned int vv = 0; vv<subdivisions1; ++vv) {
16338         const unsigned int nv = (vv+1)%subdivisions1;
16339         for (unsigned int uu = 0; uu<subdivisions2; ++uu) {
16340           const unsigned int nu = (uu+1)%subdivisions2, svv = subdivisions2*vv, snv = subdivisions2*nv;
16341           primitives.insert(CImg<tf>::vector(svv+nu,svv+uu,snv+uu));
16342           primitives.insert(CImg<tf>::vector(svv+nu,snv+uu,snv+nu));
16343         }
16344       }
16345       return points.get_append('x');
16346     }
16347 
16348     //! Return a 3D centered XY plane.
16349     template<typename tf>
16350     static CImg<floatT> plane3d(CImgList<tf>& primitives, const float sizex=100, const float sizey=100,
16351                                 const unsigned int subdivisionsx=3, const unsigned int subdivisionsy=3,
16352                                 const bool double_sided=false) {
16353       primitives.assign();
16354       if (!subdivisionsx || !subdivisionsy) return CImg<floatT>();
16355       CImgList<floatT> points;
16356       const unsigned int w = subdivisionsx + 1, h = subdivisionsy + 1;
16357       const float w2 = subdivisionsx/2.0f, h2 = subdivisionsy/2.0f, fx = (float)sizex/w, fy = (float)sizey/h;
16358       for (unsigned int yy = 0; yy<h; ++yy)
16359         for (unsigned int xx = 0; xx<w; ++xx)
16360           points.insert(CImg<floatT>::vector(fx*(xx-w2),fy*(yy-h2),0));
16361       for (unsigned int y = 0; y<subdivisionsy; ++y) for (unsigned int x = 0; x<subdivisionsx; ++x) {
16362         const int off1 = x+y*w, off2 = x+1+y*w, off3 = x+1+(y+1)*w, off4 = x+(y+1)*w;
16363         primitives.insert(CImg<tf>::vector(off1,off4,off3,off2));
16364         if (double_sided) primitives.insert(CImg<tf>::vector(off1,off2,off3,off4));
16365       }
16366       return points.get_append('x');
16367     }
16368 
16369     //! Return a 3D centered sphere.
16370     template<typename tf>
16371     static CImg<floatT> sphere3d(CImgList<tf>& primitives, const float radius=50, const unsigned int subdivisions=3) {
16372 
16373       // Create initial icosahedron
16374       primitives.assign();
16375       if (!subdivisions) return CImg<floatT>();
16376       const double tmp = (1+cimg_std::sqrt(5.0f))/2, a = 1.0/cimg_std::sqrt(1+tmp*tmp), b = tmp*a;
16377       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,
16378                               -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a);
16379       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,
16380                         8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3,
16381                         5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2);
16382 
16383       // Recurse subdivisions
16384       for (unsigned int i = 0; i<subdivisions; ++i) {
16385         const unsigned int L = primitives.size;
16386         for (unsigned int l = 0; l<L; ++l) {
16387           const unsigned int
16388             p0 = (unsigned int)primitives(0,0), p1 = (unsigned int)primitives(0,1), p2 = (unsigned int)primitives(0,2);
16389           const float
16390             x0 = points(p0,0), y0 = points(p0,1), z0 = points(p0,2),
16391             x1 = points(p1,0), y1 = points(p1,1), z1 = points(p1,2),
16392             x2 = points(p2,0), y2 = points(p2,1), z2 = points(p2,2),
16393             tnx0 = (x0+x1)/2, tny0 = (y0+y1)/2, tnz0 = (z0+z1)/2, nn0 = (float)cimg_std::sqrt(tnx0*tnx0+tny0*tny0+tnz0*tnz0),
16394             tnx1 = (x0+x2)/2, tny1 = (y0+y2)/2, tnz1 = (z0+z2)/2, nn1 = (float)cimg_std::sqrt(tnx1*tnx1+tny1*tny1+tnz1*tnz1),
16395             tnx2 = (x1+x2)/2, tny2 = (y1+y2)/2, tnz2 = (z1+z2)/2, nn2 = (float)cimg_std::sqrt(tnx2*tnx2+tny2*tny2+tnz2*tnz2),
16396             nx0 = tnx0/nn0, ny0 = tny0/nn0, nz0 = tnz0/nn0,
16397             nx1 = tnx1/nn1, ny1 = tny1/nn1, nz1 = tnz1/nn1,
16398             nx2 = tnx2/nn2, ny2 = tny2/nn2, nz2 = tnz2/nn2;
16399           int i0 = -1, i1 = -1, i2 = -1;
16400           cimglist_for(points,p) {
16401             const float x = (float)points(p,0), y = (float)points(p,1), z = (float)points(p,2);
16402             if (x==nx0 && y==ny0 && z==nz0) i0 = p;
16403             if (x==nx1 && y==ny1 && z==nz1) i1 = p;
16404             if (x==nx2 && y==ny2 && z==nz2) i2 = p;
16405           }
16406           if (i0<0) { points.insert(CImg<floatT>::vector(nx0,ny0,nz0)); i0 = points.size-1; }
16407           if (i1<0) { points.insert(CImg<floatT>::vector(nx1,ny1,nz1)); i1 = points.size-1; }
16408           if (i2<0) { points.insert(CImg<floatT>::vector(nx2,ny2,nz2)); i2 = points.size-1; }
16409           primitives.remove(0);
16410           primitives.insert(CImg<tf>::vector(p0,i0,i1)).
16411             insert(CImg<tf>::vector((tf)i0,(tf)p1,(tf)i2)).
16412             insert(CImg<tf>::vector((tf)i1,(tf)i2,(tf)p2)).
16413             insert(CImg<tf>::vector((tf)i1,(tf)i0,(tf)i2));
16414         }
16415       }
16416       return points.get_append('x')*=radius;
16417     }
16418 
16419     //! Return a 3D centered ellipsoid.
16420     template<typename tf, typename t>
16421     static CImg<floatT> ellipsoid3d(CImgList<tf>& primitives, const CImg<t>& tensor,
16422                                     const unsigned int subdivisions=3) {
16423       primitives.assign();
16424       if (!subdivisions) return CImg<floatT>();
16425       typedef typename cimg::superset<t,float>::type tfloat;
16426       CImg<tfloat> S,V;
16427       tensor.symmetric_eigen(S,V);
16428       const tfloat l0 = S[0], l1 = S[1], l2 = S[2];
16429       CImg<floatT> points = sphere(primitives,subdivisions);
16430       cimg_forX(points,p) {
16431         points(p,0) = (float)(points(p,0)*l0);
16432         points(p,1) = (float)(points(p,1)*l1);
16433         points(p,2) = (float)(points(p,2)*l2);
16434       }
16435       V.transpose();
16436       points = V*points;
16437       return points;
16438     }
16439 
16440     //! Return a 3D elevation object of the instance image.
16441     template<typename tf, typename tc, typename te>
16442     CImg<floatT> get_elevation3d(CImgList<tf>& primitives, CImgList<tc>& colors, const CImg<te>& elevation) const {
16443       primitives.assign();
16444       colors.assign();
16445       if (is_empty()) return *this;
16446       if (depth>1)
16447         throw CImgInstanceException("CImg<%s>::get_elevation3d() : Instance image (%u,%u,%u,%u,%p) is not a 2D image.",
16448                                     pixel_type(),width,height,depth,dim,data);
16449       if (!is_sameXY(elevation))
16450         throw CImgArgumentException("CImg<%s>::get_elevation3d() : Elevation image (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) "
16451                                     "have different sizes.",pixel_type(),
16452                                     elevation.width,elevation.height,elevation.depth,elevation.dim,elevation.data,
16453                                     width,height,depth,dim,data,pixel_type());
16454       float m, M = (float)maxmin(m);
16455       if (M==m) ++M;
16456       const unsigned int w = width + 1, h = height + 1;
16457       CImg<floatT> points(w*h,3);
16458       cimg_forXY(*this,x,y) {
16459         const int yw = y*w, xpyw = x + yw, xpyww = xpyw + w;
16460         points(xpyw,0) = points(xpyw+1,0) = points(xpyww+1,0) = points(xpyww,0) = (float)x;
16461         points(xpyw,1) = points(xpyw+1,1) = points(xpyww+1,1) = points(xpyww,1) = (float)y;
16462         points(xpyw,2) = points(xpyw+1,2) = points(xpyww+1,2) = points(xpyww,2) = (float)elevation(x,y);
16463         primitives.insert(CImg<tf>::vector(xpyw,xpyw+1,xpyww+1,xpyww));
16464         const unsigned char
16465           r = (unsigned char)(((*this)(x,y,0) - m)*255/(M-m)),
16466           g = dim>1?(unsigned char)(((*this)(x,y,1) - m)*255/(M-m)):r,
16467           b = dim>2?(unsigned char)(((*this)(x,y,2) - m)*255/(M-m)):(dim>1?0:r);
16468         colors.insert(CImg<tc>::vector((tc)r,(tc)g,(tc)b));
16469       }
16470       return points;
16471     }
16472 
16473     // Inner routine used by the Marching square algorithm.
16474     template<typename t>
16475     static int _marching_squares_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
16476                                         const unsigned int x, const unsigned int nx) {
16477       switch (edge) {
16478       case 0 : return (int)indices1(x,0);
16479       case 1 : return (int)indices1(nx,1);
16480       case 2 : return (int)indices2(x,0);
16481       case 3 : return (int)indices1(x,1);
16482       }
16483       return 0;
16484     }
16485 
16486     //! Polygonize an implicit 2D function by the marching squares algorithm.
16487     template<typename tf, typename tfunc>
16488     static CImg<floatT> marching_squares(CImgList<tf>& primitives, const tfunc& func, const float isovalue,
16489                                          const float x0, const float y0,
16490                                          const float x1, const float y1,
16491                                          const float resx, const float resy) {
16492       static unsigned int edges[16] = { 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc, 0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 };
16493       static int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 },
16494                                      { 1,2,-1,-1 },   { 0,1,2,3 },   { 0,2,-1,-1 }, { 2,3,-1,-1 },
16495                                      { 2,3,-1,-1 },   { 0,2,-1,-1},  { 0,3,1,2 },   { 1,2,-1,-1 },
16496                                      { 1,3,-1,-1 },   { 0,1,-1,-1},  { 0,3,-1,-1},  { -1,-1,-1,-1 } };
16497       const unsigned int
16498         nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1,
16499         ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1;
16500       if (!nxm1 || !nym1) return CImg<floatT>();
16501 
16502       primitives.assign();
16503       CImgList<floatT> points;
16504       CImg<intT> indices1(nx,1,1,2,-1), indices2(nx,1,1,2);
16505       CImg<floatT> values1(nx), values2(nx);
16506       float X = 0, Y = 0, nX = 0, nY = 0;
16507 
16508       // Fill first line with values
16509       cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=resx; }
16510 
16511       // Run the marching squares algorithm
16512       Y = y0; nY = Y + resy;
16513       for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y=nY, nY+=resy) {
16514         X = x0; nX = X + resx;
16515         indices2.fill(-1);
16516         for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X=nX, nX+=resx) {
16517 
16518           // Determine cube configuration
16519           const float
16520             val0 = values1(xi), val1 = values1(nxi),
16521             val2 = values2(nxi) = (float)func(nX,nY),
16522             val3 = values2(xi) = (float)func(X,nY);
16523 
16524           const unsigned int configuration = (val0<isovalue?1:0)  | (val1<isovalue?2:0)  | (val2<isovalue?4:0)  | (val3<isovalue?8:0),
16525             edge = edges[configuration];
16526 
16527           // Compute intersection points
16528           if (edge) {
16529             if ((edge&1) && indices1(xi,0)<0) {
16530               const float Xi = X + (isovalue-val0)*resx/(val1-val0);
16531               indices1(xi,0) = points.size;
16532               points.insert(CImg<floatT>::vector(Xi,Y));
16533             }
16534             if ((edge&2) && indices1(nxi,1)<0) {
16535               const float Yi = Y + (isovalue-val1)*resy/(val2-val1);
16536               indices1(nxi,1) = points.size;
16537               points.insert(CImg<floatT>::vector(nX,Yi));
16538             }
16539             if ((edge&4) && indices2(xi,0)<0) {
16540               const float Xi = X + (isovalue-val3)*resx/(val2-val3);
16541               indices2(xi,0) = points.size;
16542               points.insert(CImg<floatT>::vector(Xi,nY));
16543             }
16544             if ((edge&8) && indices1(xi,1)<0) {
16545               const float Yi = Y + (isovalue-val0)*resy/(val3-val0);
16546               indices1(xi,1) = points.size;
16547               points.insert(CImg<floatT>::vector(X,Yi));
16548             }
16549 
16550             // Create segments
16551             for (int *segment = segments[configuration]; *segment!=-1; ) {
16552               const unsigned int p0 = *(segment++), p1 = *(segment++);
16553               const tf
16554                 i0 = (tf)(_marching_squares_indice(p0,indices1,indices2,xi,nxi)),
16555                 i1 = (tf)(_marching_squares_indice(p1,indices1,indices2,xi,nxi));
16556               primitives.insert(CImg<tf>::vector(i0,i1));
16557             }
16558           }
16559         }
16560         values1.swap(values2);
16561         indices1.swap(indices2);
16562       }
16563       return points.get_append('x');
16564     }
16565 
16566     // Inner routine used by the Marching cube algorithm.
16567     template<typename t>
16568     static int _marching_cubes_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
16569                                       const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny) {
16570       switch (edge) {
16571       case 0 : return indices1(x,y,0);
16572       case 1 : return indices1(nx,y,1);
16573       case 2 : return indices1(x,ny,0);
16574       case 3 : return indices1(x,y,1);
16575       case 4 : return indices2(x,y,0);
16576       case 5 : return indices2(nx,y,1);
16577       case 6 : return indices2(x,ny,0);
16578       case 7 : return indices2(x,y,1);
16579       case 8 : return indices1(x,y,2);
16580       case 9 : return indices1(nx,y,2);
16581       case 10 : return indices1(nx,ny,2);
16582       case 11 : return indices1(x,ny,2);
16583       }
16584       return 0;
16585     }
16586 
16587     //! Polygonize an implicit function
16588     // This function uses the Marching Cubes Tables published on the web page :
16589     // http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/
16590     template<typename tf, typename tfunc>
16591     static CImg<floatT> marching_cubes(CImgList<tf>& primitives,
16592                                        const tfunc& func, const float isovalue,
16593                                        const float x0, const float y0, const float z0,
16594                                        const float x1, const float y1, const float z1,
16595                                        const float resx, const float resy, const float resz,
16596                                        const bool invert_faces=false) {
16597 
16598       static unsigned int edges[256] = {
16599         0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
16600         0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
16601         0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
16602         0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
16603         0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
16604         0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
16605         0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
16606         0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
16607         0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
16608         0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
16609         0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
16610         0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
16611         0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
16612         0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
16613         0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
16614         0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 };
16615 
16616       static int triangles[256][16] =
16617         {{ -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 },
16618          { 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 },
16619          { 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 },
16620          { 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 },
16621          { 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 },
16622          { 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 },
16623          { 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 },
16624          { 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 },
16625          { 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 },
16626          { 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 },
16627          { 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 },
16628          { 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 },
16629          { 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 },
16630          { 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 },
16631          { 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 },
16632          { 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 },
16633          { 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 },
16634          { 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 },
16635          { 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 },
16636          { 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 },
16637          { 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 },
16638          { 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 },
16639          { 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 },
16640          { 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 },
16641          { 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 },
16642          { 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 },
16643          { 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 },
16644          { 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 },
16645          { 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 },
16646          { 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 },
16647          { 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 },
16648          { 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 },
16649          { 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 },
16650          { 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 },
16651          { 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 },
16652          { 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 },
16653          { 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 },
16654          { 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 },
16655          { 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 },
16656          { 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 },
16657          { 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 },
16658          { 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 },
16659          { 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 },
16660          { 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 },
16661          { 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 },
16662          { 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 },
16663          { 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 },
16664          { 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 },
16665          { 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 },
16666          { 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 },
16667          { 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 },
16668          { 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 },
16669          { 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 },
16670          { 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 },
16671          { 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 },
16672          { 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 },
16673          { 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 },
16674          { 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 },
16675          { 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 },
16676          { 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 },
16677          { 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 },
16678          { 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 },
16679          { 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 },
16680          { 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 },
16681          { 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 },
16682          { 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 },
16683          { 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 },
16684          { 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 },
16685          { 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 },
16686          { 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 },
16687          { 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 },
16688          { 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 },
16689          { 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 },
16690          { 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 },
16691          { 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 },
16692          { 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 },
16693          { 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 },
16694          { 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 },
16695          { 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 },
16696          { 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 },
16697          { 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 },
16698          { 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 },
16699          { 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 },
16700          { 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 },
16701          { 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 },
16702          { 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 },
16703          { 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 },
16704          { 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 },
16705          { 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 },
16706          { 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 },
16707          { 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 },
16708          { 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 },
16709          { 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 },
16710          { 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 },
16711          { 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 },
16712          { 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 },
16713          { 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 },
16714          { 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 },
16715          { 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 },
16716          { 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 },
16717          { 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 },
16718          { 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 },
16719          { 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 },
16720          { 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 },
16721          { 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 },
16722          { 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 },
16723          { 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 },
16724          { 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 },
16725          { 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 },
16726          { 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 },
16727          { 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 },
16728          { 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 },
16729          { 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 },
16730          { 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 },
16731          { 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 },
16732          { 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 },
16733          { 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 },
16734          { 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 },
16735          { 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 },
16736          { 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 },
16737          { 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 },
16738          { 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 },
16739          { 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 },
16740          { 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 },
16741          { 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 },
16742          { 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 },
16743          { 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 },
16744          { 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 }};
16745 
16746       const unsigned int
16747         nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1,
16748         ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1,
16749         nz = (unsigned int)((z1-z0+1)/resz), nzm1 = nz-1;
16750       if (!nxm1 || !nym1 || !nzm1) return CImg<floatT>();
16751 
16752       primitives.assign();
16753       CImgList<floatT> points;
16754       CImg<intT> indices1(nx,ny,1,3,-1), indices2(indices1);
16755       CImg<floatT> values1(nx,ny), values2(nx,ny);
16756       float X = 0, Y = 0, Z = 0, nX = 0, nY = 0, nZ = 0;
16757 
16758       // Fill the first plane with function values
16759       Y = y0;
16760       cimg_forY(values1,y) {
16761         X = x0;
16762         cimg_forX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=resx; }
16763         Y+=resy;
16764       }
16765 
16766       // Run Marching Cubes algorithm
16767       Z = z0; nZ = Z + resz;
16768       for (unsigned int zi = 0; zi<nzm1; ++zi, Z = nZ, nZ+=resz) {
16769         Y = y0; nY = Y + resy;
16770         indices2.fill(-1);
16771         for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y = nY, nY+=resy) {
16772           X = x0; nX = X + resx;
16773           for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X = nX, nX+=resx) {
16774 
16775             // Determine cube configuration
16776             const float
16777               val0 = values1(xi,yi), val1 = values1(nxi,yi), val2 = values1(nxi,nyi), val3 = values1(xi,nyi),
16778               val4 = values2(xi,yi) = (float)func(X,Y,nZ),
16779               val5 = values2(nxi,yi) = (float)func(nX,Y,nZ),
16780               val6 = values2(nxi,nyi) = (float)func(nX,nY,nZ),
16781               val7 = values2(xi,nyi) = (float)func(X,nY,nZ);
16782 
16783             const unsigned int configuration =
16784               (val0<isovalue?1:0)  | (val1<isovalue?2:0)  | (val2<isovalue?4:0)  | (val3<isovalue?8:0) |
16785               (val4<isovalue?16:0) | (val5<isovalue?32:0) | (val6<isovalue?64:0) | (val7<isovalue?128:0),
16786               edge = edges[configuration];
16787 
16788             // Compute intersection points
16789             if (edge) {
16790               if ((edge&1) && indices1(xi,yi,0)<0) {
16791                 const float Xi = X + (isovalue-val0)*resx/(val1-val0);
16792                 indices1(xi,yi,0) = points.size;
16793                 points.insert(CImg<floatT>::vector(Xi,Y,Z));
16794               }
16795               if ((edge&2) && indices1(nxi,yi,1)<0) {
16796                 const float Yi = Y + (isovalue-val1)*resy/(val2-val1);
16797                 indices1(nxi,yi,1) = points.size;
16798                 points.insert(CImg<floatT>::vector(nX,Yi,Z));
16799               }
16800               if ((edge&4) && indices1(xi,nyi,0)<0) {
16801                 const float Xi = X + (isovalue-val3)*resx/(val2-val3);
16802                 indices1(xi,nyi,0) = points.size;
16803                 points.insert(CImg<floatT>::vector(Xi,nY,Z));
16804               }
16805               if ((edge&8) && indices1(xi,yi,1)<0) {
16806                 const float Yi = Y + (isovalue-val0)*resy/(val3-val0);
16807                 indices1(xi,yi,1) = points.size;
16808                 points.insert(CImg<floatT>::vector(X,Yi,Z));
16809               }
16810               if ((edge&16) && indices2(xi,yi,0)<0) {
16811                 const float Xi = X + (isovalue-val4)*resx/(val5-val4);
16812                 indices2(xi,yi,0) = points.size;
16813                 points.insert(CImg<floatT>::vector(Xi,Y,nZ));
16814               }
16815               if ((edge&32) && indices2(nxi,yi,1)<0) {
16816                 const float Yi = Y + (isovalue-val5)*resy/(val6-val5);
16817                 indices2(nxi,yi,1) = points.size;
16818                 points.insert(CImg<floatT>::vector(nX,Yi,nZ));
16819               }
16820               if ((edge&64) && indices2(xi,nyi,0)<0) {
16821                 const float Xi = X + (isovalue-val7)*resx/(val6-val7);
16822                 indices2(xi,nyi,0) = points.size;
16823                 points.insert(CImg<floatT>::vector(Xi,nY,nZ));
16824               }
16825               if ((edge&128) && indices2(xi,yi,1)<0)  {
16826                 const float Yi = Y + (isovalue-val4)*resy/(val7-val4);
16827                 indices2(xi,yi,1) = points.size;
16828                 points.insert(CImg<floatT>::vector(X,Yi,nZ));
16829               }
16830               if ((edge&256) && indices1(xi,yi,2)<0) {
16831                 const float Zi = Z+ (isovalue-val0)*resz/(val4-val0);
16832                 indices1(xi,yi,2) = points.size;
16833                 points.insert(CImg<floatT>::vector(X,Y,Zi));
16834               }
16835               if ((edge&512) && indices1(nxi,yi,2)<0)  {
16836                 const float Zi = Z + (isovalue-val1)*resz/(val5-val1);
16837                 indices1(nxi,yi,2) = points.size;
16838                 points.insert(CImg<floatT>::vector(nX,Y,Zi));
16839               }
16840               if ((edge&1024) && indices1(nxi,nyi,2)<0) {
16841                 const float Zi = Z + (isovalue-val2)*resz/(val6-val2);
16842                 indices1(nxi,nyi,2) = points.size;
16843                 points.insert(CImg<floatT>::vector(nX,nY,Zi));
16844               }
16845               if ((edge&2048) && indices1(xi,nyi,2)<0) {
16846                 const float Zi = Z + (isovalue-val3)*resz/(val7-val3);
16847                 indices1(xi,nyi,2) = points.size;
16848                 points.insert(CImg<floatT>::vector(X,nY,Zi));
16849               }
16850 
16851               // Create triangles
16852               for (int *triangle = triangles[configuration]; *triangle!=-1; ) {
16853                 const unsigned int p0 = *(triangle++), p1 = *(triangle++), p2 = *(triangle++);
16854                 const tf
16855                   i0 = (tf)(_marching_cubes_indice(p0,indices1,indices2,xi,yi,nxi,nyi)),
16856                   i1 = (tf)(_marching_cubes_indice(p1,indices1,indices2,xi,yi,nxi,nyi)),
16857                   i2 = (tf)(_marching_cubes_indice(p2,indices1,indices2,xi,yi,nxi,nyi));
16858                 if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2));
16859                 else primitives.insert(CImg<tf>::vector(i0,i2,i1));
16860               }
16861             }
16862           }
16863         }
16864         cimg::swap(values1,values2);
16865         cimg::swap(indices1,indices2);
16866       }
16867       return points.get_append('x');
16868     }
16869 
16870     struct _marching_squares_func {
16871       const CImg<T>& ref;
16872       explicit _marching_squares_func(const CImg<T>& pref):ref(pref) {}
16873       float operator()(const float x, const float y) const {
16874         return (float)ref((int)x,(int)y);
16875       }
16876     };
16877 
16878     struct _marching_cubes_func {
16879       const CImg<T>& ref;
16880       explicit _marching_cubes_func(const CImg<T>& pref):ref(pref) {}
16881       float operator()(const float x, const float y, const float z) const {
16882         return (float)ref((int)x,(int)y,(int)z);
16883       }
16884     };
16885 
16886     struct _marching_squares_func_float {
16887       const CImg<T>& ref;
16888       explicit _marching_squares_func_float(const CImg<T>& pref):ref(pref) {}
16889       float operator()(const float x, const float y) const {
16890         return (float)ref._linear_atXY(x,y);
16891       }
16892     };
16893 
16894     struct _marching_cubes_func_float {
16895       const CImg<T>& ref;
16896       explicit _marching_cubes_func_float(const CImg<T>& pref):ref(pref) {}
16897       float operator()(const float x, const float y, const float z) const {
16898         return (float)ref._linear_atXYZ(x,y,z);
16899       }
16900     };
16901 
16902     //! Compute a vectorization of an implicit function.
16903     template<typename tf>
16904     CImg<floatT> get_isovalue3d(CImgList<tf>& primitives, const float isovalue,
16905                                 const float resx=1, const float resy=1, const float resz=1,
16906                                 const bool invert_faces=false) const {
16907       primitives.assign();
16908       if (is_empty()) return *this;
16909       if (dim>1)
16910         throw CImgInstanceException("CImg<%s>::get_isovalue3d() : Instance image (%u,%u,%u,%u,%p) is not a scalar image.",
16911                                     pixel_type(),width,height,depth,dim,data);
16912       CImg<floatT> points;
16913       if (depth>1) {
16914         if (resx==1 && resy==1 && resz==1) {
16915           const _marching_cubes_func func(*this);
16916           points = marching_cubes(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,resx,resy,resz,invert_faces);
16917         } else {
16918           const _marching_cubes_func_float func(*this);
16919           points = marching_cubes(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,resx,resy,resz,invert_faces);
16920         }
16921       } else {
16922         if (resx==1 && resy==1) {
16923           const _marching_squares_func func(*this);
16924           points = marching_squares(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,resx,resy);
16925         } else {
16926           const _marching_squares_func_float func(*this);
16927           points = marching_squares(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,resx,resy);
16928         }
16929         if (points) points.resize(-100,3,1,1,0);
16930       }
16931       return points;
16932     }
16933 
16934     //! Translate a 3D object.
16935     CImg<T>& translate_object3d(const float tx, const float ty=0, const float tz=0) {
16936       get_shared_line(0)+=tx; get_shared_line(1)+=ty; get_shared_line(2)+=tz;
16937       return *this;
16938     }
16939 
16940     CImg<Tfloat> get_translate_object3d(const float tx, const float ty=0, const float tz=0) const {
16941       return CImg<Tfloat>(*this,false).translate_object3d(tx,ty,tz);
16942     }
16943 
16944     //! Translate a 3D object so that it becomes centered.
16945     CImg<T>& translate_object3d() {
16946       CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
16947       float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
16948       xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2;
16949       return *this;
16950     }
16951 
16952     CImg<Tfloat> get_translate_object3d() const {
16953       return CImg<Tfloat>(*this,false).translate_object3d();
16954     }
16955 
16956     //! Resize a 3D object.
16957     CImg<T>& resize_object3d(const float sx, const float sy=-100, const float sz=-100) {
16958       CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
16959       float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
16960       if (xm<xM) { if (sx>0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; }
16961       if (ym<yM) { if (sy>0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; }
16962       if (zm<zM) { if (sz>0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; }
16963       return *this;
16964     }
16965 
16966     CImg<Tfloat> get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const {
16967       return CImg<Tfloat>(*this,false).resize_object3d(sx,sy,sz);
16968     }
16969 
16970     // Resize a 3D object so that its max dimension if one.
16971     CImg<T> resize_object3d() const {
16972       CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
16973       float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
16974       const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz);
16975       if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; }
16976       return *this;
16977     }
16978 
16979     CImg<Tfloat> get_resize_object3d() const {
16980       return CImg<Tfloat>(*this,false).resize_object3d();
16981     }
16982 
16983     //! Append a 3D object to another one.
16984     template<typename tf, typename tp, typename tff>
16985     CImg<T>& append_object3d(CImgList<tf>& primitives, const CImg<tp>& obj_points, const CImgList<tff>& obj_primitives) {
16986       const unsigned int P = width;
16987       append(obj_points,'x');
16988       const unsigned int N = primitives.size;
16989       primitives.insert(obj_primitives);
16990       for (unsigned int i = N; i<primitives.size; ++i) {
16991         CImg<tf> &p = primitives[i];
16992         if (p.size()!=5) p+=P;
16993         else { p[0]+=P; if (p[2]==0) p[1]+=P; }
16994       }
16995       return *this;
16996     }
16997 
16998     //@}
16999     //----------------------------
17000     //
17001     //! \name Color bases
17002     //@{
17003     //----------------------------
17004 
17005     //! Return a default indexed color palette with 256 (R,G,B) entries.
17006     /**
17007        The default color palette is used by %CImg when displaying images on 256 colors displays.
17008        It consists in the quantification of the (R,G,B) color space using 3:3:2 bits for color coding
17009        (i.e 8 levels for the Red and Green and 4 levels for the Blue).
17010        \return a 1x256x1x3 color image defining the palette entries.
17011     **/
17012     static CImg<Tuchar> default_LUT8() {
17013       static CImg<Tuchar> palette;
17014       if (!palette) {
17015         palette.assign(1,256,1,3);
17016         for (unsigned int index = 0, r = 16; r<256; r+=32)
17017           for (unsigned int g = 16; g<256; g+=32)
17018             for (unsigned int b = 32; b<256; b+=64) {
17019               palette(0,index,0) = (Tuchar)r;
17020               palette(0,index,1) = (Tuchar)g;
17021               palette(0,index++,2) = (Tuchar)b;
17022             }
17023       }
17024       return palette;
17025     }
17026 
17027     //! Return a rainbow color palette with 256 (R,G,B) entries.
17028     static CImg<Tuchar> rainbow_LUT8() {
17029       static CImg<Tuchar> palette;
17030       if (!palette) {
17031         CImg<Tint> tmp(1,256,1,3,1);
17032         tmp.get_shared_channel(0).sequence(0,359);
17033         palette = tmp.HSVtoRGB();
17034       }
17035       return palette;
17036     }
17037 
17038     //! Return a contrasted color palette with 256 (R,G,B) entries.
17039     static CImg<Tuchar> contrast_LUT8() {
17040       static const unsigned char pal[] = {
17041         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,
17042         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,
17043         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,
17044         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,
17045         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,
17046         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,
17047         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,
17048         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,
17049         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,
17050         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,
17051         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,
17052         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,
17053         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,
17054         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,
17055         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,
17056         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,
17057         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,
17058         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,
17059         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,
17060         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,
17061         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,
17062         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,
17063         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,
17064         23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 };
17065       static const CImg<Tuchar> palette(pal,1,256,1,3,false);
17066       return palette;
17067     }
17068 
17069     //! Convert (R,G,B) color image to indexed color image.
17070     template<typename t>
17071     CImg<T>& RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) {
17072       return get_RGBtoLUT(palette,dithering,indexing).transfer_to(*this);
17073     }
17074 
17075     template<typename t>
17076     CImg<t> get_RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) const {
17077       if (is_empty()) return CImg<t>();
17078       if (dim!=3)
17079         throw CImgInstanceException("CImg<%s>::RGBtoLUT() : Input image dimension is dim=%u, "
17080                                     "should be a (R,G,B) image.",
17081                                     pixel_type(),dim);
17082       if (palette.data && palette.dim!=3)
17083         throw CImgArgumentException("CImg<%s>::RGBtoLUT() : Given palette dimension is dim=%u, "
17084                                     "should be a (R,G,B) palette",
17085                                     pixel_type(),palette.dim);
17086       CImg<t> res(width,height,depth,indexing?1:3);
17087       float *line1 = new float[3*width], *line2 = new float[3*width];
17088       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);
17089       cimg_forZ(*this,z) {
17090         const T *pRs = ptr(0,0,z,0), *pGs = ptr(0,0,z,1), *pBs = ptr(0,0,z,2);
17091         float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
17092         cimg_forY(*this,y) {
17093           cimg::swap(line1,line2);
17094           if (y<dimy()-1) {
17095             const int ny = y + 1;
17096             const T *pRs = ptr(0,ny,z,0), *pGs = ptr(0,ny,z,1), *pBs = ptr(0,ny,z,2);
17097             float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
17098           }
17099           float *ptr1 = line1, *ptr2 = line2;
17100           cimg_forX(*this,x) {
17101             float R = *(ptr1++), G = *(ptr1++), B = *(ptr1++);
17102             R = R<0?0:(R>255?255:R); G = G<0?0:(G>255?255:G); B = B<0?0:(B>255?255:B);
17103             t Rbest = 0, Gbest = 0, Bbest = 0;
17104             int best_index = 0;
17105             if (palette) { // find best match in given color palette
17106               const t *pRs = palette.ptr(0,0,0,0), *pGs = palette.ptr(0,0,0,1), *pBs = palette.ptr(0,0,0,2);
17107               const unsigned int Npal = palette.width*palette.height*palette.depth;
17108               float min = cimg::type<float>::max();
17109               for (unsigned int off = 0; off<Npal; ++off) {
17110                 const t Rp = *(pRs++), Gp = *(pGs++), Bp = *(pBs++);
17111                 const float error = cimg::sqr((float)Rp-(float)R) + cimg::sqr((float)Gp-(float)G) + cimg::sqr((float)Bp-(float)B);
17112                 if (error<min) { min = error; best_index = off; Rbest = Rp; Gbest = Gp; Bbest = Bp; }
17113               }
17114             } else {
17115               Rbest = (t)((unsigned char)R&0xe0); Gbest = (t)((unsigned char)G&0xe0); Bbest = (t)((unsigned char)B&0xc0);
17116               best_index = (unsigned char)Rbest | ((unsigned char)Gbest>>3) | ((unsigned char)Bbest>>6);
17117             }
17118             if (indexing) *(pRd++) = (t)best_index; else { *(pRd++) = Rbest; *(pGd++) = Gbest; *(pBd++) = Bbest; }
17119             if (dithering) { // apply dithering to neighborhood pixels if needed
17120               const float dR = (float)(R-Rbest), dG = (float)(G-Gbest), dB = (float)(B-Bbest);
17121               if (x<dimx()-1) { *(ptr1++)+= dR*7/16; *(ptr1++)+= dG*7/16; *(ptr1++)+= dB*7/16; ptr1-=3; }
17122               if (y<dimy()-1) {
17123                 *(ptr2++)+= dR*5/16; *(ptr2++)+= dG*5/16; *ptr2+= dB*5/16; ptr2-=2;
17124                 if (x>0) { *(--ptr2)+= dB*3/16; *(--ptr2)+= dG*3/16; *(--ptr2)+= dR*3/16; ptr2+=3; }
17125                 if (x<dimx()-1) { ptr2+=3; *(ptr2++)+= dR/16; *(ptr2++)+= dG/16; *ptr2+= dB/16; ptr2-=5; }
17126               }
17127             }
17128             ptr2+=3;
17129           }
17130         }
17131       }
17132       delete[] line1; delete[] line2;
17133       return res;
17134     }
17135 
17136     //! Convert color pixels from (R,G,B) to match the default palette.
17137     CImg<T>& RGBtoLUT(const bool dithering=true, const bool indexing=false) {
17138       return get_RGBtoLUT(dithering,indexing).transfer_to(*this);
17139     }
17140 
17141     CImg<Tuchar> get_RGBtoLUT(const bool dithering=true, const bool indexing=false) const {
17142       static const CImg<Tuchar> empty;
17143       return get_RGBtoLUT(empty,dithering,indexing);
17144     }
17145 
17146     //! Convert an indexed image to a (R,G,B) image using the specified color palette.
17147     CImg<T>& LUTtoRGB(const CImg<T>& palette) {
17148       return get_LUTtoRGB(palette).transfer_to(*this);
17149     }
17150 
17151     template<typename t>
17152     CImg<t> get_LUTtoRGB(const CImg<t>& palette) const {
17153       if (is_empty()) return CImg<t>();
17154       if (dim!=1)
17155         throw CImgInstanceException("CImg<%s>::LUTtoRGB() : Input image dimension is dim=%u, "
17156                                     "should be a LUT image",
17157                                     pixel_type(),dim);
17158       if (palette.data && palette.dim!=3)
17159         throw CImgArgumentException("CImg<%s>::LUTtoRGB() : Given palette dimension is dim=%u, "
17160                                     "should be a (R,G,B) palette",
17161                                     pixel_type(),palette.dim);
17162       const CImg<t> pal = palette.data?palette:CImg<t>(default_LUT8());
17163       CImg<t> res(width,height,depth,3);
17164       const t *pRs = pal.ptr(0,0,0,0), *pGs = pal.ptr(0,0,0,1), *pBs = pal.ptr(0,0,0,2);
17165       t *pRd = res.ptr(0,0,0,1), *pGd = pRd + width*height*depth, *pBd = pGd + width*height*depth;
17166       const unsigned int Npal = palette.width*palette.height*palette.depth;
17167       cimg_for(*this,ptr,T) {
17168         const unsigned int index = ((unsigned int)*ptr)%Npal;
17169         *(--pRd) = pRs[index]; *(--pGd) = pGs[index]; *(--pBd) = pBs[index];
17170       }
17171       return res;
17172     }
17173 
17174     //! Convert an indexed image (with the default palette) to a (R,G,B) image.
17175     CImg<T>& LUTtoRGB() {
17176       return get_LUTtoRGB().transfer_to(*this);
17177     }
17178 
17179     CImg<Tuchar> get_LUTtoRGB() const {
17180       static const CImg<Tuchar> empty;
17181       return get_LUTtoRGB(empty);
17182     }
17183 
17184     //! Convert color pixels from (R,G,B) to (H,S,V).
17185     CImg<T>& RGBtoHSV() {
17186       if (is_empty()) return *this;
17187       if (dim!=3)
17188         throw CImgInstanceException("CImg<%s>::RGBtoHSV() : Input image dimension is dim=%u, "
17189                                     "should be a (R,G,B) image.",
17190                                     pixel_type(),dim);
17191       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17192       for (unsigned long N = width*height*depth; N; --N) {
17193         const Tfloat
17194           R = (Tfloat)*p1,
17195           G = (Tfloat)*p2,
17196           B = (Tfloat)*p3,
17197           nR = (R<0?0:(R>255?255:R))/255,
17198           nG = (G<0?0:(G>255?255:G))/255,
17199           nB = (B<0?0:(B>255?255:B))/255,
17200           m = cimg::min(nR,nG,nB),
17201           M = cimg::max(nR,nG,nB);
17202         Tfloat H = 0, S = 0;
17203         if (M!=m) {
17204           const Tfloat
17205             f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
17206             i = (Tfloat)((nR==m)?3:((nG==m)?5:1));
17207           H = (i-f/(M-m));
17208           if (H>=6) H-=6;
17209           H*=60;
17210           S = (M-m)/M;
17211         }
17212         *(p1++) = (T)H;
17213         *(p2++) = (T)S;
17214         *(p3++) = (T)M;
17215       }
17216       return *this;
17217     }
17218 
17219     CImg<Tfloat> get_RGBtoHSV() const {
17220       return CImg<Tfloat>(*this,false).RGBtoHSV();
17221     }
17222 
17223     //! Convert color pixels from (H,S,V) to (R,G,B).
17224     CImg<T>& HSVtoRGB() {
17225     if (is_empty()) return *this;
17226     if (dim!=3)
17227       throw CImgInstanceException("CImg<%s>::HSVtoRGB() : Input image dimension is dim=%u, "
17228                                   "should be a (H,S,V) image",
17229                                   pixel_type(),dim);
17230     T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17231     for (unsigned long N = width*height*depth; N; --N) {
17232       Tfloat
17233         H = (Tfloat)*p1,
17234         S = (Tfloat)*p2,
17235         V = (Tfloat)*p3,
17236         R = 0, G = 0, B = 0;
17237       if (H==0 && S==0) R = G = B = V;
17238       else {
17239         H/=60;
17240         const int i = (int)cimg_std::floor(H);
17241         const Tfloat
17242           f = (i&1)?(H-i):(1-H+i),
17243           m = V*(1-S),
17244           n = V*(1-S*f);
17245         switch (i) {
17246         case 6 :
17247         case 0 : R = V; G = n; B = m; break;
17248         case 1 : R = n; G = V; B = m; break;
17249         case 2 : R = m; G = V; B = n; break;
17250         case 3 : R = m; G = n; B = V; break;
17251         case 4 : R = n; G = m; B = V; break;
17252         case 5 : R = V; G = m; B = n; break;
17253         }
17254       }
17255       R*=255; G*=255; B*=255;
17256       *(p1++) = (T)(R<0?0:(R>255?255:R));
17257       *(p2++) = (T)(G<0?0:(G>255?255:G));
17258       *(p3++) = (T)(B<0?0:(B>255?255:B));
17259     }
17260     return *this;
17261     }
17262 
17263     CImg<Tuchar> get_HSVtoRGB() const {
17264       return CImg<Tuchar>(*this,false).HSVtoRGB();
17265     }
17266 
17267     //! Convert color pixels from (R,G,B) to (H,S,L).
17268     CImg<T>& RGBtoHSL() {
17269       if (is_empty()) return *this;
17270       if (dim!=3)
17271         throw CImgInstanceException("CImg<%s>::RGBtoHSL() : Input image dimension is dim=%u, "
17272                                     "should be a (R,G,B) image.",
17273                                     pixel_type(),dim);
17274       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17275       for (unsigned long N = width*height*depth; N; --N) {
17276         const Tfloat
17277           R = (Tfloat)*p1,
17278           G = (Tfloat)*p2,
17279           B = (Tfloat)*p3,
17280           nR = (R<0?0:(R>255?255:R))/255,
17281           nG = (G<0?0:(G>255?255:G))/255,
17282           nB = (B<0?0:(B>255?255:B))/255,
17283           m = cimg::min(nR,nG,nB),
17284           M = cimg::max(nR,nG,nB),
17285           L = (m+M)/2;
17286         Tfloat H = 0, S = 0;
17287         if (M==m) H = S = 0;
17288         else {
17289           const Tfloat
17290             f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
17291             i = (nR==m)?3.0f:((nG==m)?5.0f:1.0f);
17292           H = (i-f/(M-m));
17293           if (H>=6) H-=6;
17294           H*=60;
17295           S = (2*L<=1)?((M-m)/(M+m)):((M-m)/(2-M-m));
17296         }
17297         *(p1++) = (T)H;
17298         *(p2++) = (T)S;
17299         *(p3++) = (T)L;
17300       }
17301       return *this;
17302     }
17303 
17304     CImg<Tfloat> get_RGBtoHSL() const {
17305       return CImg< Tfloat>(*this,false).RGBtoHSL();
17306     }
17307 
17308     //! Convert color pixels from (H,S,L) to (R,G,B).
17309     CImg<T>& HSLtoRGB() {
17310       if (is_empty()) return *this;
17311       if (dim!=3)
17312         throw CImgInstanceException("CImg<%s>::HSLtoRGB() : Input image dimension is dim=%u, "
17313                                     "should be a (H,S,V) image",
17314                                     pixel_type(),dim);
17315       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17316       for (unsigned long N = width*height*depth; N; --N) {
17317         const Tfloat
17318           H = (Tfloat)*p1,
17319           S = (Tfloat)*p2,
17320           L = (Tfloat)*p3,
17321           q = 2*L<1?L*(1+S):(L+S-L*S),
17322           p = 2*L-q,
17323           h = H/360,
17324           tr = h + 1.0f/3,
17325           tg = h,
17326           tb = h - 1.0f/3,
17327           ntr = tr<0?tr+1:(tr>1?tr-1:tr),
17328           ntg = tg<0?tg+1:(tg>1?tg-1:tg),
17329           ntb = tb<0?tb+1:(tb>1?tb-1:tb),
17330           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))),
17331           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))),
17332           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)));
17333         *(p1++) = (T)(R<0?0:(R>255?255:R));
17334         *(p2++) = (T)(G<0?0:(G>255?255:G));
17335         *(p3++) = (T)(B<0?0:(B>255?255:B));
17336       }
17337       return *this;
17338     }
17339 
17340     CImg<Tuchar> get_HSLtoRGB() const {
17341       return CImg<Tuchar>(*this,false).HSLtoRGB();
17342     }
17343 
17344     //! Convert color pixels from (R,G,B) to (H,S,I).
17345     //! Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002.
17346     CImg<T>& RGBtoHSI() {
17347       if (is_empty()) return *this;
17348       if (dim!=3)
17349         throw CImgInstanceException("CImg<%s>::RGBtoHSI() : Input image dimension is dim=%u, "
17350                                     "should be a (R,G,B) image.",
17351                                     pixel_type(),dim);
17352       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17353       for (unsigned long N = width*height*depth; N; --N) {
17354         const Tfloat
17355           R = (Tfloat)*p1,
17356           G = (Tfloat)*p2,
17357           B = (Tfloat)*p3,
17358           nR = (R<0?0:(R>255?255:R))/255,
17359           nG = (G<0?0:(G>255?255:G))/255,
17360           nB = (B<0?0:(B>255?255:B))/255,
17361           m = cimg::min(nR,nG,nB),
17362           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),
17363           sum = nR + nG + nB;
17364         Tfloat H = 0, S = 0, I = 0;
17365         if (theta>0) H = (nB<=nG)?theta:360-theta;
17366         if (sum>0) S = 1 - 3/sum*m;
17367         I = sum/3;
17368         *(p1++) = (T)H;
17369         *(p2++) = (T)S;
17370         *(p3++) = (T)I;
17371       }
17372       return *this;
17373     }
17374 
17375     CImg<Tfloat> get_RGBtoHSI() const {
17376       return CImg<Tfloat>(*this,false).RGBtoHSI();
17377     }
17378 
17379     //! Convert color pixels from (H,S,I) to (R,G,B).
17380     CImg<T>& HSItoRGB() {
17381       if (is_empty()) return *this;
17382       if (dim!=3)
17383         throw CImgInstanceException("CImg<%s>::HSItoRGB() : Input image dimension is dim=%u, "
17384                                     "should be a (H,S,I) image",
17385                                     pixel_type(),dim);
17386       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17387       for (unsigned long N = width*height*depth; N; --N) {
17388         Tfloat
17389           H = (Tfloat)*p1,
17390           S = (Tfloat)*p2,
17391           I = (Tfloat)*p3,
17392           a = I*(1-S),
17393           R = 0, G = 0, B = 0;
17394         if (H<120) {
17395           B = a;
17396           R = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
17397           G = 3*I-(R+B);
17398         } else if (H<240) {
17399           H-=120;
17400           R = a;
17401           G = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
17402           B = 3*I-(R+G);
17403         } else {
17404           H-=240;
17405           G = a;
17406           B = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
17407           R = 3*I-(G+B);
17408         }
17409         R*=255; G*=255; B*=255;
17410         *(p1++) = (T)(R<0?0:(R>255?255:R));
17411         *(p2++) = (T)(G<0?0:(G>255?255:G));
17412         *(p3++) = (T)(B<0?0:(B>255?255:B));
17413       }
17414       return *this;
17415     }
17416 
17417     CImg<Tfloat> get_HSItoRGB() const {
17418       return CImg< Tuchar>(*this,false).HSItoRGB();
17419     }
17420 
17421     //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
17422     CImg<T>& RGBtoYCbCr() {
17423       if (is_empty()) return *this;
17424       if (dim!=3)
17425         throw CImgInstanceException("CImg<%s>::RGBtoYCbCr() : Input image dimension is dim=%u, "
17426                                     "should be a (R,G,B) image (dim=3)",
17427                                     pixel_type(),dim);
17428       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17429       for (unsigned long N = width*height*depth; N; --N) {
17430         const Tfloat
17431           R = (Tfloat)*p1,
17432           G = (Tfloat)*p2,
17433           B = (Tfloat)*p3,
17434           Y = (66*R + 129*G + 25*B + 128)/256 + 16,
17435           Cb = (-38*R - 74*G + 112*B + 128)/256 + 128,
17436           Cr = (112*R - 94*G - 18*B + 128)/256 + 128;
17437         *(p1++) = (T)(Y<0?0:(Y>255?255:Y));
17438         *(p2++) = (T)(Cb<0?0:(Cb>255?255:Cb));
17439         *(p3++) = (T)(Cr<0?0:(Cr>255?255:Cr));
17440       }
17441       return *this;
17442     }
17443 
17444     CImg<Tuchar> get_RGBtoYCbCr() const {
17445       return CImg<Tuchar>(*this,false).RGBtoYCbCr();
17446     }
17447 
17448     //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
17449     CImg<T>& YCbCrtoRGB() {
17450       if (is_empty()) return *this;
17451       if (dim!=3)
17452         throw CImgInstanceException("CImg<%s>::YCbCrtoRGB() : Input image dimension is dim=%u, "
17453                                     "should be a (Y,Cb,Cr)_8 image (dim=3)",
17454                                     pixel_type(),dim);
17455       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17456       for (unsigned long N = width*height*depth; N; --N) {
17457         const Tfloat
17458           Y = (Tfloat)*p1 - 16,
17459           Cb = (Tfloat)*p2 - 128,
17460           Cr = (Tfloat)*p3 - 128,
17461           R = (298*Y + 409*Cr + 128)/256,
17462           G = (298*Y - 100*Cb - 208*Cr + 128)/256,
17463           B = (298*Y + 516*Cb + 128)/256;
17464         *(p1++) = (T)(R<0?0:(R>255?255:R));
17465         *(p2++) = (T)(G<0?0:(G>255?255:G));
17466         *(p3++) = (T)(B<0?0:(B>255?255:B));
17467       }
17468       return *this;
17469     }
17470 
17471     CImg<Tuchar> get_YCbCrtoRGB() const {
17472       return CImg<Tuchar>(*this,false).YCbCrtoRGB();
17473     }
17474 
17475     //! Convert color pixels from (R,G,B) to (Y,U,V).
17476     CImg<T>& RGBtoYUV() {
17477       if (is_empty()) return *this;
17478       if (dim!=3)
17479         throw CImgInstanceException("CImg<%s>::RGBtoYUV() : Input image dimension is dim=%u, "
17480                                     "should be a (R,G,B) image (dim=3)",
17481                                     pixel_type(),dim);
17482       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17483       for (unsigned long N = width*height*depth; N; --N) {
17484         const Tfloat
17485           R = (Tfloat)*p1/255,
17486           G = (Tfloat)*p2/255,
17487           B = (Tfloat)*p3/255,
17488           Y = 0.299f*R + 0.587f*G + 0.114f*B;
17489         *(p1++) = (T)Y;
17490         *(p2++) = (T)(0.492f*(B-Y));
17491         *(p3++) = (T)(0.877*(R-Y));
17492       }
17493       return *this;
17494     }
17495 
17496     CImg<Tfloat> get_RGBtoYUV() const {
17497       return CImg<Tfloat>(*this,false).RGBtoYUV();
17498     }
17499 
17500     //! Convert color pixels from (Y,U,V) to (R,G,B).
17501     CImg<T>& YUVtoRGB() {
17502       if (is_empty()) return *this;
17503       if (dim!=3)
17504         throw CImgInstanceException("CImg<%s>::YUVtoRGB() : Input image dimension is dim=%u, "
17505                                     "should be a (Y,U,V) image (dim=3)",
17506                                     pixel_type(),dim);
17507       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17508       for (unsigned long N = width*height*depth; N; --N) {
17509         const Tfloat
17510           Y = (Tfloat)*p1,
17511           U = (Tfloat)*p2,
17512           V = (Tfloat)*p3,
17513           R = (Y + 1.140f*V)*255,
17514           G = (Y - 0.395f*U - 0.581f*V)*255,
17515           B = (Y + 2.032f*U)*255;
17516         *(p1++) = (T)(R<0?0:(R>255?255:R));
17517         *(p2++) = (T)(G<0?0:(G>255?255:G));
17518         *(p3++) = (T)(B<0?0:(B>255?255:B));
17519       }
17520       return *this;
17521     }
17522 
17523     CImg<Tuchar> get_YUVtoRGB() const {
17524       return CImg< Tuchar>(*this,false).YUVtoRGB();
17525     }
17526 
17527     //! Convert color pixels from (R,G,B) to (C,M,Y).
17528     CImg<T>& RGBtoCMY() {
17529       if (is_empty()) return *this;
17530       if (dim!=3)
17531         throw CImgInstanceException("CImg<%s>::RGBtoCMY() : Input image dimension is dim=%u, "
17532                                     "should be a (R,G,B) image (dim=3)",
17533                                     pixel_type(),dim);
17534       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17535       for (unsigned long N = width*height*depth; N; --N) {
17536         const Tfloat
17537           R = (Tfloat)*p1/255,
17538           G = (Tfloat)*p2/255,
17539           B = (Tfloat)*p3/255;
17540         *(p1++) = (T)(1 - R);
17541         *(p2++) = (T)(1 - G);
17542         *(p3++) = (T)(1 - B);
17543       }
17544       return *this;
17545     }
17546 
17547     CImg<Tfloat> get_RGBtoCMY() const {
17548       return CImg<Tfloat>(*this,false).RGBtoCMY();
17549     }
17550 
17551     //! Convert (C,M,Y) pixels of a color image into the (R,G,B) color space.
17552     CImg<T>& CMYtoRGB() {
17553       if (is_empty()) return *this;
17554       if (dim!=3)
17555         throw CImgInstanceException("CImg<%s>::CMYtoRGB() : Input image dimension is dim=%u, "
17556                                     "should be a (C,M,Y) image (dim=3)",
17557                                     pixel_type(),dim);
17558       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17559       for (unsigned long N = width*height*depth; N; --N) {
17560         const Tfloat
17561           C = (Tfloat)*p1,
17562           M = (Tfloat)*p2,
17563           Y = (Tfloat)*p3,
17564           R = 255*(1 - C),
17565           G = 255*(1 - M),
17566           B = 255*(1 - Y);
17567         *(p1++) = (T)(R<0?0:(R>255?255:R));
17568         *(p2++) = (T)(G<0?0:(G>255?255:G));
17569         *(p3++) = (T)(B<0?0:(B>255?255:B));
17570       }
17571       return *this;
17572     }
17573 
17574     CImg<Tuchar> get_CMYtoRGB() const {
17575       return CImg<Tuchar>(*this,false).CMYtoRGB();
17576     }
17577 
17578     //! Convert color pixels from (C,M,Y) to (C,M,Y,K).
17579     CImg<T>& CMYtoCMYK() {
17580       return get_CMYtoCMYK().transfer_to(*this);
17581     }
17582 
17583     CImg<Tfloat> get_CMYtoCMYK() const {
17584       if (is_empty()) return *this;
17585       if (dim!=3)
17586         throw CImgInstanceException("CImg<%s>::CMYtoCMYK() : Input image dimension is dim=%u, "
17587                                     "should be a (C,M,Y) image (dim=3)",
17588                                     pixel_type(),dim);
17589       CImg<Tfloat> res(width,height,depth,4);
17590       const T *ps1 = ptr(0,0,0,0), *ps2 = ptr(0,0,0,1), *ps3 = ptr(0,0,0,2);
17591       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);
17592       for (unsigned long N = width*height*depth; N; --N) {
17593         Tfloat
17594           C = (Tfloat)*(ps1++),
17595           M = (Tfloat)*(ps2++),
17596           Y = (Tfloat)*(ps3++),
17597           K = cimg::min(C,M,Y);
17598         if (K==1) C = M = Y = 0;
17599         else { const Tfloat K1 = 1 - K; C = (C - K)/K1; M = (M - K)/K1; Y = (Y - K)/K1; }
17600         *(pd1++) = C;
17601         *(pd2++) = M;
17602         *(pd3++) = Y;
17603         *(pd4++) = K;
17604       }
17605       return res;
17606     }
17607 
17608     //! Convert (C,M,Y,K) pixels of a color image into the (C,M,Y) color space.
17609     CImg<T>& CMYKtoCMY() {
17610       return get_CMYKtoCMY().transfer_to(*this);
17611     }
17612 
17613     CImg<Tfloat> get_CMYKtoCMY() const {
17614       if (is_empty()) return *this;
17615       if (dim!=4)
17616         throw CImgInstanceException("CImg<%s>::CMYKtoCMY() : Input image dimension is dim=%u, "
17617                                     "should be a (C,M,Y,K) image (dim=4)",
17618                                     pixel_type(),dim);
17619       CImg<Tfloat> res(width,height,depth,3);
17620       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);
17621       Tfloat *pd1 = res.ptr(0,0,0,0), *pd2 = res.ptr(0,0,0,1), *pd3 = res.ptr(0,0,0,2);
17622       for (unsigned long N = width*height*depth; N; --N) {
17623         const Tfloat
17624           C = (Tfloat)*ps1,
17625           M = (Tfloat)*ps2,
17626           Y = (Tfloat)*ps3,
17627           K = (Tfloat)*ps4,
17628           K1 = 1 - K;
17629         *(pd1++) = C*K1 + K;
17630         *(pd2++) = M*K1 + K;
17631         *(pd3++) = Y*K1 + K;
17632       }
17633       return res;
17634     }
17635 
17636     //! Convert color pixels from (R,G,B) to (X,Y,Z)_709.
17637     CImg<T>& RGBtoXYZ() {
17638       if (is_empty()) return *this;
17639       if (dim!=3)
17640         throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, "
17641                                     "should be a (R,G,B) image (dim=3)",
17642                                     pixel_type(),dim);
17643       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17644       for (unsigned long N = width*height*depth; N; --N) {
17645         const Tfloat
17646           R = (Tfloat)*p1/255,
17647           G = (Tfloat)*p2/255,
17648           B = (Tfloat)*p3/255;
17649         *(p1++) = (T)(0.412453f*R + 0.357580f*G + 0.180423f*B);
17650         *(p2++) = (T)(0.212671f*R + 0.715160f*G + 0.072169f*B);
17651         *(p3++) = (T)(0.019334f*R + 0.119193f*G + 0.950227f*B);
17652       }
17653       return *this;
17654     }
17655 
17656     CImg<Tfloat> get_RGBtoXYZ() const {
17657       return CImg<Tfloat>(*this,false).RGBtoXYZ();
17658     }
17659 
17660     //! Convert (X,Y,Z)_709 pixels of a color image into the (R,G,B) color space.
17661     CImg<T>& XYZtoRGB() {
17662       if (is_empty()) return *this;
17663       if (dim!=3)
17664         throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, "
17665                                     "should be a (X,Y,Z) image (dim=3)",
17666                                     pixel_type(),dim);
17667       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17668       for (unsigned long N = width*height*depth; N; --N) {
17669         const Tfloat
17670           X = (Tfloat)*p1*255,
17671           Y = (Tfloat)*p2*255,
17672           Z = (Tfloat)*p3*255,
17673           R = 3.240479f*X  - 1.537150f*Y - 0.498535f*Z,
17674           G = -0.969256f*X + 1.875992f*Y + 0.041556f*Z,
17675           B = 0.055648f*X  - 0.204043f*Y + 1.057311f*Z;
17676         *(p1++) = (T)(R<0?0:(R>255?255:R));
17677         *(p2++) = (T)(G<0?0:(G>255?255:G));
17678         *(p3++) = (T)(B<0?0:(B>255?255:B));
17679       }
17680       return *this;
17681     }
17682 
17683     CImg<Tuchar> get_XYZtoRGB() const {
17684       return CImg<Tuchar>(*this,false).XYZtoRGB();
17685     }
17686 
17687     //! Convert (X,Y,Z)_709 pixels of a color image into the (L*,a*,b*) color space.
17688     CImg<T>& XYZtoLab() {
17689 #define _cimg_Labf(x) ((x)>=0.008856f?(cimg_std::pow(x,(Tfloat)1/3)):(7.787f*(x)+16.0f/116))
17690       if (is_empty()) return *this;
17691       if (dim!=3)
17692         throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, "
17693                                     "should be a (X,Y,Z) image (dim=3)",
17694                                     pixel_type(),dim);
17695       const Tfloat
17696         Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
17697         Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
17698         Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
17699       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17700       for (unsigned long N = width*height*depth; N; --N) {
17701         const Tfloat
17702           X = (Tfloat)*p1,
17703           Y = (Tfloat)*p2,
17704           Z = (Tfloat)*p3,
17705           XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn,
17706           fX = (Tfloat)_cimg_Labf(XXn),
17707           fY = (Tfloat)_cimg_Labf(YYn),
17708           fZ = (Tfloat)_cimg_Labf(ZZn);
17709         *(p1++) = (T)(116*fY - 16);
17710         *(p2++) = (T)(500*(fX - fY));
17711         *(p3++) = (T)(200*(fY - fZ));
17712       }
17713       return *this;
17714     }
17715 
17716     CImg<Tfloat> get_XYZtoLab() const {
17717       return CImg<Tfloat>(*this,false).XYZtoLab();
17718     }
17719 
17720     //! Convert (L,a,b) pixels of a color image into the (X,Y,Z) color space.
17721     CImg<T>& LabtoXYZ() {
17722 #define _cimg_Labfi(x) ((x)>=0.206893f?((x)*(x)*(x)):(((x)-16.0f/116)/7.787f))
17723       if (is_empty()) return *this;
17724       if (dim!=3)
17725         throw CImgInstanceException("CImg<%s>::LabtoXYZ() : Input image dimension is dim=%u, "
17726                                     "should be a (X,Y,Z) image (dim=3)",
17727                                     pixel_type(),dim);
17728       const Tfloat
17729         Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
17730         Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
17731         Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
17732       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17733       for (unsigned long N = width*height*depth; N; --N) {
17734         const Tfloat
17735           L = (Tfloat)*p1,
17736           a = (Tfloat)*p2,
17737           b = (Tfloat)*p3,
17738           cY = (L + 16)/116,
17739           Y = (Tfloat)(Yn*_cimg_Labfi(cY)),
17740           pY = (Tfloat)cimg_std::pow(Y/Yn,(Tfloat)1/3),
17741           cX = a/500 + pY,
17742           X = Xn*cX*cX*cX,
17743           cZ = pY - b/200,
17744           Z = Zn*cZ*cZ*cZ;
17745         *(p1++) = (T)(X);
17746         *(p2++) = (T)(Y);
17747         *(p3++) = (T)(Z);
17748       }
17749       return *this;
17750     }
17751 
17752     CImg<Tfloat> get_LabtoXYZ() const {
17753       return CImg<Tfloat>(*this,false).LabtoXYZ();
17754     }
17755 
17756     //! Convert (X,Y,Z)_709 pixels of a color image into the (x,y,Y) color space.
17757     CImg<T>& XYZtoxyY() {
17758       if (is_empty()) return *this;
17759       if (dim!=3)
17760         throw CImgInstanceException("CImg<%s>::XYZtoxyY() : Input image dimension is dim=%u, "
17761                                     "should be a (X,Y,Z) image (dim=3)",
17762                                     pixel_type(),dim);
17763       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17764       for (unsigned long N = width*height*depth; N; --N) {
17765         const Tfloat
17766           X = (Tfloat)*p1,
17767           Y = (Tfloat)*p2,
17768           Z = (Tfloat)*p3,
17769           sum = (X+Y+Z),
17770           nsum = sum>0?sum:1;
17771         *(p1++) = (T)(X/nsum);
17772         *(p2++) = (T)(Y/nsum);
17773         *(p3++) = (T)Y;
17774       }
17775       return *this;
17776     }
17777 
17778     CImg<Tfloat> get_XYZtoxyY() const {
17779       return CImg<Tfloat>(*this,false).XYZtoxyY();
17780     }
17781 
17782     //! Convert (x,y,Y) pixels of a color image into the (X,Y,Z)_709 color space.
17783     CImg<T>& xyYtoXYZ() {
17784       if (is_empty()) return *this;
17785       if (dim!=3)
17786         throw CImgInstanceException("CImg<%s>::xyYtoXYZ() : Input image dimension is dim=%u, "
17787                                     "should be a (x,y,Y) image (dim=3)",
17788                                     pixel_type(),dim);
17789       T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17790       for (unsigned long N = width*height*depth; N; --N) {
17791         const Tfloat
17792          px = (Tfloat)*p1,
17793          py = (Tfloat)*p2,
17794          Y = (Tfloat)*p3,
17795          ny = py>0?py:1;
17796         *(p1++) = (T)(px*Y/ny);
17797         *(p2++) = (T)Y;
17798         *(p3++) = (T)((1-px-py)*Y/ny);
17799       }
17800       return *this;
17801     }
17802 
17803     CImg<Tfloat> get_xyYtoXYZ() const {
17804       return CImg<Tfloat>(*this,false).xyYtoXYZ();
17805     }
17806 
17807     //! Convert a (R,G,B) image to a (L,a,b) one.
17808     CImg<T>& RGBtoLab() {
17809       return RGBtoXYZ().XYZtoLab();
17810     }
17811 
17812     CImg<Tfloat> get_RGBtoLab() const {
17813       return CImg<Tfloat>(*this,false).RGBtoLab();
17814     }
17815 
17816     //! Convert a (L,a,b) image to a (R,G,B) one.
17817     CImg<T>& LabtoRGB() {
17818       return LabtoXYZ().XYZtoRGB();
17819     }
17820 
17821     CImg<Tuchar> get_LabtoRGB() const {
17822       return CImg<Tuchar>(*this,false).LabtoRGB();
17823     }
17824 
17825     //! Convert a (R,G,B) image to a (x,y,Y) one.
17826     CImg<T>& RGBtoxyY() {
17827       return RGBtoXYZ().XYZtoxyY();
17828     }
17829 
17830     CImg<Tfloat> get_RGBtoxyY() const {
17831       return CImg<Tfloat>(*this,false).RGBtoxyY();
17832     }
17833 
17834     //! Convert a (x,y,Y) image to a (R,G,B) one.
17835     CImg<T>& xyYtoRGB() {
17836       return xyYtoXYZ().XYZtoRGB();
17837     }
17838 
17839     CImg<Tuchar> get_xyYtoRGB() const {
17840       return CImg<Tuchar>(*this,false).xyYtoRGB();
17841     }
17842 
17843     //! Convert a (R,G,B) image to a (C,M,Y,K) one.
17844     CImg<T>& RGBtoCMYK() {
17845       return RGBtoCMY().CMYtoCMYK();
17846     }
17847 
17848     CImg<Tfloat> get_RGBtoCMYK() const {
17849       return CImg<Tfloat>(*this,false).RGBtoCMYK();
17850     }
17851 
17852     //! Convert a (C,M,Y,K) image to a (R,G,B) one.
17853     CImg<T>& CMYKtoRGB() {
17854       return CMYKtoCMY().CMYtoRGB();
17855     }
17856 
17857     CImg<Tuchar> get_CMYKtoRGB() const {
17858       return CImg<Tuchar>(*this,false).CMYKtoRGB();
17859     }
17860 
17861     //! Convert a (R,G,B) image to a Bayer-coded representation.
17862     /**
17863        \note First (upper-left) pixel if the red component of the pixel color.
17864     **/
17865     CImg<T>& RGBtoBayer() {
17866       return get_RGBtoBayer().transfer_to(*this);
17867     }
17868 
17869     CImg<T> get_RGBtoBayer() const {
17870       if (is_empty()) return *this;
17871       if (dim!=3)
17872         throw CImgInstanceException("CImg<%s>::RGBtoBayer() : Input image dimension is dim=%u, "
17873                                     "should be a (R,G,B) image (dim=3)",
17874                                     pixel_type(),dim);
17875       CImg<T> res(width,height,depth,1);
17876       const T *pR = ptr(0,0,0,0), *pG = ptr(0,0,0,1), *pB = ptr(0,0,0,2);
17877       T *ptrd = res.data;
17878       cimg_forXYZ(*this,x,y,z) {
17879         if (y%2) {
17880           if (x%2) *(ptrd++) = *pB;
17881           else *(ptrd++) = *pG;
17882         } else {
17883           if (x%2) *(ptrd++) = *pG;
17884           else *(ptrd++) = *pR;
17885         }
17886         ++pR; ++pG; ++pB;
17887       }
17888       return res;
17889     }
17890 
17891     //! Convert a Bayer-coded image to a (R,G,B) color image.
17892     CImg<T>& BayertoRGB(const unsigned int interpolation_type=3) {
17893       return get_BayertoRGB(interpolation_type).transfer_to(*this);
17894     }
17895 
17896     CImg<Tuchar> get_BayertoRGB(const unsigned int interpolation_type=3) const {
17897       if (is_empty()) return *this;
17898       if (dim!=1)
17899         throw CImgInstanceException("CImg<%s>::BayertoRGB() : Input image dimension is dim=%u, "
17900                                     "should be a Bayer image (dim=1)",
17901                                     pixel_type(),dim);
17902       CImg<Tuchar> res(width,height,depth,3);
17903       CImg_3x3(I,T);
17904       Tuchar *pR = res.ptr(0,0,0,0), *pG = res.ptr(0,0,0,1), *pB = res.ptr(0,0,0,2);
17905       switch (interpolation_type) {
17906       case 3 : { // Edge-directed
17907         CImg_3x3(R,T);
17908         CImg_3x3(G,T);
17909         CImg_3x3(B,T);
17910         cimg_forXYZ(*this,x,y,z) {
17911           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;
17912           cimg_get3x3(*this,x,y,z,0,I);
17913           if (y%2) {
17914             if (x%2) {
17915               const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
17916               *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
17917             } else *pG = (Tuchar)Icc;
17918           } else {
17919             if (x%2) *pG = (Tuchar)Icc;
17920             else {
17921               const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
17922               *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
17923             }
17924           }
17925           ++pG;
17926         }
17927         cimg_forXYZ(*this,x,y,z) {
17928           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;
17929           cimg_get3x3(*this,x,y,z,0,I);
17930           cimg_get3x3(res,x,y,z,1,G);
17931           if (y%2) {
17932             if (x%2) *pB = (Tuchar)Icc;
17933             else { *pR = (Tuchar)((Icn+Icp)/2); *pB = (Tuchar)((Inc+Ipc)/2); }
17934           } else {
17935             if (x%2) { *pR = (Tuchar)((Inc+Ipc)/2); *pB = (Tuchar)((Icn+Icp)/2); }
17936             else *pR = (Tuchar)Icc;
17937           }
17938           ++pR; ++pB;
17939         }
17940         pR = res.ptr(0,0,0,0);
17941         pG = res.ptr(0,0,0,1);
17942         pB = res.ptr(0,0,0,2);
17943         cimg_forXYZ(*this,x,y,z) {
17944           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;
17945           cimg_get3x3(res,x,y,z,0,R);
17946           cimg_get3x3(res,x,y,z,1,G);
17947           cimg_get3x3(res,x,y,z,2,B);
17948           if (y%2) {
17949             if (x%2) {
17950               const float alpha = (float)cimg::sqr(Rnc-Rpc), beta = (float)cimg::sqr(Rcn-Rcp), cx = 1/(1+alpha), cy = 1/(1+beta);
17951               *pR = (Tuchar)((cx*(Rnc+Rpc) + cy*(Rcn+Rcp))/(2*(cx+cy)));
17952             }
17953           } else {
17954             if (!(x%2)) {
17955               const float alpha = (float)cimg::sqr(Bnc-Bpc), beta = (float)cimg::sqr(Bcn-Bcp), cx = 1/(1+alpha), cy = 1/(1+beta);
17956               *pB = (Tuchar)((cx*(Bnc+Bpc) + cy*(Bcn+Bcp))/(2*(cx+cy)));
17957             }
17958           }
17959           ++pR; ++pG; ++pB;
17960         }
17961       } break;
17962       case 2 : { // Linear interpolation
17963         cimg_forXYZ(*this,x,y,z) {
17964           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;
17965           cimg_get3x3(*this,x,y,z,0,I);
17966           if (y%2) {
17967             if (x%2) { *pR = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)Icc; }
17968             else { *pR = (Tuchar)((Icp+Icn)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Inc+Ipc)/2); }
17969           } else {
17970             if (x%2) { *pR = (Tuchar)((Ipc+Inc)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Icn+Icp)/2); }
17971             else { *pR = (Tuchar)Icc; *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); }
17972           }
17973           ++pR; ++pG; ++pB;
17974         }
17975       } break;
17976       case 1 : { // Nearest neighbor interpolation
17977         cimg_forXYZ(*this,x,y,z) {
17978           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;
17979           cimg_get3x3(*this,x,y,z,0,I);
17980           if (y%2) {
17981             if (x%2) { *pR = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)Icc; }
17982             else { *pR = (Tuchar)cimg::min(Icn,Icp); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Inc,Ipc); }
17983           } else {
17984             if (x%2) { *pR = (Tuchar)cimg::min(Inc,Ipc); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Icn,Icp); }
17985             else { *pR = (Tuchar)Icc; *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); }
17986           }
17987           ++pR; ++pG; ++pB;
17988         }
17989       } break;
17990       default : { // 0-filling interpolation
17991         const T *ptrs = data;
17992         res.fill(0);
17993         cimg_forXYZ(*this,x,y,z) {
17994           const T val = *(ptrs++);
17995           if (y%2) { if (x%2) *pB = val; else *pG = val; } else { if (x%2) *pG = val; else *pR = val; }
17996           ++pR; ++pG; ++pB;
17997         }
17998       }
17999       }
18000       return res;
18001     }
18002 
18003     //@}
18004     //-------------------
18005     //
18006     //! \name Drawing
18007     //@{
18008     //-------------------
18009 
18010     // The following _draw_scanline() routines are *non user-friendly functions*, used only for internal purpose.
18011     // Pre-requisites : x0<x1, y-coordinate is valid, col is valid.
18012     template<typename tc>
18013     CImg<T>& _draw_scanline(const int x0, const int x1, const int y,
18014                             const tc *const color, const float opacity=1,
18015                             const float brightness=1, const bool init=false) {
18016       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
18017       static float nopacity = 0, copacity = 0;
18018       static unsigned int whz = 0;
18019       static const tc *col = 0;
18020       if (init) {
18021         nopacity = cimg::abs(opacity);
18022         copacity = 1 - cimg::max(opacity,0);
18023         whz = width*height*depth;
18024       } else {
18025         const int nx0 = x0>0?x0:0, nx1 = x1<dimx()?x1:dimx()-1, dx = nx1 - nx0;
18026         if (dx>=0) {
18027           col = color;
18028           const unsigned int off = whz-dx-1;
18029           T *ptrd = ptr(nx0,y);
18030           if (opacity>=1) { // ** Opaque drawing **
18031             if (brightness==1) { // Brightness==1
18032               if (sizeof(T)!=1) cimg_forV(*this,k) {
18033                 const T val = (T)*(col++);
18034                 for (int x = dx; x>=0; --x) *(ptrd++) = val;
18035                 ptrd+=off;
18036               } else cimg_forV(*this,k) {
18037                 const T val = (T)*(col++);
18038                 cimg_std::memset(ptrd,(int)val,dx+1);
18039                 ptrd+=whz;
18040               }
18041             } else if (brightness<1) { // Brightness<1
18042               if (sizeof(T)!=1) cimg_forV(*this,k) {
18043                 const T val = (T)(*(col++)*brightness);
18044                 for (int x = dx; x>=0; --x) *(ptrd++) = val;
18045                 ptrd+=off;
18046               } else cimg_forV(*this,k) {
18047                 const T val = (T)(*(col++)*brightness);
18048                 cimg_std::memset(ptrd,(int)val,dx+1);
18049                 ptrd+=whz;
18050               }
18051             } else { // Brightness>1
18052               if (sizeof(T)!=1) cimg_forV(*this,k) {
18053                 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
18054                 for (int x = dx; x>=0; --x) *(ptrd++) = val;
18055                 ptrd+=off;
18056               } else cimg_forV(*this,k) {
18057                 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
18058                 cimg_std::memset(ptrd,(int)val,dx+1);
18059                 ptrd+=whz;
18060               }
18061             }
18062           } else { // ** Transparent drawing **
18063             if (brightness==1) { // Brightness==1
18064               cimg_forV(*this,k) {
18065                 const T val = (T)*(col++);
18066                 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
18067                 ptrd+=off;
18068               }
18069             } else if (brightness<=1) { // Brightness<1
18070               cimg_forV(*this,k) {
18071                 const T val = (T)(*(col++)*brightness);
18072                 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
18073                 ptrd+=off;
18074               }
18075             } else { // Brightness>1
18076               cimg_forV(*this,k) {
18077                 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
18078                 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
18079                 ptrd+=off;
18080               }
18081             }
18082           }
18083         }
18084       }
18085       return *this;
18086     }
18087 
18088     template<typename tc>
18089     CImg<T>& _draw_scanline(const tc *const color, const float opacity=1) {
18090       return _draw_scanline(0,0,0,color,opacity,0,true);
18091     }
18092 
18093     //! Draw a 2D colored point (pixel).
18094     /**
18095        \param x0 X-coordinate of the point.
18096        \param y0 Y-coordinate of the point.
18097        \param color Pointer to \c dimv() consecutive values, defining the color values.
18098        \param opacity Drawing opacity (optional).
18099        \note
18100        - Clipping is supported.
18101        - To set pixel values without clipping needs, you should use the faster CImg::operator()() function.
18102        \par Example:
18103        \code
18104        CImg<unsigned char> img(100,100,1,3,0);
18105        const unsigned char color[] = { 255,128,64 };
18106        img.draw_point(50,50,color);
18107        \endcode
18108     **/
18109     template<typename tc>
18110     CImg<T>& draw_point(const int x0, const int y0,
18111                         const tc *const color, const float opacity=1) {
18112       return draw_point(x0,y0,0,color,opacity);
18113     }
18114 
18115     //! Draw a 2D colored point (pixel).
18116     template<typename tc>
18117     CImg<T>& draw_point(const int x0, const int y0,
18118                         const CImg<tc>& color, const float opacity=1) {
18119       return draw_point(x0,y0,color.data,opacity);
18120     }
18121 
18122     //! Draw a 3D colored point (voxel).
18123     template<typename tc>
18124     CImg<T>& draw_point(const int x0, const int y0, const int z0,
18125                         const tc *const color, const float opacity=1) {
18126       if (is_empty()) return *this;
18127       if (!color)
18128         throw CImgArgumentException("CImg<%s>::draw_point() : Specified color is (null)",
18129                                     pixel_type());
18130       if (x0>=0 && y0>=0 && z0>=0 && x0<dimx() && y0<dimy() && z0<dimz()) {
18131         const unsigned int whz = width*height*depth;
18132         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18133         T *ptrd = ptr(x0,y0,z0,0);
18134         const tc *col = color;
18135         if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
18136         else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
18137       }
18138       return *this;
18139     }
18140 
18141     //! Draw a 3D colored point (voxel).
18142     template<typename tc>
18143     CImg<T>& draw_point(const int x0, const int y0, const int z0,
18144                         const CImg<tc>& color, const float opacity=1) {
18145       return draw_point(x0,y0,z0,color.data,opacity);
18146     }
18147 
18148     // Draw a cloud of colored point (internal).
18149     template<typename t, typename tc>
18150     CImg<T>& _draw_point(const t& points, const unsigned int W, const unsigned int H,
18151                          const tc *const color, const float opacity) {
18152       if (is_empty() || !points || !W) return *this;
18153       switch (H) {
18154       case 0 : case 1 :
18155         throw CImgArgumentException("CImg<%s>::draw_point() : Given list of points is not valid.",
18156                                     pixel_type());
18157       case 2 : {
18158         for (unsigned int i = 0; i<W; ++i) {
18159           const int x = (int)points(i,0), y = (int)points(i,1);
18160           draw_point(x,y,color,opacity);
18161         }
18162       } break;
18163       default : {
18164         for (unsigned int i = 0; i<W; ++i) {
18165           const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
18166           draw_point(x,y,z,color,opacity);
18167         }
18168       }
18169       }
18170       return *this;
18171     }
18172 
18173     //! Draw a cloud of colored points.
18174     /**
18175        \param points Coordinates of vertices, stored as a list of vectors.
18176        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
18177        \param opacity Drawing opacity (optional).
18178        \note
18179        - This function uses several call to the single CImg::draw_point() procedure,
18180        depending on the vectors size in \p points.
18181        \par Example:
18182        \code
18183        CImg<unsigned char> img(100,100,1,3,0);
18184        const unsigned char color[] = { 255,128,64 };
18185        CImgList<int> points;
18186        points.insert(CImg<int>::vector(0,0)).
18187              .insert(CImg<int>::vector(70,10)).
18188              .insert(CImg<int>::vector(80,60)).
18189              .insert(CImg<int>::vector(10,90));
18190        img.draw_point(points,color);
18191        \endcode
18192     **/
18193     template<typename t, typename tc>
18194     CImg<T>& draw_point(const CImgList<t>& points,
18195                         const tc *const color, const float opacity=1) {
18196       unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
18197       return _draw_point(points,points.size,H,color,opacity);
18198     }
18199 
18200     //! Draw a cloud of colored points.
18201     template<typename t, typename tc>
18202     CImg<T>& draw_point(const CImgList<t>& points,
18203                         const CImg<tc>& color, const float opacity=1) {
18204       return draw_point(points,color.data,opacity);
18205     }
18206 
18207     //! Draw a cloud of colored points.
18208     /**
18209        \note
18210        - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
18211        (sequence of vectors aligned along the x-axis).
18212     **/
18213     template<typename t, typename tc>
18214     CImg<T>& draw_point(const CImg<t>& points,
18215                         const tc *const color, const float opacity=1) {
18216       return _draw_point(points,points.width,points.height,color,opacity);
18217     }
18218 
18219     //! Draw a cloud of colored points.
18220     template<typename t, typename tc>
18221     CImg<T>& draw_point(const CImg<t>& points,
18222                         const CImg<tc>& color, const float opacity=1) {
18223       return draw_point(points,color.data,opacity);
18224     }
18225 
18226     //! Draw a 2D colored line.
18227     /**
18228        \param x0 X-coordinate of the starting line point.
18229        \param y0 Y-coordinate of the starting line point.
18230        \param x1 X-coordinate of the ending line point.
18231        \param y1 Y-coordinate of the ending line point.
18232        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
18233        \param opacity Drawing opacity (optional).
18234        \param pattern An integer whose bits describe the line pattern (optional).
18235        \param init_hatch Flag telling if a reinitialization of the hash state must be done (optional).
18236        \note
18237        - Clipping is supported.
18238        - Line routine uses Bresenham's algorithm.
18239        - Set \p init_hatch = false to draw consecutive hatched segments without breaking the line pattern.
18240        \par Example:
18241        \code
18242        CImg<unsigned char> img(100,100,1,3,0);
18243        const unsigned char color[] = { 255,128,64 };
18244         img.draw_line(40,40,80,70,color);
18245        \endcode
18246     **/
18247     template<typename tc>
18248     CImg<T>& draw_line(const int x0, const int y0,
18249                        const int x1, const int y1,
18250                        const tc *const color, const float opacity=1,
18251                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18252       if (is_empty()) return *this;
18253       if (!color)
18254         throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
18255                                     pixel_type());
18256       static unsigned int hatch = ~0U - (~0U>>1);
18257       if (init_hatch) hatch = ~0U - (~0U>>1);
18258       const bool xdir = x0<x1, ydir = y0<y1;
18259       int
18260         nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
18261         &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
18262         &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
18263         &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
18264         &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
18265       if (xright<0 || xleft>=dimx()) return *this;
18266       if (xleft<0) { yleft-=xleft*(yright - yleft)/(xright - xleft); xleft = 0; }
18267       if (xright>=dimx()) { yright-=(xright - dimx())*(yright - yleft)/(xright - xleft); xright = dimx()-1; }
18268       if (ydown<0 || yup>=dimy()) return *this;
18269       if (yup<0) { xup-=yup*(xdown - xup)/(ydown - yup); yup = 0; }
18270       if (ydown>=dimy()) { xdown-=(ydown - dimy())*(xdown - xup)/(ydown - yup); ydown = dimy()-1; }
18271       T *ptrd0 = ptr(nx0,ny0);
18272       int dx = xright - xleft, dy = ydown - yup;
18273       const bool steep = dy>dx;
18274       if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
18275       const int
18276         offx = (nx0<nx1?1:-1)*(steep?width:1),
18277         offy = (ny0<ny1?1:-1)*(steep?1:width),
18278         wh = width*height;
18279       if (opacity>=1) {
18280         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18281           if (pattern&hatch) { T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }}
18282           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18283           ptrd0+=offx;
18284           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18285         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18286           T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
18287           ptrd0+=offx;
18288           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18289         }
18290       } else {
18291         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18292         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18293           if (pattern&hatch) {
18294             T *ptrd = ptrd0; const tc* col = color;
18295             cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
18296           }
18297           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18298           ptrd0+=offx;
18299           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18300         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18301           T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
18302           ptrd0+=offx;
18303           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18304         }
18305       }
18306       return *this;
18307     }
18308 
18309     //! Draw a 2D colored line.
18310     template<typename tc>
18311     CImg<T>& draw_line(const int x0, const int y0,
18312                        const int x1, const int y1,
18313                        const CImg<tc>& color, const float opacity=1,
18314                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18315       return draw_line(x0,y0,x1,y1,color.data,opacity,pattern,init_hatch);
18316     }
18317 
18318     //! Draw a 2D colored line, with z-buffering.
18319     template<typename tc>
18320     CImg<T>& draw_line(float *const zbuffer,
18321                        const int x0, const int y0, const float z0,
18322                        const int x1, const int y1, const float z1,
18323                        const tc *const color, const float opacity=1,
18324                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18325       if (!is_empty() && z0>0 && z1>0) {
18326         if (!color)
18327           throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null).",
18328                                       pixel_type());
18329         static unsigned int hatch = ~0U - (~0U>>1);
18330         if (init_hatch) hatch = ~0U - (~0U>>1);
18331         const bool xdir = x0<x1, ydir = y0<y1;
18332         int
18333           nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
18334           &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
18335           &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
18336           &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
18337           &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
18338         float
18339           Z0 = 1/z0, Z1 = 1/z1, nz0 = Z0, nz1 = Z1, dz = Z1 - Z0,
18340           &zleft = xdir?nz0:nz1,
18341           &zright = xdir?nz1:nz0,
18342           &zup = ydir?nz0:nz1,
18343           &zdown = ydir?nz1:nz0;
18344         if (xright<0 || xleft>=dimx()) return *this;
18345         if (xleft<0) {
18346           const int D = xright - xleft;
18347           yleft-=xleft*(yright - yleft)/D;
18348           zleft-=xleft*(zright - zleft)/D;
18349           xleft = 0;
18350         }
18351         if (xright>=dimx()) {
18352           const int d = xright - dimx(), D = xright - xleft;
18353           yright-=d*(yright - yleft)/D;
18354           zright-=d*(zright - zleft)/D;
18355           xright = dimx()-1;
18356         }
18357         if (ydown<0 || yup>=dimy()) return *this;
18358         if (yup<0) {
18359           const int D = ydown - yup;
18360           xup-=yup*(xdown - xup)/D;
18361           zup-=yup*(zdown - zup)/D;
18362           yup = 0;
18363         }
18364         if (ydown>=dimy()) {
18365           const int d = ydown - dimy(), D = ydown - yup;
18366           xdown-=d*(xdown - xup)/D;
18367           zdown-=d*(zdown - zup)/D;
18368           ydown = dimy()-1;
18369         }
18370         T *ptrd0 = ptr(nx0,ny0);
18371         float *ptrz = zbuffer + nx0 + ny0*width;
18372         int dx = xright - xleft, dy = ydown - yup;
18373         const bool steep = dy>dx;
18374         if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
18375         const int
18376           offx = (nx0<nx1?1:-1)*(steep?width:1),
18377           offy = (ny0<ny1?1:-1)*(steep?1:width),
18378           wh = width*height,
18379           ndx = dx>0?dx:1;
18380         if (opacity>=1) {
18381           if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18382             const float z = Z0 + x*dz/ndx;
18383             if (z>*ptrz && pattern&hatch) {
18384               *ptrz = z;
18385               T *ptrd = ptrd0; const tc *col = color;
18386               cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
18387             }
18388             hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18389             ptrd0+=offx; ptrz+=offx;
18390             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18391           } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18392             const float z = Z0 + x*dz/ndx;
18393             if (z>*ptrz) {
18394               *ptrz = z;
18395               T *ptrd = ptrd0; const tc *col = color;
18396               cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
18397             }
18398             ptrd0+=offx; ptrz+=offx;
18399             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18400           }
18401         } else {
18402           const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18403           if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18404             const float z = Z0 + x*dz/ndx;
18405             if (z>*ptrz && pattern&hatch) {
18406               *ptrz = z;
18407               T *ptrd = ptrd0; const tc *col = color;
18408               cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
18409             }
18410             hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18411             ptrd0+=offx; ptrz+=offx;
18412             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18413           } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18414             const float z = Z0 + x*dz/ndx;
18415             if (z>*ptrz) {
18416               *ptrz = z;
18417               T *ptrd = ptrd0; const tc *col = color;
18418               cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
18419             }
18420             ptrd0+=offx; ptrz+=offx;
18421             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18422           }
18423         }
18424       }
18425       return *this;
18426     }
18427 
18428     //! Draw a 2D colored line, with z-buffering.
18429     template<typename tc>
18430     CImg<T>& draw_line(float *const zbuffer,
18431                        const int x0, const int y0, const float z0,
18432                        const int x1, const int y1, const float z1,
18433                        const CImg<tc>& color, const float opacity=1,
18434                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18435       return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
18436     }
18437 
18438     //! Draw a 3D colored line.
18439     template<typename tc>
18440     CImg<T>& draw_line(const int x0, const int y0, const int z0,
18441                        const int x1, const int y1, const int z1,
18442                        const tc *const color, const float opacity=1,
18443                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18444       if (is_empty()) return *this;
18445       if (!color)
18446         throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
18447                                     pixel_type());
18448       static unsigned int hatch = ~0U - (~0U>>1);
18449       if (init_hatch) hatch = ~0U - (~0U>>1);
18450       int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1;
18451       if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
18452       if (nx1<0 || nx0>=dimx()) return *this;
18453       if (nx0<0) { const int D = 1 + nx1 - nx0; ny0-=nx0*(1 + ny1 - ny0)/D; nz0-=nx0*(1 + nz1 - nz0)/D; nx0 = 0; }
18454       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; }
18455       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
18456       if (ny1<0 || ny0>=dimy()) return *this;
18457       if (ny0<0) { const int D = 1 + ny1 - ny0; nx0-=ny0*(1 + nx1 - nx0)/D; nz0-=ny0*(1 + nz1 - nz0)/D; ny0 = 0; }
18458       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; }
18459       if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
18460       if (nz1<0 || nz0>=dimz()) return *this;
18461       if (nz0<0) { const int D = 1 + nz1 - nz0; nx0-=nz0*(1 + nx1 - nx0)/D; ny0-=nz0*(1 + ny1 - ny0)/D; nz0 = 0; }
18462       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; }
18463       const unsigned int dmax = cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0), whz = width*height*depth;
18464       const float px = (nx1 - nx0)/(float)dmax, py = (ny1 - ny0)/(float)dmax, pz = (nz1 - nz0)/(float)dmax;
18465       float x = (float)nx0, y = (float)ny0, z = (float)nz0;
18466       if (opacity>=1) for (unsigned int t = 0; t<=dmax; ++t) {
18467         if (!(~pattern) || (~pattern && pattern&hatch)) {
18468           T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
18469           const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
18470         }
18471         x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
18472       } else {
18473         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18474         for (unsigned int t = 0; t<=dmax; ++t) {
18475           if (!(~pattern) || (~pattern && pattern&hatch)) {
18476             T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
18477             const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
18478           }
18479           x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
18480         }
18481       }
18482       return *this;
18483     }
18484 
18485     //! Draw a 3D colored line.
18486     template<typename tc>
18487     CImg<T>& draw_line(const int x0, const int y0, const int z0,
18488                        const int x1, const int y1, const int z1,
18489                        const CImg<tc>& color, const float opacity=1,
18490                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18491       return draw_line(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
18492     }
18493 
18494     //! Draw a 2D textured line.
18495     /**
18496        \param x0 X-coordinate of the starting line point.
18497        \param y0 Y-coordinate of the starting line point.
18498        \param x1 X-coordinate of the ending line point.
18499        \param y1 Y-coordinate of the ending line point.
18500        \param texture Texture image defining the pixel colors.
18501        \param tx0 X-coordinate of the starting texture point.
18502        \param ty0 Y-coordinate of the starting texture point.
18503        \param tx1 X-coordinate of the ending texture point.
18504        \param ty1 Y-coordinate of the ending texture point.
18505        \param opacity Drawing opacity (optional).
18506        \param pattern An integer whose bits describe the line pattern (optional).
18507        \param init_hatch Flag telling if the hash variable must be reinitialized (optional).
18508        \note
18509        - Clipping is supported but not for texture coordinates.
18510        - Line routine uses the well known Bresenham's algorithm.
18511        \par Example:
18512        \code
18513        CImg<unsigned char> img(100,100,1,3,0), texture("texture256x256.ppm");
18514        const unsigned char color[] = { 255,128,64 };
18515        img.draw_line(40,40,80,70,texture,0,0,255,255);
18516        \endcode
18517     **/
18518     template<typename tc>
18519     CImg<T>& draw_line(const int x0, const int y0,
18520                        const int x1, const int y1,
18521                        const CImg<tc>& texture,
18522                        const int tx0, const int ty0,
18523                        const int tx1, const int ty1,
18524                        const float opacity=1,
18525                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18526       if (is_empty()) return *this;
18527       if (!texture || texture.dim<dim)
18528         throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
18529                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
18530       if (is_overlapped(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
18531       static unsigned int hatch = ~0U - (~0U>>1);
18532       if (init_hatch) hatch = ~0U - (~0U>>1);
18533       const bool xdir = x0<x1, ydir = y0<y1;
18534       int
18535         dtx = tx1-tx0, dty = ty1-ty0,
18536         nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
18537         tnx0 = tx0, tnx1 = tx1, tny0 = ty0, tny1 = ty1,
18538         &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
18539         &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
18540         &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0,
18541         &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
18542       if (xright<0 || xleft>=dimx()) return *this;
18543       if (xleft<0) {
18544         const int D = xright - xleft;
18545         yleft-=xleft*(yright - yleft)/D;
18546         txleft-=xleft*(txright - txleft)/D;
18547         tyleft-=xleft*(tyright - tyleft)/D;
18548         xleft = 0;
18549       }
18550       if (xright>=dimx()) {
18551         const int d = xright - dimx(), D = xright - xleft;
18552         yright-=d*(yright - yleft)/D;
18553         txright-=d*(txright - txleft)/D;
18554         tyright-=d*(tyright - tyleft)/D;
18555         xright = dimx()-1;
18556       }
18557       if (ydown<0 || yup>=dimy()) return *this;
18558       if (yup<0) {
18559         const int D = ydown - yup;
18560         xup-=yup*(xdown - xup)/D;
18561         txup-=yup*(txdown - txup)/D;
18562         tyup-=yup*(tydown - tyup)/D;
18563         yup = 0;
18564       }
18565       if (ydown>=dimy()) {
18566         const int d = ydown - dimy(), D = ydown - yup;
18567         xdown-=d*(xdown - xup)/D;
18568         txdown-=d*(txdown - txup)/D;
18569         tydown-=d*(tydown - tyup)/D;
18570         ydown = dimy()-1;
18571       }
18572       T *ptrd0 = ptr(nx0,ny0);
18573       int dx = xright - xleft, dy = ydown - yup;
18574       const bool steep = dy>dx;
18575       if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
18576       const int
18577         offx = (nx0<nx1?1:-1)*(steep?width:1),
18578         offy = (ny0<ny1?1:-1)*(steep?1:width),
18579         wh = width*height,
18580         ndx = dx>0?dx:1;
18581       if (opacity>=1) {
18582         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18583           if (pattern&hatch) {
18584             T *ptrd = ptrd0;
18585             const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
18586             cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
18587           }
18588           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18589           ptrd0+=offx;
18590           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18591         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18592           T *ptrd = ptrd0;
18593           const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
18594           cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
18595           ptrd0+=offx;
18596           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18597         }
18598       } else {
18599         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18600         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18601           T *ptrd = ptrd0;
18602           if (pattern&hatch) {
18603             const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
18604             cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
18605           }
18606           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18607           ptrd0+=offx;
18608           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18609         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18610           T *ptrd = ptrd0;
18611           const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
18612           cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
18613           ptrd0+=offx;
18614           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18615         }
18616       }
18617       return *this;
18618     }
18619 
18620     //! Draw a 2D textured line, with perspective correction.
18621     template<typename tc>
18622     CImg<T>& draw_line(const int x0, const int y0, const float z0,
18623                        const int x1, const int y1, const float z1,
18624                        const CImg<tc>& texture,
18625                        const int tx0, const int ty0,
18626                        const int tx1, const int ty1,
18627                        const float opacity=1,
18628                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18629       if (is_empty() && z0<=0 && z1<=0) return *this;
18630       if (!texture || texture.dim<dim)
18631         throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
18632                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
18633       if (is_overlapped(texture)) return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
18634       static unsigned int hatch = ~0U - (~0U>>1);
18635       if (init_hatch) hatch = ~0U - (~0U>>1);
18636       const bool xdir = x0<x1, ydir = y0<y1;
18637       int
18638         nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
18639         &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
18640         &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
18641         &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
18642         &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
18643       float
18644         Tx0 = tx0/z0, Tx1 = tx1/z1,
18645         Ty0 = ty0/z0, Ty1 = ty1/z1,
18646         Z0 = 1/z0, Z1 = 1/z1,
18647         dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
18648         tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
18649         &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
18650         &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
18651         &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
18652         &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
18653       if (xright<0 || xleft>=dimx()) return *this;
18654       if (xleft<0) {
18655         const int D = xright - xleft;
18656         yleft-=xleft*(yright - yleft)/D;
18657         zleft-=xleft*(zright - zleft)/D;
18658         txleft-=xleft*(txright - txleft)/D;
18659         tyleft-=xleft*(tyright - tyleft)/D;
18660         xleft = 0;
18661       }
18662       if (xright>=dimx()) {
18663         const int d = xright - dimx(), D = xright - xleft;
18664         yright-=d*(yright - yleft)/D;
18665         zright-=d*(zright - zleft)/D;
18666         txright-=d*(txright - txleft)/D;
18667         tyright-=d*(tyright - tyleft)/D;
18668         xright = dimx()-1;
18669       }
18670       if (ydown<0 || yup>=dimy()) return *this;
18671       if (yup<0) {
18672         const int D = ydown - yup;
18673         xup-=yup*(xdown - xup)/D;
18674         zup-=yup*(zdown - zup)/D;
18675         txup-=yup*(txdown - txup)/D;
18676         tyup-=yup*(tydown - tyup)/D;
18677         yup = 0;
18678       }
18679       if (ydown>=dimy()) {
18680         const int d = ydown - dimy(), D = ydown - yup;
18681         xdown-=d*(xdown - xup)/D;
18682         zdown-=d*(zdown - zup)/D;
18683         txdown-=d*(txdown - txup)/D;
18684         tydown-=d*(tydown - tyup)/D;
18685         ydown = dimy()-1;
18686       }
18687       T *ptrd0 = ptr(nx0,ny0);
18688       int dx = xright - xleft, dy = ydown - yup;
18689       const bool steep = dy>dx;
18690       if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
18691       const int
18692         offx = (nx0<nx1?1:-1)*(steep?width:1),
18693         offy = (ny0<ny1?1:-1)*(steep?1:width),
18694         wh = width*height,
18695         ndx = dx>0?dx:1;
18696       if (opacity>=1) {
18697         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18698           if (pattern&hatch) {
18699             const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18700             T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
18701           }
18702           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18703           ptrd0+=offx;
18704           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18705         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18706           const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18707           T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
18708           ptrd0+=offx;
18709           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18710         }
18711       } else {
18712         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18713         if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18714           if (pattern&hatch) {
18715             const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18716             T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
18717           }
18718           hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18719           ptrd0+=offx;
18720           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18721         } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18722           const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18723           T *ptrd = ptrd0;
18724           cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
18725           ptrd0+=offx;
18726           if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18727         }
18728       }
18729       return *this;
18730     }
18731 
18732     //! Draw a 2D textured line, with z-buffering and perspective correction.
18733     template<typename tc>
18734     CImg<T>& draw_line(float *const zbuffer,
18735                        const int x0, const int y0, const float z0,
18736                        const int x1, const int y1, const float z1,
18737                        const CImg<tc>& texture,
18738                        const int tx0, const int ty0,
18739                        const int tx1, const int ty1,
18740                        const float opacity=1,
18741                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18742       if (!is_empty() && z0>0 && z1>0) {
18743         if (!texture || texture.dim<dim)
18744           throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
18745                                       pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
18746         if (is_overlapped(texture)) return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
18747         static unsigned int hatch = ~0U - (~0U>>1);
18748         if (init_hatch) hatch = ~0U - (~0U>>1);
18749         const bool xdir = x0<x1, ydir = y0<y1;
18750         int
18751           nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
18752           &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
18753           &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
18754           &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
18755           &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
18756         float
18757           Tx0 = tx0/z0, Tx1 = tx1/z1,
18758           Ty0 = ty0/z0, Ty1 = ty1/z1,
18759           Z0 = 1/z0, Z1 = 1/z1,
18760           dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
18761           tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
18762           &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
18763           &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
18764           &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
18765           &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
18766         if (xright<0 || xleft>=dimx()) return *this;
18767         if (xleft<0) {
18768           const int D = xright - xleft;
18769           yleft-=xleft*(yright - yleft)/D;
18770           zleft-=xleft*(zright - zleft)/D;
18771           txleft-=xleft*(txright - txleft)/D;
18772           tyleft-=xleft*(tyright - tyleft)/D;
18773           xleft = 0;
18774         }
18775         if (xright>=dimx()) {
18776           const int d = xright - dimx(), D = xright - xleft;
18777           yright-=d*(yright - yleft)/D;
18778           zright-=d*(zright - zleft)/D;
18779           txright-=d*(txright - txleft)/D;
18780           tyright-=d*(tyright - tyleft)/D;
18781           xright = dimx()-1;
18782         }
18783         if (ydown<0 || yup>=dimy()) return *this;
18784         if (yup<0) {
18785           const int D = ydown - yup;
18786           xup-=yup*(xdown - xup)/D;
18787           zup-=yup*(zdown - zup)/D;
18788           txup-=yup*(txdown - txup)/D;
18789           tyup-=yup*(tydown - tyup)/D;
18790           yup = 0;
18791         }
18792         if (ydown>=dimy()) {
18793           const int d = ydown - dimy(), D = ydown - yup;
18794           xdown-=d*(xdown - xup)/D;
18795           zdown-=d*(zdown - zup)/D;
18796           txdown-=d*(txdown - txup)/D;
18797           tydown-=d*(tydown - tyup)/D;
18798           ydown = dimy()-1;
18799         }
18800         T *ptrd0 = ptr(nx0,ny0);
18801         float *ptrz = zbuffer + nx0 + ny0*width;
18802         int dx = xright - xleft, dy = ydown - yup;
18803         const bool steep = dy>dx;
18804         if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
18805         const int
18806           offx = (nx0<nx1?1:-1)*(steep?width:1),
18807           offy = (ny0<ny1?1:-1)*(steep?1:width),
18808           wh = width*height,
18809           ndx = dx>0?dx:1;
18810         if (opacity>=1) {
18811           if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18812             if (pattern&hatch) {
18813               const float z = Z0 + x*dz/ndx;
18814               if (z>*ptrz) {
18815                 *ptrz = z;
18816                 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18817                 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
18818               }
18819             }
18820             hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18821             ptrd0+=offx; ptrz+=offx;
18822             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18823           } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18824             const float z = Z0 + x*dz/ndx;
18825             if (z>*ptrz) {
18826               *ptrz = z;
18827               const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18828               T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
18829             }
18830             ptrd0+=offx; ptrz+=offx;
18831             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18832           }
18833         } else {
18834           const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18835           if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18836             if (pattern&hatch) {
18837               const float z = Z0 + x*dz/ndx;
18838               if (z>*ptrz) {
18839                 *ptrz = z;
18840                 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18841                 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
18842               }
18843             }
18844             hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18845             ptrd0+=offx; ptrz+=offx;
18846             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18847           } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18848             const float z = Z0 + x*dz/ndx;
18849             if (z>*ptrz) {
18850               *ptrz = z;
18851               const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18852               T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
18853             }
18854             ptrd0+=offx; ptrz+=offx;
18855             if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offx; error+=dx; }
18856           }
18857         }
18858       }
18859       return *this;
18860     }
18861 
18862     // Inner routine for drawing set of consecutive lines with generic type for coordinates.
18863     template<typename t, typename tc>
18864     CImg<T>& _draw_line(const t& points, const unsigned int W, const unsigned int H,
18865                         const tc *const color, const float opacity,
18866                         const unsigned int pattern, const bool init_hatch) {
18867       if (is_empty() || !points || W<2) return *this;
18868       bool ninit_hatch = init_hatch;
18869       switch (H) {
18870       case 0 : case 1 :
18871         throw CImgArgumentException("CImg<%s>::draw_line() : Given list of points is not valid.",
18872                                     pixel_type());
18873       case 2 : {
18874         const int x0 = (int)points(0,0), y0 = (int)points(0,1);
18875         int ox = x0, oy = y0;
18876         for (unsigned int i = 1; i<W; ++i) {
18877           const int x = (int)points(i,0), y = (int)points(i,1);
18878           draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
18879           ninit_hatch = false;
18880           ox = x; oy = y;
18881         }
18882       } break;
18883       default : {
18884         const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
18885         int ox = x0, oy = y0, oz = z0;
18886         for (unsigned int i = 1; i<W; ++i) {
18887           const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
18888           draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
18889           ninit_hatch = false;
18890           ox = x; oy = y; oz = z;
18891         }
18892       }
18893       }
18894       return *this;
18895     }
18896 
18897     //! Draw a set of consecutive colored lines in the instance image.
18898     /**
18899        \param points Coordinates of vertices, stored as a list of vectors.
18900        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
18901        \param opacity Drawing opacity (optional).
18902        \param pattern An integer whose bits describe the line pattern (optional).
18903        \param init_hatch If set to true, init hatch motif.
18904        \note
18905        - This function uses several call to the single CImg::draw_line() procedure,
18906        depending on the vectors size in \p points.
18907        \par Example:
18908        \code
18909        CImg<unsigned char> img(100,100,1,3,0);
18910        const unsigned char color[] = { 255,128,64 };
18911        CImgList<int> points;
18912        points.insert(CImg<int>::vector(0,0)).
18913              .insert(CImg<int>::vector(70,10)).
18914              .insert(CImg<int>::vector(80,60)).
18915              .insert(CImg<int>::vector(10,90));
18916        img.draw_line(points,color);
18917        \endcode
18918     **/
18919     template<typename t, typename tc>
18920     CImg<T>& draw_line(const CImgList<t>& points,
18921                        const tc *const color, const float opacity=1,
18922                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18923       unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
18924       return _draw_line(points,points.size,H,color,opacity,pattern,init_hatch);
18925     }
18926 
18927     //! Draw a set of consecutive colored lines in the instance image.
18928     template<typename t, typename tc>
18929     CImg<T>& draw_line(const CImgList<t>& points,
18930                        const CImg<tc>& color, const float opacity=1,
18931                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18932       return draw_line(points,color.data,opacity,pattern,init_hatch);
18933     }
18934 
18935     //! Draw a set of consecutive colored lines in the instance image.
18936     /**
18937        \note
18938        - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
18939        (sequence of vectors aligned along the x-axis).
18940     **/
18941     template<typename t, typename tc>
18942     CImg<T>& draw_line(const CImg<t>& points,
18943                        const tc *const color, const float opacity=1,
18944                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18945       return _draw_line(points,points.width,points.height,color,opacity,pattern,init_hatch);
18946     }
18947 
18948     //! Draw a set of consecutive colored lines in the instance image.
18949     template<typename t, typename tc>
18950     CImg<T>& draw_line(const CImg<t>& points,
18951                        const CImg<tc>& color, const float opacity=1,
18952                        const unsigned int pattern=~0U, const bool init_hatch=true) {
18953       return draw_line(points,color.data,opacity,pattern,init_hatch);
18954     }
18955 
18956     // Inner routine for a drawing filled polygon with generic type for coordinates.
18957     template<typename t, typename tc>
18958     CImg<T>& _draw_polygon(const t& points, const unsigned int N,
18959                            const tc *const color, const float opacity) {
18960       if (is_empty() || !points || N<3) return *this;
18961       if (!color)
18962         throw CImgArgumentException("CImg<%s>::draw_polygon() : Specified color is (null).",
18963                                     pixel_type());
18964       _draw_scanline(color,opacity);
18965       int xmin = (int)(~0U>>1), xmax = 0, ymin = (int)(~0U>>1), ymax = 0;
18966       { for (unsigned int p = 0; p<N; ++p) {
18967         const int x = (int)points(p,0), y = (int)points(p,1);
18968         if (x<xmin) xmin = x;
18969         if (x>xmax) xmax = x;
18970         if (y<ymin) ymin = y;
18971         if (y>ymax) ymax = y;
18972       }}
18973       if (xmax<0 || xmin>=dimx() || ymax<0 || ymin>=dimy()) return *this;
18974       const unsigned int
18975         nymin = ymin<0?0:(unsigned int)ymin,
18976         nymax = ymax>=dimy()?height-1:(unsigned int)ymax,
18977         dy = 1 + nymax - nymin;
18978       CImg<intT> X(1+2*N,dy,1,1,0), tmp;
18979       int cx = (int)points(0,0), cy = (int)points(0,1);
18980       for (unsigned int cp = 0, p = 0; p<N; ++p) {
18981         const unsigned int np = (p!=N-1)?p+1:0, ap = (np!=N-1)?np+1:0;
18982         const int
18983           nx = (int)points(np,0), ny = (int)points(np,1), ay = (int)points(ap,1),
18984           y0 = cy - nymin, y1 = ny - nymin;
18985         if (y0!=y1) {
18986           const int countermin = ((ny<ay && cy<ny) || (ny>ay && cy>ny))?1:0;
18987           for (int x = cx, y = y0, _sx = 1, _sy = 1,
18988                  _dx = nx>cx?nx-cx:((_sx=-1),cx-nx),
18989                  _dy = y1>y0?y1-y0:((_sy=-1),y0-y1),
18990                  _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy),
18991                  _err = _dx>>1,
18992                  _rx = _dy?(nx-cx)/_dy:0;
18993                _counter>=countermin;
18994                --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0))
18995             if (y>=0 && y<(int)dy) X(++X(0,y),y) = x;
18996           cp = np; cx = nx; cy = ny;
18997         } else {
18998           const int pp = (cp?cp-1:N-1), py = (int)points(pp,1);
18999           if ((cy>py && ay>cy) || (cy<py && ay<cy)) X(++X(0,y0),y0) = nx;
19000           if (cy!=ay) { cp = np; cx = nx; cy = ny; }
19001         }
19002       }
19003       for (int y = 0; y<(int)dy; ++y) {
19004         tmp.assign(X.ptr(1,y),X(0,y),1,1,1,true).sort();
19005         for (int i = 1; i<=X(0,y); ) {
19006           const int xb = X(i++,y), xe = X(i++,y);
19007           _draw_scanline(xb,xe,nymin+y,color,opacity);
19008         }
19009       }
19010       return *this;
19011     }
19012 
19013     //! Draw a filled polygon in the instance image.
19014     template<typename t, typename tc>
19015     CImg<T>& draw_polygon(const CImgList<t>& points,
19016                           const tc *const color, const float opacity=1) {
19017       if (!points.is_sameY(2))
19018         throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
19019                                     pixel_type());
19020       return _draw_polygon(points,points.size,color,opacity);
19021     }
19022 
19023     //! Draw a filled polygon in the instance image.
19024     template<typename t, typename tc>
19025     CImg<T>& draw_polygon(const CImgList<t>& points,
19026                           const CImg<tc>& color, const float opacity=1) {
19027       return draw_polygon(points,color.data,opacity);
19028     }
19029 
19030     //! Draw a filled polygon in the instance image.
19031     template<typename t, typename tc>
19032     CImg<T>& draw_polygon(const CImg<t>& points,
19033                           const tc *const color, const float opacity=1) {
19034       if (points.height<2)
19035         throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
19036                                     pixel_type());
19037       return _draw_polygon(points,points.width,color,opacity);
19038     }
19039 
19040     //! Draw a filled polygon in the instance image.
19041     template<typename t, typename tc>
19042     CImg<T>& draw_polygon(const CImg<t>& points,
19043                           const CImg<tc>& color, const float opacity=1) {
19044       return draw_polygon(points,color.data,opacity);
19045     }
19046 
19047     // Inner routine for drawing an outlined polygon with generic point coordinates.
19048     template<typename t, typename tc>
19049     CImg<T>& _draw_polygon(const t& points, const unsigned int W, const unsigned int H,
19050                            const tc *const color, const float opacity,
19051                            const unsigned int pattern) {
19052       if (is_empty() || !points || W<3) return *this;
19053       bool ninit_hatch = true;
19054       switch (H) {
19055       case 0 : case 1 :
19056         throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
19057                                     pixel_type());
19058       case 2 : {
19059         const int x0 = (int)points(0,0), y0 = (int)points(0,1);
19060         int ox = x0, oy = y0;
19061         for (unsigned int i = 1; i<W; ++i) {
19062           const int x = (int)points(i,0), y = (int)points(i,1);
19063           draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
19064           ninit_hatch = false;
19065           ox = x; oy = y;
19066         }
19067         draw_line(ox,oy,x0,y0,color,opacity,pattern,false);
19068       } break;
19069       default : {
19070         const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
19071         int ox = x0, oy = y0, oz = z0;
19072         for (unsigned int i = 1; i<W; ++i) {
19073           const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
19074           draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
19075           ninit_hatch = false;
19076           ox = x; oy = y; oz = z;
19077         }
19078         draw_line(ox,oy,oz,x0,y0,z0,color,opacity,pattern,false);
19079       }
19080       }
19081       return *this;
19082     }
19083 
19084     //! Draw a polygon outline.
19085     template<typename t, typename tc>
19086     CImg<T>& draw_polygon(const CImgList<t>& points,
19087                           const tc *const color, const float opacity,
19088                           const unsigned int pattern) {
19089       unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
19090       return _draw_polygon(points,points.size,H,color,opacity,pattern);
19091     }
19092 
19093     //! Draw a polygon outline.
19094     template<typename t, typename tc>
19095     CImg<T>& draw_polygon(const CImgList<t>& points,
19096                           const CImg<tc>& color, const float opacity,
19097                           const unsigned int pattern) {
19098       return draw_polygon(points,color.data,opacity,pattern);
19099     }
19100 
19101     //! Draw a polygon outline.
19102     template<typename t, typename tc>
19103     CImg<T>& draw_polygon(const CImg<t>& points,
19104                           const tc *const color, const float opacity,
19105                           const unsigned int pattern) {
19106       return _draw_polygon(points,points.width,points.height,color,opacity,pattern);
19107     }
19108 
19109     //! Draw a polygon outline.
19110     template<typename t, typename tc>
19111     CImg<T>& draw_polygon(const CImg<t>& points,
19112                           const CImg<tc>& color, const float opacity,
19113                           const unsigned int pattern) {
19114       return draw_polygon(points,color.data,opacity,pattern);
19115     }
19116 
19117     //! Draw a cubic spline curve in the instance image.
19118     /**
19119        \param x0 X-coordinate of the starting curve point
19120        \param y0 Y-coordinate of the starting curve point
19121        \param u0 X-coordinate of the starting velocity
19122        \param v0 Y-coordinate of the starting velocity
19123        \param x1 X-coordinate of the ending curve point
19124        \param y1 Y-coordinate of the ending curve point
19125        \param u1 X-coordinate of the ending velocity
19126        \param v1 Y-coordinate of the ending velocity
19127        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
19128        \param precision Curve drawing precision (optional).
19129        \param opacity Drawing opacity (optional).
19130        \param pattern An integer whose bits describe the line pattern (optional).
19131        \param init_hatch If \c true, init hatch motif.
19132        \note
19133        - The curve is a 2D cubic Bezier spline, from the set of specified starting/ending points
19134        and corresponding velocity vectors.
19135        - The spline is drawn as a serie of connected segments. The \p precision parameter sets the
19136        average number of pixels in each drawn segment.
19137        - 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) }
19138        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
19139        \e control points.
19140        The starting and ending velocities (\p u0,\p v0) and (\p u1,\p v1) can be deduced easily from the control points as
19141        \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).
19142        \par Example:
19143        \code
19144        CImg<unsigned char> img(100,100,1,3,0);
19145        const unsigned char color[] = { 255,255,255 };
19146        img.draw_spline(30,30,0,100,90,40,0,-100,color);
19147        \endcode
19148     **/
19149     template<typename tc>
19150     CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
19151                          const int x1, const int y1, const float u1, const float v1,
19152                          const tc *const color, const float opacity=1,
19153                          const float precision=4, const unsigned int pattern=~0U,
19154                          const bool init_hatch=true) {
19155       if (is_empty()) return *this;
19156       if (!color)
19157         throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
19158                                     pixel_type());
19159       bool ninit_hatch = init_hatch;
19160       const float
19161         dx = (float)(x1 - x0),
19162         dy = (float)(y1 - y0),
19163         dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
19164         ax = -2*dx + u0 + u1,
19165         bx = 3*dx - 2*u0 - u1,
19166         ay = -2*dy + v0 + v1,
19167         by = 3*dy - 2*v0 - v1,
19168         xprecision = dmax>0?precision/dmax:1.0f,
19169         tmax = 1 + (dmax>0?xprecision:0.0f);
19170       int ox = x0, oy = y0;
19171       for (float t = 0; t<tmax; t+=xprecision) {
19172         const float
19173           t2 = t*t,
19174           t3 = t2*t;
19175         const int
19176           nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
19177           ny = (int)(ay*t3 + by*t2 + v0*t + y0);
19178         draw_line(ox,oy,nx,ny,color,opacity,pattern,ninit_hatch);
19179         ninit_hatch = false;
19180         ox = nx; oy = ny;
19181       }
19182       return *this;
19183     }
19184 
19185     //! Draw a cubic spline curve in the instance image.
19186     template<typename tc>
19187     CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
19188                          const int x1, const int y1, const float u1, const float v1,
19189                          const CImg<tc>& color, const float opacity=1,
19190                          const float precision=4, const unsigned int pattern=~0U,
19191                          const bool init_hatch=true) {
19192       return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,color.data,opacity,precision,pattern,init_hatch);
19193     }
19194 
19195     //! Draw a cubic spline curve in the instance image (for volumetric images).
19196     /**
19197        \note
19198        - Similar to CImg::draw_spline() for a 3D spline in a volumetric image.
19199     **/
19200     template<typename tc>
19201     CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
19202                          const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
19203                          const tc *const color, const float opacity=1,
19204                          const float precision=4, const unsigned int pattern=~0U,
19205                          const bool init_hatch=true) {
19206       if (is_empty()) return *this;
19207       if (!color)
19208         throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
19209                                     pixel_type());
19210       bool ninit_hatch = init_hatch;
19211       const float
19212         dx = (float)(x1 - x0),
19213         dy = (float)(y1 - y0),
19214         dz = (float)(z1 - z0),
19215         dmax = cimg::max(cimg::abs(dx),cimg::abs(dy),cimg::abs(dz)),
19216         ax = -2*dx + u0 + u1,
19217         bx = 3*dx - 2*u0 - u1,
19218         ay = -2*dy + v0 + v1,
19219         by = 3*dy - 2*v0 - v1,
19220         az = -2*dz + w0 + w1,
19221         bz = 3*dz - 2*w0 - w1,
19222         xprecision = dmax>0?precision/dmax:1.0f,
19223         tmax = 1 + (dmax>0?xprecision:0.0f);
19224       int ox = x0, oy = y0, oz = z0;
19225       for (float t = 0; t<tmax; t+=xprecision) {
19226         const float
19227           t2 = t*t,
19228           t3 = t2*t;
19229         const int
19230           nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
19231           ny = (int)(ay*t3 + by*t2 + v0*t + y0),
19232           nz = (int)(az*t3 + bz*t2 + w0*t + z0);
19233         draw_line(ox,oy,oz,nx,ny,nz,color,opacity,pattern,ninit_hatch);
19234         ninit_hatch = false;
19235         ox = nx; oy = ny; oz = nz;
19236       }
19237       return *this;
19238     }
19239 
19240     //! Draw a cubic spline curve in the instance image (for volumetric images).
19241     template<typename tc>
19242     CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
19243                          const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
19244                          const CImg<tc>& color, const float opacity=1,
19245                          const float precision=4, const unsigned int pattern=~0U,
19246                          const bool init_hatch=true) {
19247       return draw_spline(x0,y0,z0,u0,v0,w0,x1,y1,z1,u1,v1,w1,color.data,opacity,precision,pattern,init_hatch);
19248     }
19249 
19250     //! Draw a cubic spline curve in the instance image.
19251     /**
19252        \param x0 X-coordinate of the starting curve point
19253        \param y0 Y-coordinate of the starting curve point
19254        \param u0 X-coordinate of the starting velocity
19255        \param v0 Y-coordinate of the starting velocity
19256        \param x1 X-coordinate of the ending curve point
19257        \param y1 Y-coordinate of the ending curve point
19258        \param u1 X-coordinate of the ending velocity
19259        \param v1 Y-coordinate of the ending velocity
19260        \param texture Texture image defining line pixel colors.
19261        \param tx0 X-coordinate of the starting texture point.
19262        \param ty0 Y-coordinate of the starting texture point.
19263        \param tx1 X-coordinate of the ending texture point.
19264        \param ty1 Y-coordinate of the ending texture point.
19265        \param precision Curve drawing precision (optional).
19266        \param opacity Drawing opacity (optional).
19267        \param pattern An integer whose bits describe the line pattern (optional).
19268        \param init_hatch if \c true, reinit hatch motif.
19269     **/
19270     template<typename t>
19271     CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
19272                          const int x1, const int y1, const float u1, const float v1,
19273                          const CImg<t>& texture,
19274                          const int tx0, const int ty0, const int tx1, const int ty1,
19275                          const float opacity=1,
19276                          const float precision=4, const unsigned int pattern=~0U,
19277                          const bool init_hatch=true) {
19278       if (is_empty()) return *this;
19279       if (!texture || texture.dim<dim)
19280         throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
19281                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
19282       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);
19283       bool ninit_hatch = true;
19284       const float
19285         dx = (float)(x1 - x0),
19286         dy = (float)(y1 - y0),
19287         dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
19288         ax = -2*dx + u0 + u1,
19289         bx = 3*dx - 2*u0 - u1,
19290         ay = -2*dy + v0 + v1,
19291         by = 3*dy - 2*v0 - v1,
19292         xprecision = dmax>0?precision/dmax:1.0f,
19293         tmax = 1 + (dmax>0?xprecision:0.0f);
19294       int ox = x0, oy = y0, otx = tx0, oty = ty0;
19295       for (float t1 = 0; t1<tmax; t1+=xprecision) {
19296         const float
19297           t2 = t1*t1,
19298           t3 = t2*t1;
19299         const int
19300           nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0),
19301           ny = (int)(ay*t3 + by*t2 + v0*t1 + y0),
19302           ntx = tx0 + (int)((tx1-tx0)*t1/tmax),
19303           nty = ty0 + (int)((ty1-ty0)*t1/tmax);
19304         draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch);
19305         ninit_hatch = false;
19306         ox = nx; oy = ny; otx = ntx; oty = nty;
19307       }
19308       return *this;
19309     }
19310 
19311     // Draw a set of connected spline curves in the instance image (internal).
19312     template<typename tp, typename tt, typename tc>
19313     CImg<T>& _draw_spline(const tp& points, const tt& tangents, const unsigned int W, const unsigned int H,
19314                           const tc *const color, const float opacity,
19315                           const bool close_set, const float precision,
19316                           const unsigned int pattern, const bool init_hatch) {
19317       if (is_empty() || !points || !tangents || W<2) return *this;
19318       bool ninit_hatch = init_hatch;
19319       switch (H) {
19320       case 0 : case 1 :
19321         throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
19322                                     pixel_type());
19323       case 2 : {
19324         const int x0 = (int)points(0,0), y0 = (int)points(0,1);
19325         const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1);
19326         int ox = x0, oy = y0;
19327         float ou = u0, ov = v0;
19328         for (unsigned int i = 1; i<W; ++i) {
19329           const int x = (int)points(i,0), y = (int)points(i,1);
19330           const float u = (float)tangents(i,0), v = (float)tangents(i,1);
19331           draw_spline(ox,oy,ou,ov,x,y,u,v,color,precision,opacity,pattern,ninit_hatch);
19332           ninit_hatch = false;
19333           ox = x; oy = y; ou = u; ov = v;
19334         }
19335         if (close_set) draw_spline(ox,oy,ou,ov,x0,y0,u0,v0,color,precision,opacity,pattern,false);
19336       } break;
19337       default : {
19338         const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
19339         const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1), w0 = (float)tangents(0,2);
19340         int ox = x0, oy = y0, oz = z0;
19341         float ou = u0, ov = v0, ow = w0;
19342         for (unsigned int i = 1; i<W; ++i) {
19343           const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
19344           const float u = (float)tangents(i,0), v = (float)tangents(i,1), w = (float)tangents(i,2);
19345           draw_spline(ox,oy,oz,ou,ov,ow,x,y,z,u,v,w,color,opacity,pattern,ninit_hatch);
19346           ninit_hatch = false;
19347           ox = x; oy = y; oz = z; ou = u; ov = v; ow = w;
19348         }
19349         if (close_set) draw_spline(ox,oy,oz,ou,ov,ow,x0,y0,z0,u0,v0,w0,color,precision,opacity,pattern,false);
19350       }
19351       }
19352       return *this;
19353     }
19354 
19355     // Draw a set of connected spline curves in the instance image (internal).
19356     template<typename tp, typename tc>
19357     CImg<T>& _draw_spline(const tp& points, const unsigned int W, const unsigned int H,
19358                           const tc *const color, const float opacity,
19359                           const bool close_set, const float precision,
19360                           const unsigned int pattern, const bool init_hatch) {
19361       if (is_empty() || !points || W<2) return *this;
19362       CImg<Tfloat> tangents;
19363       switch (H) {
19364       case 0 : case 1 :
19365         throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
19366                                     pixel_type());
19367       case 2 : {
19368         tangents.assign(W,H);
19369         for (unsigned int p = 0; p<W; ++p) {
19370           const unsigned int
19371             p0 = close_set?(p+W-1)%W:(p?p-1:0),
19372             p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
19373           const float
19374             x = (float)points(p,0),
19375             y = (float)points(p,1),
19376             x0 = (float)points(p0,0),
19377             y0 = (float)points(p0,1),
19378             x1 = (float)points(p1,0),
19379             y1 = (float)points(p1,1),
19380             u0 = x - x0,
19381             v0 = y - y0,
19382             n0 = 1e-8f + (float)cimg_std::sqrt(u0*u0 + v0*v0),
19383             u1 = x1 - x,
19384             v1 = y1 - y,
19385             n1 = 1e-8f + (float)cimg_std::sqrt(u1*u1 + v1*v1),
19386             u = u0/n0 + u1/n1,
19387             v = v0/n0 + v1/n1,
19388             n = 1e-8f + (float)cimg_std::sqrt(u*u + v*v),
19389             fact = 0.5f*(n0 + n1);
19390           tangents(p,0) = (Tfloat)(fact*u/n);
19391           tangents(p,1) = (Tfloat)(fact*v/n);
19392         }
19393       } break;
19394       default : {
19395         tangents.assign(W,H);
19396         for (unsigned int p = 0; p<W; ++p) {
19397           const unsigned int
19398             p0 = close_set?(p+W-1)%W:(p?p-1:0),
19399             p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
19400           const float
19401             x = (float)points(p,0),
19402             y = (float)points(p,1),
19403             z = (float)points(p,2),
19404             x0 = (float)points(p0,0),
19405             y0 = (float)points(p0,1),
19406             z0 = (float)points(p0,2),
19407             x1 = (float)points(p1,0),
19408             y1 = (float)points(p1,1),
19409             z1 = (float)points(p1,2),
19410             u0 = x - x0,
19411             v0 = y - y0,
19412             w0 = z - z0,
19413             n0 = 1e-8f + (float)cimg_std::sqrt(u0*u0 + v0*v0 + w0*w0),
19414             u1 = x1 - x,
19415             v1 = y1 - y,
19416             w1 = z1 - z,
19417             n1 = 1e-8f + (float)cimg_std::sqrt(u1*u1 + v1*v1 + w1*w1),
19418             u = u0/n0 + u1/n1,
19419             v = v0/n0 + v1/n1,
19420             w = w0/n0 + w1/n1,
19421             n = 1e-8f + (float)cimg_std::sqrt(u*u + v*v + w*w),
19422             fact = 0.5f*(n0 + n1);
19423           tangents(p,0) = (Tfloat)(fact*u/n);
19424           tangents(p,1) = (Tfloat)(fact*v/n);
19425           tangents(p,2) = (Tfloat)(fact*w/n);
19426         }
19427       }
19428       }
19429       return _draw_spline(points,tangents,W,H,color,opacity,close_set,precision,pattern,init_hatch);
19430     }
19431 
19432     //! Draw a set of consecutive colored splines in the instance image.
19433     template<typename tp, typename tt, typename tc>
19434     CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
19435                          const tc *const color, const float opacity=1,
19436                          const bool close_set=false, const float precision=4,
19437                          const unsigned int pattern=~0U, const bool init_hatch=true) {
19438       unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()),(unsigned int)(tangents[p].size()));
19439       return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.size,H);
19440     }
19441 
19442     //! Draw a set of consecutive colored splines in the instance image.
19443     template<typename tp, typename tt, typename tc>
19444     CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
19445                          const CImg<tc>& color, const float opacity=1,
19446                          const bool close_set=false, const float precision=4,
19447                          const unsigned int pattern=~0U, const bool init_hatch=true) {
19448       return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
19449     }
19450 
19451     //! Draw a set of consecutive colored splines in the instance image.
19452     template<typename tp, typename tt, typename tc>
19453     CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
19454                          const tc *const color, const float opacity=1,
19455                          const bool close_set=false, const float precision=4,
19456                          const unsigned int pattern=~0U, const bool init_hatch=true) {
19457       return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
19458     }
19459 
19460     //! Draw a set of consecutive colored splines in the instance image.
19461     template<typename tp, typename tt, typename tc>
19462     CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
19463                          const CImg<tc>& color, const float opacity=1,
19464                          const bool close_set=false, const float precision=4,
19465                          const unsigned int pattern=~0U, const bool init_hatch=true) {
19466       return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
19467     }
19468 
19469     //! Draw a set of consecutive colored splines in the instance image.
19470     template<typename t, typename tc>
19471     CImg<T>& draw_spline(const CImgList<t>& points,
19472                          const tc *const color, const float opacity=1,
19473                          const bool close_set=false, const float precision=4,
19474                          const unsigned int pattern=~0U, const bool init_hatch=true) {
19475       unsigned int H = ~0U;
19476       cimglist_for(points,p) { const unsigned int s = points[p].size(); if (s<H) H = s; }
19477       return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.size,H);
19478     }
19479 
19480     //! Draw a set of consecutive colored splines in the instance image.
19481     template<typename t, typename tc>
19482     CImg<T>& draw_spline(const CImgList<t>& points,
19483                          CImg<tc>& color, const float opacity=1,
19484                          const bool close_set=false, const float precision=4,
19485                          const unsigned int pattern=~0U, const bool init_hatch=true) {
19486       return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
19487     }
19488 
19489     //! Draw a set of consecutive colored lines in the instance image.
19490     template<typename t, typename tc>
19491     CImg<T>& draw_spline(const CImg<t>& points,
19492                          const tc *const color, const float opacity=1,
19493                          const bool close_set=false, const float precision=4,
19494                          const unsigned int pattern=~0U, const bool init_hatch=true) {
19495       return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
19496     }
19497 
19498     //! Draw a set of consecutive colored lines in the instance image.
19499     template<typename t, typename tc>
19500     CImg<T>& draw_spline(const CImg<t>& points,
19501                          const CImg<tc>& color, const float opacity=1,
19502                          const bool close_set=false, const float precision=4,
19503                          const unsigned int pattern=~0U, const bool init_hatch=true) {
19504       return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
19505     }
19506 
19507     //! Draw a colored arrow in the instance image.
19508     /**
19509        \param x0 X-coordinate of the starting arrow point (tail).
19510        \param y0 Y-coordinate of the starting arrow point (tail).
19511        \param x1 X-coordinate of the ending arrow point (head).
19512        \param y1 Y-coordinate of the ending arrow point (head).
19513        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
19514        \param angle Aperture angle of the arrow head (optional).
19515        \param length Length of the arrow head. If negative, describes a percentage of the arrow length (optional).
19516        \param opacity Drawing opacity (optional).
19517        \param pattern An integer whose bits describe the line pattern (optional).
19518        \note
19519        - Clipping is supported.
19520     **/
19521     template<typename tc>
19522     CImg<T>& draw_arrow(const int x0, const int y0,
19523                         const int x1, const int y1,
19524                         const tc *const color, const float opacity=1,
19525                         const float angle=30, const float length=-10,
19526                         const unsigned int pattern=~0U) {
19527       if (is_empty()) return *this;
19528       const float u = (float)(x0 - x1), v = (float)(y0 - y1), sq = u*u + v*v,
19529         deg = (float)(angle*cimg::valuePI/180), ang = (sq>0)?(float)cimg_std::atan2(v,u):0.0f,
19530         l = (length>=0)?length:-length*(float)cimg_std::sqrt(sq)/100;
19531       if (sq>0) {
19532         const float
19533             cl = (float)cimg_std::cos(ang - deg), sl = (float)cimg_std::sin(ang - deg),
19534             cr = (float)cimg_std::cos(ang + deg), sr = (float)cimg_std::sin(ang + deg);
19535         const int
19536           xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl),
19537           xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr),
19538           xc = x1 + (int)((l+1)*(cl+cr))/2, yc = y1 + (int)((l+1)*(sl+sr))/2;
19539         draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);
19540       } else draw_point(x0,y0,color,opacity);
19541       return *this;
19542     }
19543 
19544     //! Draw a colored arrow in the instance image.
19545     template<typename tc>
19546     CImg<T>& draw_arrow(const int x0, const int y0,
19547                         const int x1, const int y1,
19548                         const CImg<tc>& color, const float opacity=1,
19549                         const float angle=30, const float length=-10,
19550                         const unsigned int pattern=~0U) {
19551       return draw_arrow(x0,y0,x1,y1,color.data,opacity,angle,length,pattern);
19552     }
19553 
19554     //! Draw an image.
19555     /**
19556        \param sprite Sprite image.
19557        \param x0 X-coordinate of the sprite position.
19558        \param y0 Y-coordinate of the sprite position.
19559        \param z0 Z-coordinate of the sprite position.
19560        \param v0 V-coordinate of the sprite position.
19561        \param opacity Drawing opacity (optional).
19562        \note
19563        - Clipping is supported.
19564     **/
19565     template<typename t>
19566     CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
19567                         const CImg<t>& sprite, const float opacity=1) {
19568       if (is_empty()) return *this;
19569       if (!sprite)
19570         throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
19571                                     pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
19572       if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
19573       const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
19574       const int
19575         lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
19576         lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
19577         lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
19578         lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
19579       const t
19580         *ptrs = sprite.data -
19581         (bx?x0:0) -
19582         (by?y0*sprite.dimx():0) -
19583         (bz?z0*sprite.dimx()*sprite.dimy():0) -
19584         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
19585       const unsigned int
19586         offX = width - lX,                soffX = sprite.width - lX,
19587         offY = width*(height - lY),       soffY = sprite.width*(sprite.height - lY),
19588         offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
19589       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
19590       if (lX>0 && lY>0 && lZ>0 && lV>0) {
19591         T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
19592         for (int v = 0; v<lV; ++v) {
19593           for (int z = 0; z<lZ; ++z) {
19594             for (int y = 0; y<lY; ++y) {
19595               if (opacity>=1) for (int x = 0; x<lX; ++x) *(ptrd++) = (T)*(ptrs++);
19596               else for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
19597               ptrd+=offX; ptrs+=soffX;
19598             }
19599             ptrd+=offY; ptrs+=soffY;
19600           }
19601           ptrd+=offZ; ptrs+=soffZ;
19602         }
19603       }
19604       return *this;
19605     }
19606 
19607 #ifndef cimg_use_visualcpp6
19608     // Optimized version (internal).
19609     CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
19610                         const CImg<T>& sprite, const float opacity=1) {
19611       if (is_empty()) return *this;
19612       if (!sprite)
19613         throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
19614                                     pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
19615       if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
19616       const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
19617       const int
19618         lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
19619         lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
19620         lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
19621         lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
19622       const T
19623         *ptrs = sprite.data -
19624         (bx?x0:0) -
19625         (by?y0*sprite.dimx():0) -
19626         (bz?z0*sprite.dimx()*sprite.dimy():0) -
19627         (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
19628       const unsigned int
19629         offX = width - lX,                soffX = sprite.width - lX,
19630         offY = width*(height - lY),       soffY = sprite.width*(sprite.height - lY),
19631         offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ),
19632         slX = lX*sizeof(T);
19633       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
19634       if (lX>0 && lY>0 && lZ>0 && lV>0) {
19635         T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
19636         for (int v = 0; v<lV; ++v) {
19637           for (int z = 0; z<lZ; ++z) {
19638             if (opacity>=1) for (int y = 0; y<lY; ++y) { cimg_std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; }
19639             else for (int y = 0; y<lY; ++y) {
19640               for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
19641               ptrd+=offX; ptrs+=soffX;
19642             }
19643             ptrd+=offY; ptrs+=soffY;
19644           }
19645           ptrd+=offZ; ptrs+=soffZ;
19646         }
19647       }
19648       return *this;
19649     }
19650 #endif
19651 
19652     //! Draw an image.
19653     template<typename t>
19654     CImg<T>& draw_image(const int x0, const int y0, const int z0,
19655                         const CImg<t>& sprite, const float opacity=1) {
19656       return draw_image(x0,y0,z0,0,sprite,opacity);
19657     }
19658 
19659     //! Draw an image.
19660     template<typename t>
19661     CImg<T>& draw_image(const int x0, const int y0,
19662                         const CImg<t>& sprite, const float opacity=1) {
19663       return draw_image(x0,y0,0,sprite,opacity);
19664     }
19665 
19666     //! Draw an image.
19667     template<typename t>
19668     CImg<T>& draw_image(const int x0,
19669                         const CImg<t>& sprite, const float opacity=1) {
19670       return draw_image(x0,0,sprite,opacity);
19671     }
19672 
19673     //! Draw an image.
19674     template<typename t>
19675     CImg<T>& draw_image(const CImg<t>& sprite, const float opacity=1) {
19676       return draw_image(0,sprite,opacity);
19677     }
19678 
19679     //! Draw a sprite image in the instance image (masked version).
19680     /**
19681        \param sprite Sprite image.
19682        \param mask Mask image.
19683        \param x0 X-coordinate of the sprite position in the instance image.
19684        \param y0 Y-coordinate of the sprite position in the instance image.
19685        \param z0 Z-coordinate of the sprite position in the instance image.
19686        \param v0 V-coordinate of the sprite position in the instance image.
19687        \param mask_valmax Maximum pixel value of the mask image \c mask (optional).
19688        \param opacity Drawing opacity.
19689        \note
19690        - Pixel values of \c mask set the opacity of the corresponding pixels in \c sprite.
19691        - Clipping is supported.
19692        - Dimensions along x,y and z of \p sprite and \p mask must be the same.
19693     **/
19694     template<typename ti, typename tm>
19695     CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
19696                         const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
19697                         const float mask_valmax=1) {
19698       if (is_empty()) return *this;
19699       if (!sprite)
19700         throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
19701                                     pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
19702       if (!mask)
19703         throw CImgArgumentException("CImg<%s>::draw_image() : Specified mask image (%u,%u,%u,%u,%p) is empty.",
19704                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
19705       if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,mask,opacity,mask_valmax);
19706       if (is_overlapped(mask))   return draw_image(x0,y0,z0,v0,sprite,+mask,opacity,mask_valmax);
19707       if (mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
19708         throw CImgArgumentException("CImg<%s>::draw_image() : Mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)",
19709                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim);
19710       const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
19711       const int
19712         lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
19713         lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
19714         lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
19715         lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
19716       const int
19717         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),
19718         ssize = mask.dimx()*mask.dimy()*mask.dimz();
19719       const ti *ptrs = sprite.data + coff;
19720       const tm *ptrm = mask.data   + coff;
19721       const unsigned int
19722         offX = width - lX,                soffX = sprite.width - lX,
19723         offY = width*(height - lY),       soffY = sprite.width*(sprite.height - lY),
19724         offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
19725       if (lX>0 && lY>0 && lZ>0 && lV>0) {
19726         T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
19727         for (int v = 0; v<lV; ++v) {
19728           ptrm = mask.data + (ptrm - mask.data)%ssize;
19729           for (int z = 0; z<lZ; ++z) {
19730             for (int y = 0; y<lY; ++y) {
19731               for (int x=0; x<lX; ++x) {
19732                 const float mopacity = (float)(*(ptrm++)*opacity),
19733                   nopacity = cimg::abs(mopacity), copacity = mask_valmax - cimg::max(mopacity,0);
19734                 *ptrd = (T)((nopacity*(*(ptrs++)) + *ptrd*copacity)/mask_valmax);
19735                 ++ptrd;
19736               }
19737               ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
19738             }
19739             ptrd+=offY; ptrs+=soffY; ptrm+=soffY;
19740           }
19741           ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;
19742         }
19743       }
19744       return *this;
19745     }
19746 
19747     //! Draw an image.
19748     template<typename ti, typename tm>
19749     CImg<T>& draw_image(const int x0, const int y0, const int z0,
19750                         const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
19751                         const float mask_valmax=1) {
19752       return draw_image(x0,y0,z0,0,sprite,mask,opacity,mask_valmax);
19753     }
19754 
19755     //! Draw an image.
19756     template<typename ti, typename tm>
19757     CImg<T>& draw_image(const int x0, const int y0,
19758                         const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
19759                         const float mask_valmax=1) {
19760       return draw_image(x0,y0,0,sprite,mask,opacity,mask_valmax);
19761     }
19762 
19763     //! Draw an image.
19764     template<typename ti, typename tm>
19765     CImg<T>& draw_image(const int x0,
19766                         const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
19767                         const float mask_valmax=1) {
19768       return draw_image(x0,0,sprite,mask,opacity,mask_valmax);
19769     }
19770 
19771     //! Draw an image.
19772     template<typename ti, typename tm>
19773     CImg<T>& draw_image(const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
19774                         const float mask_valmax=1) {
19775       return draw_image(0,sprite,mask,opacity,mask_valmax);
19776     }
19777 
19778     //! 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).
19779     /**
19780        \param x0 X-coordinate of the upper-left rectangle corner.
19781        \param y0 Y-coordinate of the upper-left rectangle corner.
19782        \param z0 Z-coordinate of the upper-left rectangle corner.
19783        \param v0 V-coordinate of the upper-left rectangle corner.
19784        \param x1 X-coordinate of the lower-right rectangle corner.
19785        \param y1 Y-coordinate of the lower-right rectangle corner.
19786        \param z1 Z-coordinate of the lower-right rectangle corner.
19787        \param v1 V-coordinate of the lower-right rectangle corner.
19788        \param val Scalar value used to fill the rectangle area.
19789        \param opacity Drawing opacity (optional).
19790        \note
19791        - Clipping is supported.
19792     **/
19793     CImg<T>& draw_rectangle(const int x0, const int y0, const int z0, const int v0,
19794                             const int x1, const int y1, const int z1, const int v1,
19795                             const T val, const float opacity=1) {
19796       if (is_empty()) return *this;
19797       const bool bx = (x0<x1), by = (y0<y1), bz = (z0<z1), bv = (v0<v1);
19798       const int
19799         nx0 = bx?x0:x1, nx1 = bx?x1:x0,
19800         ny0 = by?y0:y1, ny1 = by?y1:y0,
19801         nz0 = bz?z0:z1, nz1 = bz?z1:z0,
19802         nv0 = bv?v0:v1, nv1 = bv?v1:v0;
19803       const int
19804         lX = (1 + nx1 - nx0) + (nx1>=dimx()?dimx() - 1 - nx1:0) + (nx0<0?nx0:0),
19805         lY = (1 + ny1 - ny0) + (ny1>=dimy()?dimy() - 1 - ny1:0) + (ny0<0?ny0:0),
19806         lZ = (1 + nz1 - nz0) + (nz1>=dimz()?dimz() - 1 - nz1:0) + (nz0<0?nz0:0),
19807         lV = (1 + nv1 - nv0) + (nv1>=dimv()?dimv() - 1 - nv1:0) + (nv0<0?nv0:0);
19808       const unsigned int offX = width - lX, offY = width*(height - lY), offZ = width*height*(depth - lZ);
19809       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
19810       T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0);
19811       if (lX>0 && lY>0 && lZ>0 && lV>0)
19812         for (int v = 0; v<lV; ++v) {
19813           for (int z = 0; z<lZ; ++z) {
19814             for (int y = 0; y<lY; ++y) {
19815               if (opacity>=1) {
19816                 if (sizeof(T)!=1) { for (int x = 0; x<lX; ++x) *(ptrd++) = val; ptrd+=offX; }
19817                 else { cimg_std::memset(ptrd,(int)val,lX); ptrd+=width; }
19818               } else { for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*val + *ptrd*copacity); ++ptrd; } ptrd+=offX; }
19819             }
19820             ptrd+=offY;
19821           }
19822           ptrd+=offZ;
19823         }
19824       return *this;
19825     }
19826 
19827     //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1).
19828     /**
19829        \param x0 X-coordinate of the upper-left rectangle corner.
19830        \param y0 Y-coordinate of the upper-left rectangle corner.
19831        \param z0 Z-coordinate of the upper-left rectangle corner.
19832        \param x1 X-coordinate of the lower-right rectangle corner.
19833        \param y1 Y-coordinate of the lower-right rectangle corner.
19834        \param z1 Z-coordinate of the lower-right rectangle corner.
19835        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
19836        \param opacity Drawing opacity (optional).
19837        \note
19838        - Clipping is supported.
19839     **/
19840     template<typename tc>
19841     CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
19842                             const int x1, const int y1, const int z1,
19843                             const tc *const color, const float opacity=1) {
19844       if (!color)
19845         throw CImgArgumentException("CImg<%s>::draw_rectangle : specified color is (null)",
19846                                     pixel_type());
19847       cimg_forV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity);
19848       return *this;
19849     }
19850 
19851     //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1).
19852     template<typename tc>
19853     CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
19854                             const int x1, const int y1, const int z1,
19855                             const CImg<tc>& color, const float opacity=1) {
19856       return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity);
19857     }
19858 
19859     //! Draw a 3D outlined colored rectangle in the instance image.
19860     template<typename tc>
19861     CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
19862                             const int x1, const int y1, const int z1,
19863                             const tc *const color, const float opacity,
19864                             const unsigned int pattern) {
19865       return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true).
19866         draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false).
19867         draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false).
19868         draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false).
19869         draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true).
19870         draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false).
19871         draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false).
19872         draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false).
19873         draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true).
19874         draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true).
19875         draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true).
19876         draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true);
19877     }
19878 
19879     //! Draw a 3D outlined colored rectangle in the instance image.
19880     template<typename tc>
19881     CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
19882                             const int x1, const int y1, const int z1,
19883                             const CImg<tc>& color, const float opacity,
19884                             const unsigned int pattern) {
19885       return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern);
19886     }
19887 
19888     //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
19889     /**
19890        \param x0 X-coordinate of the upper-left rectangle corner.
19891        \param y0 Y-coordinate of the upper-left rectangle corner.
19892        \param x1 X-coordinate of the lower-right rectangle corner.
19893        \param y1 Y-coordinate of the lower-right rectangle corner.
19894        \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
19895        \param opacity Drawing opacity (optional).
19896        \note
19897        - Clipping is supported.
19898     **/
19899     template<typename tc>
19900     CImg<T>& draw_rectangle(const int x0, const int y0,
19901                             const int x1, const int y1,
19902                             const tc *const color, const float opacity=1) {
19903       return draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity);
19904     }
19905 
19906     //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
19907     template<typename tc>
19908     CImg<T>& draw_rectangle(const int x0, const int y0,
19909                             const int x1, const int y1,
19910                             const CImg<tc>& color, const float opacity=1) {
19911       return draw_rectangle(x0,y0,x1,y1,color.data,opacity);
19912     }
19913 
19914     //! Draw a 2D outlined colored rectangle.
19915     template<typename tc>
19916     CImg<T>& draw_rectangle(const int x0, const int y0,
19917                             const int x1, const int y1,
19918                             const tc *const color, const float opacity,
19919                             const unsigned int pattern) {
19920       if (is_empty()) return *this;
19921       if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true);
19922       if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true);
19923       const bool bx = (x0<x1), by = (y0<y1);
19924       const int
19925         nx0 = bx?x0:x1, nx1 = bx?x1:x0,
19926         ny0 = by?y0:y1, ny1 = by?y1:y0;
19927       if (ny1==ny0+1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
19928                       draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false);
19929       return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
19930         draw_line(nx1,ny0+1,nx1,ny1-1,color,opacity,pattern,false).
19931         draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false).
19932         draw_line(nx0,ny1-1,nx0,ny0+1,color,opacity,pattern,false);
19933     }
19934 
19935     //! Draw a 2D outlined colored rectangle.
19936     template<typename tc>
19937     CImg<T>& draw_rectangle(const int x0, const int y0,
19938                             const int x1, const int y1,
19939                             const CImg<tc>& color, const float opacity,
19940                             const unsigned int pattern) {
19941       return draw_rectangle(x0,y0,x1,y1,color.data,opacity,pattern);
19942     }
19943 
19944     // Inner macro for drawing triangles.
19945 #define _cimg_for_triangle1(img,xl,xr,y,x0,y0,x1,y1,x2,y2) \
19946         for (int y = y0<0?0:y0, \
19947                xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
19948                xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
19949                _sxn=1, \
19950                _sxr=1, \
19951                _sxl=1, \
19952                _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
19953                _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
19954                _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
19955                _dyn = y2-y1, \
19956                _dyr = y2-y0, \
19957                _dyl = y1-y0, \
19958                _counter = (_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
19959                            _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
19960                            _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
19961                            cimg::min((int)(img).height-y-1,y2-y)), \
19962                _errn = _dyn/2, \
19963                _errr = _dyr/2, \
19964                _errl = _dyl/2, \
19965                _rxn = _dyn?(x2-x1)/_dyn:0, \
19966                _rxr = _dyr?(x2-x0)/_dyr:0, \
19967                _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
19968                                        (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn); \
19969              _counter>=0; --_counter, ++y, \
19970                xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
19971                xl+=(y!=y1)?_rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0): \
19972                            (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
19973 
19974 #define _cimg_for_triangle2(img,xl,cl,xr,cr,y,x0,y0,c0,x1,y1,c1,x2,y2,c2) \
19975         for (int y = y0<0?0:y0, \
19976                xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
19977                cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
19978                xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
19979                cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
19980                _sxn=1, _scn=1, \
19981                _sxr=1, _scr=1, \
19982                _sxl=1, _scl=1, \
19983                _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
19984                _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
19985                _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
19986                _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
19987                _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
19988                _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
19989                _dyn = y2-y1, \
19990                _dyr = y2-y0, \
19991                _dyl = y1-y0, \
19992                _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
19993                           _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
19994                           _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
19995                           _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
19996                           _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
19997                           _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
19998                           cimg::min((int)(img).height-y-1,y2-y)), \
19999                _errn = _dyn/2, _errcn = _errn, \
20000                _errr = _dyr/2, _errcr = _errr, \
20001                _errl = _dyl/2, _errcl = _errl, \
20002                _rxn = _dyn?(x2-x1)/_dyn:0, \
20003                _rcn = _dyn?(c2-c1)/_dyn:0, \
20004                _rxr = _dyr?(x2-x0)/_dyr:0, \
20005                _rcr = _dyr?(c2-c0)/_dyr:0, \
20006                _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
20007                                        (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
20008                _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
20009                                        (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ); \
20010              _counter>=0; --_counter, ++y, \
20011                xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
20012                cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
20013                xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
20014                            _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
20015                (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
20016                 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
20017 
20018 #define _cimg_for_triangle3(img,xl,txl,tyl,xr,txr,tyr,y,x0,y0,tx0,ty0,x1,y1,tx1,ty1,x2,y2,tx2,ty2) \
20019         for (int y = y0<0?0:y0, \
20020                xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
20021                txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
20022                tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
20023                xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
20024                txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
20025                tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
20026                _sxn=1, _stxn=1, _styn=1, \
20027                _sxr=1, _stxr=1, _styr=1, \
20028                _sxl=1, _stxl=1, _styl=1, \
20029                _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
20030                _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
20031                _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
20032                _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
20033                _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
20034                _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
20035                _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
20036                _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
20037                _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
20038                _dyn = y2-y1, \
20039                _dyr = y2-y0, \
20040                _dyl = y1-y0, \
20041                _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
20042                           _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
20043                           _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
20044                           _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
20045                           _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
20046                           _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
20047                           _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
20048                           _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
20049                           _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
20050                           cimg::min((int)(img).height-y-1,y2-y)), \
20051                _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, \
20052                _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, \
20053                _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, \
20054                _rxn = _dyn?(x2-x1)/_dyn:0, \
20055                _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
20056                _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
20057                _rxr = _dyr?(x2-x0)/_dyr:0, \
20058                _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
20059                _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
20060                _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
20061                                        (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
20062                _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
20063                                        (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
20064                _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
20065                                        (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
20066              _counter>=0; --_counter, ++y, \
20067                xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
20068                txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
20069                tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
20070                xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
20071                             tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
20072                            _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
20073                (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
20074                 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1,\
20075                 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
20076 
20077 #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) \
20078         for (int y = y0<0?0:y0, \
20079                xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
20080                cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
20081                txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
20082                tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
20083                xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
20084                cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
20085                txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
20086                tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
20087                _sxn=1, _scn=1, _stxn=1, _styn=1, \
20088                _sxr=1, _scr=1, _stxr=1, _styr=1, \
20089                _sxl=1, _scl=1, _stxl=1, _styl=1, \
20090                _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
20091                _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
20092                _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
20093                _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
20094                _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
20095                _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
20096                _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
20097                _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
20098                _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
20099                _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
20100                _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
20101                _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
20102                _dyn = y2-y1, \
20103                _dyr = y2-y0, \
20104                _dyl = y1-y0, \
20105                _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
20106                           _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
20107                           _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
20108                           _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
20109                           _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
20110                           _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
20111                           _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
20112                           _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
20113                           _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
20114                           _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
20115                           _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
20116                           _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
20117                           cimg::min((int)(img).height-y-1,y2-y)), \
20118                _errn = _dyn/2, _errcn = _errn, _errtxn = _errn, _errtyn = _errn, \
20119                _errr = _dyr/2, _errcr = _errr, _errtxr = _errr, _errtyr = _errr, \
20120                _errl = _dyl/2, _errcl = _errl, _errtxl = _errl, _errtyl = _errl, \
20121                _rxn = _dyn?(x2-x1)/_dyn:0, \
20122                _rcn = _dyn?(c2-c1)/_dyn:0, \
20123                _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
20124                _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
20125                _rxr = _dyr?(x2-x0)/_dyr:0, \
20126                _rcr = _dyr?(c2-c0)/_dyr:0, \
20127                _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
20128                _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
20129                _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
20130                                        (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
20131                _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
20132                                        (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ), \
20133                _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
20134                                         (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
20135                _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
20136                                         (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
20137              _counter>=0; --_counter, ++y, \
20138                xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
20139                cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
20140                txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
20141                tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
20142                xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
20143                             txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
20144                             tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
20145                             _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
20146                (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
20147                 _errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
20148                 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
20149                 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
20150 
20151 #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) \
20152         for (int y = y0<0?0:y0, \
20153                xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
20154                txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
20155                tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
20156                lxr = y0>=0?lx0:(lx0-y0*(lx2-lx0)/(y2-y0)), \
20157                lyr = y0>=0?ly0:(ly0-y0*(ly2-ly0)/(y2-y0)), \
20158                xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
20159                txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
20160                tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
20161                lxl = y1>=0?(y0>=0?(y0==y1?lx1:lx0):(lx0-y0*(lx1-lx0)/(y1-y0))):(lx1-y1*(lx2-lx1)/(y2-y1)), \
20162                lyl = y1>=0?(y0>=0?(y0==y1?ly1:ly0):(ly0-y0*(ly1-ly0)/(y1-y0))):(ly1-y1*(ly2-ly1)/(y2-y1)), \
20163                _sxn=1, _stxn=1, _styn=1, _slxn=1, _slyn=1, \
20164                _sxr=1, _stxr=1, _styr=1, _slxr=1, _slyr=1, \
20165                _sxl=1, _stxl=1, _styl=1, _slxl=1, _slyl=1, \
20166                _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), _dyn = y2-y1, \
20167                _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), _dyr = y2-y0, \
20168                _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), _dyl = y1-y0, \
20169                _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
20170                _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
20171                _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
20172                _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
20173                _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
20174                _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
20175                _dlxn = lx2>lx1?lx2-lx1:(_slxn=-1,lx1-lx2), \
20176                _dlxr = lx2>lx0?lx2-lx0:(_slxr=-1,lx0-lx2), \
20177                _dlxl = lx1>lx0?lx1-lx0:(_slxl=-1,lx0-lx1), \
20178                _dlyn = ly2>ly1?ly2-ly1:(_slyn=-1,ly1-ly2), \
20179                _dlyr = ly2>ly0?ly2-ly0:(_slyr=-1,ly0-ly2), \
20180                _dlyl = ly1>ly0?ly1-ly0:(_slyl=-1,ly0-ly1), \
20181                _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
20182                           _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
20183                           _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
20184                           _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
20185                           _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
20186                           _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
20187                           _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
20188                           _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
20189                           _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
20190                           _dlxn-=_dyn?_dyn*(_dlxn/_dyn):0, \
20191                           _dlxr-=_dyr?_dyr*(_dlxr/_dyr):0, \
20192                           _dlxl-=_dyl?_dyl*(_dlxl/_dyl):0, \
20193                           _dlyn-=_dyn?_dyn*(_dlyn/_dyn):0, \
20194                           _dlyr-=_dyr?_dyr*(_dlyr/_dyr):0, \
20195                           _dlyl-=_dyl?_dyl*(_dlyl/_dyl):0, \
20196                           cimg::min((int)(img).height-y-1,y2-y)), \
20197                _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, _errlxn = _errn, _errlyn = _errn, \
20198                _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, _errlxr = _errr, _errlyr = _errr, \
20199                _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, _errlxl = _errl, _errlyl = _errl, \
20200                _rxn = _dyn?(x2-x1)/_dyn:0, \
20201                _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
20202                _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
20203                _rlxn = _dyn?(lx2-lx1)/_dyn:0, \
20204                _rlyn = _dyn?(ly2-ly1)/_dyn:0, \
20205                _rxr = _dyr?(x2-x0)/_dyr:0, \
20206                _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
20207                _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
20208                _rlxr = _dyr?(lx2-lx0)/_dyr:0, \
20209                _rlyr = _dyr?(ly2-ly0)/_dyr:0, \
20210                _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
20211                                        (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
20212                _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
20213                                         (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
20214                _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
20215                                         (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ), \
20216                _rlxl = (y0!=y1 && y1>0)?(_dyl?(lx1-lx0)/_dyl:0): \
20217                                         (_errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxn ), \
20218                _rlyl = (y0!=y1 && y1>0)?(_dyl?(ly1-ly0)/_dyl:0): \
20219                                         (_errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyn ); \
20220              _counter>=0; --_counter, ++y, \
20221                xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
20222                txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
20223                tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
20224                lxr+=_rlxr+((_errlxr-=_dlxr)<0?_errlxr+=_dyr,_slxr:0), \
20225                lyr+=_rlyr+((_errlyr-=_dlyr)<0?_errlyr+=_dyr,_slyr:0), \
20226                xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
20227                             tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
20228                             lxl+=_rlxl+((_errlxl-=_dlxl)<0?(_errlxl+=_dyl,_slxl):0), \
20229                             lyl+=_rlyl+((_errlyl-=_dlyl)<0?(_errlyl+=_dyl,_slyl):0), \
20230                             _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
20231                (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
20232                 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
20233                 _errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxl=_rlxn, lxl=lx1, \
20234                 _errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyl=_rlyn, lyl=ly1, \
20235                 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
20236 
20237     // Draw a colored triangle (inner routine, uses bresenham's algorithm).
20238     template<typename tc>
20239     CImg<T>& _draw_triangle(const int x0, const int y0,
20240                             const int x1, const int y1,
20241                             const int x2, const int y2,
20242                             const tc *const color, const float opacity,
20243                             const float brightness) {
20244       _draw_scanline(color,opacity);
20245       const float nbrightness = brightness<0?0:(brightness>2?2:brightness);
20246       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
20247       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
20248       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);
20249       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);
20250       if (ny0<dimy() && ny2>=0) {
20251         if ((nx1 - nx0)*(ny2 - ny0) - (nx2 - nx0)*(ny1 - ny0)<0)
20252           _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xl,xr,y,color,opacity,nbrightness);
20253         else
20254           _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xr,xl,y,color,opacity,nbrightness);
20255       }
20256       return *this;
20257     }
20258 
20259     //! Draw a 2D filled colored triangle.
20260     template<typename tc>
20261     CImg<T>& draw_triangle(const int x0, const int y0,
20262                            const int x1, const int y1,
20263                            const int x2, const int y2,
20264                            const tc *const color, const float opacity=1) {
20265       if (is_empty()) return *this;
20266       if (!color)
20267         throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
20268                                     pixel_type());
20269       _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1);
20270       return *this;
20271     }
20272 
20273     //! Draw a 2D filled colored triangle.
20274     template<typename tc>
20275     CImg<T>& draw_triangle(const int x0, const int y0,
20276                            const int x1, const int y1,
20277                            const int x2, const int y2,
20278                            const CImg<tc>& color, const float opacity=1) {
20279       return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity);
20280     }
20281 
20282     //! Draw a 2D outlined colored triangle.
20283     template<typename tc>
20284     CImg<T>& draw_triangle(const int x0, const int y0,
20285                            const int x1, const int y1,
20286                            const int x2, const int y2,
20287                            const tc *const color, const float opacity,
20288                            const unsigned int pattern) {
20289       if (is_empty()) return *this;
20290       if (!color)
20291         throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
20292                                     pixel_type());
20293       draw_line(x0,y0,x1,y1,color,opacity,pattern,true).
20294         draw_line(x1,y1,x2,y2,color,opacity,pattern,false).
20295         draw_line(x2,y2,x0,y0,color,opacity,pattern,false);
20296       return *this;
20297     }
20298 
20299     //! Draw a 2D outlined colored triangle.
20300     template<typename tc>
20301     CImg<T>& draw_triangle(const int x0, const int y0,
20302                            const int x1, const int y1,
20303                            const int x2, const int y2,
20304                            const CImg<tc>& color, const float opacity,
20305                            const unsigned int pattern) {
20306       return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity,pattern);
20307     }
20308 
20309     //! Draw a 2D filled colored triangle, with z-buffering.
20310     template<typename tc>
20311     CImg<T>& draw_triangle(float *const zbuffer,
20312                            const int x0, const int y0, const float z0,
20313                            const int x1, const int y1, const float z1,
20314                            const int x2, const int y2, const float z2,
20315                            const tc *const color, const float opacity=1,
20316                            const float brightness=1) {
20317       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
20318       if (!color)
20319         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
20320                                     pixel_type());
20321       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20322       const float
20323         nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
20324         nbrightness = brightness<0?0:(brightness>2?2:brightness);
20325       const int whz = width*height*depth, offx = dim*whz;
20326       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
20327       float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
20328       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
20329       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2);
20330       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2);
20331       if (ny0>=dimy() || ny2<0) return *this;
20332       float
20333         pzl = (nz1 - nz0)/(ny1 - ny0),
20334         pzr = (nz2 - nz0)/(ny2 - ny0),
20335         pzn = (nz2 - nz1)/(ny2 - ny1),
20336         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
20337         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
20338       _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
20339         if (y==ny1) { zl = nz1; pzl = pzn; }
20340         int xleft = xleft0, xright = xright0;
20341         float zleft = zl, zright = zr;
20342         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright);
20343         const int dx = xright - xleft;
20344         const float pentez = (zright - zleft)/dx;
20345         if (xleft<0 && dx) zleft-=xleft*(zright - zleft)/dx;
20346         if (xleft<0) xleft = 0;
20347         if (xright>=dimx()-1) xright = dimx()-1;
20348         T* ptrd = ptr(xleft,y,0,0);
20349         float *ptrz = zbuffer + xleft + y*width;
20350         if (opacity>=1) {
20351           if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20352             if (zleft>*ptrz) {
20353               *ptrz = zleft;
20354               const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
20355               ptrd-=offx;
20356             }
20357             zleft+=pentez;
20358           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20359             if (zleft>*ptrz) {
20360               *ptrz = zleft;
20361               const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nbrightness*(*col++)); ptrd+=whz; }
20362               ptrd-=offx;
20363             }
20364             zleft+=pentez;
20365           } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20366             if (zleft>*ptrz) {
20367               *ptrz = zleft;
20368               const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); ptrd+=whz; }
20369               ptrd-=offx;
20370             }
20371             zleft+=pentez;
20372           }
20373         } else {
20374           if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20375             if (zleft>*ptrz) {
20376               *ptrz = zleft;
20377               const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=whz; }
20378               ptrd-=offx;
20379             }
20380             zleft+=pentez;
20381           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20382             if (zleft>*ptrz) {
20383               *ptrz = zleft;
20384               const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity*nbrightness**(col++) + *ptrd*copacity); ptrd+=whz; }
20385               ptrd-=offx;
20386             }
20387             zleft+=pentez;
20388           } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20389             if (zleft>*ptrz) {
20390               *ptrz = zleft;
20391               const tc *col = color;
20392               cimg_forV(*this,k) {
20393                 const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
20394                 *ptrd = (T)(nopacity*val + *ptrd*copacity);
20395                 ptrd+=whz;
20396               }
20397               ptrd-=offx;
20398             }
20399             zleft+=pentez;
20400           }
20401         }
20402         zr+=pzr; zl+=pzl;
20403       }
20404       return *this;
20405     }
20406 
20407     //! Draw a 2D filled colored triangle, with z-buffering.
20408     template<typename tc>
20409     CImg<T>& draw_triangle(float *const zbuffer,
20410                            const int x0, const int y0, const float z0,
20411                            const int x1, const int y1, const float z1,
20412                            const int x2, const int y2, const float z2,
20413                            const CImg<tc>& color, const float opacity=1,
20414                            const float brightness=1) {
20415       return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opacity,brightness);
20416     }
20417 
20418     //! Draw a 2D Gouraud-shaded colored triangle.
20419     /**
20420        \param x0 = X-coordinate of the first corner in the instance image.
20421        \param y0 = Y-coordinate of the first corner in the instance image.
20422        \param x1 = X-coordinate of the second corner in the instance image.
20423        \param y1 = Y-coordinate of the second corner in the instance image.
20424        \param x2 = X-coordinate of the third corner in the instance image.
20425        \param y2 = Y-coordinate of the third corner in the instance image.
20426        \param color = array of dimv() values of type \c T, defining the global drawing color.
20427        \param brightness0 = brightness of the first corner (in [0,2]).
20428        \param brightness1 = brightness of the second corner (in [0,2]).
20429        \param brightness2 = brightness of the third corner (in [0,2]).
20430        \param opacity = opacity of the drawing.
20431        \note Clipping is supported.
20432     **/
20433     template<typename tc>
20434     CImg<T>& draw_triangle(const int x0, const int y0,
20435                            const int x1, const int y1,
20436                            const int x2, const int y2,
20437                            const tc *const color,
20438                            const float brightness0,
20439                            const float brightness1,
20440                            const float brightness2,
20441                            const float opacity=1) {
20442       if (is_empty()) return *this;
20443       if (!color)
20444         throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
20445                                     pixel_type());
20446       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20447       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
20448       const int whz = width*height*depth, offx = dim*whz-1;
20449       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
20450         nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
20451         nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
20452         nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
20453       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1);
20454       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2);
20455       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2);
20456       if (ny0>=dimy() || ny2<0) return *this;
20457       _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
20458         int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
20459         if (xright<xleft) cimg::swap(xleft,xright,cleft,cright);
20460         const int
20461           dx = xright - xleft,
20462           dc = cright>cleft?cright - cleft:cleft - cright,
20463           rc = dx?(cright - cleft)/dx:0,
20464           sc = cright>cleft?1:-1,
20465           ndc = dc-(dx?dx*(dc/dx):0);
20466         int errc = dx>>1;
20467         if (xleft<0 && dx) cleft-=xleft*(cright - cleft)/dx;
20468         if (xleft<0) xleft = 0;
20469         if (xright>=dimx()-1) xright = dimx()-1;
20470         T* ptrd = ptr(xleft,y);
20471         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
20472           const tc *col = color;
20473           cimg_forV(*this,k) {
20474             *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
20475             ptrd+=whz;
20476           }
20477           ptrd-=offx;
20478           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
20479         } else for (int x = xleft; x<=xright; ++x) {
20480           const tc *col = color;
20481           cimg_forV(*this,k) {
20482             const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
20483             *ptrd = (T)(nopacity*val + *ptrd*copacity);
20484             ptrd+=whz;
20485           }
20486           ptrd-=offx;
20487           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
20488         }
20489       }
20490       return *this;
20491     }
20492 
20493     //! Draw a 2D Gouraud-shaded colored triangle.
20494     template<typename tc>
20495     CImg<T>& draw_triangle(const int x0, const int y0,
20496                            const int x1, const int y1,
20497                            const int x2, const int y2,
20498                            const CImg<tc>& color,
20499                            const float brightness0,
20500                            const float brightness1,
20501                            const float brightness2,
20502                            const float opacity=1) {
20503       return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,brightness0,brightness1,brightness2,opacity);
20504     }
20505 
20506     //! Draw a 2D Gouraud-shaded colored triangle, with z-buffering.
20507     template<typename tc>
20508     CImg<T>& draw_triangle(float *const zbuffer,
20509                            const int x0, const int y0, const float z0,
20510                            const int x1, const int y1, const float z1,
20511                            const int x2, const int y2, const float z2,
20512                            const tc *const color,
20513                            const float brightness0,
20514                            const float brightness1,
20515                            const float brightness2,
20516                            const float opacity=1) {
20517       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
20518       if (!color)
20519         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
20520                                     pixel_type());
20521       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20522       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
20523       const int whz = width*height*depth, offx = dim*whz;
20524       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
20525         nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
20526         nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
20527         nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
20528       float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
20529       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1,nc0,nc1);
20530       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2,nc0,nc2);
20531       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2,nc1,nc2);
20532       if (ny0>=dimy() || ny2<0) return *this;
20533       float
20534         pzl = (nz1 - nz0)/(ny1 - ny0),
20535         pzr = (nz2 - nz0)/(ny2 - ny0),
20536         pzn = (nz2 - nz1)/(ny2 - ny1),
20537         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
20538         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
20539       _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
20540         if (y==ny1) { zl = nz1; pzl = pzn; }
20541         int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
20542         float zleft = zl, zright = zr;
20543         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,cleft,cright);
20544         const int
20545           dx = xright - xleft,
20546           dc = cright>cleft?cright - cleft:cleft - cright,
20547           rc = dx?(cright-cleft)/dx:0,
20548           sc = cright>cleft?1:-1,
20549           ndc = dc-(dx?dx*(dc/dx):0);
20550         const float pentez = (zright - zleft)/dx;
20551         int errc = dx>>1;
20552         if (xleft<0 && dx) {
20553           cleft-=xleft*(cright - cleft)/dx;
20554           zleft-=xleft*(zright - zleft)/dx;
20555         }
20556         if (xleft<0) xleft = 0;
20557         if (xright>=dimx()-1) xright = dimx()-1;
20558         T *ptrd = ptr(xleft,y);
20559         float *ptrz = zbuffer + xleft + y*width;
20560         if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
20561           if (zleft>*ptrz) {
20562             *ptrz = zleft;
20563             const tc *col = color;
20564             cimg_forV(*this,k) {
20565               *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
20566               ptrd+=whz;
20567             }
20568             ptrd-=offx;
20569           }
20570           zleft+=pentez;
20571           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
20572         } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
20573           if (zleft>*ptrz) {
20574             *ptrz = zleft;
20575             const tc *col = color;
20576             cimg_forV(*this,k) {
20577               const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
20578               *ptrd = (T)(nopacity*val + *ptrd*copacity);
20579               ptrd+=whz;
20580             }
20581             ptrd-=offx;
20582           }
20583           zleft+=pentez;
20584           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
20585         }
20586         zr+=pzr; zl+=pzl;
20587       }
20588       return *this;
20589     }
20590 
20591     //! Draw a Gouraud triangle with z-buffer consideration.
20592     template<typename tc>
20593     CImg<T>& draw_triangle(float *const zbuffer,
20594                            const int x0, const int y0, const float z0,
20595                            const int x1, const int y1, const float z1,
20596                            const int x2, const int y2, const float z2,
20597                            const CImg<tc>& color,
20598                            const float brightness0,
20599                            const float brightness1,
20600                            const float brightness2,
20601                            const float opacity=1) {
20602       return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,brightness0,brightness1,brightness2,opacity);
20603     }
20604 
20605     //! Draw a 2D textured triangle.
20606     /**
20607        \param x0 = X-coordinate of the first corner in the instance image.
20608        \param y0 = Y-coordinate of the first corner in the instance image.
20609        \param x1 = X-coordinate of the second corner in the instance image.
20610        \param y1 = Y-coordinate of the second corner in the instance image.
20611        \param x2 = X-coordinate of the third corner in the instance image.
20612        \param y2 = Y-coordinate of the third corner in the instance image.
20613        \param texture = texture image used to fill the triangle.
20614        \param tx0 = X-coordinate of the first corner in the texture image.
20615        \param ty0 = Y-coordinate of the first corner in the texture image.
20616        \param tx1 = X-coordinate of the second corner in the texture image.
20617        \param ty1 = Y-coordinate of the second corner in the texture image.
20618        \param tx2 = X-coordinate of the third corner in the texture image.
20619        \param ty2 = Y-coordinate of the third corner in the texture image.
20620        \param opacity = opacity of the drawing.
20621        \param brightness = brightness of the drawing (in [0,2]).
20622        \note Clipping is supported, but texture coordinates do not support clipping.
20623     **/
20624     template<typename tc>
20625     CImg<T>& draw_triangle(const int x0, const int y0,
20626                            const int x1, const int y1,
20627                            const int x2, const int y2,
20628                            const CImg<tc>& texture,
20629                            const int tx0, const int ty0,
20630                            const int tx1, const int ty1,
20631                            const int tx2, const int ty2,
20632                            const float opacity=1,
20633                            const float brightness=1) {
20634       if (is_empty()) return *this;
20635       if (!texture || texture.dim<dim)
20636         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
20637                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
20638       if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
20639       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20640       const float
20641         nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
20642         nbrightness = brightness<0?0:(brightness>2?2:brightness);
20643       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
20644       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
20645         ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2;
20646       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
20647       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2);
20648       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2);
20649       if (ny0>=dimy() || ny2<0) return *this;
20650       _cimg_for_triangle3(*this,xleft0,txleft0,tyleft0,xright0,txright0,tyright0,y,
20651                           nx0,ny0,ntx0,nty0,nx1,ny1,ntx1,nty1,nx2,ny2,ntx2,nty2) {
20652         int
20653           xleft = xleft0, xright = xright0,
20654           txleft = txleft0, txright = txright0,
20655           tyleft = tyleft0, tyright = tyright0;
20656         if (xright<xleft) cimg::swap(xleft,xright,txleft,txright,tyleft,tyright);
20657         const int
20658           dx = xright - xleft,
20659           dtx = txright>txleft?txright - txleft:txleft - txright,
20660           dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
20661           rtx = dx?(txright - txleft)/dx:0,
20662           rty = dx?(tyright - tyleft)/dx:0,
20663           stx = txright>txleft?1:-1,
20664           sty = tyright>tyleft?1:-1,
20665           ndtx = dtx - (dx?dx*(dtx/dx):0),
20666           ndty = dty - (dx?dx*(dty/dx):0);
20667         int errtx = dx>>1, errty = errtx;
20668         if (xleft<0 && dx) {
20669           txleft-=xleft*(txright - txleft)/dx;
20670           tyleft-=xleft*(tyright - tyleft)/dx;
20671         }
20672         if (xleft<0) xleft = 0;
20673         if (xright>=dimx()-1) xright = dimx()-1;
20674         T* ptrd = ptr(xleft,y,0,0);
20675         if (opacity>=1) {
20676           if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
20677             const tc *col = texture.ptr(txleft,tyleft);
20678             cimg_forV(*this,k) {
20679               *ptrd = (T)*col;
20680               ptrd+=whz; col+=twhz;
20681             }
20682             ptrd-=offx;
20683             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20684             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20685           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
20686             const tc *col = texture.ptr(txleft,tyleft);
20687             cimg_forV(*this,k) {
20688               *ptrd = (T)(nbrightness**col);
20689               ptrd+=whz; col+=twhz;
20690             }
20691             ptrd-=offx;
20692             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20693             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20694           } else for (int x = xleft; x<=xright; ++x) {
20695             const tc *col = texture.ptr(txleft,tyleft);
20696             cimg_forV(*this,k) {
20697               *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
20698               ptrd+=whz; col+=twhz;
20699             }
20700             ptrd-=offx;
20701             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20702             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20703           }
20704         } else {
20705           if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
20706             const tc *col = texture.ptr(txleft,tyleft);
20707             cimg_forV(*this,k) {
20708               *ptrd = (T)(nopacity**col + *ptrd*copacity);
20709               ptrd+=whz; col+=twhz;
20710             }
20711             ptrd-=offx;
20712             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20713             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20714           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
20715             const tc *col = texture.ptr(txleft,tyleft);
20716             cimg_forV(*this,k) {
20717               *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
20718               ptrd+=whz; col+=twhz;
20719             }
20720             ptrd-=offx;
20721             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20722             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20723           } else for (int x = xleft; x<=xright; ++x) {
20724             const tc *col = texture.ptr(txleft,tyleft);
20725             cimg_forV(*this,k) {
20726               const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
20727               *ptrd = (T)(nopacity*val + *ptrd*copacity);
20728               ptrd+=whz; col+=twhz;
20729             }
20730             ptrd-=offx;
20731             txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20732             tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20733           }
20734         }
20735       }
20736       return *this;
20737     }
20738 
20739     //! Draw a 2D textured triangle, with perspective correction.
20740     template<typename tc>
20741     CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
20742                            const int x1, const int y1, const float z1,
20743                            const int x2, const int y2, const float z2,
20744                            const CImg<tc>& texture,
20745                            const int tx0, const int ty0,
20746                            const int tx1, const int ty1,
20747                            const int tx2, const int ty2,
20748                            const float opacity=1,
20749                            const float brightness=1) {
20750       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
20751       if (!texture || texture.dim<dim)
20752         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
20753                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
20754       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);
20755       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20756       const float
20757         nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
20758         nbrightness = brightness<0?0:(brightness>2?2:brightness);
20759       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
20760       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
20761       float
20762         ntx0 = tx0/z0, nty0 = ty0/z0,
20763         ntx1 = tx1/z1, nty1 = ty1/z1,
20764         ntx2 = tx2/z2, nty2 = ty2/z2,
20765         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
20766       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
20767       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
20768       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
20769       if (ny0>=dimy() || ny2<0) return *this;
20770       float
20771         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
20772         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
20773         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
20774         ptyl = (nty1 - nty0)/(ny1 - ny0),
20775         ptyr = (nty2 - nty0)/(ny2 - ny0),
20776         ptyn = (nty2 - nty1)/(ny2 - ny1),
20777         pzl = (nz1 - nz0)/(ny1 - ny0),
20778         pzr = (nz2 - nz0)/(ny2 - ny0),
20779         pzn = (nz2 - nz1)/(ny2 - ny1),
20780         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
20781         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
20782         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
20783         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
20784         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
20785         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
20786       _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
20787         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
20788         int xleft = xleft0, xright = xright0;
20789         float
20790           zleft = zl, zright = zr,
20791           txleft = txl, txright = txr,
20792           tyleft = tyl, tyright = tyr;
20793         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
20794         const int dx = xright - xleft;
20795         const float
20796           pentez = (zright - zleft)/dx,
20797           pentetx = (txright - txleft)/dx,
20798           pentety = (tyright - tyleft)/dx;
20799         if (xleft<0 && dx) {
20800           zleft-=xleft*(zright - zleft)/dx;
20801           txleft-=xleft*(txright - txleft)/dx;
20802           tyleft-=xleft*(tyright - tyleft)/dx;
20803         }
20804         if (xleft<0) xleft = 0;
20805         if (xright>=dimx()-1) xright = dimx()-1;
20806         T* ptrd = ptr(xleft,y,0,0);
20807         if (opacity>=1) {
20808           if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
20809             const float invz = 1/zleft;
20810             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20811             cimg_forV(*this,k) {
20812               *ptrd = (T)*col;
20813               ptrd+=whz; col+=twhz;
20814             }
20815             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20816           } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) {
20817             const float invz = 1/zleft;
20818             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20819             cimg_forV(*this,k) {
20820               *ptrd = (T)(nbrightness**col);
20821               ptrd+=whz; col+=twhz;
20822             }
20823             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20824           } else for (int x = xleft; x<=xright; ++x) {
20825             const float invz = 1/zleft;
20826             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20827             cimg_forV(*this,k) {
20828               *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
20829               ptrd+=whz; col+=twhz;
20830             }
20831             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20832           }
20833         } else {
20834           if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
20835             const float invz = 1/zleft;
20836             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20837             cimg_forV(*this,k) {
20838               *ptrd = (T)(nopacity**col + *ptrd*copacity);
20839               ptrd+=whz; col+=twhz;
20840             }
20841             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20842           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
20843             const float invz = 1/zleft;
20844             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20845             cimg_forV(*this,k) {
20846               *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
20847               ptrd+=whz; col+=twhz;
20848             }
20849             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20850           } else for (int x = xleft; x<=xright; ++x) {
20851             const float invz = 1/zleft;
20852             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20853             cimg_forV(*this,k) {
20854               const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
20855               *ptrd = (T)(nopacity*val + *ptrd*copacity);
20856               ptrd+=whz; col+=twhz;
20857             }
20858             ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20859           }
20860         }
20861         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
20862       }
20863       return *this;
20864     }
20865 
20866     //! Draw a 2D textured triangle, with z-buffering and perspective correction.
20867     template<typename tc>
20868     CImg<T>& draw_triangle(float *const zbuffer,
20869                            const int x0, const int y0, const float z0,
20870                            const int x1, const int y1, const float z1,
20871                            const int x2, const int y2, const float z2,
20872                            const CImg<tc>& texture,
20873                            const int tx0, const int ty0,
20874                            const int tx1, const int ty1,
20875                            const int tx2, const int ty2,
20876                            const float opacity=1,
20877                            const float brightness=1) {
20878       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
20879       if (!texture || texture.dim<dim)
20880         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
20881                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
20882       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);
20883       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20884       const float
20885         nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
20886         nbrightness = brightness<0?0:(brightness>2?2:brightness);
20887       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
20888       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
20889       float
20890         ntx0 = tx0/z0, nty0 = ty0/z0,
20891         ntx1 = tx1/z1, nty1 = ty1/z1,
20892         ntx2 = tx2/z2, nty2 = ty2/z2,
20893         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
20894       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
20895       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
20896       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
20897       if (ny0>=dimy() || ny2<0) return *this;
20898       float
20899         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
20900         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
20901         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
20902         ptyl = (nty1 - nty0)/(ny1 - ny0),
20903         ptyr = (nty2 - nty0)/(ny2 - ny0),
20904         ptyn = (nty2 - nty1)/(ny2 - ny1),
20905         pzl = (nz1 - nz0)/(ny1 - ny0),
20906         pzr = (nz2 - nz0)/(ny2 - ny0),
20907         pzn = (nz2 - nz1)/(ny2 - ny1),
20908         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
20909         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
20910         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
20911         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
20912         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
20913         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
20914       _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
20915         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
20916         int xleft = xleft0, xright = xright0;
20917         float
20918           zleft = zl, zright = zr,
20919           txleft = txl, txright = txr,
20920           tyleft = tyl, tyright = tyr;
20921         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
20922         const int dx = xright - xleft;
20923         const float
20924           pentez = (zright - zleft)/dx,
20925           pentetx = (txright - txleft)/dx,
20926           pentety = (tyright - tyleft)/dx;
20927         if (xleft<0 && dx) {
20928           zleft-=xleft*(zright - zleft)/dx;
20929           txleft-=xleft*(txright - txleft)/dx;
20930           tyleft-=xleft*(tyright - tyleft)/dx;
20931         }
20932         if (xleft<0) xleft = 0;
20933         if (xright>=dimx()-1) xright = dimx()-1;
20934         T *ptrd = ptr(xleft,y,0,0);
20935         float *ptrz = zbuffer + xleft + y*width;
20936         if (opacity>=1) {
20937           if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20938             if (zleft>*ptrz) {
20939               *ptrz = zleft;
20940               const float invz = 1/zleft;
20941               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20942               cimg_forV(*this,k) {
20943                 *ptrd = (T)*col;
20944                 ptrd+=whz; col+=twhz;
20945               }
20946               ptrd-=offx;
20947             }
20948             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20949           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20950             if (zleft>*ptrz) {
20951               *ptrz = zleft;
20952               const float invz = 1/zleft;
20953               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20954               cimg_forV(*this,k) {
20955                 *ptrd = (T)(nbrightness**col);
20956                 ptrd+=whz; col+=twhz;
20957               }
20958               ptrd-=offx;
20959             }
20960             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20961           } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20962             if (zleft>*ptrz) {
20963               *ptrz = zleft;
20964               const float invz = 1/zleft;
20965               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20966               cimg_forV(*this,k) {
20967                 *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
20968                 ptrd+=whz; col+=twhz;
20969               }
20970               ptrd-=offx;
20971             }
20972             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20973           }
20974         } else {
20975           if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20976             if (zleft>*ptrz) {
20977               *ptrz = zleft;
20978               const float invz = 1/zleft;
20979               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20980               cimg_forV(*this,k) {
20981                 *ptrd = (T)(nopacity**col + *ptrd*copacity);
20982                 ptrd+=whz; col+=twhz;
20983               }
20984               ptrd-=offx;
20985             }
20986             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20987           } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20988             if (zleft>*ptrz) {
20989               *ptrz = zleft;
20990               const float invz = 1/zleft;
20991               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20992               cimg_forV(*this,k) {
20993                 *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
20994                 ptrd+=whz; col+=twhz;
20995               }
20996               ptrd-=offx;
20997             }
20998             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20999           } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
21000             if (zleft>*ptrz) {
21001               *ptrz = zleft;
21002               const float invz = 1/zleft;
21003               const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21004               cimg_forV(*this,k) {
21005                 const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
21006                 *ptrd = (T)(nopacity*val + *ptrd*copacity);
21007                 ptrd+=whz; col+=twhz;
21008               }
21009               ptrd-=offx;
21010             }
21011             zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21012           }
21013         }
21014         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
21015       }
21016       return *this;
21017     }
21018 
21019     //! Draw a 2D Pseudo-Phong-shaded triangle.
21020     /**
21021        \param x0 = X-coordinate of the first corner in the instance image.
21022        \param y0 = Y-coordinate of the first corner in the instance image.
21023        \param x1 = X-coordinate of the second corner in the instance image.
21024        \param y1 = Y-coordinate of the second corner in the instance image.
21025        \param x2 = X-coordinate of the third corner in the instance image.
21026        \param y2 = Y-coordinate of the third corner in the instance image.
21027        \param color = array of dimv() values of type \c T, defining the global drawing color.
21028        \param light = light image.
21029        \param lx0 = X-coordinate of the first corner in the light image.
21030        \param ly0 = Y-coordinate of the first corner in the light image.
21031        \param lx1 = X-coordinate of the second corner in the light image.
21032        \param ly1 = Y-coordinate of the second corner in the light image.
21033        \param lx2 = X-coordinate of the third corner in the light image.
21034        \param ly2 = Y-coordinate of the third corner in the light image.
21035        \param opacity = opacity of the drawing.
21036        \note Clipping is supported, but texture coordinates do not support clipping.
21037     **/
21038     template<typename tc, typename tl>
21039     CImg<T>& draw_triangle(const int x0, const int y0,
21040                            const int x1, const int y1,
21041                            const int x2, const int y2,
21042                            const tc *const color,
21043                            const CImg<tl>& light,
21044                            const int lx0, const int ly0,
21045                            const int lx1, const int ly1,
21046                            const int lx2, const int ly2,
21047                            const float opacity=1) {
21048       if (is_empty()) return *this;
21049       if (!color)
21050         throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
21051                                     pixel_type());
21052       if (!light)
21053         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
21054                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
21055       if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,color,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21056       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21057       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21058       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21059         nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
21060       const int whz = width*height*depth, offx = dim*whz-1;
21061       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1);
21062       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2);
21063       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2);
21064       if (ny0>=dimy() || ny2<0) return *this;
21065       _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
21066                           nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
21067         int
21068           xleft = xleft0, xright = xright0,
21069           lxleft = lxleft0, lxright = lxright0,
21070           lyleft = lyleft0, lyright = lyright0;
21071         if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright);
21072         const int
21073           dx = xright - xleft,
21074           dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
21075           dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
21076           rlx = dx?(lxright - lxleft)/dx:0,
21077           rly = dx?(lyright - lyleft)/dx:0,
21078           slx = lxright>lxleft?1:-1,
21079           sly = lyright>lyleft?1:-1,
21080           ndlx = dlx - (dx?dx*(dlx/dx):0),
21081           ndly = dly - (dx?dx*(dly/dx):0);
21082         int errlx = dx>>1, errly = errlx;
21083         if (xleft<0 && dx) {
21084           lxleft-=xleft*(lxright - lxleft)/dx;
21085           lyleft-=xleft*(lyright - lyleft)/dx;
21086         }
21087         if (xleft<0) xleft = 0;
21088         if (xright>=dimx()-1) xright = dimx()-1;
21089         T* ptrd = ptr(xleft,y,0,0);
21090         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
21091           const tl l = light(lxleft,lyleft);
21092           const tc *col = color;
21093           cimg_forV(*this,k) {
21094             *ptrd = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
21095             ptrd+=whz;
21096           }
21097           ptrd-=offx;
21098           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21099           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21100         } else  for (int x = xleft; x<=xright; ++x) {
21101           const tl l = light(lxleft,lyleft);
21102           const tc *col = color;
21103           cimg_forV(*this,k) {
21104             const T val = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
21105             *ptrd = (T)(nopacity*val + *ptrd*copacity);
21106             ptrd+=whz;
21107           }
21108           ptrd-=offx;
21109           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21110           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21111         }
21112       }
21113       return *this;
21114     }
21115 
21116     //! Draw a 2D Pseudo-Phong-shaded triangle.
21117     template<typename tc, typename tl>
21118     CImg<T>& draw_triangle(const int x0, const int y0,
21119                            const int x1, const int y1,
21120                            const int x2, const int y2,
21121                            const CImg<tc>& color,
21122                            const CImg<tl>& light,
21123                            const int lx0, const int ly0,
21124                            const int lx1, const int ly1,
21125                            const int lx2, const int ly2,
21126                            const float opacity=1) {
21127       return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21128     }
21129 
21130     //! Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
21131     template<typename tc, typename tl>
21132     CImg<T>& draw_triangle(float *const zbuffer,
21133                            const int x0, const int y0, const float z0,
21134                            const int x1, const int y1, const float z1,
21135                            const int x2, const int y2, const float z2,
21136                            const tc *const color,
21137                            const CImg<tl>& light,
21138                            const int lx0, const int ly0,
21139                            const int lx1, const int ly1,
21140                            const int lx2, const int ly2,
21141                            const float opacity=1) {
21142       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
21143       if (!color)
21144         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
21145                                     pixel_type());
21146       if (!light)
21147         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
21148                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
21149       if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,
21150                                                      +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21151       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21152       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21153       const int whz = width*height*depth, offx = dim*whz;
21154       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21155         nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
21156       float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
21157       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1,nz0,nz1);
21158       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2,nz0,nz2);
21159       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2,nz1,nz2);
21160       if (ny0>=dimy() || ny2<0) return *this;
21161       float
21162         pzl = (nz1 - nz0)/(ny1 - ny0),
21163         pzr = (nz2 - nz0)/(ny2 - ny0),
21164         pzn = (nz2 - nz1)/(ny2 - ny1),
21165         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
21166         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
21167       _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
21168                           nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
21169         if (y==ny1) { zl = nz1; pzl = pzn; }
21170         int
21171           xleft = xleft0, xright = xright0,
21172           lxleft = lxleft0, lxright = lxright0,
21173           lyleft = lyleft0, lyright = lyright0;
21174         float zleft = zl, zright = zr;
21175         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,lxleft,lxright,lyleft,lyright);
21176         const int
21177           dx = xright - xleft,
21178           dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
21179           dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
21180           rlx = dx?(lxright - lxleft)/dx:0,
21181           rly = dx?(lyright - lyleft)/dx:0,
21182           slx = lxright>lxleft?1:-1,
21183           sly = lyright>lyleft?1:-1,
21184           ndlx = dlx - (dx?dx*(dlx/dx):0),
21185           ndly = dly - (dx?dx*(dly/dx):0);
21186         const float pentez = (zright - zleft)/dx;
21187         int errlx = dx>>1, errly = errlx;
21188         if (xleft<0 && dx) {
21189           zleft-=xleft*(zright - zleft)/dx;
21190           lxleft-=xleft*(lxright - lxleft)/dx;
21191           lyleft-=xleft*(lyright - lyleft)/dx;
21192         }
21193         if (xleft<0) xleft = 0;
21194         if (xright>=dimx()-1) xright = dimx()-1;
21195         T *ptrd = ptr(xleft,y,0,0);
21196         float *ptrz = zbuffer + xleft + y*width;
21197         if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
21198           if (zleft>*ptrz) {
21199             *ptrz = zleft;
21200             const tl l = light(lxleft,lyleft);
21201             const tc *col = color;
21202             cimg_forV(*this,k) {
21203               const tc cval = *(col++);
21204               *ptrd = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
21205               ptrd+=whz;
21206             }
21207             ptrd-=offx;
21208           }
21209           zleft+=pentez;
21210           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21211           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21212         } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
21213           if (zleft>*ptrz) {
21214             *ptrz = zleft;
21215             const tl l = light(lxleft,lyleft);
21216             const tc *col = color;
21217             cimg_forV(*this,k) {
21218               const tc cval = *(col++);
21219               const T val = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
21220               *ptrd = (T)(nopacity*val + *ptrd*copacity);
21221               ptrd+=whz;
21222             }
21223             ptrd-=offx;
21224           }
21225           zleft+=pentez;
21226           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21227           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21228         }
21229         zr+=pzr; zl+=pzl;
21230       }
21231       return *this;
21232     }
21233 
21234     //! Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
21235     template<typename tc, typename tl>
21236     CImg<T>& draw_triangle(float *const zbuffer,
21237                            const int x0, const int y0, const float z0,
21238                            const int x1, const int y1, const float z1,
21239                            const int x2, const int y2, const float z2,
21240                            const CImg<tc>& color,
21241                            const CImg<tl>& light,
21242                            const int lx0, const int ly0,
21243                            const int lx1, const int ly1,
21244                            const int lx2, const int ly2,
21245                            const float opacity=1) {
21246       return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21247     }
21248 
21249     //! Draw a 2D Gouraud-shaded textured triangle.
21250     /**
21251        \param x0 = X-coordinate of the first corner in the instance image.
21252        \param y0 = Y-coordinate of the first corner in the instance image.
21253        \param x1 = X-coordinate of the second corner in the instance image.
21254        \param y1 = Y-coordinate of the second corner in the instance image.
21255        \param x2 = X-coordinate of the third corner in the instance image.
21256        \param y2 = Y-coordinate of the third corner in the instance image.
21257        \param texture = texture image used to fill the triangle.
21258        \param tx0 = X-coordinate of the first corner in the texture image.
21259        \param ty0 = Y-coordinate of the first corner in the texture image.
21260        \param tx1 = X-coordinate of the second corner in the texture image.
21261        \param ty1 = Y-coordinate of the second corner in the texture image.
21262        \param tx2 = X-coordinate of the third corner in the texture image.
21263        \param ty2 = Y-coordinate of the third corner in the texture image.
21264        \param brightness0 = brightness value of the first corner.
21265        \param brightness1 = brightness value of the second corner.
21266        \param brightness2 = brightness value of the third corner.
21267        \param opacity = opacity of the drawing.
21268        \note Clipping is supported, but texture coordinates do not support clipping.
21269     **/
21270     template<typename tc>
21271     CImg<T>& draw_triangle(const int x0, const int y0,
21272                            const int x1, const int y1,
21273                            const int x2, const int y2,
21274                            const CImg<tc>& texture,
21275                            const int tx0, const int ty0,
21276                            const int tx1, const int ty1,
21277                            const int tx2, const int ty2,
21278                            const float brightness0,
21279                            const float brightness1,
21280                            const float brightness2,
21281                            const float opacity=1) {
21282       if (is_empty()) return *this;
21283       if (!texture || texture.dim<dim)
21284         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21285                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21286       if (is_overlapped(texture))
21287         return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,brightness0,brightness1,brightness2,opacity);
21288       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21289       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21290       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
21291       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21292         ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
21293         nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
21294         nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
21295         nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
21296       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1);
21297       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2);
21298       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2);
21299       if (ny0>=dimy() || ny2<0) return *this;
21300       _cimg_for_triangle4(*this,xleft0,cleft0,txleft0,tyleft0,xright0,cright0,txright0,tyright0,y,
21301                           nx0,ny0,nc0,ntx0,nty0,nx1,ny1,nc1,ntx1,nty1,nx2,ny2,nc2,ntx2,nty2) {
21302         int
21303           xleft = xleft0, xright = xright0,
21304           cleft = cleft0, cright = cright0,
21305           txleft = txleft0, txright = txright0,
21306           tyleft = tyleft0, tyright = tyright0;
21307         if (xright<xleft) cimg::swap(xleft,xright,cleft,cright,txleft,txright,tyleft,tyright);
21308         const int
21309           dx = xright - xleft,
21310           dc = cright>cleft?cright - cleft:cleft - cright,
21311           dtx = txright>txleft?txright - txleft:txleft - txright,
21312           dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
21313           rc = dx?(cright - cleft)/dx:0,
21314           rtx = dx?(txright - txleft)/dx:0,
21315           rty = dx?(tyright - tyleft)/dx:0,
21316           sc = cright>cleft?1:-1,
21317           stx = txright>txleft?1:-1,
21318           sty = tyright>tyleft?1:-1,
21319           ndc = dc - (dx?dx*(dc/dx):0),
21320           ndtx = dtx - (dx?dx*(dtx/dx):0),
21321           ndty = dty - (dx?dx*(dty/dx):0);
21322         int errc = dx>>1, errtx = errc, errty = errc;
21323         if (xleft<0 && dx) {
21324           cleft-=xleft*(cright - cleft)/dx;
21325           txleft-=xleft*(txright - txleft)/dx;
21326           tyleft-=xleft*(tyright - tyleft)/dx;
21327         }
21328         if (xleft<0) xleft = 0;
21329         if (xright>=dimx()-1) xright = dimx()-1;
21330         T* ptrd = ptr(xleft,y,0,0);
21331         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
21332           const tc *col = texture.ptr(txleft,tyleft);
21333           cimg_forV(*this,k) {
21334             *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21335             ptrd+=whz; col+=twhz;
21336           }
21337           ptrd-=offx;
21338           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21339           txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
21340           tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
21341         } else for (int x = xleft; x<=xright; ++x) {
21342           const tc *col = texture.ptr(txleft,tyleft);
21343           cimg_forV(*this,k) {
21344             const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21345             *ptrd = (T)(nopacity*val + *ptrd*copacity);
21346             ptrd+=whz; col+=twhz;
21347           }
21348           ptrd-=offx;
21349           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21350           txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
21351           tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
21352         }
21353       }
21354       return *this;
21355     }
21356 
21357     //! Draw a 2D Gouraud-shaded textured triangle, with perspective correction.
21358     template<typename tc>
21359     CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
21360                            const int x1, const int y1, const float z1,
21361                            const int x2, const int y2, const float z2,
21362                            const CImg<tc>& texture,
21363                            const int tx0, const int ty0,
21364                            const int tx1, const int ty1,
21365                            const int tx2, const int ty2,
21366                            const float brightness0,
21367                            const float brightness1,
21368                            const float brightness2,
21369                            const float opacity=1) {
21370       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
21371       if (!texture || texture.dim<dim)
21372         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21373                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21374       if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
21375                                                        brightness0,brightness1,brightness2,opacity);
21376       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21377       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21378       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
21379       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21380         nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
21381         nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
21382         nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
21383       float
21384         ntx0 = tx0/z0, nty0 = ty0/z0,
21385         ntx1 = tx1/z1, nty1 = ty1/z1,
21386         ntx2 = tx2/z2, nty2 = ty2/z2,
21387         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
21388       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
21389       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
21390       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
21391       if (ny0>=dimy() || ny2<0) return *this;
21392       float
21393         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
21394         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
21395         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
21396         ptyl = (nty1 - nty0)/(ny1 - ny0),
21397         ptyr = (nty2 - nty0)/(ny2 - ny0),
21398         ptyn = (nty2 - nty1)/(ny2 - ny1),
21399         pzl = (nz1 - nz0)/(ny1 - ny0),
21400         pzr = (nz2 - nz0)/(ny2 - ny0),
21401         pzn = (nz2 - nz1)/(ny2 - ny1),
21402         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
21403         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
21404         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
21405         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
21406         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
21407         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
21408       _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
21409         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
21410         int
21411           xleft = xleft0, xright = xright0,
21412           cleft = cleft0, cright = cright0;
21413         float
21414           zleft = zl, zright = zr,
21415           txleft = txl, txright = txr,
21416           tyleft = tyl, tyright = tyr;
21417         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
21418         const int
21419           dx = xright - xleft,
21420           dc = cright>cleft?cright - cleft:cleft - cright,
21421           rc = dx?(cright - cleft)/dx:0,
21422           sc = cright>cleft?1:-1,
21423           ndc = dc - (dx?dx*(dc/dx):0);
21424         const float
21425           pentez = (zright - zleft)/dx,
21426           pentetx = (txright - txleft)/dx,
21427           pentety = (tyright - tyleft)/dx;
21428         int errc = dx>>1;
21429         if (xleft<0 && dx) {
21430           cleft-=xleft*(cright - cleft)/dx;
21431           zleft-=xleft*(zright - zleft)/dx;
21432           txleft-=xleft*(txright - txleft)/dx;
21433           tyleft-=xleft*(tyright - tyleft)/dx;
21434         }
21435         if (xleft<0) xleft = 0;
21436         if (xright>=dimx()-1) xright = dimx()-1;
21437         T* ptrd = ptr(xleft,y,0,0);
21438         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
21439           const float invz = 1/zleft;
21440           const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21441           cimg_forV(*this,k) {
21442             *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21443             ptrd+=whz; col+=twhz;
21444           }
21445           ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21446           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21447         } else for (int x = xleft; x<=xright; ++x) {
21448           const float invz = 1/zleft;
21449           const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21450           cimg_forV(*this,k) {
21451             const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21452             *ptrd = (T)(nopacity*val + *ptrd*copacity);
21453             ptrd+=whz; col+=twhz;
21454           }
21455           ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21456           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21457         }
21458         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
21459       }
21460       return *this;
21461     }
21462 
21463     //! Draw a 2D Gouraud-shaded textured triangle, with z-buffering and perspective correction.
21464     template<typename tc>
21465     CImg<T>& draw_triangle(float *const zbuffer,
21466                            const int x0, const int y0, const float z0,
21467                            const int x1, const int y1, const float z1,
21468                            const int x2, const int y2, const float z2,
21469                            const CImg<tc>& texture,
21470                            const int tx0, const int ty0,
21471                            const int tx1, const int ty1,
21472                            const int tx2, const int ty2,
21473                            const float brightness0,
21474                            const float brightness1,
21475                            const float brightness2,
21476                            const float opacity=1) {
21477       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
21478       if (!texture || texture.dim<dim)
21479         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21480                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21481       if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
21482                                                        brightness0,brightness1,brightness2,opacity);
21483       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21484       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21485       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
21486       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21487         nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
21488         nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
21489         nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
21490       float
21491         ntx0 = tx0/z0, nty0 = ty0/z0,
21492         ntx1 = tx1/z1, nty1 = ty1/z1,
21493         ntx2 = tx2/z2, nty2 = ty2/z2,
21494         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
21495       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
21496       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
21497       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
21498       if (ny0>=dimy() || ny2<0) return *this;
21499       float
21500         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
21501         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
21502         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
21503         ptyl = (nty1 - nty0)/(ny1 - ny0),
21504         ptyr = (nty2 - nty0)/(ny2 - ny0),
21505         ptyn = (nty2 - nty1)/(ny2 - ny1),
21506         pzl = (nz1 - nz0)/(ny1 - ny0),
21507         pzr = (nz2 - nz0)/(ny2 - ny0),
21508         pzn = (nz2 - nz1)/(ny2 - ny1),
21509         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
21510         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
21511         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
21512         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
21513         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
21514         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
21515       _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
21516         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
21517         int
21518           xleft = xleft0, xright = xright0,
21519           cleft = cleft0, cright = cright0;
21520         float
21521           zleft = zl, zright = zr,
21522           txleft = txl, txright = txr,
21523           tyleft = tyl, tyright = tyr;
21524         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
21525         const int
21526           dx = xright - xleft,
21527           dc = cright>cleft?cright - cleft:cleft - cright,
21528           rc = dx?(cright - cleft)/dx:0,
21529           sc = cright>cleft?1:-1,
21530           ndc = dc - (dx?dx*(dc/dx):0);
21531         const float
21532           pentez = (zright - zleft)/dx,
21533           pentetx = (txright - txleft)/dx,
21534           pentety = (tyright - tyleft)/dx;
21535         int errc = dx>>1;
21536         if (xleft<0 && dx) {
21537           cleft-=xleft*(cright - cleft)/dx;
21538           zleft-=xleft*(zright - zleft)/dx;
21539           txleft-=xleft*(txright - txleft)/dx;
21540           tyleft-=xleft*(tyright - tyleft)/dx;
21541         }
21542         if (xleft<0) xleft = 0;
21543         if (xright>=dimx()-1) xright = dimx()-1;
21544         T* ptrd = ptr(xleft,y);
21545         float *ptrz = zbuffer + xleft + y*width;
21546         if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
21547           if (zleft>*ptrz) {
21548             *ptrz = zleft;
21549             const float invz = 1/zleft;
21550             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21551             cimg_forV(*this,k) {
21552               *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21553               ptrd+=whz; col+=twhz;
21554             }
21555             ptrd-=offx;
21556           }
21557           zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21558           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21559         } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
21560           if (zleft>*ptrz) {
21561             *ptrz = zleft;
21562             const float invz = 1/zleft;
21563             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21564             cimg_forV(*this,k) {
21565               const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21566               *ptrd = (T)(nopacity*val + *ptrd*copacity);
21567               ptrd+=whz; col+=twhz;
21568             }
21569             ptrd-=offx;
21570           }
21571           zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21572           cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21573         }
21574         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
21575       }
21576       return *this;
21577     }
21578 
21579     //! Draw a 2D Pseudo-Phong-shaded textured triangle.
21580     /**
21581        \param x0 = X-coordinate of the first corner in the instance image.
21582        \param y0 = Y-coordinate of the first corner in the instance image.
21583        \param x1 = X-coordinate of the second corner in the instance image.
21584        \param y1 = Y-coordinate of the second corner in the instance image.
21585        \param x2 = X-coordinate of the third corner in the instance image.
21586        \param y2 = Y-coordinate of the third corner in the instance image.
21587        \param texture = texture image used to fill the triangle.
21588        \param tx0 = X-coordinate of the first corner in the texture image.
21589        \param ty0 = Y-coordinate of the first corner in the texture image.
21590        \param tx1 = X-coordinate of the second corner in the texture image.
21591        \param ty1 = Y-coordinate of the second corner in the texture image.
21592        \param tx2 = X-coordinate of the third corner in the texture image.
21593        \param ty2 = Y-coordinate of the third corner in the texture image.
21594        \param light = light image.
21595        \param lx0 = X-coordinate of the first corner in the light image.
21596        \param ly0 = Y-coordinate of the first corner in the light image.
21597        \param lx1 = X-coordinate of the second corner in the light image.
21598        \param ly1 = Y-coordinate of the second corner in the light image.
21599        \param lx2 = X-coordinate of the third corner in the light image.
21600        \param ly2 = Y-coordinate of the third corner in the light image.
21601        \param opacity = opacity of the drawing.
21602        \note Clipping is supported, but texture coordinates do not support clipping.
21603     **/
21604     template<typename tc, typename tl>
21605     CImg<T>& draw_triangle(const int x0, const int y0,
21606                            const int x1, const int y1,
21607                            const int x2, const int y2,
21608                            const CImg<tc>& texture,
21609                            const int tx0, const int ty0,
21610                            const int tx1, const int ty1,
21611                            const int tx2, const int ty2,
21612                            const CImg<tl>& light,
21613                            const int lx0, const int ly0,
21614                            const int lx1, const int ly1,
21615                            const int lx2, const int ly2,
21616                            const float opacity=1) {
21617       if (is_empty()) return *this;
21618       if (!texture || texture.dim<dim)
21619         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21620                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21621       if (!light)
21622         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
21623                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
21624       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);
21625       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);
21626       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21627       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21628       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
21629       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21630         ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
21631         nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
21632       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1);
21633       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2);
21634       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2);
21635       if (ny0>=dimy() || ny2<0) return *this;
21636       _cimg_for_triangle5(*this,xleft0,lxleft0,lyleft0,txleft0,tyleft0,xright0,lxright0,lyright0,txright0,tyright0,y,
21637                           nx0,ny0,nlx0,nly0,ntx0,nty0,nx1,ny1,nlx1,nly1,ntx1,nty1,nx2,ny2,nlx2,nly2,ntx2,nty2) {
21638         int
21639           xleft = xleft0, xright = xright0,
21640           lxleft = lxleft0, lxright = lxright0,
21641           lyleft = lyleft0, lyright = lyright0,
21642           txleft = txleft0, txright = txright0,
21643           tyleft = tyleft0, tyright = tyright0;
21644         if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright,txleft,txright,tyleft,tyright);
21645         const int
21646           dx = xright - xleft,
21647           dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
21648           dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
21649           dtx = txright>txleft?txright - txleft:txleft - txright,
21650           dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
21651           rlx = dx?(lxright - lxleft)/dx:0,
21652           rly = dx?(lyright - lyleft)/dx:0,
21653           rtx = dx?(txright - txleft)/dx:0,
21654           rty = dx?(tyright - tyleft)/dx:0,
21655           slx = lxright>lxleft?1:-1,
21656           sly = lyright>lyleft?1:-1,
21657           stx = txright>txleft?1:-1,
21658           sty = tyright>tyleft?1:-1,
21659           ndlx = dlx - (dx?dx*(dlx/dx):0),
21660           ndly = dly - (dx?dx*(dly/dx):0),
21661           ndtx = dtx - (dx?dx*(dtx/dx):0),
21662           ndty = dty - (dx?dx*(dty/dx):0);
21663         int errlx = dx>>1, errly = errlx, errtx = errlx, errty = errlx;
21664         if (xleft<0 && dx) {
21665           lxleft-=xleft*(lxright - lxleft)/dx;
21666           lyleft-=xleft*(lyright - lyleft)/dx;
21667           txleft-=xleft*(txright - txleft)/dx;
21668           tyleft-=xleft*(tyright - tyleft)/dx;
21669         }
21670         if (xleft<0) xleft = 0;
21671         if (xright>=dimx()-1) xright = dimx()-1;
21672         T* ptrd = ptr(xleft,y,0,0);
21673         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
21674           const tl l = light(lxleft,lyleft);
21675           const tc *col = texture.ptr(txleft,tyleft);
21676           cimg_forV(*this,k) {
21677             *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21678             ptrd+=whz; col+=twhz;
21679           }
21680           ptrd-=offx;
21681           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21682           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21683           txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
21684           tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
21685         } else for (int x = xleft; x<=xright; ++x) {
21686           const tl l = light(lxleft,lyleft);
21687           const tc *col = texture.ptr(txleft,tyleft);
21688           cimg_forV(*this,k) {
21689             const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21690             *ptrd = (T)(nopacity*val + *ptrd*copacity);
21691             ptrd+=whz; col+=twhz;
21692           }
21693           ptrd-=offx;
21694           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21695           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21696           txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
21697           tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
21698         }
21699       }
21700       return *this;
21701     }
21702 
21703     //! Draw a 2D Pseudo-Phong-shaded textured triangle, with perspective correction.
21704     template<typename tc, typename tl>
21705     CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
21706                            const int x1, const int y1, const float z1,
21707                            const int x2, const int y2, const float z2,
21708                            const CImg<tc>& texture,
21709                            const int tx0, const int ty0,
21710                            const int tx1, const int ty1,
21711                            const int tx2, const int ty2,
21712                            const CImg<tl>& light,
21713                            const int lx0, const int ly0,
21714                            const int lx1, const int ly1,
21715                            const int lx2, const int ly2,
21716                            const float opacity=1) {
21717       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
21718       if (!texture || texture.dim<dim)
21719         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21720                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21721       if (!light)
21722         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
21723                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
21724       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);
21725       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);
21726       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21727       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21728       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
21729       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21730         nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
21731       float
21732         ntx0 = tx0/z0, nty0 = ty0/z0,
21733         ntx1 = tx1/z1, nty1 = ty1/z1,
21734         ntx2 = tx2/z2, nty2 = ty2/z2,
21735         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
21736       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
21737       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
21738       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
21739       if (ny0>=dimy() || ny2<0) return *this;
21740       float
21741         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
21742         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
21743         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
21744         ptyl = (nty1 - nty0)/(ny1 - ny0),
21745         ptyr = (nty2 - nty0)/(ny2 - ny0),
21746         ptyn = (nty2 - nty1)/(ny2 - ny1),
21747         pzl = (nz1 - nz0)/(ny1 - ny0),
21748         pzr = (nz2 - nz0)/(ny2 - ny0),
21749         pzn = (nz2 - nz1)/(ny2 - ny1),
21750         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
21751         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
21752         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
21753         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
21754         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
21755         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
21756       _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
21757                           nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
21758         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
21759         int
21760           xleft = xleft0, xright = xright0,
21761           lxleft = lxleft0, lxright = lxright0,
21762           lyleft = lyleft0, lyright = lyright0;
21763         float
21764           zleft = zl, zright = zr,
21765           txleft = txl, txright = txr,
21766           tyleft = tyl, tyright = tyr;
21767         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
21768         const int
21769           dx = xright - xleft,
21770           dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
21771           dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
21772           rlx = dx?(lxright - lxleft)/dx:0,
21773           rly = dx?(lyright - lyleft)/dx:0,
21774           slx = lxright>lxleft?1:-1,
21775           sly = lyright>lyleft?1:-1,
21776           ndlx = dlx - (dx?dx*(dlx/dx):0),
21777           ndly = dly - (dx?dx*(dly/dx):0);
21778         const float
21779           pentez = (zright - zleft)/dx,
21780           pentetx = (txright - txleft)/dx,
21781           pentety = (tyright - tyleft)/dx;
21782         int errlx = dx>>1, errly = errlx;
21783         if (xleft<0 && dx) {
21784           zleft-=xleft*(zright - zleft)/dx;
21785           lxleft-=xleft*(lxright - lxleft)/dx;
21786           lyleft-=xleft*(lyright - lyleft)/dx;
21787           txleft-=xleft*(txright - txleft)/dx;
21788           tyleft-=xleft*(tyright - tyleft)/dx;
21789         }
21790         if (xleft<0) xleft = 0;
21791         if (xright>=dimx()-1) xright = dimx()-1;
21792         T* ptrd = ptr(xleft,y,0,0);
21793         if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
21794           const float invz = 1/zleft;
21795           const tl l = light(lxleft,lyleft);
21796           const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21797           cimg_forV(*this,k) {
21798             *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21799             ptrd+=whz; col+=twhz;
21800           }
21801           ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21802           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21803           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21804         } else for (int x = xleft; x<=xright; ++x) {
21805           const float invz = 1/zleft;
21806           const tl l = light(lxleft,lyleft);
21807           const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21808           cimg_forV(*this,k) {
21809             const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21810             *ptrd = (T)(nopacity*val + *ptrd*copacity);
21811             ptrd+=whz; col+=twhz;
21812           }
21813           ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21814           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21815           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21816         }
21817         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
21818       }
21819       return *this;
21820     }
21821 
21822     //! Draw a 2D Pseudo-Phong-shaded textured triangle, with z-buffering and perspective correction.
21823     template<typename tc, typename tl>
21824     CImg<T>& draw_triangle(float *const zbuffer,
21825                            const int x0, const int y0, const float z0,
21826                            const int x1, const int y1, const float z1,
21827                            const int x2, const int y2, const float z2,
21828                            const CImg<tc>& texture,
21829                            const int tx0, const int ty0,
21830                            const int tx1, const int ty1,
21831                            const int tx2, const int ty2,
21832                            const CImg<tl>& light,
21833                            const int lx0, const int ly0,
21834                            const int lx1, const int ly1,
21835                            const int lx2, const int ly2,
21836                            const float opacity=1) {
21837       if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
21838       if (!texture || texture.dim<dim)
21839         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21840                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21841       if (!light)
21842         throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
21843                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
21844       if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
21845                                                        +texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21846       if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
21847                                                      texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21848       static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21849       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21850       const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
21851       int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21852         nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
21853       float
21854         ntx0 = tx0/z0, nty0 = ty0/z0,
21855         ntx1 = tx1/z1, nty1 = ty1/z1,
21856         ntx2 = tx2/z2, nty2 = ty2/z2,
21857         nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
21858       if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
21859       if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
21860       if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
21861       if (ny0>=dimy() || ny2<0) return *this;
21862       float
21863         ptxl = (ntx1 - ntx0)/(ny1 - ny0),
21864         ptxr = (ntx2 - ntx0)/(ny2 - ny0),
21865         ptxn = (ntx2 - ntx1)/(ny2 - ny1),
21866         ptyl = (nty1 - nty0)/(ny1 - ny0),
21867         ptyr = (nty2 - nty0)/(ny2 - ny0),
21868         ptyn = (nty2 - nty1)/(ny2 - ny1),
21869         pzl = (nz1 - nz0)/(ny1 - ny0),
21870         pzr = (nz2 - nz0)/(ny2 - ny0),
21871         pzn = (nz2 - nz1)/(ny2 - ny1),
21872         zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
21873         txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
21874         tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
21875         zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
21876         txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
21877         tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
21878       _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
21879                           nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
21880         if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
21881         int
21882           xleft = xleft0, xright = xright0,
21883           lxleft = lxleft0, lxright = lxright0,
21884           lyleft = lyleft0, lyright = lyright0;
21885         float
21886           zleft = zl, zright = zr,
21887           txleft = txl, txright = txr,
21888           tyleft = tyl, tyright = tyr;
21889         if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
21890         const int
21891           dx = xright - xleft,
21892           dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
21893           dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
21894           rlx = dx?(lxright - lxleft)/dx:0,
21895           rly = dx?(lyright - lyleft)/dx:0,
21896           slx = lxright>lxleft?1:-1,
21897           sly = lyright>lyleft?1:-1,
21898           ndlx = dlx - (dx?dx*(dlx/dx):0),
21899           ndly = dly - (dx?dx*(dly/dx):0);
21900         const float
21901           pentez = (zright - zleft)/dx,
21902           pentetx = (txright - txleft)/dx,
21903           pentety = (tyright - tyleft)/dx;
21904         int errlx = dx>>1, errly = errlx;
21905         if (xleft<0 && dx) {
21906           zleft-=xleft*(zright - zleft)/dx;
21907           lxleft-=xleft*(lxright - lxleft)/dx;
21908           lyleft-=xleft*(lyright - lyleft)/dx;
21909           txleft-=xleft*(txright - txleft)/dx;
21910           tyleft-=xleft*(tyright - tyleft)/dx;
21911         }
21912         if (xleft<0) xleft = 0;
21913         if (xright>=dimx()-1) xright = dimx()-1;
21914         T* ptrd = ptr(xleft,y);
21915         float *ptrz = zbuffer + xleft + y*width;
21916         if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
21917           if (zleft>*ptrz) {
21918             *ptrz = zleft;
21919             const float invz = 1/zleft;
21920             const tl l = light(lxleft,lyleft);
21921             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21922             cimg_forV(*this,k) {
21923               *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21924               ptrd+=whz; col+=twhz;
21925             }
21926             ptrd-=offx;
21927           }
21928           zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21929           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21930           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21931         } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
21932           if (zleft>*ptrz) {
21933             *ptrz = zleft;
21934             const float invz = 1/zleft;
21935             const tl l = light(lxleft,lyleft);
21936             const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21937             cimg_forV(*this,k) {
21938               const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21939               *ptrd = (T)(nopacity*val + *ptrd*copacity);
21940               ptrd+=whz; col+=twhz;
21941             }
21942             ptrd-=offx;
21943           }
21944           zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21945           lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21946           lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21947         }
21948         zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
21949       }
21950       return *this;
21951     }
21952 
21953     // Draw a 2D ellipse (inner routine).
21954     template<typename tc>
21955     CImg<T>& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
21956                            const tc *const color, const float opacity,
21957                            const unsigned int pattern) {
21958       if (is_empty()) return *this;
21959       if (!color)
21960         throw CImgArgumentException("CImg<%s>::draw_ellipse : Specified color is (null).",
21961                                     pixel_type());
21962       _draw_scanline(color,opacity);
21963       const float
21964         nr1 = cimg::abs(r1), nr2 = cimg::abs(r2),
21965         norm = (float)cimg_std::sqrt(ru*ru+rv*rv),
21966         u = norm>0?ru/norm:1,
21967         v = norm>0?rv/norm:0,
21968         rmax = cimg::max(nr1,nr2),
21969         l1 = (float)cimg_std::pow(rmax/(nr1>0?nr1:1e-6),2),
21970         l2 = (float)cimg_std::pow(rmax/(nr2>0?nr2:1e-6),2),
21971         a = l1*u*u + l2*v*v,
21972         b = u*v*(l1-l2),
21973         c = l1*v*v + l2*u*u;
21974       const int
21975         yb = (int)cimg_std::sqrt(a*rmax*rmax/(a*c-b*b)),
21976         tymin = y0 - yb - 1,
21977         tymax = y0 + yb + 1,
21978         ymin = tymin<0?0:tymin,
21979         ymax = tymax>=dimy()?height-1:tymax;
21980       int oxmin = 0, oxmax = 0;
21981       bool first_line = true;
21982       for (int y = ymin; y<=ymax; ++y) {
21983         const float
21984           Y = y-y0 + (y<y0?0.5f:-0.5f),
21985           delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax),
21986           sdelta = delta>0?(float)cimg_std::sqrt(delta)/a:0.0f,
21987           bY = b*Y/a,
21988           fxmin = x0-0.5f-bY-sdelta,
21989           fxmax = x0+0.5f-bY+sdelta;
21990         const int xmin = (int)fxmin, xmax = (int)fxmax;
21991         if (!pattern) _draw_scanline(xmin,xmax,y,color,opacity);
21992         else {
21993           if (first_line) {
21994             if (y0-yb>=0) _draw_scanline(xmin,xmax,y,color,opacity);
21995             else draw_point(xmin,y,color,opacity).draw_point(xmax,y,color,opacity);
21996             first_line = false;
21997           } else {
21998             if (xmin<oxmin) _draw_scanline(xmin,oxmin-1,y,color,opacity);
21999             else _draw_scanline(oxmin+(oxmin==xmin?0:1),xmin,y,color,opacity);
22000             if (xmax<oxmax) _draw_scanline(xmax,oxmax-1,y,color,opacity);
22001             else _draw_scanline(oxmax+(oxmax==xmax?0:1),xmax,y,color,opacity);
22002             if (y==tymax) _draw_scanline(xmin+1,xmax-1,y,color,opacity);
22003           }
22004         }
22005         oxmin = xmin; oxmax = xmax;
22006       }
22007       return *this;
22008     }
22009 
22010     //! Draw a filled ellipse.
22011     /**
22012        \param x0 = X-coordinate of the ellipse center.
22013        \param y0 = Y-coordinate of the ellipse center.
22014        \param r1 = First radius of the ellipse.
22015        \param r2 = Second radius of the ellipse.
22016        \param ru = X-coordinate of the orientation vector related to the first radius.
22017        \param rv = Y-coordinate of the orientation vector related to the first radius.
22018        \param color = array of dimv() values of type \c T, defining the drawing color.
22019        \param opacity = opacity of the drawing.
22020     **/
22021     template<typename tc>
22022     CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
22023                           const tc *const color, const float opacity=1) {
22024       return _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,0U);
22025     }
22026 
22027     //! Draw a filled ellipse.
22028     template<typename tc>
22029     CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
22030                           const CImg<tc>& color, const float opacity=1) {
22031       return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity);
22032     }
22033 
22034     //! Draw a filled ellipse.
22035     /**
22036        \param x0 = X-coordinate of the ellipse center.
22037        \param y0 = Y-coordinate of the ellipse center.
22038        \param tensor = Diffusion tensor describing the ellipse.
22039        \param color = array of dimv() values of type \c T, defining the drawing color.
22040        \param opacity = opacity of the drawing.
22041     **/
22042     template<typename t, typename tc>
22043     CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
22044                           const tc *const color, const float opacity=1) {
22045       CImgList<t> eig = tensor.get_symmetric_eigen();
22046       const CImg<t> &val = eig[0], &vec = eig[1];
22047       return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity);
22048     }
22049 
22050     //! Draw a filled ellipse.
22051     template<typename t, typename tc>
22052     CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
22053                           const CImg<tc>& color, const float opacity=1) {
22054       return draw_ellipse(x0,y0,tensor,color.data,opacity);
22055     }
22056 
22057     //! Draw an outlined ellipse.
22058     /**
22059        \param x0 = X-coordinate of the ellipse center.
22060        \param y0 = Y-coordinate of the ellipse center.
22061        \param r1 = First radius of the ellipse.
22062        \param r2 = Second radius of the ellipse.
22063        \param ru = X-coordinate of the orientation vector related to the first radius.
22064        \param rv = Y-coordinate of the orientation vector related to the first radius.
22065        \param color = array of dimv() values of type \c T, defining the drawing color.
22066        \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
22067        \param opacity = opacity of the drawing.
22068     **/
22069     template<typename tc>
22070     CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
22071                           const tc *const color, const float opacity,
22072                           const unsigned int pattern) {
22073       if (pattern) _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,pattern);
22074       return *this;
22075     }
22076 
22077     //! Draw an outlined ellipse.
22078     template<typename tc>
22079     CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
22080                           const CImg<tc>& color, const float opacity,
22081                           const unsigned int pattern) {
22082       return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity,pattern);
22083     }
22084 
22085     //! Draw an outlined ellipse.
22086     /**
22087        \param x0 = X-coordinate of the ellipse center.
22088        \param y0 = Y-coordinate of the ellipse center.
22089        \param tensor = Diffusion tensor describing the ellipse.
22090        \param color = array of dimv() values of type \c T, defining the drawing color.
22091        \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
22092        \param opacity = opacity of the drawing.
22093     **/
22094     template<typename t, typename tc>
22095     CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
22096                           const tc *const color, const float opacity,
22097                           const unsigned int pattern) {
22098       CImgList<t> eig = tensor.get_symmetric_eigen();
22099       const CImg<t> &val = eig[0], &vec = eig[1];
22100       return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity,pattern);
22101     }
22102 
22103     //! Draw an outlined ellipse.
22104     template<typename t, typename tc>
22105     CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
22106                           const CImg<tc>& color, const float opacity,
22107                           const unsigned int pattern) {
22108       return draw_ellipse(x0,y0,tensor,color.data,opacity,pattern);
22109     }
22110 
22111     //! Draw a filled circle.
22112     /**
22113        \param x0 X-coordinate of the circle center.
22114        \param y0 Y-coordinate of the circle center.
22115        \param radius  Circle radius.
22116        \param color Array of dimv() values of type \c T, defining the drawing color.
22117        \param opacity Drawing opacity.
22118        \note
22119        - Circle version of the Bresenham's algorithm is used.
22120     **/
22121     template<typename tc>
22122     CImg<T>& draw_circle(const int x0, const int y0, int radius,
22123                          const tc *const color, const float opacity=1) {
22124       if (!is_empty()) {
22125         if (!color)
22126           throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
22127                                       pixel_type());
22128         _draw_scanline(color,opacity);
22129         if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
22130         if (y0>=0 && y0<dimy()) _draw_scanline(x0-radius,x0+radius,y0,color,opacity);
22131         for (int f=1-radius, ddFx=0, ddFy=-(radius<<1), x=0, y=radius; x<y; ) {
22132           if (f>=0) {
22133             const int x1 = x0-x, x2 = x0+x, y1 = y0-y, y2 = y0+y;
22134             if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
22135             if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
22136             f+=(ddFy+=2); --y;
22137           }
22138           const bool no_diag = y!=(x++);
22139           ++(f+=(ddFx+=2));
22140           const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x;
22141           if (no_diag) {
22142             if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
22143             if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
22144           }
22145         }
22146       }
22147       return *this;
22148     }
22149 
22150     //! Draw a filled circle.
22151     template<typename tc>
22152     CImg<T>& draw_circle(const int x0, const int y0, int radius,
22153                          const CImg<tc>& color, const float opacity=1) {
22154       return draw_circle(x0,y0,radius,color.data,opacity);
22155     }
22156 
22157     //! Draw an outlined circle.
22158     /**
22159        \param x0 X-coordinate of the circle center.
22160        \param y0 Y-coordinate of the circle center.
22161        \param radius Circle radius.
22162        \param color Array of dimv() values of type \c T, defining the drawing color.
22163        \param opacity Drawing opacity.
22164     **/
22165     template<typename tc>
22166     CImg<T>& draw_circle(const int x0, const int y0, int radius,
22167                          const tc *const color, const float opacity,
22168                          const unsigned int) {
22169       if (!is_empty()) {
22170         if (!color)
22171           throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
22172                                       pixel_type());
22173         if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
22174         if (!radius) return draw_point(x0,y0,color,opacity);
22175         draw_point(x0-radius,y0,color,opacity).draw_point(x0+radius,y0,color,opacity).
22176           draw_point(x0,y0-radius,color,opacity).draw_point(x0,y0+radius,color,opacity);
22177         if (radius==1) return *this;
22178         for (int f=1-radius, ddFx=0, ddFy=-(radius<<1), x=0, y=radius; x<y; ) {
22179           if (f>=0) { f+=(ddFy+=2); --y; }
22180           ++x; ++(f+=(ddFx+=2));
22181           if (x!=y+1) {
22182             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;
22183             draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity).
22184               draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity);
22185             if (x!=y)
22186               draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity).
22187                 draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity);
22188           }
22189         }
22190       }
22191       return *this;
22192     }
22193 
22194     //! Draw an outlined circle.
22195     template<typename tc>
22196     CImg<T>& draw_circle(const int x0, const int y0, int radius, const CImg<tc>& color,
22197                          const float opacity,
22198                          const unsigned int pattern) {
22199       return draw_circle(x0,y0,radius,color.data,opacity,pattern);
22200     }
22201 
22202     // Draw a text (internal).
22203     template<typename tc1, typename tc2, typename t>
22204     CImg<T>& _draw_text(const int x0, const int y0, const char *const text,
22205                         const tc1 *const foreground_color, const tc2 *const background_color,
22206                         const float opacity, const CImgList<t>& font) {
22207       if (!text) return *this;
22208       if (!font)
22209         throw CImgArgumentException("CImg<%s>::draw_text() : Specified font (%u,%p) is empty.",
22210                                     pixel_type(),font.size,font.data);
22211       const int text_length = cimg::strlen(text);
22212 
22213       if (is_empty()) {
22214         // If needed, pre-compute necessary size of the image
22215         int x = 0, y = 0, w = 0;
22216         unsigned char c = 0;
22217         for (int i = 0; i<text_length; ++i) {
22218           c = text[i];
22219           switch (c) {
22220           case '\n' : y+=font[' '].height; if (x>w) w = x; x = 0; break;
22221           case '\t' : x+=4*font[' '].width; break;
22222           default : if (c<font.size) x+=font[c].width;
22223           }
22224         }
22225         if (x!=0 || c=='\n') {
22226           if (x>w) w=x;
22227           y+=font[' '].height;
22228         }
22229         assign(x0+w,y0+y,1,font[' '].dim,0);
22230         if (background_color) cimg_forV(*this,k) get_shared_channel(k).fill((T)background_color[k]);
22231       }
22232 
22233       int x = x0, y = y0;
22234       CImg<T> letter;
22235       for (int i = 0; i<text_length; ++i) {
22236         const unsigned char c = text[i];
22237         switch (c) {
22238         case '\n' : y+=font[' '].height; x = x0; break;
22239         case '\t' : x+=4*font[' '].width; break;
22240         default : if (c<font.size) {
22241           letter = font[c];
22242           const CImg<T>& mask = (c+256)<(int)font.size?font[c+256]:font[c];
22243           if (foreground_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
22244             if (mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)(letter(p,0,0,k)*foreground_color[k]);
22245           if (background_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
22246             if (!mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)background_color[k];
22247           if (!background_color && font.size>=512) draw_image(x,y,letter,mask,opacity,(T)1);
22248           else draw_image(x,y,letter,opacity);
22249           x+=letter.width;
22250         }
22251         }
22252       }
22253       return *this;
22254     }
22255 
22256     //! Draw a text.
22257     /**
22258        \param x0 X-coordinate of the text in the instance image.
22259        \param y0 Y-coordinate of the text in the instance image.
22260        \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
22261        \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
22262        \param font Font used for drawing text.
22263        \param opacity Drawing opacity.
22264        \param format 'printf'-style format string, followed by arguments.
22265        \note Clipping is supported.
22266     **/
22267     template<typename tc1, typename tc2, typename t>
22268     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22269                        const tc1 *const foreground_color, const tc2 *const background_color,
22270                        const float opacity, const CImgList<t>& font, ...) {
22271       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
22272       cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22273       return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
22274     }
22275 
22276     //! Draw a text.
22277     template<typename tc1, typename tc2, typename t>
22278     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22279                        const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
22280                        const float opacity, const CImgList<t>& font, ...) {
22281       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
22282       cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22283       return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
22284     }
22285 
22286     //! Draw a text.
22287     template<typename tc, typename t>
22288     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22289                        const tc *const foreground_color, const int background_color,
22290                        const float opacity, const CImgList<t>& font, ...) {
22291       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
22292       cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22293       return _draw_text(x0,y0,tmp,foreground_color,(tc*)background_color,opacity,font);
22294     }
22295 
22296     //! Draw a text.
22297     template<typename tc, typename t>
22298     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22299                        const int foreground_color, const tc *const background_color,
22300                        const float opacity, const CImgList<t>& font, ...) {
22301       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
22302       cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22303       return _draw_text(x0,y0,tmp,(tc*)foreground_color,background_color,opacity,font);
22304     }
22305 
22306     //! Draw a text.
22307     /**
22308        \param x0 X-coordinate of the text in the instance image.
22309        \param y0 Y-coordinate of the text in the instance image.
22310        \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
22311        \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
22312        \param font_size Size of the font (nearest match).
22313        \param opacity Drawing opacity.
22314        \param format 'printf'-style format string, followed by arguments.
22315        \note Clipping is supported.
22316     **/
22317     template<typename tc1, typename tc2>
22318     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22319                        const tc1 *const foreground_color, const tc2 *const background_color,
22320                        const float opacity=1, const unsigned int font_size=11, ...) {
22321       static CImgList<T> font;
22322       static unsigned int fsize = 0;
22323       if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
22324       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22325       return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
22326     }
22327 
22328     //! Draw a text.
22329     template<typename tc1, typename tc2>
22330     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22331                        const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
22332                        const float opacity=1, const unsigned int font_size=11, ...) {
22333       static CImgList<T> font;
22334       static unsigned int fsize = 0;
22335       if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
22336       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22337       return _draw_text(x0,y0,tmp,foreground_color.data,background_color.data,opacity,font);
22338     }
22339 
22340     //! Draw a text.
22341     template<typename tc>
22342     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22343                        const tc *const foreground_color, const int background_color=0,
22344                        const float opacity=1, const unsigned int font_size=11, ...) {
22345       static CImgList<T> font;
22346       static unsigned int fsize = 0;
22347       if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
22348       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22349       return _draw_text(x0,y0,tmp,foreground_color,(const tc*)background_color,opacity,font);
22350     }
22351 
22352     //! Draw a text.
22353     template<typename tc>
22354     CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22355                        const int foreground_color, const tc *const background_color,
22356                        const float opacity=1, const unsigned int font_size=11, ...) {
22357       static CImgList<T> font;
22358       static unsigned int fsize = 0;
22359       if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
22360       char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22361       return _draw_text(x0,y0,tmp,(tc*)foreground_color,background_color,opacity,font);
22362     }
22363 
22364     //! Draw a vector field in the instance image, using a colormap.
22365     /**
22366        \param flow Image of 2d vectors used as input data.
22367        \param color Image of dimv()-D vectors corresponding to the color of each arrow.
22368        \param sampling Length (in pixels) between each arrow.
22369        \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
22370        \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
22371        \param opacity Opacity of the drawing.
22372        \param pattern Used pattern to draw lines.
22373        \note Clipping is supported.
22374     **/
22375     template<typename t1, typename t2>
22376     CImg<T>& draw_quiver(const CImg<t1>& flow,
22377                          const t2 *const color, const float opacity=1,
22378                          const unsigned int sampling=25, const float factor=-20,
22379                          const int quiver_type=0, const unsigned int pattern=~0U) {
22380       return draw_quiver(flow,CImg<t2>(color,dim,1,1,1,true),opacity,sampling,factor,quiver_type,pattern);
22381     }
22382 
22383     //! Draw a vector field in the instance image, using a colormap.
22384     /**
22385        \param flow Image of 2d vectors used as input data.
22386        \param color Image of dimv()-D vectors corresponding to the color of each arrow.
22387        \param sampling Length (in pixels) between each arrow.
22388        \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
22389        \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
22390        \param opacity Opacity of the drawing.
22391        \param pattern Used pattern to draw lines.
22392        \note Clipping is supported.
22393     **/
22394     template<typename t1, typename t2>
22395     CImg<T>& draw_quiver(const CImg<t1>& flow,
22396                          const CImg<t2>& color, const float opacity=1,
22397                          const unsigned int sampling=25, const float factor=-20,
22398                          const int quiver_type=0, const unsigned int pattern=~0U) {
22399       if (!is_empty()) {
22400         if (!flow || flow.dim!=2)
22401           throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.",
22402                                       pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data);
22403         if (sampling<=0)
22404           throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g",
22405                                       pixel_type(),sampling);
22406         const bool colorfield = (color.width==flow.width && color.height==flow.height && color.depth==1 && color.dim==dim);
22407         if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,quiver_type,pattern);
22408 
22409         float vmax,fact;
22410         if (factor<=0) {
22411           float m, M = (float)flow.get_pointwise_norm(2).maxmin(m);
22412           vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
22413           fact = -factor;
22414         } else { fact = factor; vmax = 1; }
22415 
22416         for (unsigned int y=sampling/2; y<height; y+=sampling)
22417           for (unsigned int x=sampling/2; x<width; x+=sampling) {
22418             const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
22419             float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
22420             if (!quiver_type) {
22421               const int xx = x+(int)u, yy = y+(int)v;
22422               if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y).data,opacity,45,sampling/5.0f,pattern);
22423               else draw_arrow(x,y,xx,yy,color,opacity,45,sampling/5.0f,pattern);
22424             } else {
22425               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);
22426               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);
22427             }
22428           }
22429       }
22430       return *this;
22431     }
22432 
22433     //! Draw a 1D graph on the instance image.
22434     /**
22435        \param data Image containing the graph values I = f(x).
22436        \param color Array of dimv() values of type \c T, defining the drawing color.
22437        \param gtype Define the type of the plot :
22438                       - 0 = Plot using points clouds.
22439                       - 1 = Plot using linear interpolation (segments).
22440                       - 2 = Plot with bars.
22441                       - 3 = Plot using cubic interpolation (3-polynomials).
22442                       - 4 = Plot using cross clouds.
22443        \param ymin Lower bound of the y-range.
22444        \param ymax Upper bound of the y-range.
22445        \param opacity Drawing opacity.
22446        \param pattern Drawing pattern.
22447        \note
22448          - if \c ymin==ymax==0, the y-range is computed automatically from the input sample.
22449     **/
22450     template<typename t, typename tc>
22451     CImg<T>& draw_graph(const CImg<t>& data,
22452                         const tc *const color, const float opacity=1,
22453                         const unsigned int plot_type=1, const unsigned int vertex_type=1,
22454                         const double ymin=0, const double ymax=0,
22455                         const unsigned int pattern=~0U) {
22456       if (is_empty() || height<=1) return *this;;
22457       const unsigned long siz = data.size();
22458       if (!color)
22459         throw CImgArgumentException("CImg<%s>::draw_graph() : Specified color is (null)",
22460                                     pixel_type());
22461       tc *color1 = 0, *color2 = 0;
22462       if (plot_type==3) {
22463         color1 = new tc[dim]; color2 = new tc[dim];
22464         cimg_forV(*this,k) { color1[k] = (tc)(color[k]*0.6f); color2[k] = (tc)(color[k]*0.3f); }
22465       }
22466 
22467       double m = ymin, M = ymax;
22468       if (ymin==ymax) m = (double)data.maxmin(M);
22469       if (m==M) { --m; ++M; }
22470       const float ca = (float)(M-m)/(height-1);
22471       bool init_hatch = true;
22472 
22473       // Draw graph edges
22474       switch (plot_type%4) {
22475       case 1 : { // Segments
22476         int oX = 0, oY = (int)((data[0]-m)/ca);
22477         for (unsigned long off = 1; off<siz; ++off) {
22478           const int
22479             X = (int)(off*width/siz),
22480             Y = (int)((data[off]-m)/ca);
22481           draw_line(oX,oY,X,Y,color,opacity,pattern,init_hatch);
22482           oX = X; oY = Y;
22483           init_hatch = false;
22484         }
22485       } break;
22486       case 2 : { // Spline
22487         const CImg<t> ndata = data.get_shared_points(0,siz-1);
22488         int oY = (int)((data[0]-m)/ca);
22489         cimg_forX(*this,x) {
22490           const int Y = (int)((ndata._cubic_atX((float)x*ndata.width/width)-m)/ca);
22491           if (x>0) draw_line(x,oY,x+1,Y,color,opacity,pattern,init_hatch);
22492           init_hatch = false;
22493           oY = Y;
22494         }
22495       } break;
22496       case 3 : { // Bars
22497         const int Y0 = (int)(-m/ca);
22498         int oX = 0;
22499         cimg_foroff(data,off) {
22500           const int
22501             X = (off+1)*width/siz-1,
22502             Y = (int)((data[off]-m)/ca);
22503           draw_rectangle(oX,Y0,X,Y,color1,opacity).
22504             draw_line(oX,Y,oX,Y0,color2,opacity).
22505             draw_line(oX,Y0,X,Y0,Y<=Y0?color2:color,opacity).
22506             draw_line(X,Y,X,Y0,color,opacity).
22507             draw_line(oX,Y,X,Y,Y<=Y0?color:color2,opacity);
22508           oX = X+1;
22509         }
22510       } break;
22511       default : break; // No edges
22512       }
22513 
22514       // Draw graph points
22515       switch (vertex_type%8) {
22516       case 1 : { // Point
22517         cimg_foroff(data,off) {
22518           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22519           draw_point(X,Y,color,opacity);
22520         }
22521       } break;
22522       case 2 : { // Standard Cross
22523         cimg_foroff(data,off) {
22524           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22525           draw_line(X-3,Y,X+3,Y,color,opacity).draw_line(X,Y-3,X,Y+3,color,opacity);
22526         }
22527       } break;
22528       case 3 : { // Rotated Cross
22529         cimg_foroff(data,off) {
22530           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22531           draw_line(X-3,Y-3,X+3,Y+3,color,opacity).draw_line(X-3,Y+3,X+3,Y-3,color,opacity);
22532         }
22533       } break;
22534       case 4 : { // Filled Circle
22535         cimg_foroff(data,off) {
22536           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22537           draw_circle(X,Y,3,color,opacity);
22538         }
22539       } break;
22540       case 5 : { // Outlined circle
22541         cimg_foroff(data,off) {
22542           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22543           draw_circle(X,Y,3,color,opacity,0U);
22544         }
22545       } break;
22546       case 6 : { // Square
22547         cimg_foroff(data,off) {
22548           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22549           draw_rectangle(X-3,Y-3,X+3,Y+3,color,opacity,~0U);
22550         }
22551       } break;
22552       case 7 : { // Diamond
22553         cimg_foroff(data,off) {
22554           const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22555           draw_line(X,Y-4,X+4,Y,color,opacity).
22556             draw_line(X+4,Y,X,Y+4,color,opacity).
22557             draw_line(X,Y+4,X-4,Y,color,opacity).
22558             draw_line(X-4,Y,X,Y-4,color,opacity);
22559         }
22560       } break;
22561       default : break; // No vertices
22562       }
22563 
22564       if (color1) delete[] color1; if (color2) delete[] color2;
22565       return *this;
22566     }
22567 
22568     //! Draw a 1D graph on the instance image.
22569     template<typename t, typename tc>
22570     CImg<T>& draw_graph(const CImg<t>& data,
22571                         const CImg<tc>& color, const float opacity=1,
22572                         const unsigned int plot_type=1, const unsigned int vertex_type=1,
22573                         const double ymin=0, const double ymax=0,
22574                         const unsigned int pattern=~0U) {
22575       return draw_graph(data,color.data,opacity,plot_type,vertex_type,ymin,ymax,pattern);
22576     }
22577 
22578     //! Draw a labeled horizontal axis on the instance image.
22579     /**
22580        \param xvalues Lower bound of the x-range.
22581        \param y Y-coordinate of the horizontal axis in the instance image.
22582        \param color Array of dimv() values of type \c T, defining the drawing color.
22583        \param opacity Drawing opacity.
22584        \param pattern Drawing pattern.
22585        \param opacity_out Drawing opacity of 'outside' axes.
22586        \note if \c precision==0, precision of the labels is automatically computed.
22587     **/
22588     template<typename t, typename tc>
22589     CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
22590                        const tc *const color, const float opacity=1,
22591                        const unsigned int pattern=~0U) {
22592       if (!is_empty()) {
22593         int siz = (int)xvalues.size()-1;
22594         if (siz<=0) draw_line(0,y,width-1,y,color,opacity,pattern);
22595         else {
22596           if (xvalues[0]<xvalues[siz]) draw_arrow(0,y,width-1,y,color,opacity,30,5,pattern);
22597           else draw_arrow(width-1,y,0,y,color,opacity,30,5,pattern);
22598           const int yt = (y+14)<dimy()?(y+3):(y-14);
22599           char txt[32];
22600           cimg_foroff(xvalues,x) {
22601             cimg_std::sprintf(txt,"%g",(double)xvalues(x));
22602             const int xi = (int)(x*(width-1)/siz), xt = xi-(int)cimg::strlen(txt)*3;
22603             draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity).
22604               draw_text(xt<0?0:xt,yt,txt,color,(tc*)0,opacity,11);
22605           }
22606         }
22607       }
22608       return *this;
22609     }
22610 
22611     //! Draw a labeled horizontal axis on the instance image.
22612     template<typename t, typename tc>
22613     CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
22614                        const CImg<tc>& color, const float opacity=1,
22615                        const unsigned int pattern=~0U) {
22616       return draw_axis(xvalues,y,color.data,opacity,pattern);
22617     }
22618 
22619     //! Draw a labeled vertical axis on the instance image.
22620     template<typename t, typename tc>
22621     CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
22622                        const tc *const color, const float opacity=1,
22623                        const unsigned int pattern=~0U) {
22624       if (!is_empty()) {
22625         int siz = (int)yvalues.size()-1;
22626         if (siz<=0) draw_line(x,0,x,height-1,color,opacity,pattern);
22627         else {
22628           if (yvalues[0]<yvalues[siz]) draw_arrow(x,0,x,height-1,color,opacity,30,5,pattern);
22629           else draw_arrow(x,height-1,x,0,color,opacity,30,5,pattern);
22630           char txt[32];
22631           cimg_foroff(yvalues,y) {
22632             cimg_std::sprintf(txt,"%g",(double)yvalues(y));
22633             const int
22634               yi = (int)(y*(height-1)/siz),
22635               tmp = yi-5,
22636               nyi = tmp<0?0:(tmp>=dimy()-11?dimy()-11:tmp),
22637               xt = x-(int)cimg::strlen(txt)*7;
22638             draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity);
22639             if (xt>0) draw_text(xt,nyi,txt,color,(tc*)0,opacity,11);
22640             else draw_text(x+3,nyi,txt,color,(tc*)0,opacity,11);
22641           }
22642         }
22643       }
22644       return *this;
22645     }
22646 
22647     //! Draw a labeled vertical axis on the instance image.
22648     template<typename t, typename tc>
22649     CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
22650                        const CImg<tc>& color, const float opacity=1,
22651                        const unsigned int pattern=~0U) {
22652       return draw_axis(x,yvalues,color.data,opacity,pattern);
22653     }
22654 
22655     //! Draw a labeled horizontal+vertical axis on the instance image.
22656     template<typename tx, typename ty, typename tc>
22657       CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
22658                          const tc *const color, const float opacity=1,
22659                          const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22660       if (!is_empty()) {
22661         const CImg<tx> nxvalues(xvalues.data,xvalues.size(),1,1,1,true);
22662         const int sizx = (int)xvalues.size()-1, wm1 = (int)(width)-1;
22663         if (sizx>0) {
22664           float ox = (float)nxvalues[0];
22665           for (unsigned int x = 1; x<width; ++x) {
22666             const float nx = (float)nxvalues._linear_atX((float)x*sizx/wm1);
22667             if (nx*ox<=0) { draw_axis(nx==0?x:x-1,yvalues,color,opacity,patterny); break; }
22668             ox = nx;
22669           }
22670         }
22671         const CImg<ty> nyvalues(yvalues.data,yvalues.size(),1,1,1,true);
22672         const int sizy = (int)yvalues.size()-1, hm1 = (int)(height)-1;
22673         if (sizy>0) {
22674           float oy = (float)nyvalues[0];
22675           for (unsigned int y = 1; y<height; ++y) {
22676             const float ny = (float)nyvalues._linear_atX((float)y*sizy/hm1);
22677             if (ny*oy<=0) { draw_axis(xvalues,ny==0?y:y-1,color,opacity,patternx); break; }
22678             oy = ny;
22679           }
22680         }
22681       }
22682       return *this;
22683     }
22684 
22685     //! Draw a labeled horizontal+vertical axis on the instance image.
22686     template<typename tx, typename ty, typename tc>
22687     CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
22688                        const CImg<tc>& color, const float opacity=1,
22689                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22690       return draw_axis(xvalues,yvalues,color.data,opacity,patternx,patterny);
22691     }
22692 
22693     //! Draw a labeled horizontal+vertical axis on the instance image.
22694     template<typename tc>
22695     CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
22696                        const tc *const color, const float opacity=1,
22697                        const int subdivisionx=-60, const int subdivisiony=-60,
22698                        const float precisionx=0, const float precisiony=0,
22699                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22700       if (!is_empty()) {
22701         const float
22702           dx = cimg::abs(x1-x0), dy = cimg::abs(y1-y0),
22703           px = (precisionx==0)?(float)cimg_std::pow(10.0,(int)cimg_std::log10(dx)-2.0):precisionx,
22704           py = (precisiony==0)?(float)cimg_std::pow(10.0,(int)cimg_std::log10(dy)-2.0):precisiony;
22705         draw_axis(CImg<floatT>::sequence(subdivisionx>0?subdivisionx:1-dimx()/subdivisionx,x0,x1).round(px),
22706                   CImg<floatT>::sequence(subdivisiony>0?subdivisiony:1-dimy()/subdivisiony,y0,y1).round(py),
22707                   color,opacity,patternx,patterny);
22708       }
22709       return *this;
22710     }
22711 
22712     //! Draw a labeled horizontal+vertical axis on the instance image.
22713     template<typename tc>
22714     CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
22715                        const CImg<tc>& color, const float opacity=1,
22716                        const int subdivisionx=-60, const int subdivisiony=-60,
22717                        const float precisionx=0, const float precisiony=0,
22718                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22719       return draw_axis(x0,x1,y0,y1,color.data,opacity,subdivisionx,subdivisiony,precisionx,precisiony,patternx,patterny);
22720     }
22721 
22722     //! Draw grid.
22723     template<typename tx, typename ty, typename tc>
22724     CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
22725                        const tc *const color, const float opacity=1,
22726                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22727       if (!is_empty()) {
22728         if (xvalues) cimg_foroff(xvalues,x) {
22729           const int xi = (int)xvalues[x];
22730           if (xi>=0 && xi<dimx()) draw_line(xi,0,xi,height-1,color,opacity,patternx);
22731         }
22732         if (yvalues) cimg_foroff(yvalues,y) {
22733           const int yi = (int)yvalues[y];
22734           if (yi>=0 && yi<dimy()) draw_line(0,yi,width-1,yi,color,opacity,patterny);
22735         }
22736       }
22737       return *this;
22738     }
22739 
22740     //! Draw grid.
22741     template<typename tx, typename ty, typename tc>
22742     CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
22743                        const CImg<tc>& color, const float opacity=1,
22744                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22745       return draw_grid(xvalues,yvalues,color.data,opacity,patternx,patterny);
22746     }
22747 
22748     //! Draw grid.
22749     template<typename tc>
22750     CImg<T>& draw_grid(const float deltax,  const float deltay,
22751                        const float offsetx, const float offsety,
22752                        const bool invertx, const bool inverty,
22753                        const tc *const color, const float opacity=1,
22754                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22755       CImg<uintT> seqx, seqy;
22756       if (deltax!=0) {
22757         const float dx = deltax>0?deltax:width*-deltax/100;
22758         const unsigned int nx = (unsigned int)(width/dx);
22759         seqx = CImg<uintT>::sequence(1+nx,0,(unsigned int)(dx*nx));
22760         if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x)+offsetx,(float)width);
22761         if (invertx) cimg_foroff(seqx,x) seqx(x) = width-1-seqx(x);
22762       }
22763 
22764       if (deltay!=0) {
22765         const float dy = deltay>0?deltay:height*-deltay/100;
22766         const unsigned int ny = (unsigned int)(height/dy);
22767         seqy = CImg<uintT>::sequence(1+ny,0,(unsigned int)(dy*ny));
22768         if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y)+offsety,(float)height);
22769         if (inverty) cimg_foroff(seqy,y) seqy(y) = height-1-seqy(y);
22770      }
22771       return draw_grid(seqx,seqy,color,opacity,patternx,patterny);
22772     }
22773 
22774     //! Draw grid.
22775     template<typename tc>
22776     CImg<T>& draw_grid(const float deltax,  const float deltay,
22777                        const float offsetx, const float offsety,
22778                        const bool invertx, const bool inverty,
22779                        const CImg<tc>& color, const float opacity=1,
22780                        const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22781       return draw_grid(deltax,deltay,offsetx,offsety,invertx,inverty,color.data,opacity,patternx,patterny);
22782     }
22783 
22784     //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
22785     /**
22786        \param x X-coordinate of the starting point of the region to fill.
22787        \param y Y-coordinate of the starting point of the region to fill.
22788        \param z Z-coordinate of the starting point of the region to fill.
22789        \param color An array of dimv() values of type \c T, defining the drawing color.
22790        \param region Image that will contain the mask of the filled region mask, as an output.
22791        \param sigma Tolerance concerning neighborhood values.
22792        \param opacity Opacity of the drawing.
22793        \param high_connexity Tells if 8-connexity must be used (only for 2D images).
22794        \return \p region is initialized with the binary mask of the filled region.
22795     **/
22796     template<typename tc, typename t>
22797     CImg<T>& draw_fill(const int x, const int y, const int z,
22798                        const tc *const color, const float opacity,
22799                        CImg<t>& region, const float sigma=0,
22800                        const bool high_connexity=false) {
22801 
22802 #define _cimg_draw_fill_test(x,y,z,res) if (region(x,y,z)) res = false; else { \
22803   res = true; \
22804   const T *reference_col = reference_color.ptr() + dim, *ptrs = ptr(x,y,z) + siz; \
22805   for (unsigned int i = dim; res && i; --i) { ptrs-=whz; res = (cimg::abs(*ptrs - *(--reference_col))<=sigma); } \
22806   region(x,y,z) = (t)(res?1:noregion); \
22807 }
22808 
22809 #define _cimg_draw_fill_set(x,y,z) { \
22810   const tc *col = color; \
22811   T *ptrd = ptr(x,y,z); \
22812   if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; } \
22813   else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; } \
22814 }
22815 
22816 #define _cimg_draw_fill_insert(x,y,z) { \
22817   if (posr1>=remaining.height) remaining.resize(3,remaining.height<<1,1,1,0); \
22818   unsigned int *ptrr = remaining.ptr(0,posr1); \
22819   *(ptrr++) = x; *(ptrr++) = y; *(ptrr++) = z; ++posr1; \
22820 }
22821 
22822 #define _cimg_draw_fill_test_neighbor(x,y,z,cond) if (cond) { \
22823   const unsigned int tx = x, ty = y, tz = z; \
22824   _cimg_draw_fill_test(tx,ty,tz,res); if (res) _cimg_draw_fill_insert(tx,ty,tz); \
22825 }
22826 
22827       if (!color)
22828         throw CImgArgumentException("CImg<%s>::draw_fill() : Specified color is (null).",
22829                                     pixel_type());
22830       region.assign(width,height,depth,1,(t)0);
22831       if (x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz()) {
22832         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
22833         const unsigned int whz = width*height*depth, siz = dim*whz, W1 = width-1, H1 = height-1, D1 = depth-1;
22834         const bool threed = depth>1;
22835         const CImg<T> reference_color = get_vector_at(x,y,z);
22836         CImg<uintT> remaining(3,512,1,1,0);
22837         remaining(0,0) = x; remaining(1,0) = y; remaining(2,0) = z;
22838         unsigned int posr0 = 0, posr1 = 1;
22839         region(x,y,z) = (t)1;
22840         const t noregion = ((t)1==(t)2)?(t)0:(t)(-1);
22841         if (threed) do { // 3D version of the filling algorithm
22842           const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++), zc = *(pcurr++);
22843           if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
22844           bool cont, res;
22845           unsigned int nxc = xc;
22846           do { // X-backward
22847             _cimg_draw_fill_set(nxc,yc,zc);
22848             _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
22849             _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
22850             _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
22851             _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
22852             if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
22853           } while (cont);
22854           nxc = xc;
22855           do { // X-forward
22856             if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
22857             if (cont) {
22858               _cimg_draw_fill_set(nxc,yc,zc);
22859               _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
22860               _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
22861               _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
22862               _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
22863             }
22864           } while (cont);
22865           unsigned int nyc = yc;
22866           do { // Y-backward
22867             if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
22868             if (cont) {
22869               _cimg_draw_fill_set(xc,nyc,zc);
22870               _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
22871               _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
22872               _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
22873               _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
22874             }
22875           } while (cont);
22876           nyc = yc;
22877           do { // Y-forward
22878             if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
22879             if (cont) {
22880               _cimg_draw_fill_set(xc,nyc,zc);
22881               _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
22882               _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
22883               _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
22884               _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
22885             }
22886           } while (cont);
22887           unsigned int nzc = zc;
22888           do { // Z-backward
22889             if (nzc) { --nzc; _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
22890             if (cont) {
22891               _cimg_draw_fill_set(xc,yc,nzc);
22892               _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
22893               _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
22894               _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
22895               _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
22896             }
22897           } while (cont);
22898           nzc = zc;
22899           do { // Z-forward
22900             if ((++nzc)<=D1) { _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
22901             if (cont) {
22902               _cimg_draw_fill_set(xc,nyc,zc);
22903               _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
22904               _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
22905               _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
22906               _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
22907             }
22908           } while (cont);
22909         } while (posr1>posr0);
22910         else do { // 2D version of the filling algorithm
22911           const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++);
22912           if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
22913           bool cont, res;
22914           unsigned int nxc = xc;
22915           do { // X-backward
22916             _cimg_draw_fill_set(nxc,yc,0);
22917             _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
22918             _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
22919             if (high_connexity) {
22920               _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
22921               _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
22922               _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
22923               _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
22924             }
22925             if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
22926           } while (cont);
22927           nxc = xc;
22928           do { // X-forward
22929             if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
22930             if (cont) {
22931               _cimg_draw_fill_set(nxc,yc,0);
22932               _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
22933               _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
22934               if (high_connexity) {
22935                 _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
22936                 _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
22937                 _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
22938                 _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
22939               }
22940             }
22941           } while (cont);
22942           unsigned int nyc = yc;
22943           do { // Y-backward
22944             if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
22945             if (cont) {
22946               _cimg_draw_fill_set(xc,nyc,0);
22947               _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
22948               _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
22949               if (high_connexity) {
22950                 _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
22951                 _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
22952                 _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
22953                 _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
22954               }
22955             }
22956           } while (cont);
22957           nyc = yc;
22958           do { // Y-forward
22959             if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
22960             if (cont) {
22961               _cimg_draw_fill_set(xc,nyc,0);
22962               _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
22963               _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
22964               if (high_connexity) {
22965                 _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
22966                 _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
22967                 _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
22968                 _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
22969               }
22970             }
22971           } while (cont);
22972         } while (posr1>posr0);
22973         if (noregion) cimg_for(region,ptr,t) if (*ptr==noregion) *ptr = (t)0;
22974       }
22975       return *this;
22976     }
22977 
22978     //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
22979     template<typename tc, typename t>
22980     CImg<T>& draw_fill(const int x, const int y, const int z,
22981                        const CImg<tc>& color, const float opacity,
22982                        CImg<t>& region, const float sigma=0, const bool high_connexity=false) {
22983       return draw_fill(x,y,z,color.data,opacity,region,sigma,high_connexity);
22984     }
22985 
22986     //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
22987     /**
22988        \param x = X-coordinate of the starting point of the region to fill.
22989        \param y = Y-coordinate of the starting point of the region to fill.
22990        \param z = Z-coordinate of the starting point of the region to fill.
22991        \param color = an array of dimv() values of type \c T, defining the drawing color.
22992        \param sigma = tolerance concerning neighborhood values.
22993        \param opacity = opacity of the drawing.
22994     **/
22995     template<typename tc>
22996     CImg<T>& draw_fill(const int x, const int y, const int z,
22997                        const tc *const color, const float opacity=1,
22998                        const float sigma=0, const bool high_connexity=false) {
22999       CImg<boolT> tmp;
23000       return draw_fill(x,y,z,color,opacity,tmp,sigma,high_connexity);
23001     }
23002 
23003     //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
23004     template<typename tc>
23005     CImg<T>& draw_fill(const int x, const int y, const int z,
23006                        const CImg<tc>& color, const float opacity=1,
23007                        const float sigma=0, const bool high_connexity=false) {
23008       return draw_fill(x,y,z,color.data,opacity,sigma,high_connexity);
23009     }
23010 
23011     //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
23012     /**
23013        \param x = X-coordinate of the starting point of the region to fill.
23014        \param y = Y-coordinate of the starting point of the region to fill.
23015        \param color = an array of dimv() values of type \c T, defining the drawing color.
23016        \param sigma = tolerance concerning neighborhood values.
23017        \param opacity = opacity of the drawing.
23018     **/
23019     template<typename tc>
23020     CImg<T>& draw_fill(const int x, const int y,
23021                        const tc *const color, const float opacity=1,
23022                        const float sigma=0, const bool high_connexity=false) {
23023       CImg<boolT> tmp;
23024       return draw_fill(x,y,0,color,opacity,tmp,sigma,high_connexity);
23025     }
23026 
23027     //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
23028     template<typename tc>
23029     CImg<T>& draw_fill(const int x, const int y,
23030                        const CImg<tc>& color, const float opacity=1,
23031                        const float sigma=0, const bool high_connexity=false) {
23032       return draw_fill(x,y,color.data,opacity,sigma,high_connexity);
23033     }
23034 
23035     //! Draw a plasma random texture.
23036     /**
23037        \param x0 = X-coordinate of the upper-left corner of the plasma.
23038        \param y0 = Y-coordinate of the upper-left corner of the plasma.
23039        \param x1 = X-coordinate of the lower-right corner of the plasma.
23040        \param y1 = Y-coordinate of the lower-right corner of the plasma.
23041        \param alpha = Alpha-parameter of the plasma.
23042        \param beta = Beta-parameter of the plasma.
23043        \param opacity = opacity of the drawing.
23044     **/
23045     CImg<T>& draw_plasma(const int x0, const int y0, const int x1, const int y1,
23046                          const float alpha=1, const float beta=1,
23047                          const float opacity=1) {
23048       if (!is_empty()) {
23049         const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
23050         int nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1;
23051         if (nx1<nx0) cimg::swap(nx0,nx1);
23052         if (ny1<ny0) cimg::swap(ny0,ny1);
23053         if (nx0<0) nx0 = 0;
23054         if (nx1>=dimx()) nx1 = width-1;
23055         if (ny0<0) ny0 = 0;
23056         if (ny1>=dimy()) ny1 = height-1;
23057         const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx = (xc-nx0), dy = (yc-ny0);
23058         const Tfloat dc = (Tfloat)(cimg_std::sqrt((float)(dx*dx+dy*dy))*alpha + beta);
23059         Tfloat val = 0;
23060         cimg_forV(*this,k) {
23061           if (opacity>=1) {
23062             const Tfloat
23063               val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
23064               val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
23065             (*this)(xc,ny0,0,k) = (T)((val0+val1)/2);
23066             (*this)(xc,ny1,0,k) = (T)((val2+val3)/2);
23067             (*this)(nx0,yc,0,k) = (T)((val0+val2)/2);
23068             (*this)(nx1,yc,0,k) = (T)((val1+val3)/2);
23069             do {
23070               val = (Tfloat)(0.25f*((Tfloat)((*this)(nx0,ny0,0,k)) +
23071                                    (Tfloat)((*this)(nx1,ny0,0,k)) +
23072                                    (Tfloat)((*this)(nx1,ny1,0,k)) +
23073                                    (Tfloat)((*this)(nx0,ny1,0,k))) +
23074                             dc*cimg::grand());
23075             } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
23076             (*this)(xc,yc,0,k) = (T)val;
23077           } else {
23078             const Tfloat
23079               val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
23080               val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
23081             (*this)(xc,ny0,0,k) = (T)(((val0+val1)*nopacity + copacity*(*this)(xc,ny0,0,k))/2);
23082             (*this)(xc,ny1,0,k) = (T)(((val2+val3)*nopacity + copacity*(*this)(xc,ny1,0,k))/2);
23083             (*this)(nx0,yc,0,k) = (T)(((val0+val2)*nopacity + copacity*(*this)(nx0,yc,0,k))/2);
23084             (*this)(nx1,yc,0,k) = (T)(((val1+val3)*nopacity + copacity*(*this)(nx1,yc,0,k))/2);
23085             do {
23086               val = (Tfloat)(0.25f*(((Tfloat)((*this)(nx0,ny0,0,k)) +
23087                                     (Tfloat)((*this)(nx1,ny0,0,k)) +
23088                                     (Tfloat)((*this)(nx1,ny1,0,k)) +
23089                                     (Tfloat)((*this)(nx0,ny1,0,k))) +
23090                                    dc*cimg::grand())*nopacity + copacity*(*this)(xc,yc,0,k));
23091             } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
23092             (*this)(xc,yc,0,k) = (T)val;
23093           }
23094         }
23095         if (xc!=nx0 || yc!=ny0) {
23096           draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity);
23097           draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity);
23098           draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity);
23099           draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity);
23100         }
23101       }
23102       return *this;
23103     }
23104 
23105     //! Draw a plasma random texture.
23106     /**
23107        \param alpha = Alpha-parameter of the plasma.
23108        \param beta = Beta-parameter of the plasma.
23109        \param opacity = opacity of the drawing.
23110     **/
23111     CImg<T>& draw_plasma(const float alpha=1, const float beta=1,
23112                          const float opacity=1) {
23113       return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity);
23114     }
23115 
23116     //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
23117     template<typename tc>
23118     CImg<T>& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1,
23119                              const CImg<tc>& color_palette, const float opacity=1,
23120                              const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
23121                              const unsigned int itermax=255,
23122                              const bool normalized_iteration=false,
23123                              const bool julia_set=false,
23124                              const double paramr=0, const double parami=0) {
23125       if (is_empty()) return *this;
23126       CImg<tc> palette;
23127       if (color_palette) palette.assign(color_palette.data,color_palette.size()/color_palette.dim,1,1,color_palette.dim,true);
23128       if (palette && palette.dim!=dim)
23129         throw CImgArgumentException("CImg<%s>::draw_mandelbrot() : Specified color palette (%u,%u,%u,%u,%p) is not \n"
23130                                     "compatible with instance image (%u,%u,%u,%u,%p).",
23131                                     pixel_type(),color_palette.width,color_palette.height,color_palette.depth,color_palette.dim,
23132                                     color_palette.data,width,height,depth,dim,data);
23133       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), ln2 = (float)cimg_std::log(2.0);
23134       unsigned int iter = 0;
23135       cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
23136         const double x = z0r + p*(z1r-z0r)/width, y = z0i + q*(z1i-z0i)/height;
23137         double zr, zi, cr, ci;
23138         if (julia_set) { zr = x; zi = y; cr = paramr; ci = parami; }
23139         else { zr = paramr; zi = parami; cr = x; ci = y; }
23140         for (iter=1; zr*zr + zi*zi<=4 && iter<=itermax; ++iter) {
23141           const double temp = zr*zr - zi*zi + cr;
23142           zi = 2*zr*zi + ci;
23143           zr = temp;
23144         }
23145         if (iter>itermax) {
23146           if (palette) {
23147             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette(0,k);
23148             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(0,k)*nopacity + (*this)(p,q,0,k)*copacity);
23149           } else {
23150             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)0;
23151             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)((*this)(p,q,0,k)*copacity);
23152           }
23153         } else if (normalized_iteration) {
23154           const float
23155             normz = (float)cimg::abs(zr*zr+zi*zi),
23156             niter = (float)(iter + 1 - cimg_std::log(cimg_std::log(normz))/ln2);
23157           if (palette) {
23158             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._linear_atX(niter,k);
23159             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette._linear_atX(niter,k)*nopacity + (*this)(p,q,0,k)*copacity);
23160           } else {
23161             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)niter;
23162             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(niter*nopacity + (*this)(p,q,0,k)*copacity);
23163           }
23164         } else {
23165           if (palette) {
23166             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._atX(iter,k);
23167             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(iter,k)*nopacity + (*this)(p,q,0,k)*copacity);
23168           } else {
23169             if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)iter;
23170             else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(iter*nopacity + (*this)(p,q,0,k)*copacity);
23171           }
23172         }
23173       }
23174       return *this;
23175     }
23176 
23177     //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
23178     template<typename tc>
23179     CImg<T>& draw_mandelbrot(const CImg<tc>& color_palette, const float opacity=1,
23180                              const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
23181                              const unsigned int itermax=255,
23182                              const bool normalized_iteration=false,
23183                              const bool julia_set=false,
23184                              const double paramr=0, const double parami=0) {
23185       return draw_mandelbrot(0,0,width-1,height-1,color_palette,opacity,z0r,z0i,z1r,z1i,itermax,normalized_iteration,julia_set,paramr,parami);
23186     }
23187 
23188     //! Draw a 1D gaussian function in the instance image.
23189     /**
23190        \param xc = X-coordinate of the gaussian center.
23191        \param sigma = Standard variation of the gaussian distribution.
23192        \param color = array of dimv() values of type \c T, defining the drawing color.
23193        \param opacity = opacity of the drawing.
23194     **/
23195     template<typename tc>
23196     CImg<T>& draw_gaussian(const float xc, const float sigma,
23197                            const tc *const color, const float opacity=1) {
23198       if (is_empty()) return *this;
23199       if (!color)
23200         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
23201                                     pixel_type());
23202       const float sigma2 = 2*sigma*sigma, nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
23203       const unsigned int whz = width*height*depth;
23204       const tc *col = color;
23205       cimg_forX(*this,x) {
23206         const float dx = (x - xc), val = (float)cimg_std::exp(-dx*dx/sigma2);
23207         T *ptrd = ptr(x,0,0,0);
23208         if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
23209         else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
23210         col-=dim;
23211       }
23212       return *this;
23213     }
23214 
23215     //! Draw a 1D gaussian function in the instance image.
23216     template<typename tc>
23217     CImg<T>& draw_gaussian(const float xc, const float sigma,
23218                            const CImg<tc>& color, const float opacity=1) {
23219       return draw_gaussian(xc,sigma,color.data,opacity);
23220     }
23221 
23222     //! Draw an anisotropic 2D gaussian function.
23223     /**
23224        \param xc = X-coordinate of the gaussian center.
23225        \param yc = Y-coordinate of the gaussian center.
23226        \param tensor = 2x2 covariance matrix.
23227        \param color = array of dimv() values of type \c T, defining the drawing color.
23228        \param opacity = opacity of the drawing.
23229     **/
23230     template<typename t, typename tc>
23231     CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
23232                            const tc *const color, const float opacity=1) {
23233       if (is_empty()) return *this;
23234       typedef typename cimg::superset<t,float>::type tfloat;
23235       if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1)
23236         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 2x2 matrix.",
23237                                     pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
23238       if (!color)
23239         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
23240                                     pixel_type());
23241       const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
23242       const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1);
23243       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
23244       const unsigned int whz = width*height*depth;
23245       const tc *col = color;
23246       float dy = -yc;
23247       cimg_forY(*this,y) {
23248         float dx = -xc;
23249         cimg_forX(*this,x) {
23250           const float val = (float)cimg_std::exp(a*dx*dx + b*dx*dy + c*dy*dy);
23251           T *ptrd = ptr(x,y,0,0);
23252           if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
23253           else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
23254           col-=dim;
23255           ++dx;
23256         }
23257         ++dy;
23258       }
23259       return *this;
23260     }
23261 
23262     //! Draw an anisotropic 2D gaussian function.
23263     template<typename t, typename tc>
23264     CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
23265                            const CImg<tc>& color, const float opacity=1) {
23266       return draw_gaussian(xc,yc,tensor,color.data,opacity);
23267     }
23268 
23269     //! Draw an anisotropic 2D gaussian function.
23270     template<typename tc>
23271     CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
23272                            const tc *const color, const float opacity=1) {
23273       const double
23274         a = r1*ru*ru + r2*rv*rv,
23275         b = (r1-r2)*ru*rv,
23276         c = r1*rv*rv + r2*ru*ru;
23277       const CImg<Tfloat> tensor(2,2,1,1, a,b,b,c);
23278       return draw_gaussian(xc,yc,tensor,color,opacity);
23279     }
23280 
23281     //! Draw an anisotropic 2D gaussian function.
23282     template<typename tc>
23283     CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
23284                            const CImg<tc>& color, const float opacity=1) {
23285       return draw_gaussian(xc,yc,r1,r2,ru,rv,color.data,opacity);
23286     }
23287 
23288     //! Draw an isotropic 2D gaussian function.
23289     /**
23290        \param xc = X-coordinate of the gaussian center.
23291        \param yc = Y-coordinate of the gaussian center.
23292        \param sigma = standard variation of the gaussian distribution.
23293        \param color = array of dimv() values of type \c T, defining the drawing color.
23294        \param opacity = opacity of the drawing.
23295     **/
23296     template<typename tc>
23297     CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
23298                            const tc *const color, const float opacity=1) {
23299       return draw_gaussian(xc,yc,CImg<floatT>::diagonal(sigma,sigma),color,opacity);
23300     }
23301 
23302     //! Draw an isotropic 2D gaussian function.
23303     template<typename tc>
23304     CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
23305                            const CImg<tc>& color, const float opacity=1) {
23306       return draw_gaussian(xc,yc,sigma,color.data,opacity);
23307     }
23308 
23309     //! Draw an anisotropic 3D gaussian function.
23310     /**
23311        \param xc = X-coordinate of the gaussian center.
23312        \param yc = Y-coordinate of the gaussian center.
23313        \param zc = Z-coordinate of the gaussian center.
23314        \param tensor = 3x3 covariance matrix.
23315        \param color = array of dimv() values of type \c T, defining the drawing color.
23316        \param opacity = opacity of the drawing.
23317     **/
23318     template<typename t, typename tc>
23319     CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
23320                            const tc *const color, const float opacity=1) {
23321       if (is_empty()) return *this;
23322       typedef typename cimg::superset<t,float>::type tfloat;
23323       if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1)
23324         throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 3x3 matrix.",
23325                                     pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
23326       const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
23327       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);
23328       const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
23329       const unsigned int whz = width*height*depth;
23330       const tc *col = color;
23331       cimg_forXYZ(*this,x,y,z) {
23332         const float
23333           dx = (x - xc), dy = (y - yc), dz = (z - zc),
23334           val = (float)cimg_std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz);
23335         T *ptrd = ptr(x,y,z,0);
23336         if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
23337         else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
23338         col-=dim;
23339       }
23340       return *this;
23341     }
23342 
23343     //! Draw an anisotropic 3D gaussian function.
23344     template<typename t, typename tc>
23345     CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
23346                            const CImg<tc>& color, const float opacity=1) {
23347       return draw_gaussian(xc,yc,zc,tensor,color.data,opacity);
23348     }
23349 
23350     //! Draw an isotropic 3D gaussian function.
23351    /**
23352        \param xc = X-coordinate of the gaussian center.
23353        \param yc = Y-coordinate of the gaussian center.
23354        \param zc = Z-coordinate of the gaussian center.
23355        \param sigma = standard variation of the gaussian distribution.
23356        \param color = array of dimv() values of type \c T, defining the drawing color.
23357        \param opacity = opacity of the drawing.
23358     **/
23359     template<typename tc>
23360     CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
23361                            const tc *const color, const float opacity=1) {
23362       return draw_gaussian(xc,yc,zc,CImg<floatT>::diagonal(sigma,sigma,sigma),color,opacity);
23363     }
23364 
23365     //! Draw an isotropic 3D gaussian function.
23366     template<typename tc>
23367     CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
23368                            const CImg<tc>& color, const float opacity=1) {
23369       return draw_gaussian(xc,yc,zc,sigma,color.data,opacity);
23370     }
23371 
23372     // Draw a 3D object (internal)
23373     template<typename tc, typename to>
23374     void _draw_object3d_sprite(const int x, const int y,
23375                                const CImg<tc>& color, const CImg<to>& opacity, const CImg<T>& sprite) {
23376       if (opacity.width==color.width && opacity.height==color.height)
23377         draw_image(x,y,sprite,opacity.get_resize(sprite.width,sprite.height,1,sprite.dim,1));
23378       else
23379         draw_image(x,y,sprite,opacity(0));
23380     }
23381 
23382     template<typename tc>
23383     void _draw_object3d_sprite(const int x, const int y,
23384                                const CImg<tc>& color, const float opacity, const CImg<T>& sprite) {
23385       if (color) draw_image(x,y,sprite,opacity);
23386     }
23387 
23388     template<typename tp, typename tf, typename tc, typename to>
23389     CImg<T>& _draw_object3d(void *const pboard, float *const zbuffer,
23390                             const float X, const float Y, const float Z,
23391                             const tp& points, const unsigned int nb_points,
23392                             const CImgList<tf>& primitives,
23393                             const CImgList<tc>& colors,
23394                             const to& opacities, const unsigned int nb_opacities,
23395                             const unsigned int render_type,
23396                             const bool double_sided, const float focale,
23397                             const float lightx, const float lighty, const float lightz,
23398                             const float specular_light, const float specular_shine) {
23399       if (is_empty()) return *this;
23400 #ifndef cimg_use_board
23401       if (pboard) return *this;
23402 #endif
23403       const float
23404         nspec = 1-(specular_light<0?0:(specular_light>1?1:specular_light)),
23405         nspec2 = 1+(specular_shine<0?0:specular_shine),
23406         nsl1 = (nspec2-1)/cimg::sqr(nspec-1),
23407         nsl2 = (1-2*nsl1*nspec),
23408         nsl3 = nspec2-nsl1-nsl2;
23409 
23410       // Create light texture for phong-like rendering
23411       static CImg<floatT> light_texture;
23412       if (render_type==5) {
23413         if (colors.size>primitives.size) light_texture.assign(colors[primitives.size])/=255;
23414         else {
23415           static float olightx = 0, olighty = 0, olightz = 0, ospecular_shine = 0;
23416           if (!light_texture || lightx!=olightx || lighty!=olighty || lightz!=olightz || specular_shine!=ospecular_shine) {
23417             light_texture.assign(512,512);
23418             const float white[] = { 1 },
23419               dlx = lightx-X, dly = lighty-Y, dlz = lightz-Z,
23420                 nl = (float)cimg_std::sqrt(dlx*dlx+dly*dly+dlz*dlz),
23421                 nlx = light_texture.width/2*(1+dlx/nl),
23422                 nly = light_texture.height/2*(1+dly/nl);
23423               light_texture.draw_gaussian(nlx,nly,light_texture.width/3.0f,white);
23424               cimg_forXY(light_texture,x,y) {
23425                 const float factor = light_texture(x,y);
23426                 if (factor>nspec) light_texture(x,y) = cimg::min(2,nsl1*factor*factor+nsl2*factor+nsl3);
23427               }
23428               olightx = lightx; olighty = lighty; olightz = lightz; ospecular_shine = specular_shine;
23429           }
23430         }
23431       }
23432 
23433       // Compute 3D to 2D projection
23434       CImg<floatT> projections(nb_points,2);
23435       cimg_forX(projections,l) {
23436         const float
23437           x = (float)points(l,0),
23438           y = (float)points(l,1),
23439           z = (float)points(l,2);
23440         const float projectedz = z + Z + focale;
23441         projections(l,1) = Y + focale*y/projectedz;
23442         projections(l,0) = X + focale*x/projectedz;
23443       }
23444 
23445       // Compute and sort visible primitives
23446       CImg<uintT> visibles(primitives.size);
23447       CImg<floatT> zrange(primitives.size);
23448       unsigned int nb_visibles = 0;
23449       const float zmin = -focale+1.5f;
23450       { cimglist_for(primitives,l) {
23451         const CImg<tf>& primitive = primitives[l];
23452         switch (primitive.size()) {
23453 
23454         case 1 : { // Point
23455           const unsigned int i0 = (unsigned int)primitive(0);
23456           const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2));
23457           if (z0>zmin && x0>=0 && x0<width && y0>=0 && y0<height) {
23458             visibles(nb_visibles) = (unsigned int)l;
23459             zrange(nb_visibles++) = z0;
23460           }
23461         } break;
23462         case 5 : { // Sphere
23463           const unsigned int
23464             i0 = (unsigned int)primitive(0),
23465             i1 = (unsigned int)primitive(1),
23466             i2 = (unsigned int)primitive(2);
23467           const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2));
23468           int radius;
23469           if (i2) radius = (int)(i2*focale/(z0+focale));
23470           else {
23471             const float x1 = projections(i1,0), y1 = projections(i1,1);
23472             const int deltax = (int)(x1-x0), deltay = (int)(y1-y0);
23473             radius = (int)cimg_std::sqrt((float)(deltax*deltax + deltay*deltay));
23474           }
23475           if (z0>zmin && x0+radius>=0 && x0-radius<width && y0+radius>=0 && y0-radius<height) {
23476             visibles(nb_visibles) = (unsigned int)l;
23477             zrange(nb_visibles++) = z0;
23478           }
23479         } break;
23480         case 2 : // Line
23481         case 6 : {
23482           const unsigned int
23483             i0 = (unsigned int)primitive(0),
23484             i1 = (unsigned int)primitive(1);
23485           const float
23486             x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
23487             x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2));
23488           float xm, xM, ym, yM;
23489           if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
23490           if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
23491           if (z0>zmin && z1>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
23492             visibles(nb_visibles) = (unsigned int)l;
23493             zrange(nb_visibles++) = 0.5f*(z0+z1);
23494           }
23495         } break;
23496         case 3 :  // Triangle
23497         case 9 : {
23498           const unsigned int
23499             i0 = (unsigned int)primitive(0),
23500             i1 = (unsigned int)primitive(1),
23501             i2 = (unsigned int)primitive(2);
23502           const float
23503             x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
23504             x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)),
23505             x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2));
23506           float xm, xM, ym, yM;
23507           if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
23508           if (x2<xm) xm = x2;
23509           if (x2>xM) xM = x2;
23510           if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
23511           if (y2<ym) ym = y2;
23512           if (y2>yM) yM = y2;
23513           if (z0>zmin && z1>zmin && z2>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
23514             const float d = (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);
23515             if (double_sided || d<0) {
23516               visibles(nb_visibles) = (unsigned int)l;
23517               zrange(nb_visibles++) = (z0+z1+z2)/3;
23518             }
23519           }
23520         } break;
23521         case 4 : // Rectangle
23522         case 12 : {
23523           const unsigned int
23524             i0 = (unsigned int)primitive(0),
23525             i1 = (unsigned int)primitive(1),
23526             i2 = (unsigned int)primitive(2),
23527             i3 = (unsigned int)primitive(3);
23528           const float
23529             x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
23530             x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)),
23531             x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2)),
23532             x3 = projections(i3,0), y3 = projections(i3,1), z3 = (float)(Z+points(i3,2));
23533           float xm, xM, ym, yM;
23534           if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
23535           if (x2<xm) xm = x2;
23536           if (x2>xM) xM = x2;
23537           if (x3<xm) xm = x3;
23538           if (x3>xM) xM = x3;
23539           if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
23540           if (y2<ym) ym = y2;
23541           if (y2>yM) yM = y2;
23542           if (y3<ym) ym = y3;
23543           if (y3>yM) yM = y3;
23544           if (z0>zmin && z1>zmin && z2>zmin && z3>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
23545             const float d = (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0);
23546             if (double_sided || d<0) {
23547               visibles(nb_visibles) = (unsigned int)l;
23548               zrange(nb_visibles++) = (z0 + z1 + z2 + z3)/4;
23549             }
23550           }
23551         } break;
23552         default :
23553           throw CImgArgumentException("CImg<%s>::draw_object3d() : Primitive %u is invalid (size = %u, can be 1,2,3,4,5,6,9 or 12)",
23554                                       pixel_type(),l,primitive.size());
23555         }}
23556       }
23557       if (nb_visibles<=0) return *this;
23558       CImg<uintT> permutations;
23559       CImg<floatT>(zrange.data,nb_visibles,1,1,1,true).sort(permutations,false);
23560 
23561       // Compute light properties
23562       CImg<floatT> lightprops;
23563       switch (render_type) {
23564       case 3 : { // Flat Shading
23565         lightprops.assign(nb_visibles);
23566         cimg_forX(lightprops,l) {
23567           const CImg<tf>& primitive = primitives(visibles(permutations(l)));
23568           const unsigned int psize = primitive.size();
23569           if (psize==3 || psize==4 || psize==9 || psize==12) {
23570             const unsigned int
23571               i0 = (unsigned int)primitive(0),
23572               i1 = (unsigned int)primitive(1),
23573               i2 = (unsigned int)primitive(2);
23574             const float
23575               x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2),
23576               x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2),
23577               x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2),
23578               dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
23579               dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
23580               nx = dy1*dz2 - dz1*dy2,
23581               ny = dz1*dx2 - dx1*dz2,
23582               nz = dx1*dy2 - dy1*dx2,
23583               norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
23584               lx = X + (x0 + x1 + x2)/3 - lightx,
23585               ly = Y + (y0 + y1 + y2)/3 - lighty,
23586               lz = Z + (z0 + z1 + z2)/3 - lightz,
23587               nl = (float)cimg_std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
23588               factor = cimg::max(cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
23589             lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
23590           } else lightprops[l] = 1;
23591         }
23592       } break;
23593 
23594       case 4 : // Gouraud Shading
23595       case 5 : { // Phong-Shading
23596         CImg<floatT> points_normals(nb_points,3,1,1,0);
23597         for (unsigned int l=0; l<nb_visibles; ++l) {
23598           const CImg<tf>& primitive = primitives[visibles(l)];
23599           const unsigned int psize = primitive.size();
23600           const bool
23601             triangle_flag = (psize==3) || (psize==9),
23602             rectangle_flag = (psize==4) || (psize==12);
23603           if (triangle_flag || rectangle_flag) {
23604             const unsigned int
23605               i0 = (unsigned int)primitive(0),
23606               i1 = (unsigned int)primitive(1),
23607               i2 = (unsigned int)primitive(2),
23608               i3 = rectangle_flag?(unsigned int)primitive(3):0;
23609             const float
23610               x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2),
23611               x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2),
23612               x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2),
23613               dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
23614               dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
23615               nnx = dy1*dz2 - dz1*dy2,
23616               nny = dz1*dx2 - dx1*dz2,
23617               nnz = dx1*dy2 - dy1*dx2,
23618               norm = 1e-5f + (float)cimg_std::sqrt(nnx*nnx + nny*nny + nnz*nnz),
23619               nx = nnx/norm,
23620               ny = nny/norm,
23621               nz = nnz/norm;
23622             points_normals(i0,0)+=nx; points_normals(i0,1)+=ny; points_normals(i0,2)+=nz;
23623             points_normals(i1,0)+=nx; points_normals(i1,1)+=ny; points_normals(i1,2)+=nz;
23624             points_normals(i2,0)+=nx; points_normals(i2,1)+=ny; points_normals(i2,2)+=nz;
23625             if (rectangle_flag) { points_normals(i3,0)+=nx; points_normals(i3,1)+=ny; points_normals(i3,2)+=nz; }
23626           }
23627         }
23628 
23629         if (double_sided) cimg_forX(points_normals,p) if (points_normals(p,2)>0) {
23630           points_normals(p,0) = -points_normals(p,0);
23631           points_normals(p,1) = -points_normals(p,1);
23632           points_normals(p,2) = -points_normals(p,2);
23633         }
23634 
23635         if (render_type==4) {
23636           lightprops.assign(nb_points);
23637           cimg_forX(lightprops,ll) {
23638             const float
23639               nx = points_normals(ll,0),
23640               ny = points_normals(ll,1),
23641               nz = points_normals(ll,2),
23642               norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
23643               lx = (float)(X + points(ll,0) - lightx),
23644               ly = (float)(Y + points(ll,1) - lighty),
23645               lz = (float)(Z + points(ll,2) - lightz),
23646               nl = (float)cimg_std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
23647               factor = cimg::max((-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
23648             lightprops[ll] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
23649           }
23650         } else {
23651           const unsigned int
23652             lw2 = light_texture.width/2 - 1,
23653             lh2 = light_texture.height/2 - 1;
23654           lightprops.assign(nb_points,2);
23655           cimg_forX(lightprops,ll) {
23656             const float
23657               nx = points_normals(ll,0),
23658               ny = points_normals(ll,1),
23659               nz = points_normals(ll,2),
23660               norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
23661               nnx = nx/norm,
23662               nny = ny/norm;
23663             lightprops(ll,0) = lw2*(1 + nnx);
23664             lightprops(ll,1) = lh2*(1 + nny);
23665           }
23666         }
23667       } break;
23668       }
23669 
23670       // Draw visible primitives
23671       const CImg<tc> default_color(1,dim,1,1,(tc)200);
23672       { for (unsigned int l = 0; l<nb_visibles; ++l) {
23673         const unsigned int n_primitive = visibles(permutations(l));
23674         const CImg<tf>& primitive = primitives[n_primitive];
23675         const CImg<tc>& color = n_primitive<colors.size?colors[n_primitive]:default_color;
23676         const float opac = n_primitive<nb_opacities?opacities(n_primitive,0):1.0f;
23677 #ifdef cimg_use_board
23678         BoardLib::Board &board = *(BoardLib::Board*)pboard;
23679 #endif
23680 
23681         switch (primitive.size()) {
23682         case 1 : { // Colored point or sprite
23683           const unsigned int n0 = (unsigned int)primitive[0];
23684           const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
23685           if (color.size()==dim) {
23686             draw_point(x0,y0,color,opac);
23687 #ifdef cimg_use_board
23688             if (pboard) {
23689               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23690               board.fillCircle((float)x0,dimy()-(float)y0,0);
23691             }
23692 #endif
23693           } else {
23694             const float z = Z + points(n0,2);
23695             const int
23696               factor = (int)(focale*100/(z+focale)),
23697               sw = color.width*factor/200,
23698               sh = color.height*factor/200;
23699             if (x0+sw>=0 && x0-sw<dimx() && y0+sh>=0 && y0-sh<dimy()) {
23700               const CImg<T> sprite = color.get_resize(-factor,-factor,1,-100,render_type<=3?1:3);
23701               _draw_object3d_sprite(x0-sw,y0-sh,color,opacities[n_primitive%nb_opacities],sprite);
23702 #ifdef cimg_use_board
23703                 if (pboard) {
23704                   board.setPenColorRGBi(128,128,128);
23705                   board.setFillColor(BoardLib::Color::none);
23706                   board.drawRectangle((float)x0-sw,dimy()-(float)y0+sh,sw,sh);
23707                 }
23708 #endif
23709             }
23710           }
23711         } break;
23712         case 2 : { // Colored line
23713           const unsigned int
23714             n0 = (unsigned int)primitive[0],
23715             n1 = (unsigned int)primitive[1];
23716           const int
23717             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
23718             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
23719           const float
23720             z0 = points(n0,2) + Z + focale,
23721             z1 = points(n1,2) + Z + focale;
23722           if (render_type) {
23723             if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac);
23724             else draw_line(x0,y0,x1,y1,color,opac);
23725 #ifdef cimg_use_board
23726             if (pboard) {
23727               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23728               board.drawLine((float)x0,dimy()-(float)y0,x1,dimy()-(float)y1);
23729             }
23730 #endif
23731           } else {
23732             draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac);
23733 #ifdef cimg_use_board
23734             if (pboard) {
23735               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23736               board.drawCircle((float)x0,dimy()-(float)y0,0);
23737               board.drawCircle((float)x1,dimy()-(float)y1,0);
23738             }
23739 #endif
23740           }
23741         } break;
23742         case 5 : { // Colored sphere
23743           const unsigned int
23744             n0 = (unsigned int)primitive[0],
23745             n1 = (unsigned int)primitive[1],
23746             n2 = (unsigned int)primitive[2];
23747           const int
23748             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
23749           int radius;
23750           if (n2) radius = (int)(n2*focale/(Z+points(n0,2)+focale));
23751           else {
23752             const int
23753               x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
23754               deltax = x1-x0, deltay = y1-y0;
23755             radius = (int)cimg_std::sqrt((float)(deltax*deltax + deltay*deltay));
23756           }
23757           switch (render_type) {
23758           case 0 :
23759             draw_point(x0,y0,color,opac);
23760 #ifdef cimg_use_board
23761             if (pboard) {
23762               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23763               board.fillCircle((float)x0,dimy()-(float)y0,0);
23764             }
23765 #endif
23766             break;
23767           case 1 :
23768             draw_circle(x0,y0,radius,color,opac,~0U);
23769 #ifdef cimg_use_board
23770             if (pboard) {
23771               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23772               board.setFillColor(BoardLib::Color::none);
23773               board.drawCircle((float)x0,dimy()-(float)y0,(float)radius);
23774             }
23775 #endif
23776             break;
23777           default :
23778             draw_circle(x0,y0,radius,color,opac);
23779 #ifdef cimg_use_board
23780             if (pboard) {
23781               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23782               board.fillCircle((float)x0,dimy()-(float)y0,(float)radius);
23783             }
23784 #endif
23785             break;
23786           }
23787         } break;
23788         case 6 : { // Textured line
23789           const unsigned int
23790             n0 = (unsigned int)primitive[0],
23791             n1 = (unsigned int)primitive[1],
23792             tx0 = (unsigned int)primitive[2],
23793             ty0 = (unsigned int)primitive[3],
23794             tx1 = (unsigned int)primitive[4],
23795             ty1 = (unsigned int)primitive[5];
23796           const int
23797             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
23798             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
23799           const float
23800             z0 = points(n0,2) + Z + focale,
23801             z1 = points(n1,2) + Z + focale;
23802           if (render_type) {
23803             if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac);
23804             else draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opac);
23805 #ifdef cimg_use_board
23806             if (pboard) {
23807               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
23808               board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
23809             }
23810 #endif
23811           } else {
23812             draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
23813               draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac);
23814 #ifdef cimg_use_board
23815             if (pboard) {
23816               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
23817               board.drawCircle((float)x0,dimy()-(float)y0,0);
23818               board.drawCircle((float)x1,dimy()-(float)y1,0);
23819             }
23820 #endif
23821           }
23822         } break;
23823         case 3 : { // Colored triangle
23824           const unsigned int
23825             n0 = (unsigned int)primitive[0],
23826             n1 = (unsigned int)primitive[1],
23827             n2 = (unsigned int)primitive[2];
23828           const int
23829             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
23830             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
23831             x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
23832           const float
23833             z0 = points(n0,2) + Z + focale,
23834             z1 = points(n1,2) + Z + focale,
23835             z2 = points(n2,2) + Z + focale;
23836           switch (render_type) {
23837           case 0 :
23838             draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).draw_point(x2,y2,color,opac);
23839 #ifdef cimg_use_board
23840             if (pboard) {
23841               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23842               board.drawCircle((float)x0,dimy()-(float)y0,0);
23843               board.drawCircle((float)x1,dimy()-(float)y1,0);
23844               board.drawCircle((float)x2,dimy()-(float)y2,0);
23845             }
23846 #endif
23847             break;
23848           case 1 :
23849             if (zbuffer)
23850               draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,opac).
23851                 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac);
23852             else
23853               draw_line(x0,y0,x1,y1,color,opac).draw_line(x0,y0,x2,y2,color,opac).
23854                 draw_line(x1,y1,x2,y2,color,opac);
23855 #ifdef cimg_use_board
23856             if (pboard) {
23857               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23858               board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
23859               board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
23860               board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
23861             }
23862 #endif
23863             break;
23864           case 2 :
23865             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,opac);
23866             else draw_triangle(x0,y0,x1,y1,x2,y2,color,opac);
23867 #ifdef cimg_use_board
23868             if (pboard) {
23869               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23870               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
23871             }
23872 #endif
23873             break;
23874           case 3 :
23875             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l));
23876             else _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l));
23877 #ifdef cimg_use_board
23878             if (pboard) {
23879               const float lp = cimg::min(lightprops(l),1);
23880               board.setPenColorRGBi((unsigned char)(color[0]*lp),
23881                                      (unsigned char)(color[1]*lp),
23882                                      (unsigned char)(color[2]*lp),
23883                                      (unsigned char)(opac*255));
23884               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
23885             }
23886 #endif
23887             break;
23888           case 4 :
23889             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
23890             else draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
23891 #ifdef cimg_use_board
23892             if (pboard) {
23893               board.setPenColorRGBi((unsigned char)(color[0]),
23894                                      (unsigned char)(color[1]),
23895                                      (unsigned char)(color[2]),
23896                                      (unsigned char)(opac*255));
23897               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
23898                                          (float)x1,dimy()-(float)y1,lightprops(n1),
23899                                          (float)x2,dimy()-(float)y2,lightprops(n2));
23900             }
23901 #endif
23902             break;
23903           case 5 : {
23904             const unsigned int
23905               lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
23906               lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
23907               lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1);
23908             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
23909             else draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
23910 #ifdef cimg_use_board
23911             if (pboard) {
23912               const float
23913                 l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
23914                 l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
23915                 l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
23916               board.setPenColorRGBi((unsigned char)(color[0]),
23917                                      (unsigned char)(color[1]),
23918                                      (unsigned char)(color[2]),
23919                                      (unsigned char)(opac*255));
23920               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
23921                                          (float)x1,dimy()-(float)y1,l1,
23922                                          (float)x2,dimy()-(float)y2,l2);
23923             }
23924 #endif
23925           } break;
23926           }
23927         } break;
23928         case 4 : { // Colored rectangle
23929           const unsigned int
23930             n0 = (unsigned int)primitive[0],
23931             n1 = (unsigned int)primitive[1],
23932             n2 = (unsigned int)primitive[2],
23933             n3 = (unsigned int)primitive[3];
23934           const int
23935             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
23936             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
23937             x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
23938             x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
23939           const float
23940             z0 = points(n0,2) + Z + focale,
23941             z1 = points(n1,2) + Z + focale,
23942             z2 = points(n2,2) + Z + focale,
23943             z3 = points(n3,2) + Z + focale;
23944           switch (render_type) {
23945           case 0 :
23946             draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).
23947               draw_point(x2,y2,color,opac).draw_point(x3,y3,color,opac);
23948 #ifdef cimg_use_board
23949             if (pboard) {
23950               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23951               board.drawCircle((float)x0,dimy()-(float)y0,0);
23952               board.drawCircle((float)x1,dimy()-(float)y1,0);
23953               board.drawCircle((float)x2,dimy()-(float)y2,0);
23954               board.drawCircle((float)x3,dimy()-(float)y3,0);
23955             }
23956 #endif
23957             break;
23958           case 1 :
23959             if (zbuffer)
23960               draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac).
23961                 draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,opac).draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,opac);
23962             else
23963               draw_line(x0,y0,x1,y1,color,opac).draw_line(x1,y1,x2,y2,color,opac).
23964                 draw_line(x2,y2,x3,y3,color,opac).draw_line(x3,y3,x0,y0,color,opac);
23965 #ifdef cimg_use_board
23966             if (pboard) {
23967               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23968               board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
23969               board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
23970               board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
23971               board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
23972             }
23973 #endif
23974             break;
23975           case 2 :
23976             if (zbuffer)
23977               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);
23978             else
23979               draw_triangle(x0,y0,x1,y1,x2,y2,color,opac).draw_triangle(x0,y0,x2,y2,x3,y3,color,opac);
23980 #ifdef cimg_use_board
23981             if (pboard) {
23982               board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23983               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
23984               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
23985             }
23986 #endif
23987             break;
23988           case 3 :
23989             if (zbuffer)
23990               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l)).
23991                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color.data,opac,lightprops(l));
23992             else
23993               _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l)).
23994                 _draw_triangle(x0,y0,x2,y2,x3,y3,color.data,opac,lightprops(l));
23995 #ifdef cimg_use_board
23996             if (pboard) {
23997               const float lp = cimg::min(lightprops(l),1);
23998               board.setPenColorRGBi((unsigned char)(color[0]*lp),
23999                                      (unsigned char)(color[1]*lp),
24000                                      (unsigned char)(color[2]*lp),(unsigned char)(opac*255));
24001               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24002               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
24003             }
24004 #endif
24005             break;
24006           case 4 : {
24007             const float
24008               lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
24009               lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
24010             if (zbuffer)
24011               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprop0,lightprop1,lightprop2,opac).
24012                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,lightprop0,lightprop2,lightprop3,opac);
24013             else
24014               draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprop0,lightprop1,lightprop2,opac).
24015                 draw_triangle(x0,y0,x2,y2,x3,y3,color,lightprop0,lightprop2,lightprop3,opac);
24016 #ifdef cimg_use_board
24017             if (pboard) {
24018               board.setPenColorRGBi((unsigned char)(color[0]),
24019                                      (unsigned char)(color[1]),
24020                                      (unsigned char)(color[2]),
24021                                      (unsigned char)(opac*255));
24022               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
24023                                          (float)x1,dimy()-(float)y1,lightprop1,
24024                                          (float)x2,dimy()-(float)y2,lightprop2);
24025               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
24026                                          (float)x2,dimy()-(float)y2,lightprop2,
24027                                          (float)x3,dimy()-(float)y3,lightprop3);
24028             }
24029 #endif
24030           } break;
24031           case 5 : {
24032             const unsigned int
24033               lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
24034               lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
24035               lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
24036               lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
24037             if (zbuffer)
24038               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
24039                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
24040             else
24041               draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
24042                 draw_triangle(x0,y0,x2,y2,x3,y3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
24043 #ifdef cimg_use_board
24044             if (pboard) {
24045               const float
24046                 l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
24047                 l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
24048                 l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
24049                 l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
24050               board.setPenColorRGBi((unsigned char)(color[0]),
24051                                      (unsigned char)(color[1]),
24052                                      (unsigned char)(color[2]),
24053                                      (unsigned char)(opac*255));
24054               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
24055                                          (float)x1,dimy()-(float)y1,l1,
24056                                          (float)x2,dimy()-(float)y2,l2);
24057               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
24058                                          (float)x2,dimy()-(float)y2,l2,
24059                                          (float)x3,dimy()-(float)y3,l3);
24060             }
24061 #endif
24062           } break;
24063           }
24064         } break;
24065         case 9 : { // Textured triangle
24066           const unsigned int
24067             n0 = (unsigned int)primitive[0],
24068             n1 = (unsigned int)primitive[1],
24069             n2 = (unsigned int)primitive[2],
24070             tx0 = (unsigned int)primitive[3],
24071             ty0 = (unsigned int)primitive[4],
24072             tx1 = (unsigned int)primitive[5],
24073             ty1 = (unsigned int)primitive[6],
24074             tx2 = (unsigned int)primitive[7],
24075             ty2 = (unsigned int)primitive[8];
24076           const int
24077             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
24078             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
24079             x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
24080           const float
24081             z0 = points(n0,2) + Z + focale,
24082             z1 = points(n1,2) + Z + focale,
24083             z2 = points(n2,2) + Z + focale;
24084           switch (render_type) {
24085           case 0 :
24086             draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
24087               draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
24088               draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac);
24089 #ifdef cimg_use_board
24090             if (pboard) {
24091               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24092               board.drawCircle((float)x0,dimy()-(float)y0,0);
24093               board.drawCircle((float)x1,dimy()-(float)y1,0);
24094               board.drawCircle((float)x2,dimy()-(float)y2,0);
24095             }
24096 #endif
24097             break;
24098           case 1 :
24099             if (zbuffer)
24100               draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
24101                 draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
24102                 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
24103             else
24104               draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
24105                 draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
24106                 draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
24107 #ifdef cimg_use_board
24108             if (pboard) {
24109               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24110               board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
24111               board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
24112               board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24113             }
24114 #endif
24115             break;
24116           case 2 :
24117             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
24118             else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
24119 #ifdef cimg_use_board
24120             if (pboard) {
24121               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24122               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24123             }
24124 #endif
24125             break;
24126           case 3 :
24127             if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
24128             else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
24129 #ifdef cimg_use_board
24130             if (pboard) {
24131               const float lp = cimg::min(lightprops(l),1);
24132               board.setPenColorRGBi((unsigned char)(128*lp),
24133                                      (unsigned char)(128*lp),
24134                                      (unsigned char)(128*lp),
24135                                      (unsigned char)(opac*255));
24136               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24137             }
24138 #endif
24139             break;
24140           case 4 :
24141             if (zbuffer)
24142               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);
24143             else
24144               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);
24145 #ifdef cimg_use_board
24146             if (pboard) {
24147               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24148               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
24149                                          (float)x1,dimy()-(float)y1,lightprops(n1),
24150                                          (float)x2,dimy()-(float)y2,lightprops(n2));
24151             }
24152 #endif
24153             break;
24154           case 5 :
24155             if (zbuffer)
24156               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
24157                             (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
24158                             (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
24159                             (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
24160                             opac);
24161             else
24162               draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
24163                             (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
24164                             (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
24165                             (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
24166                             opac);
24167 #ifdef cimg_use_board
24168             if (pboard) {
24169               const float
24170                 l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
24171                 l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
24172                 l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
24173               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24174               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,(float)x1,dimy()-(float)y1,l1,(float)x2,dimy()-(float)y2,l2);
24175             }
24176 #endif
24177             break;
24178           }
24179         } break;
24180         case 12 : { // Textured rectangle
24181           const unsigned int
24182             n0 = (unsigned int)primitive[0],
24183             n1 = (unsigned int)primitive[1],
24184             n2 = (unsigned int)primitive[2],
24185             n3 = (unsigned int)primitive[3],
24186             tx0 = (unsigned int)primitive[4],
24187             ty0 = (unsigned int)primitive[5],
24188             tx1 = (unsigned int)primitive[6],
24189             ty1 = (unsigned int)primitive[7],
24190             tx2 = (unsigned int)primitive[8],
24191             ty2 = (unsigned int)primitive[9],
24192             tx3 = (unsigned int)primitive[10],
24193             ty3 = (unsigned int)primitive[11];
24194           const int
24195             x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
24196             x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
24197             x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
24198             x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
24199           const float
24200             z0 = points(n0,2) + Z + focale,
24201             z1 = points(n1,2) + Z + focale,
24202             z2 = points(n2,2) + Z + focale,
24203             z3 = points(n3,2) + Z + focale;
24204           switch (render_type) {
24205           case 0 :
24206             draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
24207               draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
24208               draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac).
24209               draw_point(x3,y3,color.get_vector_at(tx3,ty3),opac);
24210 #ifdef cimg_use_board
24211             if (pboard) {
24212               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24213               board.drawCircle((float)x0,dimy()-(float)y0,0);
24214               board.drawCircle((float)x1,dimy()-(float)y1,0);
24215               board.drawCircle((float)x2,dimy()-(float)y2,0);
24216               board.drawCircle((float)x3,dimy()-(float)y3,0);
24217             }
24218 #endif
24219             break;
24220           case 1 :
24221             if (zbuffer)
24222               draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
24223                 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
24224                 draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
24225                 draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
24226             else
24227               draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
24228                 draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
24229                 draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
24230                 draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
24231 #ifdef cimg_use_board
24232             if (pboard) {
24233               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24234               board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
24235               board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24236               board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
24237               board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
24238             }
24239 #endif
24240             break;
24241           case 2 :
24242             if (zbuffer)
24243               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
24244                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
24245             else
24246               draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
24247                 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
24248 #ifdef cimg_use_board
24249             if (pboard) {
24250               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24251               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24252               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
24253             }
24254 #endif
24255             break;
24256           case 3 :
24257             if (zbuffer)
24258               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
24259                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
24260             else
24261               draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
24262                 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
24263 #ifdef cimg_use_board
24264             if (pboard) {
24265               const float lp = cimg::min(lightprops(l),1);
24266               board.setPenColorRGBi((unsigned char)(128*lp),
24267                                      (unsigned char)(128*lp),
24268                                      (unsigned char)(128*lp),
24269                                      (unsigned char)(opac*255));
24270               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24271               board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
24272             }
24273 #endif
24274             break;
24275           case 4 : {
24276             const float
24277               lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
24278               lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
24279             if (zbuffer)
24280               draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
24281                 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
24282             else
24283               draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
24284                 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
24285 #ifdef cimg_use_board
24286             if (pboard) {
24287               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24288               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
24289                                          (float)x1,dimy()-(float)y1,lightprop1,
24290                                          (float)x2,dimy()-(float)y2,lightprop2);
24291               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
24292                                          (float)x2,dimy()-(float)y2,lightprop2,
24293                                          (float)x3,dimy()-(float)y3,lightprop3);
24294             }
24295 #endif
24296           } break;
24297           case 5 : {
24298             const unsigned int
24299               lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
24300               lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
24301               lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
24302               lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
24303             if (zbuffer)
24304               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).
24305                 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);
24306             else
24307               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).
24308                 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);
24309 #ifdef cimg_use_board
24310             if (pboard) {
24311               const float
24312                 l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
24313                 l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
24314                 l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
24315                 l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
24316               board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24317               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
24318                                          (float)x1,dimy()-(float)y1,l1,
24319                                          (float)x2,dimy()-(float)y2,l2);
24320               board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
24321                                          (float)x2,dimy()-(float)y2,l2,
24322                                          (float)x3,dimy()-(float)y3,l3);
24323             }
24324 #endif
24325           } break;
24326           }
24327         } break;
24328         }
24329       }
24330       }
24331       return *this;
24332     }
24333 
24334     //! Draw a 3D object.
24335     /**
24336        \param X = X-coordinate of the 3d object position
24337        \param Y = Y-coordinate of the 3d object position
24338        \param Z = Z-coordinate of the 3d object position
24339        \param points = Image N*3 describing 3D point coordinates
24340        \param primitives = List of P primitives
24341        \param colors = List of P color (or textures)
24342        \param opacities = Image of P opacities
24343        \param render_type = Render type (0=Points, 1=Lines, 2=Faces (no light), 3=Faces (flat), 4=Faces(Gouraud)
24344        \param double_sided = Tell if object faces have two sides or are oriented.
24345        \param focale = length of the focale
24346        \param lightx = X-coordinate of the light
24347        \param lighty = Y-coordinate of the light
24348        \param lightz = Z-coordinate of the light
24349        \param specular_shine = Shininess of the object
24350     **/
24351     template<typename tp, typename tf, typename tc, typename to>
24352     CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
24353                            const CImg<tp>& points, const CImgList<tf>& primitives,
24354                            const CImgList<tc>& colors, const CImgList<to>& opacities,
24355                            const unsigned int render_type=4,
24356                            const bool double_sided=false, const float focale=500,
24357                            const float lightx=0, const float lighty=0, const float lightz=-5000,
24358                            const float specular_light=0.2f, const float specular_shine=0.1f,
24359                            float *const zbuffer=0) {
24360       if (!points) return *this;
24361       return _draw_object3d(0,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
24362                             primitives,colors,opacities,opacities.size,
24363                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24364     }
24365 
24366 #ifdef cimg_use_board
24367     template<typename tp, typename tf, typename tc, typename to>
24368     CImg<T>& draw_object3d(BoardLib::Board& board,
24369                            const float x0, const float y0, const float z0,
24370                            const CImg<tp>& points, const CImgList<tf>& primitives,
24371                            const CImgList<tc>& colors, const CImgList<to>& opacities,
24372                            const unsigned int render_type=4,
24373                            const bool double_sided=false, const float focale=500,
24374                            const float lightx=0, const float lighty=0, const float lightz=-5000,
24375                            const float specular_light=0.2f, const float specular_shine=0.1f,
24376                            float *const zbuffer=0) {
24377       if (!points) return *this;
24378       return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
24379                             primitives,colors,opacities,opacities.size,
24380                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24381     }
24382 #endif
24383 
24384     //! Draw a 3D object.
24385     template<typename tp, typename tf, typename tc, typename to>
24386     CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
24387                            const CImgList<tp>& points, const CImgList<tf>& primitives,
24388                            const CImgList<tc>& colors, const CImgList<to>& opacities,
24389                            const unsigned int render_type=4,
24390                            const bool double_sided=false, const float focale=500,
24391                            const float lightx=0, const float lighty=0, const float lightz=-5000,
24392                            const float specular_light=0.2f, const float specular_shine=0.1f,
24393                            float *const zbuffer=0) {
24394       if (!points) return *this;
24395       return _draw_object3d(0,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size,
24396                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24397     }
24398 
24399 #ifdef cimg_use_board
24400     template<typename tp, typename tf, typename tc, typename to>
24401     CImg<T>& draw_object3d(BoardLib::Board& board,
24402                            const float x0, const float y0, const float z0,
24403                            const CImgList<tp>& points, const CImgList<tf>& primitives,
24404                            const CImgList<tc>& colors, const CImgList<to>& opacities,
24405                            const unsigned int render_type=4,
24406                            const bool double_sided=false, const float focale=500,
24407                            const float lightx=0, const float lighty=0, const float lightz=-5000,
24408                            const float specular_light=0.2f, const float specular_shine=0.1f,
24409                            float *const zbuffer=0) {
24410       if (!points) return *this;
24411       return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size,
24412                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24413     }
24414 #endif
24415 
24416     //! Draw a 3D object.
24417     template<typename tp, typename tf, typename tc, typename to>
24418     CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
24419                            const CImg<tp>& points, const CImgList<tf>& primitives,
24420                            const CImgList<tc>& colors, const CImg<to>& opacities,
24421                            const unsigned int render_type=4,
24422                            const bool double_sided=false, const float focale=500,
24423                            const float lightx=0, const float lighty=0, const float lightz=-5000,
24424                            const float specular_light=0.2f, const float specular_shine=0.1f,
24425                            float *const zbuffer=0) {
24426       if (!points) return *this;
24427       return _draw_object3d(0,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
24428                             primitives,colors,opacities,opacities.size(),
24429                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24430     }
24431 
24432 #ifdef cimg_use_board
24433     template<typename tp, typename tf, typename tc, typename to>
24434     CImg<T>& draw_object3d(BoardLib::Board& board,
24435                            const float x0, const float y0, const float z0,
24436                            const CImg<tp>& points, const CImgList<tf>& primitives,
24437                            const CImgList<tc>& colors, const CImg<to>& opacities,
24438                            const unsigned int render_type=4,
24439                            const bool double_sided=false, const float focale=500,
24440                            const float lightx=0, const float lighty=0, const float lightz=-5000,
24441                            const float specular_light=0.2f, const float specular_shine=0.1f,
24442                            float *const zbuffer=0) {
24443       if (!points) return *this;
24444       return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width
24445                             ,primitives,colors,opacities,opacities.size(),
24446                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24447     }
24448 #endif
24449 
24450     //! Draw a 3D object.
24451     template<typename tp, typename tf, typename tc, typename to>
24452     CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
24453                            const CImgList<tp>& points, const CImgList<tf>& primitives,
24454                            const CImgList<tc>& colors, const CImg<to>& opacities,
24455                            const unsigned int render_type=4,
24456                            const bool double_sided=false, const float focale=500,
24457                            const float lightx=0, const float lighty=0, const float lightz=-5000,
24458                            const float specular_light=0.2f, const float specular_shine=0.1f,
24459                            float *const zbuffer=0) {
24460       if (!points) return *this;
24461       return _draw_object3d(0,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size(),
24462                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24463     }
24464 
24465 #ifdef cimg_use_board
24466     template<typename tp, typename tf, typename tc, typename to>
24467     CImg<T>& draw_object3d(BoardLib::Board& board,
24468                            const float x0, const float y0, const float z0,
24469                            const CImgList<tp>& points, const CImgList<tf>& primitives,
24470                            const CImgList<tc>& colors, const CImg<to>& opacities,
24471                            const unsigned int render_type=4,
24472                            const bool double_sided=false, const float focale=500,
24473                            const float lightx=0, const float lighty=0, const float lightz=-5000,
24474                            const float specular_light=0.2f, const float specular_shine=0.1f,
24475                            float *const zbuffer=0) {
24476       if (!points) return *this;
24477       return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size(),
24478                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24479     }
24480 #endif
24481 
24482     //! Draw a 3D object.
24483     template<typename tp, typename tf, typename tc>
24484     CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
24485                            const tp& points, const CImgList<tf>& primitives,
24486                            const CImgList<tc>& colors,
24487                            const unsigned int render_type=4,
24488                            const bool double_sided=false, const float focale=500,
24489                            const float lightx=0, const float lighty=0, const float lightz=-5000,
24490                            const float specular_light=0.2f, const float specular_shine=0.1f,
24491                            float *const zbuffer=0) {
24492       static const CImg<floatT> opacities;
24493       return draw_object3d(x0,y0,z0,points,primitives,colors,opacities,
24494                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
24495     }
24496 
24497 #ifdef cimg_use_board
24498     template<typename tp, typename tf, typename tc, typename to>
24499     CImg<T>& draw_object3d(BoardLib::Board& board,
24500                            const float x0, const float y0, const float z0,
24501                            const tp& points, const CImgList<tf>& primitives,
24502                            const CImgList<tc>& colors,
24503                            const unsigned int render_type=4,
24504                            const bool double_sided=false, const float focale=500,
24505                            const float lightx=0, const float lighty=0, const float lightz=-5000,
24506                            const float specular_light=0.2f, const float specular_shine=0.1f,
24507                            float *const zbuffer=0) {
24508       static const CImg<floatT> opacities;
24509       return draw_object3d(x0,y0,z0,points,primitives,colors,opacities,
24510                            render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
24511     }
24512 #endif
24513 
24514     //@}
24515     //----------------------------
24516     //
24517     //! \name Image Filtering
24518     //@{
24519     //----------------------------
24520 
24521     //! Compute the correlation of the instance image by a mask.
24522     /**
24523        The correlation of the instance image \p *this by the mask \p mask is defined to be :
24524 
24525        res(x,y,z) = sum_{i,j,k} (*this)(x+i,y+j,z+k)*mask(i,j,k)
24526 
24527        \param mask = the correlation kernel.
24528        \param cond = the border condition type (0=zero, 1=dirichlet)
24529        \param weighted_correl = enable local normalization.
24530     **/
24531     template<typename t>
24532     CImg<T>& correlate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_correl=false) {
24533       return get_correlate(mask,cond,weighted_correl).transfer_to(*this);
24534     }
24535 
24536     template<typename t>
24537     CImg<typename cimg::superset2<T,t,float>::type> get_correlate(const CImg<t>& mask, const unsigned int cond=1,
24538                                                                   const bool weighted_correl=false) const {
24539       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
24540       if (is_empty()) return *this;
24541       if (!mask || mask.dim!=1)
24542         throw CImgArgumentException("CImg<%s>::correlate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
24543                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
24544       CImg<Ttfloat> dest(width,height,depth,dim);
24545       if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) {
24546         // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with cond=1)
24547         switch (mask.depth) {
24548         case 3 : {
24549           T I[27] = { 0 };
24550           cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24551             (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] +
24552              I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
24553              I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] +
24554              I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
24555              I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
24556              I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
24557              I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] +
24558              I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
24559              I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26]);
24560           if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) {
24561             const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] +
24562                                            I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +
24563                                            I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] +
24564                                            I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
24565                                            I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
24566                                            I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
24567                                            I[18]*I[18] + I[19]*I[19] + I[20]*I[20] +
24568                                            I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
24569                                            I[24]*I[24] + I[25]*I[25] + I[26]*I[26]);
24570             if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24571           }
24572         } break;
24573         case 2 : {
24574           T I[8] = { 0 };
24575           cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24576             (I[0]*mask[0] + I[1]*mask[1] +
24577              I[2]*mask[2] + I[3]*mask[3] +
24578              I[4]*mask[4] + I[5]*mask[5] +
24579              I[6]*mask[6] + I[7]*mask[7]);
24580           if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) {
24581             const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
24582                                            I[2]*I[2] + I[3]*I[3] +
24583                                            I[4]*I[4] + I[5]*I[5] +
24584                                            I[6]*I[6] + I[7]*I[7]);
24585             if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24586           }
24587         } break;
24588         default :
24589         case 1 :
24590           switch (mask.width) {
24591           case 6 : {
24592             T I[36] = { 0 };
24593             cimg_forZV(*this,z,v) cimg_for6x6(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24594               (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
24595                I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
24596                I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
24597                I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
24598                I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26] + I[27]*mask[27] + I[28]*mask[28] + I[29]*mask[29] +
24599                I[30]*mask[30] + I[31]*mask[31] + I[32]*mask[32] + I[33]*mask[33] + I[34]*mask[34] + I[35]*mask[35]);
24600             if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
24601               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] +
24602                                              I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
24603                                              I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
24604                                              I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
24605                                              I[24]*I[24] + I[25]*I[25] + I[26]*I[26] + I[27]*I[27] + I[28]*I[28] + I[29]*I[29] +
24606                                              I[30]*I[30] + I[31]*I[31] + I[32]*I[32] + I[33]*I[33] + I[34]*I[34] + I[35]*I[35]);
24607               if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24608             }
24609           } break;
24610           case 5 : {
24611             T I[25] = { 0 };
24612             cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24613               (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] +
24614                I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] +
24615                I[10]*mask[10] + I[11]*mask[11] + I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
24616                I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] + I[18]*mask[18] + I[19]*mask[19] +
24617                I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] + I[24]*mask[24]);
24618             if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
24619               const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] +
24620                                              I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] +
24621                                              I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
24622                                              I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] +
24623                                              I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24]);
24624               if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24625             }
24626           } break;
24627           case 4 : {
24628             T I[16] = { 0 };
24629             cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24630               (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] +
24631                I[ 4]*mask[ 4] + I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] +
24632                I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
24633                I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15]);
24634             if (weighted_correl) cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) {
24635               const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] +
24636                                              I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] +
24637                                              I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
24638                                              I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15]);
24639               if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24640             }
24641           } break;
24642           case 3 : {
24643             T I[9] = { 0 };
24644             cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24645               (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
24646                I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
24647                I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
24648             if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) {
24649               const double weight = (double)(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] +
24650                                              I[3]*I[3] + I[4]*I[4] + I[5]*I[5] +
24651                                              I[6]*I[6] + I[7]*I[7] + I[8]*I[8]);
24652               if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24653             }
24654           } break;
24655           case 2 : {
24656             T I[4] = { 0 };
24657             cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24658               (I[0]*mask[0] + I[1]*mask[1] +
24659                I[2]*mask[2] + I[3]*mask[3]);
24660             if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) {
24661               const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
24662                                              I[2]*I[2] + I[3]*I[3]);
24663               if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24664             }
24665           } break;
24666           case 1 : (dest.assign(*this))*=mask(0); break;
24667           }
24668         }
24669       } else { // Generic version for other masks
24670         const int
24671           mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
24672           mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
24673           mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
24674         cimg_forV(*this,v)
24675           if (!weighted_correl) { // Classical correlation
24676             for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24677               Ttfloat val = 0;
24678               for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
24679                 val+=(*this)(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
24680               dest(x,y,z,v) = (Ttfloat)val;
24681             }
24682             if (cond)
24683               cimg_forYZV(*this,y,z,v)
24684                 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24685                   Ttfloat val = 0;
24686                   for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
24687                     val+=_atXYZ(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
24688                   dest(x,y,z,v) = (Ttfloat)val;
24689                 }
24690             else
24691               cimg_forYZV(*this,y,z,v)
24692                 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24693                   Ttfloat val = 0;
24694                   for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
24695                     val+=atXYZ(x+xm,y+ym,z+zm,v,0)*mask(mx1+xm,my1+ym,mz1+zm);
24696                   dest(x,y,z,v) = (Ttfloat)val;
24697                 }
24698           } else { // Weighted correlation
24699             for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24700               Ttfloat val = 0, weight = 0;
24701               for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24702                 const Ttfloat cval = (Ttfloat)(*this)(x+xm,y+ym,z+zm,v);
24703                 val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
24704                 weight+=cval*cval;
24705               }
24706               dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
24707             }
24708             if (cond)
24709               cimg_forYZV(*this,y,z,v)
24710                 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24711                   Ttfloat val = 0, weight = 0;
24712                   for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24713                     const Ttfloat cval = (Ttfloat)_atXYZ(x+xm,y+ym,z+zm,v);
24714                     val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
24715                     weight+=cval*cval;
24716                   }
24717                   dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
24718                 }
24719             else
24720               cimg_forYZV(*this,y,z,v)
24721                 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24722                   Ttfloat val = 0, weight = 0;
24723                   for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24724                     const Ttfloat cval = (Ttfloat)atXYZ(x+xm,y+ym,z+zm,v,0);
24725                     val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
24726                     weight+=cval*cval;
24727                   }
24728                   dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
24729                 }
24730           }
24731       }
24732       return dest;
24733     }
24734 
24735     //! Compute the convolution of the image by a mask.
24736     /**
24737        The result \p res of the convolution of an image \p img by a mask \p mask is defined to be :
24738 
24739        res(x,y,z) = sum_{i,j,k} img(x-i,y-j,z-k)*mask(i,j,k)
24740 
24741        \param mask = the correlation kernel.
24742        \param cond = the border condition type (0=zero, 1=dirichlet)
24743        \param weighted_convol = enable local normalization.
24744     **/
24745     template<typename t>
24746     CImg<T>& convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) {
24747       return get_convolve(mask,cond,weighted_convol).transfer_to(*this);
24748     }
24749 
24750     template<typename t>
24751     CImg<typename cimg::superset2<T,t,float>::type> get_convolve(const CImg<t>& mask, const unsigned int cond=1,
24752                                                                  const bool weighted_convol=false) const {
24753       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
24754       if (is_empty()) return *this;
24755       if (!mask || mask.dim!=1)
24756         throw CImgArgumentException("CImg<%s>::convolve() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
24757                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
24758       return get_correlate(CImg<t>(mask.ptr(),mask.size(),1,1,1,true).get_mirror('x').resize(mask,-1),cond,weighted_convol);
24759     }
24760 
24761     //! Return the erosion of the image by a structuring element.
24762     template<typename t>
24763     CImg<T>& erode(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) {
24764       return get_erode(mask,cond,weighted_erosion).transfer_to(*this);
24765     }
24766 
24767     template<typename t>
24768     CImg<typename cimg::superset<T,t>::type> get_erode(const CImg<t>& mask, const unsigned int cond=1,
24769                                                        const bool weighted_erosion=false) const {
24770       typedef typename cimg::superset<T,t>::type Tt;
24771       if (is_empty()) return *this;
24772       if (!mask || mask.dim!=1)
24773         throw CImgArgumentException("CImg<%s>::erode() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
24774                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
24775       CImg<Tt> dest(width,height,depth,dim);
24776       const int
24777         mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
24778         mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
24779         mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
24780       cimg_forV(*this,v)
24781         if (!weighted_erosion) { // Classical erosion
24782           for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24783             Tt min_val = cimg::type<Tt>::max();
24784             for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24785               const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
24786               if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
24787             }
24788             dest(x,y,z,v) = min_val;
24789           }
24790           if (cond)
24791             cimg_forYZV(*this,y,z,v)
24792               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24793                 Tt min_val = cimg::type<Tt>::max();
24794                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24795                   const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
24796                   if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
24797                 }
24798                 dest(x,y,z,v) = min_val;
24799               }
24800           else
24801             cimg_forYZV(*this,y,z,v)
24802               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24803                 Tt min_val = cimg::type<Tt>::max();
24804                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24805                   const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
24806                   if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
24807                 }
24808                 dest(x,y,z,v) = min_val;
24809               }
24810         } else { // Weighted erosion
24811           for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24812             Tt min_val = cimg::type<Tt>::max();
24813             for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24814               const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24815               const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) + mval);
24816               if (mval && cval<min_val) min_val = cval;
24817             }
24818             dest(x,y,z,v) = min_val;
24819           }
24820           if (cond)
24821             cimg_forYZV(*this,y,z,v)
24822               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24823                 Tt min_val = cimg::type<Tt>::max();
24824                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24825                   const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24826                   const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) + mval);
24827                   if (mval && cval<min_val) min_val = cval;
24828                 }
24829                 dest(x,y,z,v) = min_val;
24830               }
24831           else
24832             cimg_forYZV(*this,y,z,v)
24833               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24834                 Tt min_val = cimg::type<Tt>::max();
24835                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24836                   const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24837                   const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) + mval);
24838                   if (mval && cval<min_val) min_val = cval;
24839                 }
24840                 dest(x,y,z,v) = min_val;
24841               }
24842         }
24843       return dest;
24844     }
24845 
24846     //! Erode the image by a square structuring element of size n.
24847     CImg<T>& erode(const unsigned int n, const unsigned int cond=1) {
24848       if (n<2) return *this;
24849       return get_erode(n,cond).transfer_to(*this);
24850     }
24851 
24852     CImg<T> get_erode(const unsigned int n, const unsigned int cond=1) const {
24853       static CImg<T> mask;
24854       if (n<2) return *this;
24855       if (mask.width!=n) mask.assign(n,n,1,1,1);
24856       const CImg<T> res = get_erode(mask,cond,false);
24857       if (n>20) mask.assign();
24858       return res;
24859     }
24860 
24861     //! Dilate the image by a structuring element.
24862     template<typename t>
24863     CImg<T>& dilate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) {
24864       return get_dilate(mask,cond,weighted_dilatation).transfer_to(*this);
24865     }
24866 
24867     template<typename t>
24868     CImg<typename cimg::superset<T,t>::type> get_dilate(const CImg<t>& mask, const unsigned int cond=1,
24869                                                         const bool weighted_dilatation=false) const {
24870       typedef typename cimg::superset<T,t>::type Tt;
24871       if (is_empty()) return *this;
24872       if (!mask || mask.dim!=1)
24873         throw CImgArgumentException("CImg<%s>::dilate() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
24874                                     pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
24875       CImg<Tt> dest(width,height,depth,dim);
24876       const int
24877         mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
24878         mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
24879         mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
24880       cimg_forV(*this,v)
24881         if (!weighted_dilatation) { // Classical dilatation
24882           for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24883             Tt max_val = cimg::type<Tt>::min();
24884             for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24885               const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
24886               if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
24887             }
24888             dest(x,y,z,v) = max_val;
24889           }
24890           if (cond)
24891             cimg_forYZV(*this,y,z,v)
24892               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24893                 Tt max_val = cimg::type<Tt>::min();
24894                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24895                   const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
24896                   if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
24897                 }
24898                 dest(x,y,z,v) = max_val;
24899               }
24900           else
24901             cimg_forYZV(*this,y,z,v)
24902               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24903                 Tt max_val = cimg::type<Tt>::min();
24904                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24905                   const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
24906                   if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
24907                 }
24908                 dest(x,y,z,v) = max_val;
24909               }
24910         } else { // Weighted dilatation
24911           for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24912             Tt max_val = cimg::type<Tt>::min();
24913             for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24914               const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24915               const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) - mval);
24916               if (mval && cval>max_val) max_val = cval;
24917             }
24918             dest(x,y,z,v) = max_val;
24919           }
24920           if (cond)
24921             cimg_forYZV(*this,y,z,v)
24922               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24923                 Tt max_val = cimg::type<Tt>::min();
24924                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24925                   const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24926                   const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) - mval);
24927                   if (mval && cval>max_val) max_val = cval;
24928                 }
24929                 dest(x,y,z,v) = max_val;
24930               }
24931           else
24932             cimg_forYZV(*this,y,z,v)
24933               for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24934                 Tt max_val = cimg::type<Tt>::min();
24935                 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24936                   const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24937                   const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) - mval);
24938                   if (mval && cval>max_val) max_val = cval;
24939                 }
24940                 dest(x,y,z,v) = max_val;
24941               }
24942         }
24943       return dest;
24944     }
24945 
24946     //! Dilate the image by a square structuring element of size n.
24947     CImg<T>& dilate(const unsigned int n, const unsigned int cond=1) {
24948       if (n<2) return *this;
24949       return get_dilate(n,cond).transfer_to(*this);
24950     }
24951 
24952     CImg<T> get_dilate(const unsigned int n, const unsigned int cond=1) const {
24953       static CImg<T> mask;
24954       if (n<2) return *this;
24955       if (mask.width!=n) mask.assign(n,n,1,1,1);
24956       const CImg<T> res = get_dilate(mask,cond,false);
24957       if (n>20) mask.assign();
24958       return res;
24959     }
24960 
24961     //! Add noise to the image.
24962     /**
24963        \param sigma = power of the noise. if sigma<0, it corresponds to the percentage of the maximum image value.
24964        \param ntype = noise type. can be 0=gaussian, 1=uniform or 2=Salt and Pepper, 3=Poisson, 4=Rician.
24965        \return A noisy version of the instance image.
24966     **/
24967     CImg<T>& noise(const double sigma, const unsigned int noise_type=0) {
24968       if (!is_empty()) {
24969         double nsigma = sigma, max = (double)cimg::type<T>::max(), min = (double)cimg::type<T>::min();
24970         Tfloat m = 0, M = 0;
24971         if (nsigma==0 && noise_type!=3) return *this;
24972         if (nsigma<0 || noise_type==2) m = (Tfloat)minmax(M);
24973         if (nsigma<0) nsigma = -nsigma*(M-m)/100.0;
24974         switch (noise_type) {
24975         case 0 : { // Gaussian noise
24976           cimg_for(*this,ptr,T) {
24977             double val = *ptr + nsigma*cimg::grand();
24978             if (val>max) val = max;
24979             if (val<min) val = min;
24980             *ptr = (T)val;
24981           }
24982         } break;
24983         case 1 : { // Uniform noise
24984           cimg_for(*this,ptr,T) {
24985             double val = *ptr + nsigma*cimg::crand();
24986             if (val>max) val = max;
24987             if (val<min) val = min;
24988             *ptr = (T)val;
24989           }
24990         } break;
24991         case 2 : { // Salt & Pepper noise
24992           if (nsigma<0) nsigma = -nsigma;
24993           if (M==m) { m = 0; M = (float)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); }
24994           cimg_for(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr = (T)(cimg::rand()<0.5?M:m);
24995         } break;
24996 
24997         case 3 : { // Poisson Noise
24998           cimg_for(*this,ptr,T) *ptr = (T)cimg::prand(*ptr);
24999         } break;
25000 
25001         case 4 : { // Rice noise
25002           const double sqrt2 = (double)cimg_std::sqrt(2.0);
25003           cimg_for(*this,ptr,T) {
25004             const double
25005               val0 = (double)*ptr/sqrt2,
25006               re = val0 + nsigma*cimg::grand(),
25007               im = val0 + nsigma*cimg::grand();
25008             double val = cimg_std::sqrt(re*re + im*im);
25009             if (val>max) val = max;
25010             if (val<min) val = min;
25011             *ptr = (T)val;
25012           }
25013         } break;
25014         default :
25015           throw CImgArgumentException("CImg<%s>::noise() : Invalid noise type %d "
25016                                       "(should be {0=Gaussian, 1=Uniform, 2=Salt&Pepper, 3=Poisson}).",pixel_type(),noise_type);
25017         }
25018       }
25019       return *this;
25020     }
25021 
25022     CImg<T> get_noise(const double sigma, const unsigned int noise_type=0) const {
25023       return (+*this).noise(sigma,noise_type);
25024     }
25025 
25026     //! Compute the result of the Deriche filter.
25027     /**
25028        The Canny-Deriche filter is a recursive algorithm allowing to compute blurred derivatives of
25029        order 0,1 or 2 of an image.
25030     **/
25031     CImg<T>& deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) {
25032 #define _cimg_deriche2_apply \
25033   Tfloat *ptrY = Y.data, yb = 0, yp = 0; \
25034   T xp = (T)0; \
25035   if (cond) { xp = *ptrX; yb = yp = (Tfloat)(coefp*xp); } \
25036   for (int m=0; m<N; ++m) { \
25037     const T xc = *ptrX; ptrX+=off; \
25038     const Tfloat yc = *(ptrY++) = (Tfloat)(a0*xc + a1*xp - b1*yp - b2*yb); \
25039     xp = xc; yb = yp; yp = yc; \
25040   } \
25041   T xn = (T)0, xa = (T)0; \
25042   Tfloat yn = 0, ya = 0; \
25043   if (cond) { xn = xa = *(ptrX-off); yn = ya = (Tfloat)coefn*xn; } \
25044   for (int n=N-1; n>=0; --n) { \
25045     const T xc = *(ptrX-=off); \
25046     const Tfloat yc = (Tfloat)(a2*xn + a3*xa - b1*yn - b2*ya); \
25047     xa = xn; xn = xc; ya = yn; yn = yc; \
25048     *ptrX = (T)(*(--ptrY)+yc); \
25049   }
25050       if (sigma<0)
25051         throw CImgArgumentException("CImg<%s>::deriche() : Given filter variance (sigma = %g) is negative",
25052                                     pixel_type(),sigma);
25053       if (is_empty() || (sigma<0.1 && !order)) return *this;
25054       const float
25055         nsigma = sigma<0.1f?0.1f:sigma,
25056         alpha = 1.695f/nsigma,
25057         ema = (float)cimg_std::exp(-alpha),
25058         ema2 = (float)cimg_std::exp(-2*alpha),
25059         b1 = -2*ema,
25060         b2 = ema2;
25061       float a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0;
25062       switch (order) {
25063       case 0 : {
25064         const float k = (1-ema)*(1-ema)/(1+2*alpha*ema-ema2);
25065         a0 = k;
25066         a1 = k*(alpha-1)*ema;
25067         a2 = k*(alpha+1)*ema;
25068         a3 = -k*ema2;
25069       } break;
25070       case 1 : {
25071         const float k = (1-ema)*(1-ema)/ema;
25072         a0 = k*ema;
25073         a1 = a3 = 0;
25074         a2 = -a0;
25075       } break;
25076       case 2 : {
25077         const float
25078           ea = (float)cimg_std::exp(-alpha),
25079           k = -(ema2-1)/(2*alpha*ema),
25080           kn = (-2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea));
25081         a0 = kn;
25082         a1 = -kn*(1+k*alpha)*ema;
25083         a2 = kn*(1-k*alpha)*ema;
25084         a3 = -kn*ema2;
25085       } break;
25086       default :
25087         throw CImgArgumentException("CImg<%s>::deriche() : Given filter order (order = %u) must be 0,1 or 2",
25088                                     pixel_type(),order);
25089       }
25090       coefp = (a0+a1)/(1+b1+b2);
25091       coefn = (a2+a3)/(1+b1+b2);
25092       switch (cimg::uncase(axis)) {
25093       case 'x' : {
25094         const int N = width, off = 1;
25095         CImg<Tfloat> Y(N);
25096         cimg_forYZV(*this,y,z,v) { T *ptrX = ptr(0,y,z,v); _cimg_deriche2_apply; }
25097       } break;
25098       case 'y' : {
25099         const int N = height, off = width;
25100         CImg<Tfloat> Y(N);
25101         cimg_forXZV(*this,x,z,v) { T *ptrX = ptr(x,0,z,v); _cimg_deriche2_apply; }
25102       } break;
25103       case 'z' : {
25104         const int N = depth, off = width*height;
25105         CImg<Tfloat> Y(N);
25106         cimg_forXYV(*this,x,y,v) { T *ptrX = ptr(x,y,0,v); _cimg_deriche2_apply; }
25107       } break;
25108       case 'v' : {
25109         const int N = dim, off = width*height*depth;
25110         CImg<Tfloat> Y(N);
25111         cimg_forXYZ(*this,x,y,z) { T *ptrX = ptr(x,y,z,0); _cimg_deriche2_apply; }
25112       } break;
25113       }
25114       return *this;
25115     }
25116 
25117     CImg<Tfloat> get_deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) const {
25118       return CImg<Tfloat>(*this,false).deriche(sigma,order,axis,cond);
25119     }
25120 
25121     //! Return a blurred version of the image, using a Canny-Deriche filter.
25122     /**
25123        Blur the image with an anisotropic exponential filter (Deriche filter of order 0).
25124     **/
25125     CImg<T>& blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) {
25126       if (!is_empty()) {
25127         if (width>1  && sigmax>0) deriche(sigmax,0,'x',cond);
25128         if (height>1 && sigmay>0) deriche(sigmay,0,'y',cond);
25129         if (depth>1  && sigmaz>0) deriche(sigmaz,0,'z',cond);
25130       }
25131       return *this;
25132     }
25133 
25134     CImg<Tfloat> get_blur(const float sigmax, const float sigmay, const float sigmaz,
25135                           const bool cond=true) const {
25136       return CImg<Tfloat>(*this,false).blur(sigmax,sigmay,sigmaz,cond);
25137     }
25138 
25139     //! Return a blurred version of the image, using a Canny-Deriche filter.
25140     CImg<T>& blur(const float sigma, const bool cond=true) {
25141       return blur(sigma,sigma,sigma,cond);
25142     }
25143 
25144     CImg<Tfloat> get_blur(const float sigma, const bool cond=true) const {
25145       return CImg<Tfloat>(*this,false).blur(sigma,cond);
25146     }
25147 
25148     //! Blur the image anisotropically following a field of diffusion tensors.
25149     /**
25150        \param G = Field of square roots of diffusion tensors used to drive the smoothing.
25151        \param amplitude = amplitude of the smoothing.
25152        \param dl = spatial discretization.
25153        \param da = angular discretization.
25154        \param gauss_prec = precision of the gaussian function.
25155        \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
25156        \param fast_approx = Tell to use the fast approximation or not.
25157     **/
25158     template<typename t>
25159     CImg<T>& blur_anisotropic(const CImg<t>& G, const float amplitude=60, const float dl=0.8f, const float da=30,
25160                               const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true) {
25161 #define _cimg_valign2d(i,j) \
25162     { Tfloat &u = W(i,j,0,0), &v = W(i,j,0,1); \
25163     if (u*curru + v*currv<0) { u=-u; v=-v; }}
25164 #define _cimg_valign3d(i,j,k) \
25165     { Tfloat &u = W(i,j,k,0), &v = W(i,j,k,1), &w = W(i,j,k,2); \
25166     if (u*curru + v*currv + w*currw<0) { u=-u; v=-v; w=-w; }}
25167 
25168       // Check arguments and init variables
25169       if (!is_empty() && amplitude>0) {
25170         if (!G || (G.dim!=3 && G.dim!=6) || G.width!=width || G.height!=height || G.depth!=depth)
25171           throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Specified tensor field (%u,%u,%u,%u) is not valid.",
25172                                       pixel_type(),G.width,G.height,G.depth,G.dim);
25173 
25174         const float sqrt2amplitude = (float)cimg_std::sqrt(2*amplitude);
25175         const bool threed = (G.dim>=6);
25176         const int
25177           dx1 = dimx()-1,
25178           dy1 = dimy()-1,
25179           dz1 = dimz()-1;
25180         CImg<Tfloat>
25181           dest(width,height,depth,dim,0),
25182           W(width,height,depth,threed?4:3),
25183           tmp(dim);
25184         int N = 0;
25185 
25186         if (threed)
25187           // 3D version of the algorithm
25188           for (float phi=(180%(int)da)/2.0f; phi<=180; phi+=da) {
25189             const float
25190               phir = (float)(phi*cimg::valuePI/180),
25191               datmp = (float)(da/cimg_std::cos(phir)),
25192               da2 = datmp<1?360.0f:datmp;
25193 
25194             for (float theta=0; theta<360; (theta+=da2),++N) {
25195               const float
25196                 thetar = (float)(theta*cimg::valuePI/180),
25197                 vx = (float)(cimg_std::cos(thetar)*cimg_std::cos(phir)),
25198                 vy = (float)(cimg_std::sin(thetar)*cimg_std::cos(phir)),
25199                 vz = (float)cimg_std::sin(phir);
25200               const t
25201                 *pa = G.ptr(0,0,0,0),
25202                 *pb = G.ptr(0,0,0,1),
25203                 *pc = G.ptr(0,0,0,2),
25204                 *pd = G.ptr(0,0,0,3),
25205                 *pe = G.ptr(0,0,0,4),
25206                 *pf = G.ptr(0,0,0,5);
25207               Tfloat
25208                 *pd0 = W.ptr(0,0,0,0),
25209                 *pd1 = W.ptr(0,0,0,1),
25210                 *pd2 = W.ptr(0,0,0,2),
25211                 *pd3 = W.ptr(0,0,0,3);
25212               cimg_forXYZ(G,xg,yg,zg) {
25213                 const t
25214                   a = *(pa++), b = *(pb++), c = *(pc++),
25215                   d = *(pd++), e = *(pe++), f = *(pf++);
25216                 const float
25217                   u = (float)(a*vx + b*vy + c*vz),
25218                   v = (float)(b*vx + d*vy + e*vz),
25219                   w = (float)(c*vx + e*vy + f*vz),
25220                   n = (float)cimg_std::sqrt(1e-5+u*u+v*v+w*w),
25221                   dln = dl/n;
25222                 *(pd0++) = (Tfloat)(u*dln);
25223                 *(pd1++) = (Tfloat)(v*dln);
25224                 *(pd2++) = (Tfloat)(w*dln);
25225                 *(pd3++) = (Tfloat)n;
25226               }
25227 
25228               cimg_forXYZ(*this,x,y,z) {
25229                 tmp.fill(0);
25230                 const float
25231                   cu = (float)W(x,y,z,0),
25232                   cv = (float)W(x,y,z,1),
25233                   cw = (float)W(x,y,z,2),
25234                   n = (float)W(x,y,z,3),
25235                   fsigma = (float)(n*sqrt2amplitude),
25236                   length = gauss_prec*fsigma,
25237                   fsigma2 = 2*fsigma*fsigma;
25238                 float
25239                   S = 0,
25240                   pu = cu,
25241                   pv = cv,
25242                   pw = cw,
25243                   X = (float)x,
25244                   Y = (float)y,
25245                   Z = (float)z;
25246 
25247                 switch (interpolation_type) {
25248                 case 0 : {
25249                   // Nearest neighbor
25250                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
25251                     const int
25252                       cx = (int)(X+0.5f),
25253                       cy = (int)(Y+0.5f),
25254                       cz = (int)(Z+0.5f);
25255                     float
25256                       u = (float)W(cx,cy,cz,0),
25257                       v = (float)W(cx,cy,cz,1),
25258                       w = (float)W(cx,cy,cz,2);
25259                     if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
25260                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,cz,k); ++S; }
25261                     else {
25262                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25263                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,cz,k));
25264                       S+=coef;
25265                     }
25266                     X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
25267                   }
25268                 } break;
25269 
25270                 case 1 : {
25271                   // Linear interpolation
25272                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
25273                     const int
25274                       cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
25275                       cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
25276                       cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
25277                     const float
25278                       curru = (float)W(cx,cy,cz,0),
25279                       currv = (float)W(cx,cy,cz,1),
25280                       currw = (float)W(cx,cy,cz,2);
25281                     _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
25282                     _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
25283                     _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
25284                     _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
25285                     _cimg_valign3d(px,cy,cz);                           _cimg_valign3d(nx,cy,cz);
25286                     _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
25287                     _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
25288                     _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
25289                     _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
25290                     float
25291                       u = (float)(W._linear_atXYZ(X,Y,Z,0)),
25292                       v = (float)(W._linear_atXYZ(X,Y,Z,1)),
25293                       w = (float)(W._linear_atXYZ(X,Y,Z,2));
25294                     if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
25295                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
25296                     else {
25297                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25298                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
25299                       S+=coef;
25300                     }
25301                     X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
25302                   }
25303                 } break;
25304 
25305                 default : {
25306                   // 2nd order Runge Kutta
25307                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
25308                     const int
25309                       cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
25310                       cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
25311                       cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
25312                     const float
25313                       curru = (float)W(cx,cy,cz,0),
25314                       currv = (float)W(cx,cy,cz,1),
25315                       currw = (float)W(cx,cy,cz,2);
25316                     _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
25317                     _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
25318                     _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
25319                     _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
25320                     _cimg_valign3d(px,cy,cz);                           _cimg_valign3d(nx,cy,cz);
25321                     _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
25322                     _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
25323                     _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
25324                     _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
25325                     const float
25326                       u0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,0)),
25327                       v0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,1)),
25328                       w0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,2));
25329                     float
25330                       u = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,0)),
25331                       v = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,1)),
25332                       w = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,2));
25333                     if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
25334                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
25335                     else {
25336                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25337                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
25338                       S+=coef;
25339                     }
25340                     X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
25341                   }
25342                 } break;
25343                 }
25344                 if (S>0) cimg_forV(dest,k) dest(x,y,z,k)+=tmp[k]/S;
25345                 else cimg_forV(dest,k) dest(x,y,z,k)+=(Tfloat)((*this)(x,y,z,k));
25346                 cimg_plugin_greycstoration_count;
25347               }
25348             }
25349           } else
25350             // 2D version of the algorithm
25351             for (float theta=(360%(int)da)/2.0f; theta<360; (theta+=da),++N) {
25352               const float
25353                 thetar = (float)(theta*cimg::valuePI/180),
25354                 vx = (float)(cimg_std::cos(thetar)),
25355                 vy = (float)(cimg_std::sin(thetar));
25356               const t
25357                 *pa = G.ptr(0,0,0,0),
25358                 *pb = G.ptr(0,0,0,1),
25359                 *pc = G.ptr(0,0,0,2);
25360               Tfloat
25361                 *pd0 = W.ptr(0,0,0,0),
25362                 *pd1 = W.ptr(0,0,0,1),
25363                 *pd2 = W.ptr(0,0,0,2);
25364               cimg_forXY(G,xg,yg) {
25365                 const t a = *(pa++), b = *(pb++), c = *(pc++);
25366                 const float
25367                   u = (float)(a*vx + b*vy),
25368                   v = (float)(b*vx + c*vy),
25369                   n = (float)cimg_std::sqrt(1e-5+u*u+v*v),
25370                   dln = dl/n;
25371                 *(pd0++) = (Tfloat)(u*dln);
25372                 *(pd1++) = (Tfloat)(v*dln);
25373                 *(pd2++) = (Tfloat)n;
25374               }
25375 
25376               cimg_forXY(*this,x,y) {
25377                 tmp.fill(0);
25378                 const float
25379                   cu = (float)W(x,y,0,0),
25380                   cv = (float)W(x,y,0,1),
25381                   n = (float)W(x,y,0,2),
25382                   fsigma = (float)(n*sqrt2amplitude),
25383                   length = gauss_prec*fsigma,
25384                   fsigma2 = 2*fsigma*fsigma;
25385                 float
25386                   S = 0,
25387                   pu = cu,
25388                   pv = cv,
25389                   X = (float)x,
25390                   Y = (float)y;
25391 
25392                 switch (interpolation_type) {
25393 
25394                 case 0 : {
25395                   // Nearest-neighbor interpolation for 2D images
25396                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
25397                     const int
25398                       cx = (int)(X+0.5f),
25399                       cy = (int)(Y+0.5f);
25400                     float
25401                       u = (float)W(cx,cy,0,0),
25402                       v = (float)W(cx,cy,0,1);
25403                     if ((pu*u + pv*v)<0) { u=-u; v=-v; }
25404                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,0,k); ++S; }
25405                     else {
25406                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25407                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,0,k));
25408                       S+=coef;
25409                     }
25410                     X+=(pu=u); Y+=(pv=v);
25411                   }
25412                 } break;
25413 
25414                 case 1 : {
25415                   // Linear interpolation for 2D images
25416                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
25417                     const int
25418                       cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
25419                       cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
25420                     const float
25421                       curru = (float)W(cx,cy,0,0),
25422                       currv = (float)W(cx,cy,0,1);
25423                     _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
25424                     _cimg_valign2d(px,cy);                        _cimg_valign2d(nx,cy);
25425                     _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
25426                     float
25427                       u = (float)(W._linear_atXY(X,Y,0,0)),
25428                       v = (float)(W._linear_atXY(X,Y,0,1));
25429                     if ((pu*u + pv*v)<0) { u=-u; v=-v; }
25430                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
25431                     else {
25432                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25433                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
25434                       S+=coef;
25435                     }
25436                     X+=(pu=u); Y+=(pv=v);
25437                   }
25438                 } break;
25439 
25440                 default : {
25441                   // 2nd-order Runge-kutta interpolation for 2D images
25442                   for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
25443                     const int
25444                       cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
25445                       cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
25446                     const float
25447                       curru = (float)W(cx,cy,0,0),
25448                       currv = (float)W(cx,cy,0,1);
25449                     _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
25450                     _cimg_valign2d(px,cy);                        _cimg_valign2d(nx,cy);
25451                     _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
25452                     const float
25453                       u0 = (float)(0.5f*W._linear_atXY(X,Y,0,0)),
25454                       v0 = (float)(0.5f*W._linear_atXY(X,Y,0,1));
25455                     float
25456                       u = (float)(W._linear_atXY(X+u0,Y+v0,0,0)),
25457                       v = (float)(W._linear_atXY(X+u0,Y+v0,0,1));
25458                     if ((pu*u + pv*v)<0) { u=-u; v=-v; }
25459                     if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
25460                     else {
25461                       const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25462                       cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
25463                       S+=coef;
25464                     }
25465                     X+=(pu=u); Y+=(pv=v);
25466                   }
25467                 }
25468                 }
25469                 if (S>0) cimg_forV(dest,k) dest(x,y,0,k)+=tmp[k]/S;
25470                 else cimg_forV(dest,k) dest(x,y,0,k)+=(Tfloat)((*this)(x,y,0,k));
25471                 cimg_plugin_greycstoration_count;
25472               }
25473             }
25474         const Tfloat *ptrs = dest.data+dest.size();
25475         const T m = cimg::type<T>::min(), M = cimg::type<T>::max();
25476         cimg_for(*this,ptrd,T) { const Tfloat val = *(--ptrs)/N; *ptrd = val<m?m:(val>M?M:(T)val); }
25477       }
25478       return *this;
25479     }
25480 
25481     template<typename t>
25482     CImg<T> get_blur_anisotropic(const CImg<t>& G, const float amplitude=60, const float dl=0.8f, const float da=30,
25483                                  const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true) const {
25484       return (+*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
25485     }
25486 
25487     //! Blur an image in an anisotropic way.
25488     /**
25489        \param mask Binary mask.
25490        \param amplitude Amplitude of the anisotropic blur.
25491        \param sharpness Contour preservation.
25492        \param anisotropy Smoothing anisotropy.
25493        \param alpha Image pre-blurring (gaussian).
25494        \param sigma Regularity of the tensor-valued geometry.
25495        \param dl Spatial discretization.
25496        \param da Angular discretization.
25497        \param gauss_prec Precision of the gaussian function.
25498        \param interpolation_type Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
25499        \param fast_approx Tell to use the fast approximation or not
25500        \param geom_factor Geometry factor.
25501     **/
25502     template<typename tm>
25503     CImg<T>& blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
25504                               const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,
25505                               const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true,
25506                               const float geom_factor=1) {
25507       if (!is_empty() && amplitude>0) {
25508         if (amplitude==0) return *this;
25509         if (amplitude<0 || sharpness<0 || anisotropy<0 || anisotropy>1 || alpha<0 || sigma<0 || dl<0 || da<0 || gauss_prec<0)
25510           throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Given parameters are amplitude(%g), sharpness(%g), "
25511                                       "anisotropy(%g), alpha(%g), sigma(%g), dl(%g), da(%g), gauss_prec(%g).\n"
25512                                       "Admissible parameters are in the range : amplitude>0, sharpness>0, anisotropy in [0,1], "
25513                                       "alpha>0, sigma>0, dl>0, da>0, gauss_prec>0.",
25514                                       pixel_type(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec);
25515         const bool threed = (depth>1), no_mask = mask.is_empty();
25516         const float nsharpness = cimg::max(sharpness,1e-5f), power1 = 0.5f*nsharpness, power2 = power1/(1e-7f+1-anisotropy);
25517         CImg<floatT> blurred = CImg<floatT>(*this,false).blur(alpha);
25518         if (geom_factor>0) blurred*=geom_factor;
25519         else blurred.normalize(0,-geom_factor);
25520 
25521         if (threed) { // Field for 3D volumes
25522           cimg_plugin_greycstoration_lock;
25523           CImg<floatT> val(3), vec(3,3), G(blurred.get_structure_tensor());
25524           if (sigma>0) G.blur(sigma);
25525           cimg_forXYZ(*this,x,y,z) {
25526             if (no_mask || mask(x,y,z)) {
25527               G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
25528               const float l1 = val[2], l2 = val[1], l3 = val[0],
25529                 ux = vec(0,0), uy = vec(0,1), uz = vec(0,2),
25530                 vx = vec(1,0), vy = vec(1,1), vz = vec(1,2),
25531                 wx = vec(2,0), wy = vec(2,1), wz = vec(2,2),
25532                 n1 = (float)cimg_std::pow(1+l1+l2+l3,-power1),
25533                 n2 = (float)cimg_std::pow(1+l1+l2+l3,-power2);
25534               G(x,y,z,0) = n1*(ux*ux + vx*vx) + n2*wx*wx;
25535               G(x,y,z,1) = n1*(ux*uy + vx*vy) + n2*wx*wy;
25536               G(x,y,z,2) = n1*(ux*uz + vx*vz) + n2*wx*wz;
25537               G(x,y,z,3) = n1*(uy*uy + vy*vy) + n2*wy*wy;
25538               G(x,y,z,4) = n1*(uy*uz + vy*vz) + n2*wy*wz;
25539               G(x,y,z,5) = n1*(uz*uz + vz*vz) + n2*wz*wz;
25540             } 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;
25541             cimg_plugin_greycstoration_count;
25542           }
25543           cimg_plugin_greycstoration_unlock;
25544           blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
25545         } else { // Field for 2D images
25546           cimg_plugin_greycstoration_lock;
25547           CImg<floatT> val(2), vec(2,2), G(blurred.get_structure_tensor());
25548           if (sigma>0) G.blur(sigma);
25549           cimg_forXY(*this,x,y) {
25550             if (no_mask || mask(x,y)) {
25551               G.get_tensor_at(x,y).symmetric_eigen(val,vec);
25552               const float l1 = val[1], l2 = val[0],
25553                 ux = vec(1,0), uy = vec(1,1),
25554                 vx = vec(0,0), vy = vec(0,1),
25555                 n1 = (float)cimg_std::pow(1+l1+l2,-power1),
25556                 n2 = (float)cimg_std::pow(1+l1+l2,-power2);
25557               G(x,y,0,0) = n1*ux*ux + n2*vx*vx;
25558               G(x,y,0,1) = n1*ux*uy + n2*vx*vy;
25559               G(x,y,0,2) = n1*uy*uy + n2*vy*vy;
25560             } else G(x,y,0,0) = G(x,y,0,1) = G(x,y,0,2) = 0;
25561             cimg_plugin_greycstoration_count;
25562           }
25563           cimg_plugin_greycstoration_unlock;
25564           blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
25565         }
25566       }
25567       return *this;
25568     }
25569 
25570     template<typename tm>
25571     CImg<T> get_blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
25572                                  const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
25573                                  const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0,
25574                                  const bool fast_approx=true, const float geom_factor=1) const {
25575       return (+*this).blur_anisotropic(mask,amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
25576     }
25577 
25578     //! Blur an image following in an anisotropic way.
25579     CImg<T>& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
25580                               const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,
25581                               const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true,
25582                               const float geom_factor=1) {
25583       return blur_anisotropic(CImg<T>(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
25584     }
25585 
25586     CImg<T> get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
25587                                  const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
25588                                  const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0,
25589                                  const bool fast_approx=true, const float geom_factor=1) const {
25590       return (+*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
25591     }
25592 
25593     //! Blur an image using the bilateral filter.
25594     /**
25595        \param sigmax Amount of blur along the X-axis.
25596        \param sigmay Amount of blur along the Y-axis.
25597        \param sigmaz Amount of blur along the Z-axis.
25598        \param sigmar Amount of blur along the range axis.
25599        \param bgridx Size of the bilateral grid along the X-axis.
25600        \param bgridy Size of the bilateral grid along the Y-axis.
25601        \param bgridz Size of the bilateral grid along the Z-axis.
25602        \param bgridr Size of the bilateral grid along the range axis.
25603        \param interpolation_type Use interpolation for image slicing.
25604        \note This algorithm uses the optimisation technique proposed by S. Paris and F. Durand, in ECCV'2006
25605        (extended for 3D volumetric images).
25606     **/
25607     CImg<T>& blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
25608                             const int bgridx, const int bgridy, const int bgridz, const int bgridr,
25609                             const bool interpolation_type=true) {
25610       T m, M = maxmin(m);
25611       const float range = (float)(1.0f+M-m);
25612       const unsigned int
25613         bx0 = bgridx>=0?bgridx:width*(-bgridx)/100,
25614         by0 = bgridy>=0?bgridy:height*(-bgridy)/100,
25615         bz0 = bgridz>=0?bgridz:depth*(-bgridz)/100,
25616         br0 = bgridr>=0?bgridr:(int)(-range*bgridr/100),
25617         bx = bx0>0?bx0:1,
25618         by = by0>0?by0:1,
25619         bz = bz0>0?bz0:1,
25620         br = br0>0?br0:1;
25621       const float
25622         nsigmax = sigmax*bx/width,
25623         nsigmay = sigmay*by/height,
25624         nsigmaz = sigmaz*bz/depth,
25625         nsigmar = sigmar*br/range;
25626       if (nsigmax>0 || nsigmay>0 || nsigmaz>0 || nsigmar>0) {
25627         const bool threed = depth>1;
25628         if (threed) { // 3d version of the algorithm
25629           CImg<floatT> bgrid(bx,by,bz,br), bgridw(bx,by,bz,br);
25630           cimg_forV(*this,k) {
25631             bgrid.fill(0); bgridw.fill(0);
25632             cimg_forXYZ(*this,x,y,z) {
25633               const T val = (*this)(x,y,z,k);
25634               const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
25635               bgrid(X,Y,Z,R) = (float)val;
25636               bgridw(X,Y,Z,R) = 1;
25637             }
25638             bgrid.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
25639             bgridw.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
25640             if (interpolation_type) cimg_forXYZ(*this,x,y,z) {
25641               const T val = (*this)(x,y,z,k);
25642               const float X = (float)x*bx/width, Y = (float)y*by/height, Z = (float)z*bz/depth, R = (float)((val-m)*br/range),
25643                 bval0 = bgrid._linear_atXYZV(X,Y,Z,R), bval1 = bgridw._linear_atXYZV(X,Y,Z,R);
25644               (*this)(x,y,z,k) = (T)(bval0/bval1);
25645             } else cimg_forXYZ(*this,x,y,z) {
25646               const T val = (*this)(x,y,z,k);
25647               const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
25648               const float bval0 = bgrid(X,Y,Z,R), bval1 = bgridw(X,Y,Z,R);
25649               (*this)(x,y,z,k) = (T)(bval0/bval1);
25650             }
25651           }
25652         } else { // 2d version of the algorithm
25653           CImg<floatT> bgrid(bx,by,br,2);
25654           cimg_forV(*this,k) {
25655             bgrid.fill(0);
25656             cimg_forXY(*this,x,y) {
25657               const T val = (*this)(x,y,k);
25658               const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
25659               bgrid(X,Y,R,0) = (float)val;
25660               bgrid(X,Y,R,1) = 1;
25661             }
25662             bgrid.blur(nsigmax,nsigmay,0,true).blur(0,0,nsigmar,false);
25663             if (interpolation_type) cimg_forXY(*this,x,y) {
25664               const T val = (*this)(x,y,k);
25665               const float X = (float)x*bx/width, Y = (float)y*by/height, R = (float)((val-m)*br/range),
25666                 bval0 = bgrid._linear_atXYZ(X,Y,R,0), bval1 = bgrid._linear_atXYZ(X,Y,R,1);
25667               (*this)(x,y,k) = (T)(bval0/bval1);
25668             } else cimg_forXY(*this,x,y) {
25669               const T val = (*this)(x,y,k);
25670               const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
25671               const float bval0 = bgrid(X,Y,R,0), bval1 = bgrid(X,Y,R,1);
25672               (*this)(x,y,k) = (T)(bval0/bval1);
25673             }
25674           }
25675         }
25676       }
25677       return *this;
25678     }
25679 
25680     CImg<T> get_blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
25681                                const int bgridx, const int bgridy, const int bgridz, const int bgridr,
25682                                const bool interpolation_type=true) const {
25683       return (+*this).blur_bilateral(sigmax,sigmay,sigmaz,sigmar,bgridx,bgridy,bgridz,bgridr,interpolation_type);
25684     }
25685 
25686     //! Blur an image using the bilateral filter.
25687     CImg<T>& blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
25688                             const bool interpolation_type=true) {
25689       return blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
25690     }
25691 
25692     CImg<T> get_blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
25693                                const bool interpolation_type=true) const {
25694       return (+*this).blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
25695     }
25696 
25697     //! Blur an image in its patch-based space.
25698     CImg<T>& blur_patch(const unsigned int patch_size, const float sigma_p, const float sigma_s=10,
25699                         const unsigned int lookup_size=4, const bool fast_approx=true) {
25700 
25701 #define _cimg_blur_patch_fastfunc(x) ((x)>3?0:1)
25702 #define _cimg_blur_patch_slowfunc(x) cimg_std::exp(-(x))
25703 #define _cimg_blur_patch3d(N,func) { \
25704   const unsigned int N3 = N*N*N; \
25705   cimg_for##N##XYZ(*this,x,y,z) { \
25706     cimg_plugin_greycstoration_count; \
25707     cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,x,y,z,k,P.ptr(N3*k)); \
25708     const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \
25709     float sum_weights = 0; \
25710     cimg_for_in##N##XYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) { \
25711       cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,p,q,r,k,Q.ptr(N3*k)); \
25712       float distance2 = 0; \
25713       const T *pQ = Q.end(); \
25714       cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(--pQ); distance2+=dI*dI; } \
25715       distance2/=Pnorm; \
25716       const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \
25717         alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = (float)func(alldist); \
25718       sum_weights+=weight; \
25719       { cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k); } \
25720     } \
25721     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)); \
25722   }}
25723 #define _cimg_blur_patch2d(N,func) { \
25724   const unsigned int N2 = N*N; \
25725   cimg_for##N##XY(*this,x,y) { \
25726     cimg_plugin_greycstoration_count; \
25727     cimg_forV(*this,k) cimg_get##N##x##N(*this,x,y,0,k,P.ptr(N2*k)); \
25728     const int x0 = x-rsize1, y0 = y-rsize1, x1 = x+rsize2, y1 = y+rsize2; \
25729     float sum_weights = 0; \
25730     cimg_for_in##N##XY(*this,x0,y0,x1,y1,p,q) { \
25731       cimg_forV(*this,k) cimg_get##N##x##N(*this,p,q,0,k,Q.ptr(N2*k)); \
25732       float distance2 = 0; \
25733       const T *pQ = Q.end(); \
25734       cimg_for(P,pP,T) { const float dI = (float)*pP-(float)*(--pQ); distance2+=dI*dI; } \
25735       distance2/=Pnorm; \
25736       const float dx = (float)p-x, dy = (float)q-y, \
25737         alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = (float)func(alldist); \
25738       sum_weights+=weight; \
25739       { cimg_forV(*this,k) res(x,y,k)+=weight*(*this)(p,q,k); } \
25740     } \
25741     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)); \
25742   }}
25743 
25744       CImg<Tfloat> res(width,height,depth,dim,0);
25745       CImg<T> P(patch_size*patch_size*dim), Q(P);
25746       const float sigma_s2 = sigma_s*sigma_s, sigma_p2 = sigma_p*sigma_p, Pnorm = P.size()*sigma_p2;
25747       const int rsize2 = (int)lookup_size/2, rsize1 = rsize2-1+(lookup_size%2);
25748       if (depth>1) switch (patch_size) { // 3D version
25749       case 2 :
25750         if (fast_approx) { _cimg_blur_patch3d(2,_cimg_blur_patch_fastfunc); }
25751         else { _cimg_blur_patch3d(2,_cimg_blur_patch_slowfunc); }
25752         break;
25753       case 3 :
25754         if (fast_approx) { _cimg_blur_patch3d(3,_cimg_blur_patch_fastfunc); }
25755         else { _cimg_blur_patch3d(3,_cimg_blur_patch_slowfunc); }
25756         break;
25757       default : {
25758         const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
25759         cimg_forXYZ(*this,x,y,z) {
25760           cimg_plugin_greycstoration_count;
25761           P = get_crop(x - psize0,y - psize0,z - psize0,x + psize1,y + psize1,z + psize1,true);
25762           const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2;
25763           float sum_weights = 0;
25764           cimg_for_inXYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) {
25765             (Q = get_crop(p - psize0,q - psize0,r - psize0,p + psize1,q + psize1,r + psize1,true))-=P;
25766             const float
25767               dx = (float)x - p, dy = (float)y - q, dz = (float)z - r,
25768               distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),
25769               weight = (float)cimg_std::exp(-distance2);
25770             sum_weights+=weight;
25771             cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k);
25772           }
25773           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));
25774         }
25775       }
25776       } else switch (patch_size) { // 2D version
25777       case 2 :
25778         if (fast_approx) { _cimg_blur_patch2d(2,_cimg_blur_patch_fastfunc); }
25779         else { _cimg_blur_patch2d(2,_cimg_blur_patch_slowfunc); }
25780         break;
25781       case 3 :
25782         if (fast_approx) { _cimg_blur_patch2d(3,_cimg_blur_patch_fastfunc); }
25783         else { _cimg_blur_patch2d(3,_cimg_blur_patch_slowfunc); }
25784         break;
25785       case 4 :
25786         if (fast_approx) { _cimg_blur_patch2d(4,_cimg_blur_patch_fastfunc); }
25787         else { _cimg_blur_patch2d(4,_cimg_blur_patch_slowfunc); }
25788         break;
25789       case 5 :
25790         if (fast_approx) { _cimg_blur_patch2d(5,_cimg_blur_patch_fastfunc); }
25791         else { _cimg_blur_patch2d(5,_cimg_blur_patch_slowfunc); }
25792         break;
25793       case 6 :
25794         if (fast_approx) { _cimg_blur_patch2d(6,_cimg_blur_patch_fastfunc); }
25795         else { _cimg_blur_patch2d(6,_cimg_blur_patch_slowfunc); }
25796         break;
25797       case 7 :
25798         if (fast_approx) { _cimg_blur_patch2d(7,_cimg_blur_patch_fastfunc); }
25799         else { _cimg_blur_patch2d(7,_cimg_blur_patch_slowfunc); }
25800         break;
25801       case 8 :
25802         if (fast_approx) { _cimg_blur_patch2d(8,_cimg_blur_patch_fastfunc); }
25803         else { _cimg_blur_patch2d(8,_cimg_blur_patch_slowfunc); }
25804         break;
25805       case 9 :
25806         if (fast_approx) { _cimg_blur_patch2d(9,_cimg_blur_patch_fastfunc); }
25807         else { _cimg_blur_patch2d(9,_cimg_blur_patch_slowfunc); }
25808         break;
25809       default : {
25810         const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
25811         cimg_forXY(*this,x,y) {
25812           cimg_plugin_greycstoration_count;
25813           P = get_crop(x - psize0,y - psize0,x + psize1,y + psize1,true);
25814           const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2;
25815           float sum_weights = 0;
25816           cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
25817             (Q = get_crop(p - psize0,q - psize0,p + psize1,q + psize1,true))-=P;
25818             const float
25819               dx = (float)x - p, dy = (float)y - q,
25820               distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),
25821               weight = (float)cimg_std::exp(-distance2);
25822             sum_weights+=weight;
25823             cimg_forV(*this,k) res(x,y,0,k)+=weight*(*this)(p,q,0,k);
25824           }
25825           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));
25826         }
25827       }
25828       }
25829       return res.transfer_to(*this);
25830     }
25831 
25832     CImg<T> get_blur_patch(const unsigned int patch_size, const float sigma_p, const float sigma_s=10,
25833                            const unsigned int lookup_size=4, const bool fast_approx=true) const {
25834       return (+*this).blur_patch(patch_size,sigma_p,sigma_s,lookup_size,fast_approx);
25835     }
25836 
25837     //! Compute the Fast Fourier Transform of an image (along a specified axis).
25838     CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
25839       return CImgList<Tfloat>(*this).FFT(axis,invert);
25840     }
25841 
25842     //! Compute the Fast Fourier Transform on an image.
25843     CImgList<Tfloat> get_FFT(const bool invert=false) const {
25844       return CImgList<Tfloat>(*this).FFT(invert);
25845     }
25846 
25847     //! Apply a median filter.
25848     CImg<T>& blur_median(const unsigned int n) {
25849       return get_blur_median(n).transfer_to(*this);
25850     }
25851 
25852     CImg<T> get_blur_median(const unsigned int n) {
25853       CImg<T> res(width,height,depth,dim);
25854       if (!n || n==1) return *this;
25855       const int hl=n/2, hr=hl-1+n%2;
25856       if (res.depth!=1) {  // 3D median filter
25857         CImg<T> vois;
25858         cimg_forXYZV(*this,x,y,z,k) {
25859           const int
25860             x0 = x - hl, y0 = y - hl, z0 = z-hl, x1 = x + hr, y1 = y + hr, z1 = z+hr,
25861             nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,
25862             nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1, nz1 = z1>=dimz()?dimz()-1:z1;
25863           vois = get_crop(nx0,ny0,nz0,k,nx1,ny1,nz1,k);
25864           res(x,y,z,k) = vois.median();
25865         }
25866       } else {
25867 #define _cimg_median_sort(a,b) if ((a)>(b)) cimg::swap(a,b)
25868         if (res.height!=1) switch (n) { // 2D median filter
25869         case 3 : {
25870           T I[9] = { 0 };
25871           CImg_3x3(J,T);
25872           cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
25873             cimg_std::memcpy(J,I,9*sizeof(T));
25874             _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
25875             _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jpn, Jcn);
25876             _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
25877             _cimg_median_sort(Jpp, Jpc); _cimg_median_sort(Jnc, Jnn); _cimg_median_sort(Jcc, Jcn);
25878             _cimg_median_sort(Jpc, Jpn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jnp, Jnc);
25879             _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcc, Jnp); _cimg_median_sort(Jpn, Jcc);
25880             _cimg_median_sort(Jcc, Jnp);
25881             res(x,y,0,k) = Jcc;
25882           }
25883         } break;
25884         case 5 : {
25885           T I[25] = { 0 };
25886           CImg_5x5(J,T);
25887           cimg_forV(*this,k) cimg_for5x5(*this,x,y,0,k,I) {
25888             cimg_std::memcpy(J,I,25*sizeof(T));
25889             _cimg_median_sort(Jbb, Jpb); _cimg_median_sort(Jnb, Jab); _cimg_median_sort(Jcb, Jab); _cimg_median_sort(Jcb, Jnb);
25890             _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbp, Jcp); _cimg_median_sort(Jbp, Jpp); _cimg_median_sort(Jap, Jbc);
25891             _cimg_median_sort(Jnp, Jbc); _cimg_median_sort(Jnp, Jap); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jpc, Jnc);
25892             _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jbn, Jpn); _cimg_median_sort(Jac, Jpn); _cimg_median_sort(Jac, Jbn);
25893             _cimg_median_sort(Jnn, Jan); _cimg_median_sort(Jcn, Jan); _cimg_median_sort(Jcn, Jnn); _cimg_median_sort(Jpa, Jca);
25894             _cimg_median_sort(Jba, Jca); _cimg_median_sort(Jba, Jpa); _cimg_median_sort(Jna, Jaa); _cimg_median_sort(Jcb, Jbp);
25895             _cimg_median_sort(Jnb, Jpp); _cimg_median_sort(Jbb, Jpp); _cimg_median_sort(Jbb, Jnb); _cimg_median_sort(Jab, Jcp);
25896             _cimg_median_sort(Jpb, Jcp); _cimg_median_sort(Jpb, Jab); _cimg_median_sort(Jpc, Jac); _cimg_median_sort(Jnp, Jac);
25897             _cimg_median_sort(Jnp, Jpc); _cimg_median_sort(Jcc, Jbn); _cimg_median_sort(Jap, Jbn); _cimg_median_sort(Jap, Jcc);
25898             _cimg_median_sort(Jnc, Jpn); _cimg_median_sort(Jbc, Jpn); _cimg_median_sort(Jbc, Jnc); _cimg_median_sort(Jba, Jna);
25899             _cimg_median_sort(Jcn, Jna); _cimg_median_sort(Jcn, Jba); _cimg_median_sort(Jpa, Jaa); _cimg_median_sort(Jnn, Jaa);
25900             _cimg_median_sort(Jnn, Jpa); _cimg_median_sort(Jan, Jca); _cimg_median_sort(Jnp, Jcn); _cimg_median_sort(Jap, Jnn);
25901             _cimg_median_sort(Jbb, Jnn); _cimg_median_sort(Jbb, Jap); _cimg_median_sort(Jbc, Jan); _cimg_median_sort(Jpb, Jan);
25902             _cimg_median_sort(Jpb, Jbc); _cimg_median_sort(Jpc, Jba); _cimg_median_sort(Jcb, Jba); _cimg_median_sort(Jcb, Jpc);
25903             _cimg_median_sort(Jcc, Jpa); _cimg_median_sort(Jnb, Jpa); _cimg_median_sort(Jnb, Jcc); _cimg_median_sort(Jnc, Jca);
25904             _cimg_median_sort(Jab, Jca); _cimg_median_sort(Jab, Jnc); _cimg_median_sort(Jac, Jna); _cimg_median_sort(Jbp, Jna);
25905             _cimg_median_sort(Jbp, Jac); _cimg_median_sort(Jbn, Jaa); _cimg_median_sort(Jpp, Jaa); _cimg_median_sort(Jpp, Jbn);
25906             _cimg_median_sort(Jcp, Jpn); _cimg_median_sort(Jcp, Jan); _cimg_median_sort(Jnc, Jpa); _cimg_median_sort(Jbn, Jna);
25907             _cimg_median_sort(Jcp, Jnc); _cimg_median_sort(Jcp, Jbn); _cimg_median_sort(Jpb, Jap); _cimg_median_sort(Jnb, Jpc);
25908             _cimg_median_sort(Jbp, Jcn); _cimg_median_sort(Jpc, Jcn); _cimg_median_sort(Jap, Jcn); _cimg_median_sort(Jab, Jbc);
25909             _cimg_median_sort(Jpp, Jcc); _cimg_median_sort(Jcp, Jac); _cimg_median_sort(Jab, Jpp); _cimg_median_sort(Jab, Jcp);
25910             _cimg_median_sort(Jcc, Jac); _cimg_median_sort(Jbc, Jac); _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbc, Jcc);
25911             _cimg_median_sort(Jpp, Jbc); _cimg_median_sort(Jpp, Jcn); _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcp, Jcn);
25912             _cimg_median_sort(Jcp, Jbc); _cimg_median_sort(Jcc, Jnn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jbc, Jnn);
25913             _cimg_median_sort(Jcc, Jba); _cimg_median_sort(Jbc, Jba); _cimg_median_sort(Jbc, Jcc);
25914             res(x,y,0,k) = Jcc;
25915           }
25916         } break;
25917         default : {
25918           CImg<T> vois;
25919           cimg_forXYV(*this,x,y,k) {
25920             const int
25921               x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,
25922               nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,
25923               nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1;
25924             vois = get_crop(nx0,ny0,0,k,nx1,ny1,0,k);
25925             res(x,y,0,k) = vois.median();
25926           }
25927         }
25928         } else switch (n) { // 1D median filter
25929         case 2 : {
25930           T I[4] = { 0 };
25931           cimg_forV(*this,k) cimg_for2x2(*this,x,y,0,k,I) res(x,0,0,k) = (T)(0.5f*(I[0]+I[1]));
25932         } break;
25933         case 3 : {
25934           T I[9] = { 0 };
25935           cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
25936             res(x,0,0,k) = I[3]<I[4]?
25937               (I[4]<I[5]?I[4]:
25938                (I[3]<I[5]?I[5]:I[3])):
25939               (I[3]<I[5]?I[3]:
25940                (I[4]<I[5]?I[5]:I[4]));
25941           }
25942         } break;
25943         default : {
25944           CImg<T> vois;
25945           cimg_forXV(*this,x,k) {
25946             const int
25947               x0 = x - hl, x1 = x + hr,
25948               nx0 = x0<0?0:x0, nx1 = x1>=dimx()?dimx()-1:x1;
25949             vois = get_crop(nx0,0,0,k,nx1,0,0,k);
25950             res(x,0,0,k) = vois.median();
25951           }
25952         }
25953         }
25954       }
25955       return res;
25956     }
25957 
25958     //! Sharpen image using anisotropic shock filters or inverse diffusion.
25959     CImg<T>& sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) {
25960       if (is_empty()) return *this;
25961       T valm, valM = maxmin(valm);
25962       const bool threed = (depth>1);
25963       const float nedge = 0.5f*edge;
25964       CImg<Tfloat> val, vec, veloc(width,height,depth,dim);
25965 
25966       if (threed) {
25967         CImg_3x3x3(I,T);
25968         if (sharpen_type) { // 3D Shock filter.
25969           CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
25970           if (sigma>0) G.blur(sigma);
25971 
25972           cimg_forXYZ(G,x,y,z) {
25973             G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
25974             G(x,y,z,0) = vec(0,0);
25975             G(x,y,z,1) = vec(0,1);
25976             G(x,y,z,2) = vec(0,2);
25977             G(x,y,z,3) = 1 - (Tfloat)cimg_std::pow(1+val[0]+val[1]+val[2],-(Tfloat)nedge);
25978           }
25979           cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
25980             const Tfloat
25981               u = G(x,y,z,0),
25982               v = G(x,y,z,1),
25983               w = G(x,y,z,2),
25984               amp = G(x,y,z,3),
25985               ixx = (Tfloat)Incc + Ipcc - 2*Iccc,
25986               ixy = 0.25f*((Tfloat)Innc + Ippc - Inpc - Ipnc),
25987               ixz = 0.25f*((Tfloat)Incn + Ipcp - Incp - Ipcn),
25988               iyy = (Tfloat)Icnc + Icpc - 2*Iccc,
25989               iyz = 0.25f*((Tfloat)Icnn + Icpp - Icnp - Icpn),
25990               izz = (Tfloat)Iccn + Iccp - 2*Iccc,
25991               ixf = (Tfloat)Incc - Iccc,
25992               ixb = (Tfloat)Iccc - Ipcc,
25993               iyf = (Tfloat)Icnc - Iccc,
25994               iyb = (Tfloat)Iccc - Icpc,
25995               izf = (Tfloat)Iccn - Iccc,
25996               izb = (Tfloat)Iccc - Iccp,
25997               itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz,
25998               it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb);
25999             veloc(x,y,z,k) = -amp*cimg::sign(itt)*cimg::abs(it);
26000           }
26001         } 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.
26002       } else {
26003         CImg_3x3(I,T);
26004         if (sharpen_type) { // 2D Shock filter.
26005           CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
26006           if (sigma>0) G.blur(sigma);
26007           cimg_forXY(G,x,y) {
26008             G.get_tensor_at(x,y).symmetric_eigen(val,vec);
26009             G(x,y,0) = vec(0,0);
26010             G(x,y,1) = vec(0,1);
26011             G(x,y,2) = 1 - (Tfloat)cimg_std::pow(1+val[0]+val[1],-(Tfloat)nedge);
26012           }
26013           cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
26014             const Tfloat
26015               u = G(x,y,0),
26016               v = G(x,y,1),
26017               amp = G(x,y,2),
26018               ixx = (Tfloat)Inc + Ipc - 2*Icc,
26019               ixy = 0.25f*((Tfloat)Inn + Ipp - Inp - Ipn),
26020               iyy = (Tfloat)Icn + Icp - 2*Icc,
26021               ixf = (Tfloat)Inc - Icc,
26022               ixb = (Tfloat)Icc - Ipc,
26023               iyf = (Tfloat)Icn - Icc,
26024               iyb = (Tfloat)Icc - Icp,
26025               itt = u*u*ixx + v*v*iyy + 2*u*v*ixy,
26026               it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb);
26027             veloc(x,y,k) = -amp*cimg::sign(itt)*cimg::abs(it);
26028           }
26029         } 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.
26030       }
26031       float m, M = (float)veloc.maxmin(m);
26032       const float vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
26033       if (vmax!=0) { veloc*=amplitude/vmax; (*this)+=veloc; }
26034       return cut(valm,valM);
26035     }
26036 
26037     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 {
26038       return (+*this).sharpen(amplitude,sharpen_type,edge,alpha,sigma);
26039     }
26040 
26041     //! Compute the Haar multiscale wavelet transform (monodimensional version).
26042     /**
26043        \param axis Axis considered for the transform.
26044        \param invert Set inverse of direct transform.
26045        \param nb_scales Number of scales used for the transform.
26046     **/
26047     CImg<T>& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) {
26048       return get_haar(axis,invert,nb_scales).transfer_to(*this);
26049     }
26050 
26051     CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const {
26052       if (is_empty() || !nb_scales) return *this;
26053       CImg<Tfloat> res;
26054 
26055       if (nb_scales==1) {
26056         switch (cimg::uncase(axis)) { // Single scale transform
26057         case 'x' : {
26058           const unsigned int w = width/2;
26059           if (w) {
26060             if (w%2)
26061               throw CImgInstanceException("CImg<%s>::haar() : Sub-image width = %u is not even at a particular scale (=%u).",
26062                                           pixel_type(),w);
26063             res.assign(width,height,depth,dim);
26064             if (invert) cimg_forYZV(*this,y,z,v) { // Inverse transform along X
26065               for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
26066                 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(xw,y,z,v);
26067                 res(x2++,y,z,v) = val0 - val1;
26068                 res(x2++,y,z,v) = val0 + val1;
26069               }
26070             } else cimg_forYZV(*this,y,z,v) { // Direct transform along X
26071               for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
26072                 const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,v), val1 = (Tfloat)(*this)(x2++,y,z,v);
26073                 res(x,y,z,v) = (val0 + val1)/2;
26074                 res(xw,y,z,v) = (val1 - val0)/2;
26075               }
26076             }
26077           } else return *this;
26078         } break;
26079         case 'y' : {
26080           const unsigned int h = height/2;
26081           if (h) {
26082             if (h%2)
26083               throw CImgInstanceException("CImg<%s>::haar() : Sub-image height = %u is not even at a particular scale.",
26084                                           pixel_type(),h);
26085             res.assign(width,height,depth,dim);
26086             if (invert) cimg_forXZV(*this,x,z,v) { // Inverse transform along Y
26087               for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) {
26088                 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,yh,z,v);
26089                 res(x,y2++,z,v) = val0 - val1;
26090                 res(x,y2++,z,v) = val0 + val1;
26091               }
26092             } else cimg_forXZV(*this,x,z,v) {
26093               for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) { // Direct transform along Y
26094                 const Tfloat val0 = (Tfloat)(*this)(x,y2++,z,v), val1 = (Tfloat)(*this)(x,y2++,z,v);
26095                 res(x,y,z,v) = (val0 + val1)/2;
26096                 res(x,yh,z,v) = (val1 - val0)/2;
26097               }
26098             }
26099           } else return *this;
26100         } break;
26101         case 'z' : {
26102           const unsigned int d = depth/2;
26103           if (d) {
26104             if (d%2)
26105               throw CImgInstanceException("CImg<%s>::haar() : Sub-image depth = %u is not even at a particular scale.",
26106                                           pixel_type(),d);
26107             res.assign(width,height,depth,dim);
26108             if (invert) cimg_forXYV(*this,x,y,v) { // Inverse transform along Z
26109               for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) {
26110                 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,y,zd,v);
26111                 res(x,y,z2++,v) = val0 - val1;
26112                 res(x,y,z2++,v) = val0 + val1;
26113               }
26114             } else cimg_forXYV(*this,x,y,v) {
26115               for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) { // Direct transform along Z
26116                 const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,v), val1 = (Tfloat)(*this)(x,y,z2++,v);
26117                 res(x,y,z,v) = (val0 + val1)/2;
26118                 res(x,y,zd,v) = (val1 - val0)/2;
26119               }
26120             }
26121           } else return *this;
26122         } break;
26123         default :
26124           throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
26125                                       pixel_type(),axis);
26126         }
26127       } else { // Multi-scale version
26128         if (invert) {
26129           res.assign(*this);
26130           switch (cimg::uncase(axis)) {
26131           case 'x' : {
26132             unsigned int w = width;
26133             for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
26134             for (w=w?w:1; w<=width; w*=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',true,1));
26135           } break;
26136           case 'y' : {
26137             unsigned int h = width;
26138             for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
26139             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));
26140           } break;
26141           case 'z' : {
26142             unsigned int d = depth;
26143             for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
26144             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));
26145           } break;
26146           default :
26147             throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
26148                                         pixel_type(),axis);
26149           }
26150         } else { // Direct transform
26151           res = get_haar(axis,false,1);
26152           switch (cimg::uncase(axis)) {
26153           case 'x' : {
26154             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));
26155           } break;
26156           case 'y' : {
26157             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));
26158           } break;
26159           case 'z' : {
26160             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));
26161           } break;
26162           default :
26163             throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
26164                                         pixel_type(),axis);
26165           }
26166         }
26167       }
26168       return res;
26169     }
26170 
26171     //! Compute the Haar multiscale wavelet transform.
26172     /**
26173        \param invert Set inverse of direct transform.
26174        \param nb_scales Number of scales used for the transform.
26175     **/
26176     CImg<T>& haar(const bool invert=false, const unsigned int nb_scales=1) {
26177       return get_haar(invert,nb_scales).transfer_to(*this);
26178     }
26179 
26180     CImg<Tfloat> get_haar(const bool invert=false, const unsigned int nb_scales=1) const {
26181       CImg<Tfloat> res;
26182 
26183       if (nb_scales==1) { // Single scale transform
26184         if (width>1) get_haar('x',invert,1).transfer_to(res);
26185         if (height>1) { if (res) res.get_haar('y',invert,1).transfer_to(res); else get_haar('y',invert,1).transfer_to(res); }
26186         if (depth>1) { if (res) res.get_haar('z',invert,1).transfer_to(res); else get_haar('z',invert,1).transfer_to(res); }
26187         if (res) return res;
26188       } else { // Multi-scale transform
26189         if (invert) { // Inverse transform
26190           res.assign(*this);
26191           if (width>1) {
26192             if (height>1) {
26193               if (depth>1) {
26194                 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; }
26195                 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)
26196                   res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).get_haar(true,1));
26197               } else {
26198                 unsigned int w = width, h = height; for (unsigned int s=1; w && h && s<nb_scales; ++s) { w/=2; h/=2; }
26199                 for (w=w?w:1, h=h?h:1; w<=width && h<=height; w*=2, h*=2)
26200                   res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).get_haar(true,1));
26201               }
26202             } else {
26203               if (depth>1) {
26204                 unsigned int w = width, d = depth; for (unsigned int s=1; w && d && s<nb_scales; ++s) { w/=2; d/=2; }
26205                 for (w=w?w:1, d=d?d:1; w<=width && d<=depth; w*=2, d*=2)
26206                   res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).get_haar(true,1));
26207               } else {
26208                 unsigned int w = width; for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
26209                 for (w=w?w:1; w<=width; w*=2)
26210                   res.draw_image(res.get_crop(0,0,0,w-1,0,0).get_haar(true,1));
26211               }
26212             }
26213           } else {
26214             if (height>1) {
26215               if (depth>1) {
26216                 unsigned int h = height, d = depth; for (unsigned int s=1; h && d && s<nb_scales; ++s) { h/=2; d/=2; }
26217                 for (h=h?h:1, d=d?d:1; h<=height && d<=depth; h*=2, d*=2)
26218                   res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).get_haar(true,1));
26219               } else {
26220                 unsigned int h = height; for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
26221                 for (h=h?h:1; h<=height; h*=2)
26222                   res.draw_image(res.get_crop(0,0,0,0,h-1,0).get_haar(true,1));
26223               }
26224             } else {
26225               if (depth>1) {
26226                 unsigned int d = depth; for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
26227                 for (d=d?d:1; d<=depth; d*=2)
26228                   res.draw_image(res.get_crop(0,0,0,0,0,d-1).get_haar(true,1));
26229               } else return *this;
26230             }
26231           }
26232         } else { // Direct transform
26233           res = get_haar(false,1);
26234           if (width>1) {
26235             if (height>1) {
26236               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)
26237                 res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).haar(false,1));
26238               else for (unsigned int s=1, w=width/2, h=height/2; w && h && s<nb_scales; ++s, w/=2, h/=2)
26239                 res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).haar(false,1));
26240             } else {
26241               if (depth>1) for (unsigned int s=1, w=width/2, d=depth/2; w && d && s<nb_scales; ++s, w/=2, d/=2)
26242                 res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).haar(false,1));
26243               else for (unsigned int s=1, w=width/2; w && s<nb_scales; ++s, w/=2)
26244                 res.draw_image(res.get_crop(0,0,0,w-1,0,0).haar(false,1));
26245             }
26246           } else {
26247             if (height>1) {
26248               if (depth>1) for (unsigned int s=1, h=height/2, d=depth/2; h && d && s<nb_scales; ++s, h/=2, d/=2)
26249                 res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).haar(false,1));
26250               else for (unsigned int s=1, h=height/2; h && s<nb_scales; ++s, h/=2)
26251                 res.draw_image(res.get_crop(0,0,0,0,h-1,0).haar(false,1));
26252             } else {
26253               if (depth>1) for (unsigned int s=1, d=depth/2; d && s<nb_scales; ++s, d/=2)
26254                 res.draw_image(res.get_crop(0,0,0,0,0,d-1).haar(false,1));
26255               else return *this;
26256             }
26257           }
26258         }
26259         return res;
26260       }
26261       return *this;
26262     }
26263 
26264     //! Estimate a displacement field between instance image and given target image.
26265     CImg<T>& displacement_field(const CImg<T>& target, const float smooth=0.1f, const float precision=0.1f,
26266                                 const unsigned int nb_scales=0, const unsigned int itermax=10000) {
26267       return get_displacement_field(target,smooth,precision,nb_scales,itermax).transfer_to(*this);
26268     }
26269 
26270     CImg<Tfloat> get_displacement_field(const CImg<T>& target,
26271                                         const float smoothness=0.1f, const float precision=0.1f,
26272                                         const unsigned int nb_scales=0, const unsigned int itermax=10000) const {
26273       if (is_empty() || !target) return *this;
26274       if (!is_sameXYZV(target))
26275         throw CImgArgumentException("CImg<%s>::displacement_field() : Instance image (%u,%u,%u,%u,%p) and target image (%u,%u,%u,%u,%p) "
26276                                     "have different size.",
26277                                     pixel_type(),width,height,depth,dim,data,
26278                                     target.width,target.height,target.depth,target.dim,target.data);
26279       if (smoothness<0)
26280         throw CImgArgumentException("CImg<%s>::displacement_field() : Smoothness parameter %g is negative.",
26281                                     pixel_type(),smoothness);
26282       if (precision<0)
26283         throw CImgArgumentException("CImg<%s>::displacement_field() : Precision parameter %g is negative.",
26284                                     pixel_type(),precision);
26285 
26286       const unsigned int nscales = nb_scales>0?nb_scales:(unsigned int)(2*cimg_std::log((double)(cimg::max(width,height,depth))));
26287       Tfloat m1, M1 = (Tfloat)maxmin(m1), m2, M2 = (Tfloat)target.maxmin(m2);
26288       const Tfloat factor = cimg::max(cimg::abs(m1),cimg::abs(M1),cimg::abs(m2),cimg::abs(M2));
26289       CImg<Tfloat> U0;
26290       const bool threed = (depth>1);
26291 
26292       // Begin multi-scale motion estimation
26293       for (int scale = (int)nscales-1; scale>=0; --scale) {
26294         const float sfactor = (float)cimg_std::pow(1.5f,(float)scale), sprecision = (float)(precision/cimg_std::pow(2.25,1+scale));
26295         const int
26296           sw = (int)(width/sfactor), sh = (int)(height/sfactor), sd = (int)(depth/sfactor),
26297           swidth = sw?sw:1, sheight = sh?sh:1, sdepth = sd?sd:1;
26298         CImg<Tfloat>
26299           I1 = get_resize(swidth,sheight,sdepth,-100,2),
26300           I2 = target.get_resize(swidth,sheight,sdepth,-100,2);
26301         I1/=factor; I2/=factor;
26302         CImg<Tfloat> U;
26303         if (U0) U = (U0*=1.5f).get_resize(I1.dimx(),I1.dimy(),I1.dimz(),-100,3);
26304         else U.assign(I1.dimx(),I1.dimy(),I1.dimz(),threed?3:2,0);
26305 
26306         // Begin single-scale motion estimation
26307         CImg<Tfloat> veloc(U);
26308         float dt = 2, Energy = cimg::type<float>::max();
26309         const CImgList<Tfloat> dI = I2.get_gradient();
26310         for (unsigned int iter=0; iter<itermax; iter++) {
26311           veloc.fill(0);
26312           float nEnergy = 0;
26313           if (threed) {
26314             cimg_for3XYZ(U,x,y,z) {
26315               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));
26316               cimg_forV(U,k) {
26317                 const Tfloat
26318                   Ux = 0.5f*(U(_n1x,y,z,k) - U(_p1x,y,z,k)),
26319                   Uy = 0.5f*(U(x,_n1y,z,k) - U(x,_p1y,z,k)),
26320                   Uz = 0.5f*(U(x,y,_n1z,k) - U(x,y,_p1z,k)),
26321                   Uxx = U(_n1x,y,z,k) + U(_p1x,y,z,k) - 2*U(x,y,z,k),
26322                   Uyy = U(x,_n1y,z,k) + U(x,_p1y,z,k) - 2*U(x,y,z,k),
26323                   Uzz = U(x,y,_n1z,k) + U(x,y,_n1z,k) - 2*U(x,y,z,k);
26324                 nEnergy += (float)(smoothness*(Ux*Ux + Uy*Uy + Uz*Uz));
26325                 Tfloat deltaIgrad = 0;
26326                 cimg_forV(I1,i) {
26327                   const Tfloat deltaIi = (float)(I2._linear_atXYZ(X,Y,Z,i) - I1(x,y,z,i));
26328                   nEnergy += (float)(deltaIi*deltaIi/2);
26329                   deltaIgrad+=-deltaIi*dI[k]._linear_atXYZ(X,Y,Z,i);
26330                 }
26331                 veloc(x,y,z,k) = deltaIgrad + smoothness*(Uxx + Uyy + Uzz);
26332               }
26333             }
26334           } else {
26335             cimg_for3XY(U,x,y) {
26336               const float X = (float)(x + U(x,y,0)), Y = (float)(y + U(x,y,1));
26337               cimg_forV(U,k) {
26338                 const Tfloat
26339                   Ux = 0.5f*(U(_n1x,y,k) - U(_p1x,y,k)),
26340                   Uy = 0.5f*(U(x,_n1y,k) - U(x,_p1y,k)),
26341                   Uxx = U(_n1x,y,k) + U(_p1x,y,k) - 2*U(x,y,k),
26342                   Uyy = U(x,_n1y,k) + U(x,_p1y,k) - 2*U(x,y,k);
26343                 nEnergy += (float)(smoothness*(Ux*Ux + Uy*Uy));
26344                 Tfloat deltaIgrad = 0;
26345                 cimg_forV(I1,i) {
26346                   const Tfloat deltaIi = (float)(I2._linear_atXY(X,Y,i) - I1(x,y,i));
26347                   nEnergy += (float)(deltaIi*deltaIi/2);
26348                   deltaIgrad+=-deltaIi*dI[k]._linear_atXY(X,Y,i);
26349                 }
26350                 veloc(x,y,k) = deltaIgrad + smoothness*(Uxx + Uyy);
26351               }
26352             }
26353           }
26354           const Tfloat vmax = cimg::max(cimg::abs(veloc.min()), cimg::abs(veloc.max()));
26355           U+=(veloc*=dt/vmax);
26356           if (cimg::abs(nEnergy-Energy)<sprecision) break;
26357           if (nEnergy<Energy) dt*=0.5f;
26358           Energy = nEnergy;
26359         }
26360         U.transfer_to(U0);
26361       }
26362       return U0;
26363     }
26364 
26365     //@}
26366     //-----------------------------
26367     //
26368     //! \name Matrix and Vectors
26369     //@{
26370     //-----------------------------
26371 
26372     //! Return a vector with specified coefficients.
26373     static CImg<T> vector(const T& a0) {
26374       static CImg<T> r(1,1); r[0] = a0;
26375       return r;
26376     }
26377 
26378     //! Return a vector with specified coefficients.
26379     static CImg<T> vector(const T& a0, const T& a1) {
26380       static CImg<T> r(1,2); T *ptr = r.data;
26381       *(ptr++) = a0; *(ptr++) = a1;
26382       return r;
26383     }
26384 
26385     //! Return a vector with specified coefficients.
26386     static CImg<T> vector(const T& a0, const T& a1, const T& a2) {
26387       static CImg<T> r(1,3); T *ptr = r.data;
26388       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
26389       return r;
26390     }
26391 
26392     //! Return a vector with specified coefficients.
26393     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3) {
26394       static CImg<T> r(1,4); T *ptr = r.data;
26395       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26396       return r;
26397     }
26398 
26399     //! Return a vector with specified coefficients.
26400     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
26401       static CImg<T> r(1,5); T *ptr = r.data;
26402       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
26403       return r;
26404     }
26405 
26406     //! Return a vector with specified coefficients.
26407     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {
26408       static CImg<T> r(1,6); T *ptr = r.data;
26409       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
26410       return r;
26411     }
26412 
26413     //! Return a vector with specified coefficients.
26414     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26415                           const T& a4, const T& a5, const T& a6) {
26416       static CImg<T> r(1,7); T *ptr = r.data;
26417       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26418       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6;
26419       return r;
26420     }
26421 
26422     //! Return a vector with specified coefficients.
26423     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26424                           const T& a4, const T& a5, const T& a6, const T& a7) {
26425       static CImg<T> r(1,8); T *ptr = r.data;
26426       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26427       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26428       return r;
26429     }
26430 
26431     //! Return a vector with specified coefficients.
26432     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26433                           const T& a4, const T& a5, const T& a6, const T& a7,
26434                           const T& a8) {
26435       static CImg<T> r(1,9); T *ptr = r.data;
26436       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26437       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26438       *(ptr++) = a8;
26439       return r;
26440     }
26441 
26442     //! Return a vector with specified coefficients.
26443     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26444                           const T& a4, const T& a5, const T& a6, const T& a7,
26445                           const T& a8, const T& a9) {
26446       static CImg<T> r(1,10); T *ptr = r.data;
26447       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26448       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26449       *(ptr++) = a8; *(ptr++) = a9;
26450       return r;
26451     }
26452 
26453     //! Return a vector with specified coefficients.
26454     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26455                           const T& a4, const T& a5, const T& a6, const T& a7,
26456                           const T& a8, const T& a9, const T& a10) {
26457       static CImg<T> r(1,11); T *ptr = r.data;
26458       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26459       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26460       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10;
26461       return r;
26462     }
26463 
26464     //! Return a vector with specified coefficients.
26465     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26466                           const T& a4, const T& a5, const T& a6, const T& a7,
26467                           const T& a8, const T& a9, const T& a10, const T& a11) {
26468       static CImg<T> r(1,12); T *ptr = r.data;
26469       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26470       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26471       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26472       return r;
26473     }
26474 
26475     //! Return a vector with specified coefficients.
26476     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26477                           const T& a4, const T& a5, const T& a6, const T& a7,
26478                           const T& a8, const T& a9, const T& a10, const T& a11,
26479                           const T& a12) {
26480       static CImg<T> r(1,13); T *ptr = r.data;
26481       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26482       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26483       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26484       *(ptr++) = a12;
26485       return r;
26486     }
26487 
26488     //! Return a vector with specified coefficients.
26489     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26490                           const T& a4, const T& a5, const T& a6, const T& a7,
26491                           const T& a8, const T& a9, const T& a10, const T& a11,
26492                           const T& a12, const T& a13) {
26493       static CImg<T> r(1,14); T *ptr = r.data;
26494       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26495       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26496       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26497       *(ptr++) = a12; *(ptr++) = a13;
26498       return r;
26499     }
26500 
26501     //! Return a vector with specified coefficients.
26502     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26503                           const T& a4, const T& a5, const T& a6, const T& a7,
26504                           const T& a8, const T& a9, const T& a10, const T& a11,
26505                           const T& a12, const T& a13, const T& a14) {
26506       static CImg<T> r(1,15); T *ptr = r.data;
26507       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26508       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26509       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26510       *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
26511       return r;
26512     }
26513 
26514     //! Return a vector with specified coefficients.
26515     static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26516                           const T& a4, const T& a5, const T& a6, const T& a7,
26517                           const T& a8, const T& a9, const T& a10, const T& a11,
26518                           const T& a12, const T& a13, const T& a14, const T& a15) {
26519       static CImg<T> r(1,16); T *ptr = r.data;
26520       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26521       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26522       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26523       *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
26524       return r;
26525     }
26526 
26527     //! Return a 1x1 square matrix with specified coefficients.
26528     static CImg<T> matrix(const T& a0) {
26529       return vector(a0);
26530     }
26531 
26532     //! Return a 2x2 square matrix with specified coefficients.
26533     static CImg<T> matrix(const T& a0, const T& a1,
26534                           const T& a2, const T& a3) {
26535       static CImg<T> r(2,2); T *ptr = r.data;
26536       *(ptr++) = a0; *(ptr++) = a1;
26537       *(ptr++) = a2; *(ptr++) = a3;
26538       return r;
26539     }
26540 
26541     //! Return a 3x3 square matrix with specified coefficients.
26542     static CImg<T> matrix(const T& a0, const T& a1, const T& a2,
26543                           const T& a3, const T& a4, const T& a5,
26544                           const T& a6, const T& a7, const T& a8) {
26545       static CImg<T> r(3,3); T *ptr = r.data;
26546       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
26547       *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
26548       *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8;
26549       return r;
26550     }
26551 
26552     //! Return a 4x4 square matrix with specified coefficients.
26553     static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3,
26554                           const T& a4, const T& a5, const T& a6, const T& a7,
26555                           const T& a8, const T& a9, const T& a10, const T& a11,
26556                           const T& a12, const T& a13, const T& a14, const T& a15) {
26557       static CImg<T> r(4,4); T *ptr = r.data;
26558       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26559       *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26560       *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26561       *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
26562       return r;
26563     }
26564 
26565     //! Return a 5x5 square matrix with specified coefficients.
26566     static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4,
26567                           const T& a5, const T& a6, const T& a7, const T& a8, const T& a9,
26568                           const T& a10, const T& a11, const T& a12, const T& a13, const T& a14,
26569                           const T& a15, const T& a16, const T& a17, const T& a18, const T& a19,
26570                           const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) {
26571       static CImg<T> r(5,5); T *ptr = r.data;
26572       *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
26573       *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9;
26574       *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
26575       *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19;
26576       *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24;
26577       return r;
26578     }
26579 
26580     //! Return a 1x1 symmetric matrix with specified coefficients.
26581     static CImg<T> tensor(const T& a1) {
26582       return matrix(a1);
26583     }
26584 
26585     //! Return a 2x2 symmetric matrix tensor with specified coefficients.
26586     static CImg<T> tensor(const T& a1, const T& a2, const T& a3) {
26587       return matrix(a1,a2,a2,a3);
26588     }
26589 
26590     //! Return a 3x3 symmetric matrix with specified coefficients.
26591     static CImg<T> tensor(const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) {
26592       return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6);
26593     }
26594 
26595     //! Return a 1x1 diagonal matrix with specified coefficients.
26596     static CImg<T> diagonal(const T& a0) {
26597       return matrix(a0);
26598     }
26599 
26600     //! Return a 2x2 diagonal matrix with specified coefficients.
26601     static CImg<T> diagonal(const T& a0, const T& a1) {
26602       return matrix(a0,0,0,a1);
26603     }
26604 
26605     //! Return a 3x3 diagonal matrix with specified coefficients.
26606     static CImg<T> diagonal(const T& a0, const T& a1, const T& a2) {
26607       return matrix(a0,0,0,0,a1,0,0,0,a2);
26608     }
26609 
26610     //! Return a 4x4 diagonal matrix with specified coefficients.
26611     static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3) {
26612       return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3);
26613     }
26614 
26615     //! Return a 5x5 diagonal matrix with specified coefficients.
26616     static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
26617       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);
26618     }
26619 
26620     //! Return a NxN identity matrix.
26621     static CImg<T> identity_matrix(const unsigned int N) {
26622       CImg<T> res(N,N,1,1,0);
26623       cimg_forX(res,x) res(x,x) = 1;
26624       return res;
26625     }
26626 
26627     //! Return a N-numbered sequence vector from \p a0 to \p a1.
26628     static CImg<T> sequence(const unsigned int N, const T a0, const T a1) {
26629       if (N) return CImg<T>(1,N).sequence(a0,a1);
26630       return CImg<T>();
26631     }
26632 
26633     //! Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w.
26634     static CImg<T> rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) {
26635       float X,Y,Z,W;
26636       if (!quaternion_data) {
26637         const float norm = (float)cimg_std::sqrt(x*x + y*y + z*z),
26638           nx = norm>0?x/norm:0,
26639           ny = norm>0?y/norm:0,
26640           nz = norm>0?z/norm:1,
26641           nw = norm>0?w:0,
26642           sina = (float)cimg_std::sin(nw/2),
26643           cosa = (float)cimg_std::cos(nw/2);
26644         X = nx*sina;
26645         Y = ny*sina;
26646         Z = nz*sina;
26647         W = cosa;
26648       } else {
26649         const float norm = (float)cimg_std::sqrt(x*x + y*y + z*z + w*w);
26650         if (norm>0) { X = x/norm; Y = y/norm; Z = z/norm; W = w/norm; }
26651         else { X = Y = Z = 0; W = 1; }
26652       }
26653       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;
26654       return CImg<T>::matrix((T)(1-2*(yy+zz)), (T)(2*(xy+zw)),   (T)(2*(xz-yw)),
26655                              (T)(2*(xy-zw)),   (T)(1-2*(xx+zz)), (T)(2*(yz+xw)),
26656                              (T)(2*(xz+yw)),   (T)(2*(yz-xw)),   (T)(1-2*(xx+yy)));
26657     }
26658 
26659     //! Return a new image corresponding to the vector located at (\p x,\p y,\p z) of the current vector-valued image.
26660     CImg<T> get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
26661       static CImg<T> dest;
26662       if (dest.height!=dim) dest.assign(1,dim);
26663       const unsigned int whz = width*height*depth;
26664       const T *ptrs = ptr(x,y,z);
26665       T *ptrd = dest.data;
26666       cimg_forV(*this,k) { *(ptrd++) = *ptrs; ptrs+=whz; }
26667       return dest;
26668     }
26669 
26670     //! 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.
26671     template<typename t>
26672     CImg<T>& set_vector_at(const CImg<t>& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) {
26673       if (x<width && y<height && z<depth) {
26674         const unsigned int whz = width*height*depth;
26675         const t *ptrs = vec.data;
26676         T *ptrd = ptr(x,y,z);
26677         for (unsigned int k=cimg::min((unsigned int)vec.size(),dim); k; --k) { *ptrd = (T)*(ptrs++); ptrd+=whz; }
26678       }
26679       return *this;
26680     }
26681 
26682     //! 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.
26683     CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
26684       const int n = (int)cimg_std::sqrt((double)dim);
26685       CImg<T> dest(n,n);
26686       cimg_forV(*this,k) dest[k]=(*this)(x,y,z,k);
26687       return dest;
26688     }
26689 
26690     //! 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.
26691     template<typename t>
26692     CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
26693       return set_vector_at(mat,x,y,z);
26694     }
26695 
26696     //! 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.
26697     CImg<T> get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
26698       if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2),
26699                                 (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5));
26700       if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2));
26701       return tensor((*this)(x,y,z,0));
26702     }
26703 
26704     //! 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.
26705     template<typename t>
26706     CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
26707       if (ten.height==2) {
26708         (*this)(x,y,z,0) = (T)ten[0];
26709         (*this)(x,y,z,1) = (T)ten[1];
26710         (*this)(x,y,z,2) = (T)ten[3];
26711       }
26712       else {
26713         (*this)(x,y,z,0) = (T)ten[0];
26714         (*this)(x,y,z,1) = (T)ten[1];
26715         (*this)(x,y,z,2) = (T)ten[2];
26716         (*this)(x,y,z,3) = (T)ten[4];
26717         (*this)(x,y,z,4) = (T)ten[5];
26718         (*this)(x,y,z,5) = (T)ten[8];
26719       }
26720       return *this;
26721     }
26722 
26723     //! Unroll all images values into a one-column vector.
26724     CImg<T>& vector() {
26725       return unroll('y');
26726     }
26727 
26728     CImg<T> get_vector() const {
26729       return get_unroll('y');
26730     }
26731 
26732     //! Realign pixel values of the instance image as a square matrix
26733     CImg<T>& matrix() {
26734       const unsigned int siz = size();
26735       switch (siz) {
26736       case 1 : break;
26737       case 4 : width = height = 2; break;
26738       case 9 : width = height = 3; break;
26739       case 16 : width = height = 4; break;
26740       case 25 : width = height = 5; break;
26741       case 36 : width = height = 6; break;
26742       case 49 : width = height = 7; break;
26743       case 64 : width = height = 8; break;
26744       case 81 : width = height = 9; break;
26745       case 100 : width = height = 10; break;
26746       default : {
26747         unsigned int i = 11, i2 = i*i;
26748         while (i2<siz) { i2+=2*i+1; ++i; }
26749         if (i2==siz) width = height = i;
26750         else throw CImgInstanceException("CImg<%s>::matrix() : Image size = %u is not a square number",
26751                                          pixel_type(),siz);
26752       }
26753       }
26754       return *this;
26755     }
26756 
26757     CImg<T> get_matrix() const {
26758       return (+*this).matrix();
26759     }
26760 
26761     //! Realign pixel values of the instance image as a symmetric tensor.
26762     CImg<T>& tensor() {
26763       return get_tensor().transfer_to(*this);
26764     }
26765 
26766     CImg<T> get_tensor() const {
26767       CImg<T> res;
26768       const unsigned int siz = size();
26769       switch (siz) {
26770       case 1 : break;
26771       case 3 :
26772         res.assign(2,2);
26773         res(0,0) = (*this)(0);
26774         res(1,0) = res(0,1) = (*this)(1);
26775         res(1,1) = (*this)(2);
26776         break;
26777       case 6 :
26778         res.assign(3,3);
26779         res(0,0) = (*this)(0);
26780         res(1,0) = res(0,1) = (*this)(1);
26781         res(2,0) = res(0,2) = (*this)(2);
26782         res(1,1) = (*this)(3);
26783         res(2,1) = res(1,2) = (*this)(4);
26784         res(2,2) = (*this)(5);
26785         break;
26786       default :
26787         throw CImgInstanceException("CImg<%s>::tensor() : Wrong vector dimension = %u in instance image.",
26788                                     pixel_type(), dim);
26789       }
26790       return res;
26791     }
26792 
26793     //! Unroll all images values into specified axis.
26794     CImg<T>& unroll(const char axis) {
26795       const unsigned int siz = size();
26796       if (siz) switch (axis) {
26797       case 'x' : width = siz; height=depth=dim=1; break;
26798       case 'y' : height = siz; width=depth=dim=1; break;
26799       case 'z' : depth = siz; width=height=dim=1; break;
26800       case 'v' : dim = siz; width=height=depth=1; break;
26801       default :
26802         throw CImgArgumentException("CImg<%s>::unroll() : Given axis is '%c' which is not 'x','y','z' or 'v'",
26803                                     pixel_type(),axis);
26804       }
26805       return *this;
26806     }
26807 
26808     CImg<T> get_unroll(const char axis) const {
26809       return (+*this).unroll(axis);
26810     }
26811 
26812     //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image.
26813     CImg<T>& diagonal() {
26814       return get_diagonal().transfer_to(*this);
26815     }
26816 
26817     CImg<T> get_diagonal() const {
26818       if (is_empty()) return *this;
26819       CImg<T> res(size(),size(),1,1,0);
26820       cimg_foroff(*this,off) res(off,off) = (*this)(off);
26821       return res;
26822     }
26823 
26824     //! Get an identity matrix having same dimension than instance image.
26825     CImg<T>& identity_matrix() {
26826       return identity_matrix(cimg::max(width,height)).transfer_to(*this);
26827     }
26828 
26829     CImg<T> get_identity_matrix() const {
26830       return identity_matrix(cimg::max(width,height));
26831     }
26832 
26833     //! Return a N-numbered sequence vector from \p a0 to \p a1.
26834     CImg<T>& sequence(const T a0, const T a1) {
26835       if (is_empty()) return *this;
26836       const unsigned int siz = size() - 1;
26837       T* ptr = data;
26838       if (siz) {
26839         const Tfloat delta = (Tfloat)a1 - a0;
26840         cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);
26841       } else *ptr = a0;
26842       return *this;
26843     }
26844 
26845     CImg<T> get_sequence(const T a0, const T a1) const {
26846       return (+*this).sequence(a0,a1);
26847     }
26848 
26849     //! Transpose the current matrix.
26850     CImg<T>& transpose() {
26851       if (width==1) { width=height; height=1; return *this; }
26852       if (height==1) { height=width; width=1; return *this; }
26853       if (width==height) {
26854         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));
26855         return *this;
26856       }
26857       return get_transpose().transfer_to(*this);
26858     }
26859 
26860     CImg<T> get_transpose() const {
26861       return get_permute_axes("yxzv");
26862     }
26863 
26864     //! Invert the current matrix.
26865     CImg<T>& invert(const bool use_LU=true) {
26866       if (!is_empty()) {
26867         if (width!=height || depth!=1 || dim!=1)
26868           throw CImgInstanceException("CImg<%s>::invert() : Instance matrix (%u,%u,%u,%u,%p) is not square.",
26869                                       pixel_type(),width,height,depth,dim,data);
26870 #ifdef cimg_use_lapack
26871         int INFO = (int)use_LU, N = width, LWORK = 4*N, *IPIV = new int[N];
26872         Tfloat
26873           *lapA = new Tfloat[N*N],
26874           *WORK = new Tfloat[LWORK];
26875         cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
26876         cimg::getrf(N,lapA,IPIV,INFO);
26877         if (INFO)
26878           cimg::warn("CImg<%s>::invert() : LAPACK library function dgetrf_() returned error code %d.",
26879                      pixel_type(),INFO);
26880         else {
26881           cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
26882           if (INFO)
26883             cimg::warn("CImg<%s>::invert() : LAPACK library function dgetri_() returned Error code %d",
26884                        pixel_type(),INFO);
26885         }
26886         if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N+l]); else fill(0);
26887         delete[] IPIV; delete[] lapA; delete[] WORK;
26888 #else
26889         const double dete = width>3?-1.0:det();
26890         if (dete!=0.0 && width==2) {
26891           const double
26892             a = data[0], c = data[1],
26893             b = data[2], d = data[3];
26894           data[0] = (T)(d/dete); data[1] = (T)(-c/dete);
26895           data[2] = (T)(-b/dete); data[3] = (T)(a/dete);
26896         } else if (dete!=0.0 && width==3) {
26897           const double
26898             a = data[0], d = data[1], g = data[2],
26899             b = data[3], e = data[4], h = data[5],
26900             c = data[6], f = data[7], i = data[8];
26901           data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete);
26902           data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete);
26903           data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete);
26904         } else {
26905           if (use_LU) { // LU-based inverse computation
26906             CImg<Tfloat> A(*this), indx, col(1,width);
26907             bool d;
26908             A._LU(indx,d);
26909             cimg_forX(*this,j) {
26910               col.fill(0);
26911               col(j) = 1;
26912               col._solve(A,indx);
26913               cimg_forX(*this,i) (*this)(j,i) = (T)col(i);
26914             }
26915           } else { // SVD-based inverse computation
26916             CImg<Tfloat> U(width,width), S(1,width), V(width,width);
26917             SVD(U,S,V,false);
26918             U.transpose();
26919             cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k];
26920             S.diagonal();
26921             *this = V*S*U;
26922           }
26923         }
26924 #endif
26925       }
26926       return *this;
26927     }
26928 
26929     CImg<Tfloat> get_invert(const bool use_LU=true) const {
26930       return CImg<Tfloat>(*this,false).invert(use_LU);
26931     }
26932 
26933     //! Compute the pseudo-inverse (Moore-Penrose) of the matrix.
26934     CImg<T>& pseudoinvert() {
26935       return get_pseudoinvert().transfer_to(*this);
26936     }
26937 
26938     CImg<Tfloat> get_pseudoinvert() const {
26939       CImg<Tfloat> U, S, V;
26940       SVD(U,S,V);
26941       cimg_forX(V,x) {
26942         const Tfloat s = S(x), invs = s!=0?1/s:(Tfloat)0;
26943         cimg_forY(V,y) V(x,y)*=invs;
26944       }
26945       return V*U.transpose();
26946     }
26947 
26948     //! Compute the cross product between two 3d vectors.
26949     template<typename t>
26950     CImg<T>& cross(const CImg<t>& img) {
26951       if (width!=1 || height<3 || img.width!=1 || img.height<3)
26952         throw CImgInstanceException("CImg<%s>::cross() : Arguments (%u,%u,%u,%u,%p) and (%u,%u,%u,%u,%p) must be both 3d vectors.",
26953                                     pixel_type(),width,height,depth,dim,data,img.width,img.height,img.depth,img.dim,img.data);
26954       const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
26955       (*this)[0] = (T)(y*img[2]-z*img[1]);
26956       (*this)[1] = (T)(z*img[0]-x*img[2]);
26957       (*this)[2] = (T)(x*img[1]-y*img[0]);
26958       return *this;
26959     }
26960 
26961     template<typename t>
26962     CImg<typename cimg::superset<T,t>::type> get_cross(const CImg<t>& img) const {
26963       typedef typename cimg::superset<T,t>::type Tt;
26964       return CImg<Tt>(*this).cross(img);
26965     }
26966 
26967     //! Solve a linear system AX=B where B=*this.
26968     template<typename t>
26969     CImg<T>& solve(const CImg<t>& A) {
26970       if (width!=1 || depth!=1 || dim!=1 || height!=A.height || A.depth!=1 || A.dim!=1)
26971         throw CImgArgumentException("CImg<%s>::solve() : Instance matrix size is (%u,%u,%u,%u) while "
26972                                     "size of given matrix A is (%u,%u,%u,%u).",
26973                                     pixel_type(),width,height,depth,dim,A.width,A.height,A.depth,A.dim);
26974 
26975       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
26976       if (A.width==A.height) {
26977 #ifdef cimg_use_lapack
26978         char TRANS='N';
26979         int INFO, N = height, LWORK = 4*N, one = 1, *IPIV = new int[N];
26980         Ttfloat
26981           *lapA = new Ttfloat[N*N],
26982           *lapB = new Ttfloat[N],
26983           *WORK = new Ttfloat[LWORK];
26984         cimg_forXY(A,k,l) lapA[k*N+l] = (Ttfloat)(A(k,l));
26985         cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));
26986         cimg::getrf(N,lapA,IPIV,INFO);
26987         if (INFO)
26988           cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrf_() returned error code %d.",
26989                      pixel_type(),INFO);
26990         if (!INFO) {
26991           cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
26992           if (INFO)
26993             cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrs_() returned Error code %d",
26994                        pixel_type(),INFO);
26995         }
26996         if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
26997         delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
26998 #else
26999         CImg<Ttfloat> lu(A);
27000         CImg<Ttfloat> indx;
27001         bool d;
27002         lu._LU(indx,d);
27003         _solve(lu,indx);
27004 #endif
27005       } else assign(A.get_pseudoinvert()*(*this));
27006       return *this;
27007     }
27008 
27009     template<typename t>
27010     CImg<typename cimg::superset2<T,t,float>::type> get_solve(const CImg<t>& A) const {
27011       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
27012       return CImg<Ttfloat>(*this,false).solve(A);
27013     }
27014 
27015     template<typename t, typename ti>
27016     CImg<T>& _solve(const CImg<t>& A, const CImg<ti>& indx) {
27017       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
27018       const int N = size();
27019       int ii = -1;
27020       Ttfloat sum;
27021       for (int i=0; i<N; ++i) {
27022         const int ip = (int)indx[i];
27023         Ttfloat sum = (*this)(ip);
27024         (*this)(ip) = (*this)(i);
27025         if (ii>=0) for (int j=ii; j<=i-1; ++j) sum-=A(j,i)*(*this)(j);
27026         else if (sum!=0) ii=i;
27027         (*this)(i) = (T)sum;
27028       }
27029       { for (int i=N-1; i>=0; --i) {
27030         sum = (*this)(i);
27031         for (int j=i+1; j<N; ++j) sum-=A(j,i)*(*this)(j);
27032         (*this)(i) = (T)(sum/A(i,i));
27033       }}
27034       return *this;
27035     }
27036 
27037     //! 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 ].
27038     // (Use the Thomas Algorithm).
27039     template<typename t>
27040     CImg<T>& solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) {
27041       const int siz = (int)size();
27042       if ((int)a.size()!=siz || (int)b.size()!=siz || (int)c.size()!=siz)
27043         throw CImgArgumentException("CImg<%s>::solve_tridiagonal() : arrays of triagonal coefficients have different size.",pixel_type);
27044       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
27045       CImg<Ttfloat> nc(siz);
27046       const T *ptra = a.data, *ptrb = b.data, *ptrc = c.data;
27047       T *ptrnc = nc.data, *ptrd = data;
27048       const Ttfloat valb0 = (Ttfloat)*(ptrb++);
27049       *ptrnc = *(ptrc++)/valb0;
27050       Ttfloat vald = (Ttfloat)(*(ptrd++)/=valb0);
27051       for (int i = 1; i<siz; ++i) {
27052         const Ttfloat
27053           vala = (Tfloat)*(ptra++),
27054           id = 1/(*(ptrb++) - *(ptrnc++)*vala);
27055         *ptrnc = *(ptrc++)*id;
27056         vald = ((*ptrd-=vala*vald)*=id);
27057         ++ptrd;
27058       }
27059       vald = *(--ptrd);
27060       for (int i = siz-2; i>=0; --i) vald = (*(--ptrd)-=*(--ptrnc)*vald);
27061       return *this;
27062     }
27063 
27064     template<typename t>
27065     CImg<typename cimg::superset2<T,t,float>::type> get_solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) const {
27066       typedef typename cimg::superset2<T,t,float>::type Ttfloat;
27067       return CImg<Ttfloat>(*this,false).solve_tridiagonal(a,b,c);
27068     }
27069 
27070     //! Sort values of a vector and get permutations.
27071     template<typename t>
27072     CImg<T>& sort(CImg<t>& permutations, const bool increasing=true) {
27073       if (is_empty()) permutations.assign();
27074       else {
27075         if (permutations.size()!=size()) permutations.assign(size());
27076         cimg_foroff(permutations,off) permutations[off] = (t)off;
27077         _quicksort(0,size()-1,permutations,increasing);
27078       }
27079       return *this;
27080     }
27081 
27082     template<typename t>
27083     CImg<T> get_sort(CImg<t>& permutations, const bool increasing=true) const {
27084       return (+*this).sort(permutations,increasing);
27085     }
27086 
27087     // Sort image values.
27088     CImg<T>& sort(const bool increasing=true) {
27089       CImg<T> foo;
27090       return sort(foo,increasing);
27091     }
27092 
27093     CImg<T> get_sort(const bool increasing=true) const {
27094       return (+*this).sort(increasing);
27095     }
27096 
27097     template<typename t>
27098     CImg<T>& _quicksort(const int min, const int max, CImg<t>& permutations, const bool increasing) {
27099       if (min<max) {
27100         const int mid = (min+max)/2;
27101         if (increasing) {
27102           if ((*this)[min]>(*this)[mid]) {
27103             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
27104           if ((*this)[mid]>(*this)[max]) {
27105             cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
27106           if ((*this)[min]>(*this)[mid]) {
27107             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
27108         } else {
27109           if ((*this)[min]<(*this)[mid]) {
27110             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
27111           if ((*this)[mid]<(*this)[max]) {
27112             cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
27113           if ((*this)[min]<(*this)[mid]) {
27114             cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
27115         }
27116         if (max-min>=3) {
27117           const T pivot = (*this)[mid];
27118           int i = min, j = max;
27119           if (increasing) {
27120             do {
27121               while ((*this)[i]<pivot) ++i;
27122               while ((*this)[j]>pivot) --j;
27123               if (i<=j) {
27124                 cimg::swap((*this)[i],(*this)[j]);
27125                 cimg::swap(permutations[i++],permutations[j--]);
27126               }
27127             } while (i<=j);
27128           } else {
27129             do {
27130               while ((*this)[i]>pivot) ++i;
27131               while ((*this)[j]<pivot) --j;
27132               if (i<=j) {
27133                 cimg::swap((*this)[i],(*this)[j]);
27134                 cimg::swap(permutations[i++],permutations[j--]);
27135               }
27136             } while (i<=j);
27137           }
27138           if (min<j) _quicksort(min,j,permutations,increasing);
27139           if (i<max) _quicksort(i,max,permutations,increasing);
27140         }
27141       }
27142       return *this;
27143     }
27144 
27145     //! Get a permutation of the pixels.
27146     template<typename t>
27147     CImg<T>& permute(const CImg<t>& permutation) {
27148       return get_permute(permutation).transfer_to(*this);
27149     }
27150 
27151     template<typename t>
27152     CImg<T> get_permute(const CImg<t>& permutation) const {
27153       if (permutation.size()!=size())
27154         throw CImgArgumentException("CImg<%s>::permute() : Instance image (%u,%u,%u,%u,%p) and permutation (%u,%u,%u,%u,%p)"
27155                                     "have different sizes.",
27156                                     pixel_type(),width,height,depth,dim,data,
27157                                     permutation.width,permutation.height,permutation.depth,permutation.dim,permutation.data);
27158       CImg<T> res(width,height,depth,dim);
27159       const t *p = permutation.ptr(permutation.size());
27160       cimg_for(res,ptr,T) *ptr = (*this)[*(--p)];
27161       return res;
27162     }
27163 
27164     //! Compute the SVD of a general matrix.
27165     template<typename t>
27166     const CImg<T>& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V,
27167                        const bool sorting=true, const unsigned int max_iter=40, const float lambda=0) const {
27168       if (is_empty()) { U.assign(); S.assign(); V.assign(); }
27169       else {
27170         U = *this;
27171         if (lambda!=0) {
27172           const unsigned int delta = cimg::min(U.width,U.height);
27173           for (unsigned int i=0; i<delta; ++i) U(i,i) = (t)(U(i,i) + lambda);
27174         }
27175         if (S.size()<width) S.assign(1,width);
27176         if (V.width<width || V.height<height) V.assign(width,width);
27177         CImg<t> rv1(width);
27178         t anorm = 0, c, f, g = 0, h, s, scale = 0;
27179         int l = 0, nm = 0;
27180 
27181         cimg_forX(U,i) {
27182           l = i+1; rv1[i] = scale*g; g = s = scale = 0;
27183           if (i<dimy()) {
27184             for (int k=i; k<dimy(); ++k) scale+= cimg::abs(U(i,k));
27185             if (scale) {
27186               for (int k=i; k<dimy(); ++k) { U(i,k)/=scale; s+= U(i,k)*U(i,k); }
27187               f = U(i,i); g = (t)((f>=0?-1:1)*cimg_std::sqrt(s)); h=f*g-s; U(i,i) = f-g;
27188               for (int j=l; j<dimx(); ++j) {
27189                 s = 0; for (int k=i; k<dimy(); ++k) s+= U(i,k)*U(j,k);
27190                 f = s/h;
27191                 { for (int k=i; k<dimy(); ++k) U(j,k)+= f*U(i,k); }
27192               }
27193               { for (int k=i; k<dimy(); ++k) U(i,k)*= scale; }
27194             }
27195           }
27196           S[i]=scale*g;
27197 
27198           g = s = scale = 0;
27199           if (i<dimy() && i!=dimx()-1) {
27200             for (int k=l; k<dimx(); ++k) scale += cimg::abs(U(k,i));
27201             if (scale) {
27202               for (int k=l; k<dimx(); ++k) { U(k,i)/= scale; s+= U(k,i)*U(k,i); }
27203               f = U(l,i); g = (t)((f>=0?-1:1)*cimg_std::sqrt(s)); h = f*g-s; U(l,i) = f-g;
27204               { for (int k=l; k<dimx(); ++k) rv1[k]=U(k,i)/h; }
27205               for (int j=l; j<dimy(); ++j) {
27206                 s = 0; for (int k=l; k<dimx(); ++k) s+= U(k,j)*U(k,i);
27207                 { for (int k=l; k<dimx(); ++k) U(k,j)+= s*rv1[k]; }
27208               }
27209               { for (int k=l; k<dimx(); ++k) U(k,i)*= scale; }
27210             }
27211           }
27212           anorm = (t)cimg::max((float)anorm,(float)(cimg::abs(S[i])+cimg::abs(rv1[i])));
27213         }
27214 
27215         { for (int i=dimx()-1; i>=0; --i) {
27216           if (i<dimx()-1) {
27217             if (g) {
27218               { for (int j=l; j<dimx(); ++j) V(i,j) =(U(j,i)/U(l,i))/g; }
27219               for (int j=l; j<dimx(); ++j) {
27220                 s = 0; for (int k=l; k<dimx(); ++k) s+= U(k,i)*V(j,k);
27221                 { for (int k=l; k<dimx(); ++k) V(j,k)+= s*V(i,k); }
27222               }
27223             }
27224             for (int j=l; j<dimx(); ++j) V(j,i) = V(i,j) = (t)0.0;
27225           }
27226           V(i,i) = (t)1.0; g = rv1[i]; l = i;
27227         }
27228         }
27229 
27230         { for (int i=cimg::min(dimx(),dimy())-1; i>=0; --i) {
27231           l = i+1; g = S[i];
27232           for (int j=l; j<dimx(); ++j) U(j,i) = 0;
27233           if (g) {
27234             g = 1/g;
27235             for (int j=l; j<dimx(); ++j) {
27236               s = 0; for (int k=l; k<dimy(); ++k) s+= U(i,k)*U(j,k);
27237               f = (s/U(i,i))*g;
27238               { for (int k=i; k<dimy(); ++k) U(j,k)+= f*U(i,k); }
27239             }
27240             { for (int j=i; j<dimy(); ++j) U(i,j)*= g; }
27241           } else for (int j=i; j<dimy(); ++j) U(i,j) = 0;
27242           ++U(i,i);
27243         }
27244         }
27245 
27246         for (int k=dimx()-1; k>=0; --k) {
27247           for (unsigned int its=0; its<max_iter; ++its) {
27248             bool flag = true;
27249             for (l=k; l>=1; --l) {
27250               nm = l-1;
27251               if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; }
27252               if ((cimg::abs(S[nm])+anorm)==anorm) break;
27253             }
27254             if (flag) {
27255               c = 0; s = 1;
27256               for (int i=l; i<=k; ++i) {
27257                 f = s*rv1[i]; rv1[i] = c*rv1[i];
27258                 if ((cimg::abs(f)+anorm)==anorm) break;
27259                 g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;
27260                 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; }
27261               }
27262             }
27263             const t z = S[k];
27264             if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; }
27265             nm = k-1;
27266             t x = S[l], y = S[nm];
27267             g = rv1[nm]; h = rv1[k];
27268             f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y);
27269             g = (t)cimg::_pythagore(f,1.0);
27270             f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x;
27271             c = s = 1;
27272             for (int j=l; j<=nm; ++j) {
27273               const int i = j+1;
27274               g = rv1[i]; h = s*g; g = c*g;
27275               t y = S[i];
27276               t z = (t)cimg::_pythagore(f,h);
27277               rv1[j] = z; c = f/z; s = h/z;
27278               f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c;
27279               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; }
27280               z = (t)cimg::_pythagore(f,h); S[j] = z;
27281               if (z) { z = 1/z; c = f*z; s = h*z; }
27282               f = c*g+s*y; x = c*y-s*g;
27283               { 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; }}
27284             }
27285             rv1[l] = 0; rv1[k]=f; S[k]=x;
27286           }
27287         }
27288 
27289         if (sorting) {
27290           CImg<intT> permutations(width);
27291           CImg<t> tmp(width);
27292           S.sort(permutations,false);
27293           cimg_forY(U,k) {
27294             cimg_forX(permutations,x) tmp(x) = U(permutations(x),k);
27295             cimg_std::memcpy(U.ptr(0,k),tmp.data,sizeof(t)*width);
27296           }
27297           { cimg_forY(V,k) {
27298             cimg_forX(permutations,x) tmp(x) = V(permutations(x),k);
27299             cimg_std::memcpy(V.ptr(0,k),tmp.data,sizeof(t)*width);
27300           }}
27301         }
27302       }
27303     return *this;
27304     }
27305 
27306     //! Compute the SVD of a general matrix.
27307     template<typename t>
27308     const CImg<T>& SVD(CImgList<t>& USV) const {
27309       if (USV.size<3) USV.assign(3);
27310       return SVD(USV[0],USV[1],USV[2]);
27311     }
27312 
27313     //! Compute the SVD of a general matrix.
27314     CImgList<Tfloat> get_SVD(const bool sorting=true) const {
27315       CImgList<Tfloat> res(3);
27316       SVD(res[0],res[1],res[2],sorting);
27317       return res;
27318     }
27319 
27320     // INNER ROUTINE : Compute the LU decomposition of a permuted matrix (c.f. numerical recipes)
27321     template<typename t>
27322     CImg<T>& _LU(CImg<t>& indx, bool& d) {
27323       const int N = dimx();
27324       int imax = 0;
27325       CImg<Tfloat> vv(N);
27326       indx.assign(N);
27327       d = true;
27328       cimg_forX(*this,i) {
27329         Tfloat vmax = 0;
27330         cimg_forX(*this,j) {
27331           const Tfloat tmp = cimg::abs((*this)(j,i));
27332           if (tmp>vmax) vmax = tmp;
27333         }
27334         if (vmax==0) { indx.fill(0); return fill(0); }
27335         vv[i] = 1/vmax;
27336       }
27337       cimg_forX(*this,j) {
27338         for (int i=0; i<j; ++i) {
27339           Tfloat sum=(*this)(j,i);
27340           for (int k=0; k<i; ++k) sum-=(*this)(k,i)*(*this)(j,k);
27341           (*this)(j,i) = (T)sum;
27342         }
27343         Tfloat vmax = 0;
27344         { for (int i=j; i<dimx(); ++i) {
27345           Tfloat sum=(*this)(j,i);
27346           for (int k=0; k<j; ++k) sum-=(*this)(k,i)*(*this)(j,k);
27347           (*this)(j,i) = (T)sum;
27348           const Tfloat tmp = vv[i]*cimg::abs(sum);
27349           if (tmp>=vmax) { vmax=tmp; imax=i; }
27350         }}
27351         if (j!=imax) {
27352           cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j));
27353           d =!d;
27354           vv[imax] = vv[j];
27355         }
27356         indx[j] = (t)imax;
27357         if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20;
27358         if (j<N) {
27359           const Tfloat tmp = 1/(Tfloat)(*this)(j,j);
27360           for (int i=j+1; i<N; ++i) (*this)(j,i) = (T)((*this)(j,i)*tmp);
27361         }
27362       }
27363       return *this;
27364     }
27365 
27366     //! Compute the eigenvalues and eigenvectors of a matrix.
27367     template<typename t>
27368     const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
27369       if (is_empty()) { val.assign(); vec.assign(); }
27370       else {
27371         if (width!=height || depth>1 || dim>1)
27372           throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
27373                                       pixel_type(),width,height,depth,dim,data);
27374         if (val.size()<width) val.assign(1,width);
27375         if (vec.size()<width*width) vec.assign(width,width);
27376         switch (width) {
27377         case 1 : { val[0]=(t)(*this)[0]; vec[0]=(t)1; } break;
27378         case 2 : {
27379           const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a+d;
27380           double f = e*e-4*(a*d-b*c);
27381           if (f<0)
27382             cimg::warn("CImg<%s>::eigen() : Complex eigenvalues",
27383                        pixel_type());
27384           f = cimg_std::sqrt(f);
27385           const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);
27386           const double theta1 = cimg_std::atan2(l2-a,b), theta2 = cimg_std::atan2(l1-a,b);
27387           val[0]=(t)l2;
27388           val[1]=(t)l1;
27389           vec(0,0) = (t)cimg_std::cos(theta1);
27390           vec(0,1) = (t)cimg_std::sin(theta1);
27391           vec(1,0) = (t)cimg_std::cos(theta2);
27392           vec(1,1) = (t)cimg_std::sin(theta2);
27393         } break;
27394         default :
27395           throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited"
27396                                       "to 2x2 matrices (given is %ux%u)",
27397                                       pixel_type(),width,height);
27398         }
27399       }
27400       return *this;
27401     }
27402 
27403     //! Compute the eigenvalues and eigenvectors of a matrix.
27404     CImgList<Tfloat> get_eigen() const {
27405       CImgList<Tfloat> res(2);
27406       eigen(res[0],res[1]);
27407       return res;
27408     }
27409 
27410     //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
27411     template<typename t>
27412     const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& vec) const {
27413       if (is_empty()) { val.assign(); vec.assign(); }
27414       else {
27415 #ifdef cimg_use_lapack
27416         char JOB = 'V', UPLO = 'U';
27417         int N = width, LWORK = 4*N, INFO;
27418         Tfloat
27419           *lapA = new Tfloat[N*N],
27420           *lapW = new Tfloat[N],
27421           *WORK = new Tfloat[LWORK];
27422         cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
27423         cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO);
27424         if (INFO)
27425           cimg::warn("CImg<%s>::symmetric_eigen() : LAPACK library function dsyev_() returned error code %d.",
27426                      pixel_type(),INFO);
27427         val.assign(1,N);
27428         vec.assign(N,N);
27429         if (!INFO) {
27430           cimg_forY(val,i) val(i) = (T)lapW[N-1-i];
27431           cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N-1-k)*N+l]);
27432         } else { val.fill(0); vec.fill(0); }
27433         delete[] lapA; delete[] lapW; delete[] WORK;
27434 #else
27435         if (width!=height || depth>1 || dim>1)
27436           throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
27437                                       pixel_type(),width,height,depth,dim,data);
27438         val.assign(1,width);
27439         if (vec.data) vec.assign(width,width);
27440         if (width<3) return eigen(val,vec);
27441         CImg<t> V(width,width);
27442         SVD(vec,val,V,false);
27443         bool ambiguous = false;
27444         float eig = 0;
27445         cimg_forY(val,p) {       // check for ambiguous cases.
27446           if (val[p]>eig) eig = (float)val[p];
27447           t scal = 0;
27448           cimg_forY(vec,y) scal+=vec(p,y)*V(p,y);
27449           if (cimg::abs(scal)<0.9f) ambiguous = true;
27450           if (scal<0) val[p] = -val[p];
27451         }
27452         if (ambiguous) {
27453           (eig*=2)++;
27454           SVD(vec,val,V,false,40,eig);
27455           val-=eig;
27456         }
27457         CImg<intT> permutations(width);  // sort eigenvalues in decreasing order
27458         CImg<t> tmp(width);
27459         val.sort(permutations,false);
27460         cimg_forY(vec,k) {
27461           cimg_forX(permutations,x) tmp(x) = vec(permutations(x),k);
27462           cimg_std::memcpy(vec.ptr(0,k),tmp.data,sizeof(t)*width);
27463         }
27464 #endif
27465       }
27466       return *this;
27467     }
27468 
27469     //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
27470     CImgList<Tfloat> get_symmetric_eigen() const {
27471       CImgList<Tfloat> res(2);
27472       symmetric_eigen(res[0],res[1]);
27473       return res;
27474     }
27475 
27476     //@}
27477     //-------------------
27478     //
27479     //! \name Display
27480     //@{
27481     //-------------------
27482 
27483     //! Display an image into a CImgDisplay window.
27484     const CImg<T>& display(CImgDisplay& disp) const {
27485       disp.display(*this);
27486       return *this;
27487     }
27488 
27489     //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n
27490     const CImg<T>& display(CImgDisplay &disp, const bool display_info) const {
27491       return _display(disp,0,display_info);
27492     }
27493 
27494     //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n
27495     const CImg<T>& display(const char *const title=0, const bool display_info=true) const {
27496       CImgDisplay disp;
27497       return _display(disp,title,display_info);
27498     }
27499 
27500     const CImg<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info) const {
27501       if (is_empty())
27502         throw CImgInstanceException("CImg<%s>::display() : Instance image (%u,%u,%u,%u,%p) is empty.",
27503                                     pixel_type(),width,height,depth,dim,data);
27504       unsigned int oldw = 0, oldh = 0, XYZ[3], key = 0, mkey = 0;
27505       int x0 = 0, y0 = 0, z0 = 0, x1 = dimx()-1, y1 = dimy()-1, z1 = dimz()-1;
27506       float frametiming = 5;
27507 
27508       char ntitle[256] = { 0 };
27509       if (!disp) {
27510         if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
27511         disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
27512       }
27513       cimg_std::strncpy(ntitle,disp.title,255);
27514       if (display_info) print(ntitle);
27515 
27516       CImg<T> zoom;
27517       for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
27518         if (reset_view) {
27519           XYZ[0] = (x0 + x1)/2; XYZ[1] = (y0 + y1)/2; XYZ[2] = (z0 + z1)/2;
27520           x0 = 0; y0 = 0; z0 = 0; x1 = width-1; y1 = height-1; z1 = depth-1;
27521           oldw = disp.width; oldh = disp.height;
27522           reset_view = false;
27523         }
27524         if (!x0 && !y0 && !z0 && x1==dimx()-1 && y1==dimy()-1 && z1==dimz()-1) zoom.assign();
27525         else zoom = get_crop(x0,y0,z0,x1,y1,z1);
27526 
27527         const unsigned int
27528           dx = 1 + x1 - x0, dy = 1 + y1 - y0, dz = 1 + z1 - z0,
27529           tw = dx + (dz>1?dz:0), th = dy + (dz>1?dz:0);
27530         if (resize_disp) {
27531           const unsigned int
27532             ttw = tw*disp.width/oldw, tth = th*disp.height/oldh,
27533             dM = cimg::max(ttw,tth), diM = cimg::max(disp.width,disp.height),
27534             imgw = cimg::max(16U,ttw*diM/dM), imgh = cimg::max(16U,tth*diM/dM);
27535           disp.normalscreen().resize(cimg_fitscreen(imgw,imgh,1),false);
27536           resize_disp = false;
27537         }
27538         oldw = tw; oldh = th;
27539 
27540         bool
27541           go_up = false, go_down = false, go_left = false, go_right = false,
27542           go_inc = false, go_dec = false, go_in = false, go_out = false,
27543           go_in_center = false;
27544         const CImg<T>& visu = zoom?zoom:*this;
27545         const CImg<intT> selection = visu._get_select(disp,0,2,XYZ,0,x0,y0,z0);
27546         if (disp.wheel) {
27547           if (disp.is_keyCTRLLEFT) { if (!mkey || mkey==1) go_out = !(go_in = disp.wheel>0); go_in_center = false; mkey = 1; }
27548           else if (disp.is_keySHIFTLEFT) { if (!mkey || mkey==2) go_right = !(go_left = disp.wheel>0); mkey = 2; }
27549           else if (disp.is_keyALT || depth==1) { if (!mkey || mkey==3) go_down = !(go_up = disp.wheel>0); mkey = 3; }
27550           else mkey = 0;
27551           disp.wheel = 0;
27552         } else mkey = 0;
27553         const int
27554           sx0 = selection(0), sy0 = selection(1), sz0 = selection(2),
27555           sx1 = selection(3), sy1 = selection(4), sz1 = selection(5);
27556         if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) {
27557           x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1; x0+=sx0; y0+=sy0; z0+=sz0;
27558           if (sx0==sx1 && sy0==sy1 && sz0==sz1) reset_view = true;
27559           resize_disp = true;
27560         } else switch (key = disp.key) {
27561         case 0 : case cimg::keyCTRLLEFT : case cimg::keyPAD5 : case cimg::keySHIFTLEFT : case cimg::keyALT : disp.key = key = 0; break;
27562         case cimg::keyP : if (visu.depth>1 && disp.is_keyCTRLLEFT) { // Special mode : play stack of frames
27563           const unsigned int
27564             w1 = visu.width*disp.width/(visu.width+(visu.depth>1?visu.depth:0)),
27565             h1 = visu.height*disp.height/(visu.height+(visu.depth>1?visu.depth:0));
27566           disp.resize(cimg_fitscreen(w1,h1,1),false).key = disp.wheel = key = 0;
27567           for (unsigned int timer = 0; !key && !disp.is_closed && !disp.button; ) {
27568             if (disp.is_resized) disp.resize();
27569             if (!timer) {
27570               visu.get_slice(XYZ[2]).display(disp.set_title("%s | z=%d",ntitle,XYZ[2]));
27571               if (++XYZ[2]>=visu.depth) XYZ[2] = 0;
27572             }
27573             if (++timer>(unsigned int)frametiming) timer = 0;
27574             if (disp.wheel) { frametiming-=disp.wheel/3.0f; disp.wheel = 0; }
27575             switch (key = disp.key) {
27576             case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
27577             case cimg::keyPAGEUP : frametiming-=0.3f; key = 0; break;
27578             case cimg::keyPAGEDOWN : frametiming+=0.3f; key = 0; break;
27579             case cimg::keyD : if (disp.is_keyCTRLLEFT) {
27580               disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
27581                                          CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false);
27582               disp.key = key = 0;
27583             } break;
27584             case cimg::keyC : if (disp.is_keyCTRLLEFT) {
27585               disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false);
27586               disp.key = key = 0;
27587             } break;
27588             case cimg::keyR : if (disp.is_keyCTRLLEFT) {
27589               disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false);
27590               disp.key = key = 0;
27591             } break;
27592             case cimg::keyF : if (disp.is_keyCTRLLEFT) {
27593               disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen();
27594               disp.key = key = 0;
27595             } break;
27596             }
27597             frametiming = frametiming<1?1:(frametiming>39?39:frametiming);
27598             disp.wait(20);
27599           }
27600           const unsigned int
27601             w2 = (visu.width + (visu.depth>1?visu.depth:0))*disp.width/visu.width,
27602             h2 = (visu.height + (visu.depth>1?visu.depth:0))*disp.height/visu.height;
27603           disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(ntitle);
27604           key = disp.key = disp.button = disp.wheel = 0;
27605         } break;
27606         case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
27607         case cimg::keyPADADD : go_in = true; go_in_center = true; key = 0; break;
27608         case cimg::keyPADSUB : go_out = true; key = 0; break;
27609         case cimg::keyARROWLEFT : case cimg::keyPAD4: go_left = true; key = 0; break;
27610         case cimg::keyARROWRIGHT : case cimg::keyPAD6: go_right = true; key = 0; break;
27611         case cimg::keyARROWUP : case cimg::keyPAD8: go_up = true; key = 0; break;
27612         case cimg::keyARROWDOWN : case cimg::keyPAD2: go_down = true; key = 0; break;
27613         case cimg::keyPAD7 : go_up = go_left = true; key = 0; break;
27614         case cimg::keyPAD9 : go_up = go_right = true; key = 0; break;
27615         case cimg::keyPAD1 : go_down = go_left = true; key = 0; break;
27616         case cimg::keyPAD3 : go_down = go_right = true; key = 0; break;
27617         case cimg::keyPAGEUP : go_inc = true; key = 0; break;
27618         case cimg::keyPAGEDOWN : go_dec = true; key = 0; break;
27619         }
27620         if (go_in) {
27621           const int
27622             mx = go_in_center?disp.dimx()/2:disp.mouse_x,
27623             my = go_in_center?disp.dimy()/2:disp.mouse_y,
27624             mX = mx*(width+(depth>1?depth:0))/disp.width,
27625             mY = my*(height+(depth>1?depth:0))/disp.height;
27626           int X = XYZ[0], Y = XYZ[1], Z = XYZ[2];
27627           if (mX<dimx() && mY<dimy())  { X = x0 + mX*(1+x1-x0)/width; Y = y0 + mY*(1+y1-y0)/height; Z = XYZ[2]; }
27628           if (mX<dimx() && mY>=dimy()) { X = x0 + mX*(1+x1-x0)/width; Z = z0 + (mY-height)*(1+z1-z0)/depth; Y = XYZ[1]; }
27629           if (mX>=dimx() && mY<dimy()) { Y = y0 + mY*(1+y1-y0)/height; Z = z0 + (mX-width)*(1+z1-z0)/depth; X = XYZ[0]; }
27630           if (x1-x0>4) { x0 = X - 7*(X-x0)/8; x1 = X + 7*(x1-X)/8; }
27631           if (y1-y0>4) { y0 = Y - 7*(Y-y0)/8; y1 = Y + 7*(y1-Y)/8; }
27632           if (z1-z0>4) { z0 = Z - 7*(Z-z0)/8; z1 = Z + 7*(z1-Z)/8; }
27633         }
27634         if (go_out) {
27635           const int
27636             deltax = (x1-x0)/8, deltay = (y1-y0)/8, deltaz = (z1-z0)/8,
27637             ndeltax = deltax?deltax:(width>1?1:0),
27638             ndeltay = deltay?deltay:(height>1?1:0),
27639             ndeltaz = deltaz?deltaz:(depth>1?1:0);
27640           x0-=ndeltax; y0-=ndeltay; z0-=ndeltaz;
27641           x1+=ndeltax; y1+=ndeltay; z1+=ndeltaz;
27642           if (x0<0) { x1-=x0; x0 = 0; if (x1>=dimx()) x1 = dimx()-1; }
27643           if (y0<0) { y1-=y0; y0 = 0; if (y1>=dimy()) y1 = dimy()-1; }
27644           if (z0<0) { z1-=z0; z0 = 0; if (z1>=dimz()) z1 = dimz()-1; }
27645           if (x1>=dimx()) { x0-=(x1-dimx()+1); x1 = dimx()-1; if (x0<0) x0 = 0; }
27646           if (y1>=dimy()) { y0-=(y1-dimy()+1); y1 = dimy()-1; if (y0<0) y0 = 0; }
27647           if (z1>=dimz()) { z0-=(z1-dimz()+1); z1 = dimz()-1; if (z0<0) z0 = 0; }
27648         }
27649         if (go_left) {
27650           const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
27651           if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
27652           else { x1-=x0; x0 = 0; }
27653         }
27654         if (go_right) {
27655           const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
27656           if (x1+ndelta<dimx()) { x0+=ndelta; x1+=ndelta; }
27657           else { x0+=(dimx()-1-x1); x1 = dimx()-1; }
27658         }
27659         if (go_up) {
27660           const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
27661           if (y0-ndelta>=0) { y0-=ndelta; y1-=ndelta; }
27662           else { y1-=y0; y0 = 0; }
27663         }
27664         if (go_down) {
27665           const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
27666           if (y1+ndelta<dimy()) { y0+=ndelta; y1+=ndelta; }
27667           else { y0+=(dimy()-1-y1); y1 = dimy()-1; }
27668         }
27669         if (go_inc) {
27670           const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
27671           if (z0-ndelta>=0) { z0-=ndelta; z1-=ndelta; }
27672           else { z1-=z0; z0 = 0; }
27673         }
27674         if (go_dec) {
27675           const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
27676           if (z1+ndelta<dimz()) { z0+=ndelta; z1+=ndelta; }
27677           else { z0+=(depth-1-z1); z1 = depth-1; }
27678         }
27679       }
27680       disp.key = key;
27681       return *this;
27682     }
27683 
27684     //! Simple interface to select a shape from an image.
27685     /**
27686        \param selection  Array of 6 values containing the selection result
27687        \param coords_type Determine shape type to select (0=point, 1=vector, 2=rectangle, 3=circle)
27688        \param disp       Display window used to make the selection
27689        \param XYZ        Initial XYZ position (for volumetric images only)
27690        \param color      Color of the shape selector.
27691     **/
27692     CImg<T>& select(CImgDisplay &disp,
27693                     const int select_type=2, unsigned int *const XYZ=0,
27694                     const unsigned char *const color=0) {
27695       return get_select(disp,select_type,XYZ,color).transfer_to(*this);
27696     }
27697 
27698     //! Simple interface to select a shape from an image.
27699     CImg<T>& select(const char *const title,
27700                     const int select_type=2, unsigned int *const XYZ=0,
27701                     const unsigned char *const color=0) {
27702       return get_select(title,select_type,XYZ,color).transfer_to(*this);
27703     }
27704 
27705     //! Simple interface to select a shape from an image.
27706     CImg<intT> get_select(CImgDisplay &disp,
27707                           const int select_type=2, unsigned int *const XYZ=0,
27708                           const unsigned char *const color=0) const {
27709       return _get_select(disp,0,select_type,XYZ,color,0,0,0);
27710     }
27711 
27712     //! Simple interface to select a shape from an image.
27713     CImg<intT> get_select(const char *const title,
27714                           const int select_type=2, unsigned int *const XYZ=0,
27715                           const unsigned char *const color=0) const {
27716       CImgDisplay disp;
27717       return _get_select(disp,title,select_type,XYZ,color,0,0,0);
27718     }
27719 
27720     CImg<intT> _get_select(CImgDisplay &disp, const char *const title,
27721                            const int coords_type, unsigned int *const XYZ,
27722                            const unsigned char *const color,
27723                            const int origX, const int origY, const int origZ) const {
27724       if (is_empty())
27725         throw CImgInstanceException("CImg<%s>::select() : Instance image (%u,%u,%u,%u,%p) is empty.",
27726                                     pixel_type(),width,height,depth,dim,data);
27727       if (!disp) {
27728         char ntitle[64] = { 0 }; if (!title) { cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); }
27729         disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
27730       }
27731 
27732       const unsigned int
27733         old_normalization = disp.normalization,
27734         hatch = 0x55555555;
27735 
27736       bool old_is_resized = disp.is_resized;
27737       disp.normalization = 0;
27738       disp.show().key = 0;
27739 
27740       unsigned char foreground_color[] = { 255,255,105 }, background_color[] = { 0,0,0 };
27741       if (color) cimg_std::memcpy(foreground_color,color,sizeof(unsigned char)*cimg::min(3,dimv()));
27742 
27743       int area = 0, clicked_area = 0, phase = 0,
27744         X0 = (int)((XYZ?XYZ[0]:width/2)%width), Y0 = (int)((XYZ?XYZ[1]:height/2)%height), Z0 = (int)((XYZ?XYZ[2]:depth/2)%depth),
27745         X1 =-1, Y1 = -1, Z1 = -1,
27746         X = -1, Y = -1, Z = -1,
27747         oX = X, oY = Y, oZ = Z;
27748       unsigned int old_button = 0, key = 0;
27749 
27750       bool shape_selected = false, text_down = false;
27751       CImg<ucharT> visu, visu0;
27752       char text[1024] = { 0 };
27753 
27754       while (!key && !disp.is_closed && !shape_selected) {
27755 
27756         // Handle mouse motion and selection
27757         oX = X; oY = Y; oZ = Z;
27758         int mx = disp.mouse_x, my = disp.mouse_y;
27759         const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height;
27760 
27761         area = 0;
27762         if (mX<dimx() && mY<dimy())  { area = 1; X = mX; Y = mY; Z = phase?Z1:Z0; }
27763         if (mX<dimx() && mY>=dimy()) { area = 2; X = mX; Z = mY-height; Y = phase?Y1:Y0; }
27764         if (mX>=dimx() && mY<dimy()) { area = 3; Y = mY; Z = mX-width; X = phase?X1:X0; }
27765 
27766         switch (key = disp.key) {
27767         case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
27768         case cimg::keyPAGEUP : if (disp.is_keyCTRLLEFT) { ++disp.wheel; key = 0; } break;
27769         case cimg::keyPAGEDOWN : if (disp.is_keyCTRLLEFT) { --disp.wheel; key = 0; } break;
27770         case cimg::keyD : if (disp.is_keyCTRLLEFT) {
27771           disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
27772                                      CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
27773           disp.key = key = 0;
27774         } break;
27775         case cimg::keyC : if (disp.is_keyCTRLLEFT) {
27776           disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
27777           disp.key = key = 0; visu0.assign();
27778         } break;
27779         case cimg::keyR : if (disp.is_keyCTRLLEFT) {
27780           disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false).is_resized = true;
27781           disp.key = key = 0; visu0.assign();
27782         } break;
27783         case cimg::keyF : if (disp.is_keyCTRLLEFT) {
27784           disp.resize(disp.screen_dimx(),disp.screen_dimy(),false).toggle_fullscreen().is_resized = true;
27785           disp.key = key = 0; visu0.assign();
27786         } break;
27787         case cimg::keyS : if (disp.is_keyCTRLLEFT) {
27788           static unsigned int snap_number = 0;
27789           char filename[32] = { 0 };
27790           cimg_std::FILE *file;
27791           do {
27792             cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
27793             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
27794           } while (file);
27795           if (visu0) {
27796             visu.draw_text(2,2,"Saving snapshot...",foreground_color,background_color,0.8f,11).display(disp);
27797             visu0.save(filename);
27798             visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
27799           }
27800           disp.key = key = 0;
27801         } break;
27802         case cimg::keyO : if (disp.is_keyCTRLLEFT) {
27803           static unsigned int snap_number = 0;
27804           char filename[32] = { 0 };
27805           cimg_std::FILE *file;
27806           do {
27807             cimg_std::sprintf(filename,"CImg_%.4u.cimg",snap_number++);
27808             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
27809           } while (file);
27810           visu.draw_text(2,2,"Saving instance...",foreground_color,background_color,0.8f,11).display(disp);
27811           save(filename);
27812           visu.draw_text(2,2,"Instance '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
27813           disp.key = key = 0;
27814         } break;
27815         }
27816 
27817         if (!area) mx = my = X = Y = Z = -1;
27818         else {
27819           if (disp.button&1 && phase<2) { X1 = X; Y1 = Y; Z1 = Z; }
27820           if (!(disp.button&1) && phase>=2) {
27821             switch (clicked_area) {
27822             case 1 : Z1 = Z; break;
27823             case 2 : Y1 = Y; break;
27824             case 3 : X1 = X; break;
27825             }
27826           }
27827           if (disp.button&2) { if (phase) { X1 = X; Y1 = Y; Z1 = Z; } else { X0 = X; Y0 = Y; Z0 = Z; } }
27828           if (disp.button&4) { oX = X = X0; oY = Y = Y0; oZ = Z = Z0; phase = 0; visu.assign(); }
27829           if (disp.wheel) {
27830             if (depth>1 && !disp.is_keyCTRLLEFT && !disp.is_keySHIFTLEFT && !disp.is_keyALT) {
27831               switch (area) {
27832               case 1 : if (phase) Z = (Z1+=disp.wheel); else Z = (Z0+=disp.wheel); break;
27833               case 2 : if (phase) Y = (Y1+=disp.wheel); else Y = (Y0+=disp.wheel); break;
27834               case 3 : if (phase) X = (X1+=disp.wheel); else X = (X0+=disp.wheel); break;
27835               }
27836               disp.wheel = 0;
27837             } else key = ~0U;
27838           }
27839           if ((disp.button&1)!=old_button) {
27840             switch (phase++) {
27841             case 0 : X0 = X1 = X; Y0 = Y1 = Y; Z0 = Z1 = Z; clicked_area = area; break;
27842             case 1 : X1 = X; Y1 = Y; Z1 = Z; break;
27843             }
27844             old_button = disp.button&1;
27845           }
27846           if (depth>1 && (X!=oX || Y!=oY || Z!=oZ)) visu0.assign();
27847         }
27848 
27849         if (phase) {
27850           if (!coords_type) shape_selected = phase?true:false;
27851           else {
27852             if (depth>1) shape_selected = (phase==3)?true:false;
27853             else shape_selected = (phase==2)?true:false;
27854           }
27855         }
27856 
27857         if (X0<0) X0 = 0; if (X0>=dimx()) X0 = dimx()-1; if (Y0<0) Y0 = 0; if (Y0>=dimy()) Y0 = dimy()-1;
27858         if (Z0<0) Z0 = 0; if (Z0>=dimz()) Z0 = dimz()-1;
27859         if (X1<1) X1 = 0; if (X1>=dimx()) X1 = dimx()-1; if (Y1<0) Y1 = 0; if (Y1>=dimy()) Y1 = dimy()-1;
27860         if (Z1<0) Z1 = 0; if (Z1>=dimz()) Z1 = dimz()-1;
27861 
27862         // Draw visualization image on the display
27863         if (oX!=X || oY!=Y || oZ!=Z || !visu0) {
27864           if (!visu0) {
27865             CImg<Tuchar> tmp, tmp0;
27866             if (depth!=1) {
27867               tmp0 = (!phase)?get_projections2d(X0,Y0,Z0):get_projections2d(X1,Y1,Z1);
27868               tmp = tmp0.get_channels(0,cimg::min(2U,dim-1));
27869             } else tmp = get_channels(0,cimg::min(2U,dim-1));
27870             switch (old_normalization) {
27871             case 0 : visu0 = tmp; break;
27872             case 3 :
27873               if (cimg::type<T>::is_float()) visu0 = tmp.normalize(0,(T)255);
27874               else {
27875                 const float m = (float)cimg::type<T>::min(), M = (float)cimg::type<T>::max();
27876                 visu0.assign(tmp.width,tmp.height,1,tmp.dim);
27877                 unsigned char *ptrd = visu0.end();
27878                 cimg_for(tmp,ptrs,Tuchar) *(--ptrd) = (unsigned char)((*ptrs-m)*255.0f/(M-m));
27879               } break;
27880             default : visu0 = tmp.normalize(0,255);
27881             }
27882             visu0.resize(disp);
27883           }
27884           visu = visu0;
27885           if (!color) {
27886             if (visu.mean()<200) {
27887               foreground_color[0] = foreground_color[1] = foreground_color[2] = 255;
27888               background_color[0] = background_color[1] = background_color[2] = 0;
27889             } else {
27890               foreground_color[0] = foreground_color[1] = foreground_color[2] = 0;
27891               background_color[0] = background_color[1] = background_color[2] = 255;
27892             }
27893           }
27894 
27895           const int d = (depth>1)?depth:0;
27896           if (phase) switch (coords_type) {
27897           case 1 : {
27898             const int
27899               x0 = (int)((X0+0.5f)*disp.width/(width+d)),
27900               y0 = (int)((Y0+0.5f)*disp.height/(height+d)),
27901               x1 = (int)((X1+0.5f)*disp.width/(width+d)),
27902               y1 = (int)((Y1+0.5f)*disp.height/(height+d));
27903             visu.draw_arrow(x0,y0,x1,y1,foreground_color,0.6f,30,5,hatch);
27904             if (d) {
27905               const int
27906                 zx0 = (int)((width+Z0+0.5f)*disp.width/(width+d)),
27907                 zx1 = (int)((width+Z1+0.5f)*disp.width/(width+d)),
27908                 zy0 = (int)((height+Z0+0.5f)*disp.height/(height+d)),
27909                 zy1 = (int)((height+Z1+0.5f)*disp.height/(height+d));
27910               visu.draw_arrow(zx0,y0,zx1,y1,foreground_color,0.6f,30,5,hatch).
27911                 draw_arrow(x0,zy0,x1,zy1,foreground_color,0.6f,30,5,hatch);
27912             }
27913           } break;
27914           case 2 : {
27915             const int
27916               x0 = (X0<X1?X0:X1)*disp.width/(width+d), y0 = (Y0<Y1?Y0:Y1)*disp.height/(height+d),
27917               x1 = ((X0<X1?X1:X0)+1)*disp.width/(width+d)-1, y1 = ((Y0<Y1?Y1:Y0)+1)*disp.height/(height+d)-1;
27918             visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.2f).draw_rectangle(x0,y0,x1,y1,foreground_color,0.6f,hatch);
27919             if (d) {
27920               const int
27921                 zx0 = (int)((width+(Z0<Z1?Z0:Z1))*disp.width/(width+d)),
27922                 zy0 = (int)((height+(Z0<Z1?Z0:Z1))*disp.height/(height+d)),
27923                 zx1 = (int)((width+(Z0<Z1?Z1:Z0)+1)*disp.width/(width+d))-1,
27924                 zy1 = (int)((height+(Z0<Z1?Z1:Z0)+1)*disp.height/(height+d))-1;
27925               visu.draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.2f).draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.6f,hatch);
27926               visu.draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.2f).draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.6f,hatch);
27927             }
27928           } break;
27929           case 3 : {
27930             const int
27931               x0 = X0*disp.width/(width+d),
27932               y0 = Y0*disp.height/(height+d),
27933               x1 = X1*disp.width/(width+d)-1,
27934               y1 = Y1*disp.height/(height+d)-1;
27935             visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1,0,foreground_color,0.2f).
27936               draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1,0,foreground_color,0.6f,hatch);
27937             if (d) {
27938               const int
27939                 zx0 = (int)((width+Z0)*disp.width/(width+d)),
27940                 zy0 = (int)((height+Z0)*disp.height/(height+d)),
27941                 zx1 = (int)((width+Z1+1)*disp.width/(width+d))-1,
27942                 zy1 = (int)((height+Z1+1)*disp.height/(height+d))-1;
27943               visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1,0,foreground_color,0.2f).
27944                 draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1,0,foreground_color,0.6f,hatch).
27945                 draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1,0,foreground_color,0.2f).
27946                 draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1,0,foreground_color,0.6f,hatch);
27947             }
27948           } break;
27949           } else {
27950             const int
27951               x0 = X*disp.width/(width+d),
27952               y0 = Y*disp.height/(height+d),
27953               x1 = (X+1)*disp.width/(width+d)-1,
27954               y1 = (Y+1)*disp.height/(height+d)-1;
27955             if (x1-x0>=4 && y1-y0>=4) visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.4f,~0U);
27956           }
27957 
27958           if (my<12) text_down = true;
27959           if (my>=visu.dimy()-11) text_down = false;
27960           if (!coords_type || !phase) {
27961             if (X>=0 && Y>=0 && Z>=0 && X<dimx() && Y<dimy() && Z<dimz()) {
27962               if (depth>1) cimg_std::sprintf(text,"Point (%d,%d,%d) = [ ",origX+X,origY+Y,origZ+Z);
27963               else cimg_std::sprintf(text,"Point (%d,%d) = [ ",origX+X,origY+Y);
27964               char *ctext = text + cimg::strlen(text), *const ltext = text + 512;
27965               for (unsigned int k=0; k<dim && ctext<ltext; ++k) {
27966                 cimg_std::sprintf(ctext,cimg::type<T>::format(),cimg::type<T>::format((*this)(X,Y,Z,k)));
27967                 ctext = text + cimg::strlen(text);
27968                 *(ctext++) = ' '; *ctext = '\0';
27969               }
27970               cimg_std::sprintf(text + cimg::strlen(text),"]");
27971             }
27972           } else switch (coords_type) {
27973           case 1 : {
27974             const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), norm = cimg_std::sqrt(dX*dX+dY*dY+dZ*dZ);
27975             if (depth>1) cimg_std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), Norm = %g",
27976                                       origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,norm);
27977             else cimg_std::sprintf(text,"Vect (%d,%d)-(%d,%d), Norm = %g",
27978                               origX+X0,origY+Y0,origX+X1,origY+Y1,norm);
27979           } break;
27980           case 2 :
27981             if (depth>1) cimg_std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size = (%d,%d,%d)",
27982                                       origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origZ+(Z0<Z1?Z0:Z1),
27983                                       origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),origZ+(Z0<Z1?Z1:Z0),
27984                                       1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
27985             else  cimg_std::sprintf(text,"Box (%d,%d)-(%d,%d), Size = (%d,%d)",
27986                                origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),
27987                                1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
27988             break;
27989           default :
27990             if (depth>1) cimg_std::sprintf(text,"Ellipse (%d,%d,%d)-(%d,%d,%d), Radii = (%d,%d,%d)",
27991                                       origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,
27992                                       1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
27993             else  cimg_std::sprintf(text,"Ellipse (%d,%d)-(%d,%d), Radii = (%d,%d)",
27994                                origX+X0,origY+Y0,origX+X1,origY+Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
27995 
27996           }
27997           if (phase || (mx>=0 && my>=0)) visu.draw_text(0,text_down?visu.dimy()-11:0,text,foreground_color,background_color,0.7f,11);
27998           disp.display(visu).wait(25);
27999         } else if (!shape_selected) disp.wait();
28000 
28001         if (disp.is_resized) { disp.resize(false); old_is_resized = true; disp.is_resized = false; visu0.assign(); }
28002       }
28003 
28004       // Return result
28005       CImg<intT> res(1,6,1,1,-1);
28006       if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; }
28007       if (shape_selected) {
28008         if (coords_type==2) {
28009           if (X0>X1) cimg::swap(X0,X1);
28010           if (Y0>Y1) cimg::swap(Y0,Y1);
28011           if (Z0>Z1) cimg::swap(Z0,Z1);
28012         }
28013         if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1;
28014         switch (coords_type) {
28015         case 1 :
28016         case 2 :  res[3] = X1; res[4] = Y1; res[5] = Z1;
28017         default : res[0] = X0; res[1] = Y0; res[2] = Z0;
28018         }
28019       }
28020       disp.button = 0;
28021       disp.normalization = old_normalization;
28022       disp.is_resized = old_is_resized;
28023       if (key!=~0U) disp.key = key;
28024       return res;
28025     }
28026 
28027     //! High-level interface for displaying a 3d object.
28028     template<typename tp, typename tf, typename tc, typename to>
28029     const CImg<T>& display_object3d(CImgDisplay& disp,
28030                                     const CImg<tp>& points, const CImgList<tf>& primitives,
28031                                     const CImgList<tc>& colors, const to& opacities,
28032                                     const bool centering=true,
28033                                     const int render_static=4, const int render_motion=1,
28034                                     const bool double_sided=false, const float focale=500,
28035                                     const float specular_light=0.2f, const float specular_shine=0.1f,
28036                                     const bool display_axes=true, float *const pose_matrix=0) const {
28037       return _display_object3d(disp,0,points,points.width,primitives,colors,opacities,centering,render_static,
28038                                render_motion,double_sided,focale,specular_light,specular_shine,
28039                                display_axes,pose_matrix);
28040     }
28041 
28042     //! High-level interface for displaying a 3d object.
28043     template<typename tp, typename tf, typename tc, typename to>
28044     const CImg<T>& display_object3d(const char *const title,
28045                                     const CImg<tp>& points, const CImgList<tf>& primitives,
28046                                     const CImgList<tc>& colors, const to& opacities,
28047                                     const bool centering=true,
28048                                     const int render_static=4, const int render_motion=1,
28049                                     const bool double_sided=false, const float focale=500,
28050                                     const float specular_light=0.2f, const float specular_shine=0.1f,
28051                                     const bool display_axes=true, float *const pose_matrix=0) const {
28052       CImgDisplay disp;
28053       return _display_object3d(disp,title,points,points.width,primitives,colors,opacities,centering,render_static,
28054                                render_motion,double_sided,focale,specular_light,specular_shine,
28055                                display_axes,pose_matrix);
28056     }
28057 
28058     //! High-level interface for displaying a 3d object.
28059     template<typename tp, typename tf, typename tc, typename to>
28060     const CImg<T>& display_object3d(CImgDisplay& disp,
28061                                     const CImgList<tp>& points, const CImgList<tf>& primitives,
28062                                     const CImgList<tc>& colors, const to& opacities,
28063                                     const bool centering=true,
28064                                     const int render_static=4, const int render_motion=1,
28065                                     const bool double_sided=false, const float focale=500,
28066                                     const float specular_light=0.2f, const float specular_shine=0.1f,
28067                                     const bool display_axes=true, float *const pose_matrix=0) const {
28068       return _display_object3d(disp,0,points,points.size,primitives,colors,opacities,centering,render_static,
28069                                render_motion,double_sided,focale,specular_light,specular_shine,
28070                                display_axes,pose_matrix);
28071     }
28072 
28073     //! High-level interface for displaying a 3d object.
28074     template<typename tp, typename tf, typename tc, typename to>
28075     const CImg<T>& display_object3d(const char *const title,
28076                                     const CImgList<tp>& points, const CImgList<tf>& primitives,
28077                                     const CImgList<tc>& colors, const to& opacities,
28078                                     const bool centering=true,
28079                                     const int render_static=4, const int render_motion=1,
28080                                     const bool double_sided=false, const float focale=500,
28081                                     const float specular_light=0.2f, const float specular_shine=0.1f,
28082                                     const bool display_axes=true, float *const pose_matrix=0) const {
28083       CImgDisplay disp;
28084       return _display_object3d(disp,title,points,points.size,primitives,colors,opacities,centering,render_static,
28085                                render_motion,double_sided,focale,specular_light,specular_shine,
28086                                display_axes,pose_matrix);
28087     }
28088 
28089    //! High-level interface for displaying a 3d object.
28090     template<typename tp, typename tf, typename tc>
28091     const CImg<T>& display_object3d(CImgDisplay &disp,
28092                                     const tp& points, const CImgList<tf>& primitives,
28093                                     const CImgList<tc>& colors,
28094                                     const bool centering=true,
28095                                     const int render_static=4, const int render_motion=1,
28096                                     const bool double_sided=false, const float focale=500,
28097                                     const float specular_light=0.2f, const float specular_shine=0.1f,
28098                                     const bool display_axes=true, float *const pose_matrix=0) const {
28099       return display_object3d(disp,points,primitives,colors,CImg<floatT>(),centering,
28100                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28101                               display_axes,pose_matrix);
28102     }
28103 
28104     //! High-level interface for displaying a 3d object.
28105     template<typename tp, typename tf, typename tc>
28106     const CImg<T>& display_object3d(const char *const title,
28107                                     const tp& points, const CImgList<tf>& primitives,
28108                                     const CImgList<tc>& colors,
28109                                     const bool centering=true,
28110                                     const int render_static=4, const int render_motion=1,
28111                                     const bool double_sided=false, const float focale=500,
28112                                     const float specular_light=0.2f, const float specular_shine=0.1f,
28113                                     const bool display_axes=true, float *const pose_matrix=0) const {
28114       return display_object3d(title,points,primitives,colors,CImg<floatT>(),centering,
28115                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28116                               display_axes,pose_matrix);
28117     }
28118 
28119     //! High-level interface for displaying a 3d object.
28120     template<typename tp, typename tf>
28121     const CImg<T>& display_object3d(CImgDisplay &disp,
28122                                     const tp& points, const CImgList<tf>& primitives,
28123                                     const bool centering=true,
28124                                     const int render_static=4, const int render_motion=1,
28125                                     const bool double_sided=false, const float focale=500,
28126                                     const float specular_light=0.2f, const float specular_shine=0.1f,
28127                                     const bool display_axes=true, float *const pose_matrix=0) const {
28128       return display_object3d(disp,points,primitives,CImgList<T>(),centering,
28129                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28130                               display_axes,pose_matrix);
28131     }
28132 
28133     //! High-level interface for displaying a 3d object.
28134     template<typename tp, typename tf>
28135     const CImg<T>& display_object3d(const char *const title,
28136                                     const tp& points, const CImgList<tf>& primitives,
28137                                     const bool centering=true,
28138                                     const int render_static=4, const int render_motion=1,
28139                                     const bool double_sided=false, const float focale=500,
28140                                     const float specular_light=0.2f, const float specular_shine=0.1f,
28141                                     const bool display_axes=true, float *const pose_matrix=0) const {
28142       return display_object3d(title,points,primitives,CImgList<T>(),centering,
28143                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28144                               display_axes,pose_matrix);
28145     }
28146 
28147     //! High-level interface for displaying a 3d object.
28148     template<typename tp>
28149     const CImg<T>& display_object3d(CImgDisplay &disp,
28150                                     const tp& points,
28151                                     const bool centering=true,
28152                                     const int render_static=4, const int render_motion=1,
28153                                     const bool double_sided=false, const float focale=500,
28154                                     const float specular_light=0.2f, const float specular_shine=0.1f,
28155                                     const bool display_axes=true, float *const pose_matrix=0) const {
28156       return display_object3d(disp,points,CImgList<uintT>(),centering,
28157                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28158                               display_axes,pose_matrix);
28159     }
28160 
28161     //! High-level interface for displaying a 3d object.
28162     template<typename tp>
28163     const CImg<T>& display_object3d(const char *const title,
28164                                     const tp& points,
28165                                     const bool centering=true,
28166                                     const int render_static=4, const int render_motion=1,
28167                                     const bool double_sided=false, const float focale=500,
28168                                     const float specular_light=0.2f, const float specular_shine=0.1f,
28169                                     const bool display_axes=true, float *const pose_matrix=0) const {
28170       return display_object3d(title,points,CImgList<uintT>(),centering,
28171                               render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28172                               display_axes,pose_matrix);
28173     }
28174 
28175     T _display_object3d_at2(const int i, const int j) const {
28176       return atXY(i,j,0,0,0);
28177     }
28178 
28179     template<typename tp, typename tf, typename tc, typename to>
28180     const CImg<T>& _display_object3d(CImgDisplay& disp, const char *const title,
28181                                      const tp& points, const unsigned int Npoints,
28182                                      const CImgList<tf>& primitives,
28183                                      const CImgList<tc>& colors, const to& opacities,
28184                                      const bool centering,
28185                                      const int render_static, const int render_motion,
28186                                      const bool double_sided, const float focale,
28187                                      const float specular_light, const float specular_shine,
28188                                      const bool display_axes, float *const pose_matrix) const {
28189 
28190       // Check input arguments
28191       if (!points || !Npoints)
28192         throw CImgArgumentException("CImg<%s>::display_object3d() : Given points are empty.",
28193                                     pixel_type());
28194       if (is_empty()) {
28195         if (disp) return CImg<T>(disp.width,disp.height,1,colors[0].size(),0).
28196                     _display_object3d(disp,title,points,Npoints,primitives,colors,opacities,centering,
28197                                      render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28198                                      display_axes,pose_matrix);
28199         else return CImg<T>(cimg_fitscreen(640,480,1),1,colors[0].size(),0).
28200                _display_object3d(disp,title,points,Npoints,primitives,colors,opacities,centering,
28201                                  render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28202                                  display_axes,pose_matrix);
28203       }
28204       if (!primitives) {
28205         CImgList<tf> nprimitives(Npoints,1,1,1,1);
28206         cimglist_for(nprimitives,l) nprimitives(l,0) = l;
28207         return _display_object3d(disp,title,points,Npoints,nprimitives,colors,opacities,
28208                                  centering,render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28209                                  display_axes,pose_matrix);
28210       }
28211       if (!disp) {
28212         char ntitle[64] = { 0 }; if (!title) { cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); }
28213         disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
28214       }
28215 
28216       CImgList<tc> _colors;
28217       if (!colors) _colors.insert(primitives.size,CImg<tc>::vector(200,200,200));
28218       const CImgList<tc> &ncolors = colors?colors:_colors;
28219 
28220       // Init 3D objects and compute object statistics
28221       CImg<floatT>
28222         pose, rot_mat, zbuffer,
28223         centered_points = centering?CImg<floatT>(Npoints,3):CImg<floatT>(),
28224         rotated_points(Npoints,3),
28225         bbox_points, rotated_bbox_points,
28226         axes_points, rotated_axes_points,
28227         bbox_opacities, axes_opacities;
28228       CImgList<uintT> bbox_primitives, axes_primitives;
28229       CImgList<T> bbox_colors, bbox_colors2, axes_colors;
28230       float dx = 0, dy = 0, dz = 0, ratio = 1;
28231 
28232       T minval = (T)0, maxval = (T)255;
28233       if (disp.normalization && colors) {
28234         minval = colors.minmax(maxval);
28235         if (minval==maxval) { minval = (T)0; maxval = (T)255; }
28236       }
28237       const float meanval = (float)mean();
28238       bool color_model = true;
28239       if (cimg::abs(meanval-minval)>cimg::abs(meanval-maxval)) color_model = false;
28240       const CImg<T>
28241         background_color(1,1,1,dim,color_model?minval:maxval),
28242         foreground_color(1,1,1,dim,color_model?maxval:minval);
28243 
28244       float xm = cimg::type<float>::max(), xM = 0, ym = xm, yM = 0, zm = xm, zM = 0;
28245       for (unsigned int i = 0; i<Npoints; ++i) {
28246         const float
28247           x = points._display_object3d_at2(i,0),
28248           y = points._display_object3d_at2(i,1),
28249           z = points._display_object3d_at2(i,2);
28250         if (x<xm) xm = x;
28251         if (x>xM) xM = x;
28252         if (y<ym) ym = y;
28253         if (y>yM) yM = y;
28254         if (z<zm) zm = z;
28255         if (z>zM) zM = z;
28256       }
28257       const float delta = cimg::max(xM-xm,yM-ym,zM-zm);
28258 
28259       if (display_axes) {
28260         rotated_axes_points = axes_points.assign(7,3,1,1,
28261                                                  0,20,0,0,22,-6,-6,
28262                                                  0,0,20,0,-6,22,-6,
28263                                                  0,0,0,20,0,0,22);
28264         axes_opacities.assign(3,1,1,1,1);
28265         axes_colors.assign(3,dim,1,1,1,foreground_color[0]);
28266         axes_primitives.assign(3,1,2,1,1, 0,1, 0,2, 0,3);
28267       }
28268 
28269       // Begin user interaction loop
28270       CImg<T> visu0(*this), visu;
28271       bool init = true, clicked = false, redraw = true;
28272       unsigned int key = 0;
28273       int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
28274       disp.show().flush();
28275 
28276       while (!disp.is_closed && !key) {
28277 
28278         // Init object position and scale if necessary
28279         if (init) {
28280           ratio = delta>0?(2.0f*cimg::min(disp.width,disp.height)/(3.0f*delta)):0;
28281           dx = 0.5f*(xM + xm); dy = 0.5f*(yM + ym); dz = 0.5f*(zM + zm);
28282           if (centering) {
28283             cimg_forX(centered_points,l) {
28284               centered_points(l,0) = (float)((points(l,0) - dx)*ratio);
28285               centered_points(l,1) = (float)((points(l,1) - dy)*ratio);
28286               centered_points(l,2) = (float)((points(l,2) - dz)*ratio);
28287             }
28288           }
28289 
28290           if (render_static<0 || render_motion<0) {
28291             rotated_bbox_points = bbox_points.assign(8,3,1,1,
28292                                                      xm,xM,xM,xm,xm,xM,xM,xm,
28293                                                      ym,ym,yM,yM,ym,ym,yM,yM,
28294                                                      zm,zm,zm,zm,zM,zM,zM,zM);
28295             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);
28296             bbox_colors.assign(6,dim,1,1,1,background_color[0]);
28297             bbox_colors2.assign(6,dim,1,1,1,foreground_color[0]);
28298             bbox_opacities.assign(bbox_colors.size,1,1,1,0.3f);
28299           }
28300 
28301           if (!pose) {
28302             if (pose_matrix) pose = CImg<floatT>(pose_matrix,4,4,1,1,false);
28303             else pose = CImg<floatT>::identity_matrix(4);
28304           }
28305           init = false;
28306           redraw = true;
28307         }
28308 
28309         // Rotate and Draw 3D object
28310         if (redraw) {
28311           const float
28312             r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0),
28313             r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1),
28314             r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2);
28315           if ((clicked && render_motion>=0) || (!clicked && render_static>=0)) {
28316             if (centering) cimg_forX(centered_points,l) {
28317                 const float x = centered_points(l,0), y = centered_points(l,1), z = centered_points(l,2);
28318                 rotated_points(l,0) = r00*x + r10*y + r20*z + r30;
28319                 rotated_points(l,1) = r01*x + r11*y + r21*z + r31;
28320                 rotated_points(l,2) = r02*x + r12*y + r22*z + r32;
28321               } else for (unsigned int l = 0; l<Npoints; ++l) {
28322                 const float
28323                   x = (float)points._display_object3d_at2(l,0),
28324                   y = (float)points._display_object3d_at2(l,1),
28325                   z = (float)points._display_object3d_at2(l,2);
28326                 rotated_points(l,0) = r00*x + r10*y + r20*z + r30;
28327                 rotated_points(l,1) = r01*x + r11*y + r21*z + r31;
28328                 rotated_points(l,2) = r02*x + r12*y + r22*z + r32;
28329               }
28330           } else {
28331             if (!centering) cimg_forX(bbox_points,l) {
28332                 const float x = bbox_points(l,0), y = bbox_points(l,1), z = bbox_points(l,2);
28333                 rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30;
28334                 rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31;
28335                 rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32;
28336               } else cimg_forX(bbox_points,l) {
28337                 const float x = (bbox_points(l,0)-dx)*ratio, y = (bbox_points(l,1)-dy)*ratio, z = (bbox_points(l,2)-dz)*ratio;
28338                 rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30;
28339                 rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31;
28340                 rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32;
28341               }
28342           }
28343 
28344           // Draw object
28345           visu = visu0;
28346           if ((clicked && render_motion<0) || (!clicked && render_static<0))
28347             visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_points,bbox_primitives,bbox_colors,bbox_opacities,2,false,focale).
28348               draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_points,bbox_primitives,bbox_colors2,1,false,focale);
28349           else visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,
28350                                   rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
28351                                   double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
28352                                   (!clicked && render_static>0)?zbuffer.fill(0).ptr():0);
28353 
28354           // Draw axes
28355           if (display_axes) {
28356             const float Xaxes = 25, Yaxes = visu.height - 35.0f;
28357             cimg_forX(axes_points,l) {
28358               const float x = axes_points(l,0), y = axes_points(l,1), z = axes_points(l,2);
28359               rotated_axes_points(l,0) = r00*x + r10*y + r20*z;
28360               rotated_axes_points(l,1) = r01*x + r11*y + r21*z;
28361               rotated_axes_points(l,2) = r02*x + r12*y + r22*z;
28362             }
28363             axes_opacities(0,0) = (rotated_axes_points(1,2)>0)?0.5f:1.0f;
28364             axes_opacities(1,0) = (rotated_axes_points(2,2)>0)?0.5f:1.0f;
28365             axes_opacities(2,0) = (rotated_axes_points(3,2)>0)?0.5f:1.0f;
28366             visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_points,axes_primitives,axes_colors,axes_opacities,1,false,focale).
28367               draw_text((int)(Xaxes+rotated_axes_points(4,0)),
28368                         (int)(Yaxes+rotated_axes_points(4,1)),
28369                         "X",axes_colors[0].data,0,axes_opacities(0,0),11).
28370               draw_text((int)(Xaxes+rotated_axes_points(5,0)),
28371                         (int)(Yaxes+rotated_axes_points(5,1)),
28372                         "Y",axes_colors[1].data,0,axes_opacities(1,0),11).
28373               draw_text((int)(Xaxes+rotated_axes_points(6,0)),
28374                         (int)(Yaxes+rotated_axes_points(6,1)),
28375                         "Z",axes_colors[2].data,0,axes_opacities(2,0),11);
28376           }
28377           visu.display(disp);
28378           if (!clicked || render_motion==render_static) redraw = false;
28379         }
28380 
28381         // Handle user interaction
28382         disp.wait();
28383         if ((disp.button || disp.wheel) && disp.mouse_x>=0 && disp.mouse_y>=0) {
28384           redraw = true;
28385           if (!clicked) { x0 = x1 = disp.mouse_x; y0 = y1 = disp.mouse_y; if (!disp.wheel) clicked = true; }
28386           else { x1 = disp.mouse_x; y1 = disp.mouse_y; }
28387           if (disp.button&1) {
28388             const float
28389               R = 0.45f*cimg::min(disp.width,disp.height),
28390               R2 = R*R,
28391               u0 = (float)(x0-disp.dimx()/2),
28392               v0 = (float)(y0-disp.dimy()/2),
28393               u1 = (float)(x1-disp.dimx()/2),
28394               v1 = (float)(y1-disp.dimy()/2),
28395               n0 = (float)cimg_std::sqrt(u0*u0+v0*v0),
28396               n1 = (float)cimg_std::sqrt(u1*u1+v1*v1),
28397               nu0 = n0>R?(u0*R/n0):u0,
28398               nv0 = n0>R?(v0*R/n0):v0,
28399               nw0 = (float)cimg_std::sqrt(cimg::max(0,R2-nu0*nu0-nv0*nv0)),
28400               nu1 = n1>R?(u1*R/n1):u1,
28401               nv1 = n1>R?(v1*R/n1):v1,
28402               nw1 = (float)cimg_std::sqrt(cimg::max(0,R2-nu1*nu1-nv1*nv1)),
28403               u = nv0*nw1-nw0*nv1,
28404               v = nw0*nu1-nu0*nw1,
28405               w = nv0*nu1-nu0*nv1,
28406               n = (float)cimg_std::sqrt(u*u+v*v+w*w),
28407               alpha = (float)cimg_std::asin(n/R2);
28408             rot_mat = CImg<floatT>::rotation_matrix(u,v,w,alpha);
28409             rot_mat *= pose.get_crop(0,0,2,2);
28410             pose.draw_image(rot_mat);
28411             x0=x1; y0=y1;
28412           }
28413           if (disp.button&2) { pose(3,2)+=(y1-y0); x0 = x1; y0 = y1; }
28414           if (disp.wheel) { pose(3,2)-=focale*disp.wheel/10; disp.wheel = 0; }
28415           if (disp.button&4) { pose(3,0)+=(x1-x0); pose(3,1)+=(y1-y0); x0 = x1; y0 = y1; }
28416           if ((disp.button&1) && (disp.button&2)) { init = true; disp.button = 0; x0 = x1; y0 = y1; pose = CImg<floatT>::identity_matrix(4); }
28417         } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; }
28418 
28419         switch (key = disp.key) {
28420         case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
28421         case cimg::keyD: if (disp.is_keyCTRLLEFT) {
28422           disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
28423                                      CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
28424           disp.key = key = 0;
28425         } break;
28426         case cimg::keyC : if (disp.is_keyCTRLLEFT) {
28427           disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
28428           disp.key = key = 0;
28429         } break;
28430         case cimg::keyR : if (disp.is_keyCTRLLEFT) {
28431           disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false).is_resized = true;
28432           disp.key = key = 0;
28433         } break;
28434         case cimg::keyF : if (disp.is_keyCTRLLEFT) {
28435           disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
28436           disp.key = key = 0;
28437         } break;
28438         case cimg::keyZ : if (disp.is_keyCTRLLEFT) { // Enable/Disable Z-buffer
28439           if (zbuffer) zbuffer.assign();
28440           else zbuffer.assign(disp.width,disp.height);
28441           disp.key = key = 0; redraw = true;
28442         } break;
28443         case cimg::keyS : if (disp.is_keyCTRLLEFT) { // Save snapshot
28444           static unsigned int snap_number = 0;
28445           char filename[32] = { 0 };
28446           cimg_std::FILE *file;
28447           do {
28448             cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
28449             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
28450           } while (file);
28451           (+visu).draw_text(2,2,"Saving BMP snapshot...",foreground_color,background_color,1,11).display(disp);
28452           visu.save(filename);
28453           visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
28454           disp.key = key = 0;
28455         } break;
28456         case cimg::keyO : if (disp.is_keyCTRLLEFT) { // Save object as an .OFF file
28457           static unsigned int snap_number = 0;
28458           char filename[32] = { 0 };
28459           cimg_std::FILE *file;
28460           do {
28461             cimg_std::sprintf(filename,"CImg_%.4u.off",snap_number++);
28462             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
28463           } while (file);
28464           visu.draw_text(2,2,"Saving object...",foreground_color,background_color,1,11).display(disp);
28465           points.save_off(filename,primitives,ncolors);
28466           visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
28467           disp.key = key = 0;
28468         } break;
28469 #ifdef cimg_use_board
28470         case cimg::keyP : if (disp.is_keyCTRLLEFT) { // Save object as a .EPS file
28471           static unsigned int snap_number = 0;
28472           char filename[32] = { 0 };
28473           cimg_std::FILE *file;
28474           do {
28475             cimg_std::sprintf(filename,"CImg_%.4u.eps",snap_number++);
28476             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
28477           } while (file);
28478           visu.draw_text(2,2,"Saving EPS snapshot...",foreground_color,background_color,1,11).display(disp);
28479           BoardLib::Board board;
28480           (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
28481                                 rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
28482                                 double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
28483                                 zbuffer.fill(0).ptr());
28484           board.saveEPS(filename);
28485           visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
28486           disp.key = key = 0;
28487         } break;
28488         case cimg::keyV : if (disp.is_keyCTRLLEFT) { // Save object as a .SVG file
28489           static unsigned int snap_number = 0;
28490           char filename[32] = { 0 };
28491           cimg_std::FILE *file;
28492           do {
28493             cimg_std::sprintf(filename,"CImg_%.4u.svg",snap_number++);
28494             if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
28495           } while (file);
28496           visu.draw_text(2,2,"Saving SVG snapshot...",foreground_color,background_color,1,11).display(disp);
28497           BoardLib::Board board;
28498           (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
28499                                 rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
28500                                 double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
28501                                 zbuffer.fill(0).ptr());
28502           board.saveSVG(filename);
28503           visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
28504           disp.key = key = 0;
28505         } break;
28506 #endif
28507         }
28508         if (disp.is_resized) { disp.resize(false); visu0 = get_resize(disp,1); if (zbuffer) zbuffer.assign(disp.width,disp.height); redraw = true; }
28509       }
28510       if (pose_matrix) cimg_std::memcpy(pose_matrix,pose.data,16*sizeof(float));
28511       disp.button = 0;
28512       disp.key = key;
28513       return *this;
28514     }
28515 
28516     //! High-level interface for displaying a graph.
28517     const CImg<T>& display_graph(CImgDisplay &disp,
28518                                  const unsigned int plot_type=1, const unsigned int vertex_type=1,
28519                                  const char *const labelx=0, const double xmin=0, const double xmax=0,
28520                                  const char *const labely=0, const double ymin=0, const double ymax=0) const {
28521       if (is_empty())
28522         throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
28523                                     pixel_type(),width,height,depth,dim,data);
28524       const unsigned int siz = width*height*depth, onormalization = disp.normalization;
28525       if (!disp) { char ntitle[64] = { 0 }; cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
28526       disp.show().flush().normalization = 0;
28527       double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax;
28528       if (nxmin==nxmax) { nxmin = 0; nxmax = siz - 1.0; }
28529       int x0 = 0, x1 = size()/dimv()-1, key = 0;
28530 
28531       for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
28532         if (reset_view) { x0 = 0; x1 = size()/dimv()-1; y0 = ymin; y1 = ymax; reset_view = false; }
28533         CImg<T> zoom(x1-x0+1,1,1,dimv());
28534         cimg_forV(*this,k) zoom.get_shared_channel(k) = CImg<T>(ptr(x0,0,0,k),x1-x0+1,1,1,1,true);
28535 
28536         if (y0==y1) y0 = zoom.minmax(y1);
28537         if (y0==y1) { --y0; ++y1; }
28538         const CImg<intT> selection = zoom.get_select_graph(disp,plot_type,vertex_type,
28539                                                            labelx,nxmin + x0*(nxmax-nxmin)/siz,nxmin + x1*(nxmax-nxmin)/siz,
28540                                                            labely,y0,y1);
28541 
28542         const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
28543         if (selection[0]>=0 && selection[2]>=0) {
28544           x1 = x0 + selection[2];
28545           x0 += selection[0];
28546           if (x0==x1) reset_view = true;
28547           if (selection[1]>=0 && selection[3]>=0) {
28548             y0 = y1 - selection[3]*(y1-y0)/(disp.dimy()-32);
28549             y1 -= selection[1]*(y1-y0)/(disp.dimy()-32);
28550           }
28551         } else {
28552           bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false;
28553           switch (key = disp.key) {
28554           case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
28555           case cimg::keyPADADD : go_in = true; key = 0; break;
28556           case cimg::keyPADSUB : go_out = true; key = 0; break;
28557           case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; key = 0; break;
28558           case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; key = 0; break;
28559           case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; key = 0; break;
28560           case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; key = 0; break;
28561           case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; break;
28562           case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; break;
28563           case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; break;
28564           case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; break;
28565           }
28566           if (disp.wheel) go_out = !(go_in = disp.wheel>0);
28567 
28568           if (go_in) {
28569             const int
28570               xsiz = x1 - x0,
28571               mx = (mouse_x-16)*xsiz/(disp.dimx()-32),
28572               cx = x0 + (mx<0?0:(mx>=xsiz?xsiz:mx));
28573             if (x1-x0>4) {
28574               x0 = cx - 7*(cx-x0)/8; x1 = cx + 7*(x1-cx)/8;
28575               if (disp.is_keyCTRLLEFT) {
28576                 const double
28577                   ysiz = y1 - y0,
28578                   my = (mouse_y-16)*ysiz/(disp.dimy()-32),
28579                   cy = y1 - (my<0?0:(my>=ysiz?ysiz:my));
28580                 y0 = cy - 7*(cy-y0)/8; y1 = cy + 7*(y1-cy)/8;
28581               } else y0 = y1 = 0;
28582             }
28583           }
28584           if (go_out) {
28585             const int deltax = (x1-x0)/8, ndeltax = deltax?deltax:(siz>1?1:0);
28586             x0-=ndeltax; x1+=ndeltax;
28587             if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz-1; }
28588             if (x1>=(int)siz) { x0-=(x1-siz+1); x1 = (int)siz-1; if (x0<0) x0 = 0; }
28589             if (disp.is_keyCTRLLEFT) {
28590               const double deltay = (y1-y0)/8, ndeltay = deltay?deltay:0.01;
28591               y0-=ndeltay; y1+=ndeltay;
28592             }
28593           }
28594           if (go_left) {
28595             const int delta = (x1-x0)/5, ndelta = delta?delta:1;
28596             if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
28597             else { x1-=x0; x0 = 0; }
28598             go_left = false;
28599           }
28600           if (go_right) {
28601             const int delta = (x1-x0)/5, ndelta = delta?delta:1;
28602             if (x1+ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; }
28603             else { x0+=(siz-1-x1); x1 = siz-1; }
28604             go_right = false;
28605           }
28606           if (go_up) {
28607             const double delta = (y1-y0)/10, ndelta = delta?delta:1;
28608             y0+=ndelta; y1+=ndelta;
28609             go_up = false;
28610           }
28611           if (go_down) {
28612             const double delta = (y1-y0)/10, ndelta = delta?delta:1;
28613             y0-=ndelta; y1-=ndelta;
28614             go_down = false;
28615           }
28616         }
28617       }
28618       disp.normalization = onormalization;
28619       return *this;
28620     }
28621 
28622     //! High-level interface for displaying a graph.
28623     const CImg<T>& display_graph(const char *const title=0,
28624                                  const unsigned int plot_type=1, const unsigned int vertex_type=1,
28625                                  const char *const labelx=0, const double xmin=0, const double xmax=0,
28626                                  const char *const labely=0, const double ymin=0, const double ymax=0) const {
28627       if (is_empty())
28628         throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
28629                                     pixel_type(),width,height,depth,dim,data);
28630       char ntitle[64] = { 0 }; if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
28631       CImgDisplay disp(cimg_fitscreen(640,480,1),title?title:ntitle,0);
28632       return display_graph(disp,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax);
28633     }
28634 
28635     //! Select sub-graph in a graph.
28636     CImg<intT> get_select_graph(CImgDisplay &disp,
28637                                 const unsigned int plot_type=1, const unsigned int vertex_type=1,
28638                                 const char *const labelx=0, const double xmin=0, const double xmax=0,
28639                                 const char *const labely=0, const double ymin=0, const double ymax=0) const {
28640       if (is_empty())
28641         throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
28642                                     pixel_type(),width,height,depth,dim,data);
28643       const unsigned int siz = width*height*depth, onormalization = disp.normalization;
28644       if (!disp) { char ntitle[64] = { 0 }; cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
28645       disp.show().key = disp.normalization = disp.button = disp.wheel = 0;  // Must keep 'key' field unchanged.
28646       double nymin = ymin, nymax = ymax, nxmin = xmin, nxmax = xmax;
28647       if (nymin==nymax) nymin = (Tfloat)minmax(nymax);
28648       if (nymin==nymax) { --nymin; ++nymax; }
28649       if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; }
28650 
28651       const unsigned char black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 220,220,220 };
28652       const unsigned char gray2[] = { 110,110,110 }, ngray[] = { 35,35,35 };
28653       static unsigned int odimv = 0;
28654       static CImg<ucharT> palette;
28655       if (odimv!=dim) {
28656         odimv = dim;
28657         palette = CImg<ucharT>(3,dim,1,1,120).noise(70,1);
28658         if (dim==1) { palette[0] = palette[1] = 120; palette[2] = 200; }
28659         else {
28660           palette(0,0) = 220; palette(1,0) = 10; palette(2,0) = 10;
28661           if (dim>1) { palette(0,1) = 10; palette(1,1) = 220; palette(2,1) = 10; }
28662           if (dim>2) { palette(0,2) = 10; palette(1,2) = 10; palette(2,2) = 220; }
28663         }
28664       }
28665 
28666       CImg<ucharT> visu0, visu, graph, text, axes;
28667       const unsigned int whz = width*height*depth;
28668       int x0 = -1, x1 = -1, y0 = -1, y1 = -1, omouse_x = -2, omouse_y = -2;
28669       char message[1024] = { 0 };
28670       unsigned int okey = 0, obutton = 0;
28671       CImg_3x3(I,unsigned char);
28672 
28673       for (bool selected = false; !selected && !disp.is_closed && !okey && !disp.wheel; ) {
28674         const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
28675         const unsigned int key = disp.key, button = disp.button;
28676 
28677         // Generate graph representation.
28678         if (!visu0) {
28679           visu0.assign(disp.dimx(),disp.dimy(),1,3,220);
28680           const int gdimx = disp.dimx() - 32, gdimy = disp.dimy() - 32;
28681           if (gdimx>0 && gdimy>0) {
28682             graph.assign(gdimx,gdimy,1,3,255);
28683             graph.draw_grid(-10,-10,0,0,false,true,black,0.2f,0x33333333,0x33333333);
28684             cimg_forV(*this,k) graph.draw_graph(get_shared_channel(k),&palette(0,k),(plot_type!=3 || dim==1)?1:0.6f,
28685                                                 plot_type,vertex_type,nymax,nymin);
28686 
28687             axes.assign(gdimx,gdimy,1,1,0);
28688             const float
28689               dx = (float)cimg::abs(nxmax-nxmin), dy = (float)cimg::abs(nymax-nymin),
28690               px = (float)cimg_std::pow(10.0,(int)cimg_std::log10(dx)-2.0),
28691               py = (float)cimg_std::pow(10.0,(int)cimg_std::log10(dy)-2.0);
28692             const CImg<Tdouble>
28693               seqx = CImg<Tdouble>::sequence(1 + gdimx/60,nxmin,nxmax).round(px),
28694               seqy = CImg<Tdouble>::sequence(1 + gdimy/60,nymax,nymin).round(py);
28695             axes.draw_axis(seqx,seqy,white);
28696             if (nymin>0) axes.draw_axis(seqx,gdimy-1,gray);
28697             if (nymax<0) axes.draw_axis(seqx,0,gray);
28698             if (nxmin>0) axes.draw_axis(0,seqy,gray);
28699             if (nxmax<0) axes.draw_axis(gdimx-1,seqy,gray);
28700 
28701             cimg_for3x3(axes,x,y,0,0,I)
28702               if (Icc) {
28703                 if (Icc==255) cimg_forV(graph,k) graph(x,y,k) = 0;
28704                 else cimg_forV(graph,k) graph(x,y,k) = (unsigned char)(2*graph(x,y,k)/3);
28705               }
28706               else if (Ipc || Inc || Icp || Icn || Ipp || Inn || Ipn || Inp) cimg_forV(graph,k) graph(x,y,k) = (graph(x,y,k)+255)/2;
28707 
28708             visu0.draw_image(16,16,graph);
28709             visu0.draw_line(15,15,16+gdimx,15,gray2).draw_line(16+gdimx,15,16+gdimx,16+gdimy,gray2).
28710               draw_line(16+gdimx,16+gdimy,15,16+gdimy,white).draw_line(15,16+gdimy,15,15,white);
28711           } else graph.assign();
28712           text.assign().draw_text(0,0,labelx?labelx:"X-axis",white,ngray,1);
28713           visu0.draw_image((visu0.dimx()-text.dimx())/2,visu0.dimy()-14,~text);
28714           text.assign().draw_text(0,0,labely?labely:"Y-axis",white,ngray,1).rotate(-90);
28715           visu0.draw_image(2,(visu0.dimy()-text.dimy())/2,~text);
28716           visu.assign();
28717         }
28718 
28719         // Generate and display current view.
28720         if (!visu) {
28721           visu.assign(visu0);
28722           if (graph && x0>=0 && x1>=0) {
28723             const int
28724               nx0 = x0<=x1?x0:x1,
28725               nx1 = x0<=x1?x1:x0,
28726               ny0 = y0<=y1?y0:y1,
28727               ny1 = y0<=y1?y1:y0,
28728               sx0 = 16 + nx0*(visu.dimx()-32)/whz,
28729               sx1 = 15 + (nx1+1)*(visu.dimx()-32)/whz,
28730               sy0 = 16 + ny0,
28731               sy1 = 16 + ny1;
28732 
28733             if (y0>=0 && y1>=0)
28734               visu.draw_rectangle(sx0,sy0,sx1,sy1,gray,0.5f).draw_rectangle(sx0,sy0,sx1,sy1,black,0.5f,0xCCCCCCCCU);
28735             else visu.draw_rectangle(sx0,0,sx1,visu.dimy()-17,gray,0.5f).
28736                    draw_line(sx0,16,sx0,visu.dimy()-17,black,0.5f,0xCCCCCCCCU).
28737                    draw_line(sx1,16,sx1,visu.dimy()-17,black,0.5f,0xCCCCCCCCU);
28738           }
28739           if (mouse_x>=16 && mouse_y>=16 && mouse_x<visu.dimx()-16 && mouse_y<visu.dimy()-16) {
28740             if (graph) visu.draw_line(mouse_x,16,mouse_x,visu.dimy()-17,black,0.5f,0x55555555U);
28741             const unsigned x = (mouse_x-16)*whz/(disp.dimx()-32);
28742             const double cx = nxmin + x*(nxmax-nxmin)/whz;
28743             if (dim>=7)
28744               cimg_std::sprintf(message,"Value[%g] = ( %g %g %g ... %g %g %g )",cx,
28745                            (double)(*this)(x,0,0,0),(double)(*this)(x,0,0,1),(double)(*this)(x,0,0,2),
28746                            (double)(*this)(x,0,0,dim-4),(double)(*this)(x,0,0,dim-3),(double)(*this)(x,0,0,dim-1));
28747             else {
28748               cimg_std::sprintf(message,"Value[%g] = ( ",cx);
28749               cimg_forV(*this,k) cimg_std::sprintf(message+cimg::strlen(message),"%g ",(double)(*this)(x,0,0,k));
28750               cimg_std::sprintf(message+cimg::strlen(message),")");
28751             }
28752             if (x0>=0 && x1>=0) {
28753               const int
28754                  nx0 = x0<=x1?x0:x1,
28755                  nx1 = x0<=x1?x1:x0,
28756                  ny0 = y0<=y1?y0:y1,
28757                  ny1 = y0<=y1?y1:y0;
28758               const double
28759                  cx0 = nxmin + nx0*(nxmax-nxmin)/(visu.dimx()-32),
28760                  cx1 = nxmin + nx1*(nxmax-nxmin)/(visu.dimx()-32),
28761                  cy0 = nymax - ny0*(nymax-nymin)/(visu.dimy()-32),
28762                  cy1 = nymax - ny1*(nymax-nymin)/(visu.dimy()-32);
28763               if (y0>=0 && y1>=0)
28764                 cimg_std::sprintf(message+cimg::strlen(message)," - Range ( %g, %g ) - ( %g, %g )",cx0,cy0,cx1,cy1);
28765               else
28766                 cimg_std::sprintf(message+cimg::strlen(message)," - Range [ %g - %g ]",cx0,cx1);
28767             }
28768             text.assign().draw_text(0,0,message,white,ngray,1);
28769             visu.draw_image((visu.dimx()-text.dimx())/2,2,~text);
28770           }
28771           visu.display(disp);
28772         }
28773 
28774         // Test keys.
28775         switch (okey = key) {
28776         case cimg::keyCTRLLEFT : okey = 0; break;
28777         case cimg::keyD : if (disp.is_keyCTRLLEFT) {
28778           disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
28779                                      CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
28780           disp.key = okey = 0;
28781         } break;
28782         case cimg::keyC : if (disp.is_keyCTRLLEFT) {
28783           disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
28784           disp.key = okey = 0;
28785         } break;
28786         case cimg::keyR : if (disp.is_keyCTRLLEFT) {
28787           disp.normalscreen().resize(cimg_fitscreen(640,480,1),false).is_resized = true;
28788           disp.key = okey = 0;
28789         } break;
28790         case cimg::keyF : if (disp.is_keyCTRLLEFT) {
28791           disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
28792           disp.key = okey = 0;
28793         } break;
28794         case cimg::keyS : if (disp.is_keyCTRLLEFT) {
28795           static unsigned int snap_number = 0;
28796           if (visu || visu0) {
28797             CImg<ucharT> &screen = visu?visu:visu0;
28798             char filename[32] = { 0 };
28799             cimg_std::FILE *file;
28800             do {
28801               cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
28802               if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
28803             } while (file);
28804             (+screen).draw_text(2,2,"Saving BMP snapshot...",black,gray,1,11).display(disp);
28805             screen.save(filename);
28806             screen.draw_text(2,2,"Snapshot '%s' saved.",black,gray,1,11,filename).display(disp);
28807           }
28808           disp.key = okey = 0;
28809         } break;
28810         }
28811 
28812         // Handle mouse motion and mouse buttons
28813         if (obutton!=button || omouse_x!=mouse_x || omouse_y!=mouse_y) {
28814           visu.assign();
28815           if (disp.mouse_x>=0 && disp.mouse_y>=0) {
28816             const int
28817               mx = (mouse_x-16)*(int)whz/(disp.dimx()-32),
28818               cx = mx<0?0:(mx>=(int)whz?whz-1:mx),
28819               my = mouse_y-16,
28820               cy = my<=0?0:(my>=(disp.dimy()-32)?(disp.dimy()-32):my);
28821             if (button&1) { if (!obutton) { x0 = cx; y0 = -1; } else { x1 = cx; y1 = -1; }}
28822             else if (button&2) { if (!obutton) { x0 = cx; y0 = cy; } else { x1 = cx; y1 = cy; }}
28823             else if (obutton) { x1 = cx; y1 = y1>=0?cy:-1; selected = true; }
28824           } else if (!button && obutton) selected = true;
28825           obutton = button; omouse_x = mouse_x; omouse_y = mouse_y;
28826         }
28827         if (disp.is_resized) { disp.resize(false); visu0.assign(); }
28828         if (visu && visu0) disp.wait();
28829       }
28830       disp.normalization = onormalization;
28831       if (x1<x0) cimg::swap(x0,x1);
28832       if (y1<y0) cimg::swap(y0,y1);
28833       disp.key = okey;
28834       return CImg<intT>(4,1,1,1,x0,y0,x1,y1);
28835     }
28836 
28837     //@}
28838     //---------------------------
28839     //
28840     //! \name Image File Loading
28841     //@{
28842     //---------------------------
28843 
28844     //! Load an image from a file.
28845     /**
28846        \param filename is the name of the image file to load.
28847        \note The extension of \c filename defines the file format. If no filename
28848        extension is provided, CImg<T>::get_load() will try to load a .cimg file.
28849     **/
28850     CImg<T>& load(const char *const filename) {
28851       if (!filename)
28852         throw CImgArgumentException("CImg<%s>::load() : Cannot load (null) filename.",
28853                                     pixel_type());
28854       const char *ext = cimg::split_filename(filename);
28855       const unsigned int odebug = cimg::exception_mode();
28856       cimg::exception_mode() = 0;
28857       assign();
28858       try {
28859 #ifdef cimg_load_plugin
28860         cimg_load_plugin(filename);
28861 #endif
28862 #ifdef cimg_load_plugin1
28863         cimg_load_plugin1(filename);
28864 #endif
28865 #ifdef cimg_load_plugin2
28866         cimg_load_plugin2(filename);
28867 #endif
28868 #ifdef cimg_load_plugin3
28869         cimg_load_plugin3(filename);
28870 #endif
28871 #ifdef cimg_load_plugin4
28872         cimg_load_plugin4(filename);
28873 #endif
28874 #ifdef cimg_load_plugin5
28875         cimg_load_plugin5(filename);
28876 #endif
28877 #ifdef cimg_load_plugin6
28878         cimg_load_plugin6(filename);
28879 #endif
28880 #ifdef cimg_load_plugin7
28881         cimg_load_plugin7(filename);
28882 #endif
28883 #ifdef cimg_load_plugin8
28884         cimg_load_plugin8(filename);
28885 #endif
28886         // ASCII formats
28887         if (!cimg::strcasecmp(ext,"asc")) load_ascii(filename);
28888         if (!cimg::strcasecmp(ext,"dlm") ||
28889             !cimg::strcasecmp(ext,"txt")) load_dlm(filename);
28890 
28891         // 2D binary formats
28892         if (!cimg::strcasecmp(ext,"bmp")) load_bmp(filename);
28893         if (!cimg::strcasecmp(ext,"jpg") ||
28894             !cimg::strcasecmp(ext,"jpeg") ||
28895             !cimg::strcasecmp(ext,"jpe") ||
28896             !cimg::strcasecmp(ext,"jfif") ||
28897             !cimg::strcasecmp(ext,"jif")) load_jpeg(filename);
28898         if (!cimg::strcasecmp(ext,"png")) load_png(filename);
28899         if (!cimg::strcasecmp(ext,"ppm") ||
28900             !cimg::strcasecmp(ext,"pgm") ||
28901             !cimg::strcasecmp(ext,"pnm")) load_pnm(filename);
28902         if (!cimg::strcasecmp(ext,"tif") ||
28903             !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
28904         if (!cimg::strcasecmp(ext,"cr2") ||
28905             !cimg::strcasecmp(ext,"crw") ||
28906             !cimg::strcasecmp(ext,"dcr") ||
28907             !cimg::strcasecmp(ext,"mrw") ||
28908             !cimg::strcasecmp(ext,"nef") ||
28909             !cimg::strcasecmp(ext,"orf") ||
28910             !cimg::strcasecmp(ext,"pix") ||
28911             !cimg::strcasecmp(ext,"ptx") ||
28912             !cimg::strcasecmp(ext,"raf") ||
28913             !cimg::strcasecmp(ext,"srf")) load_dcraw_external(filename);
28914 
28915         // 3D binary formats
28916         if (!cimg::strcasecmp(ext,"dcm") ||
28917             !cimg::strcasecmp(ext,"dicom")) load_medcon_external(filename);
28918         if (!cimg::strcasecmp(ext,"hdr") ||
28919             !cimg::strcasecmp(ext,"nii")) load_analyze(filename);
28920         if (!cimg::strcasecmp(ext,"par") ||
28921             !cimg::strcasecmp(ext,"rec")) load_parrec(filename);
28922         if (!cimg::strcasecmp(ext,"inr")) load_inr(filename);
28923         if (!cimg::strcasecmp(ext,"pan")) load_pandore(filename);
28924         if (!cimg::strcasecmp(ext,"cimg") ||
28925             !cimg::strcasecmp(ext,"cimgz") ||
28926             *ext=='\0')  return load_cimg(filename);
28927 
28928         // Archive files
28929         if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
28930 
28931         // Image sequences
28932         if (!cimg::strcasecmp(ext,"avi") ||
28933             !cimg::strcasecmp(ext,"mov") ||
28934             !cimg::strcasecmp(ext,"asf") ||
28935             !cimg::strcasecmp(ext,"divx") ||
28936             !cimg::strcasecmp(ext,"flv") ||
28937             !cimg::strcasecmp(ext,"mpg") ||
28938             !cimg::strcasecmp(ext,"m1v") ||
28939             !cimg::strcasecmp(ext,"m2v") ||
28940             !cimg::strcasecmp(ext,"m4v") ||
28941             !cimg::strcasecmp(ext,"mjp") ||
28942             !cimg::strcasecmp(ext,"mkv") ||
28943             !cimg::strcasecmp(ext,"mpe") ||
28944             !cimg::strcasecmp(ext,"movie") ||
28945             !cimg::strcasecmp(ext,"ogm") ||
28946             !cimg::strcasecmp(ext,"qt") ||
28947             !cimg::strcasecmp(ext,"rm") ||
28948             !cimg::strcasecmp(ext,"vob") ||
28949             !cimg::strcasecmp(ext,"wmv") ||
28950             !cimg::strcasecmp(ext,"xvid") ||
28951             !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
28952         if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
28953       } catch (CImgException& e) {
28954         if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
28955           cimg::exception_mode() = odebug;
28956           throw CImgIOException("CImg<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
28957         } else try {
28958           const char *const ftype = cimg::file_type(0,filename);
28959           assign();
28960           if (!cimg::strcmp(ftype,"pnm")) load_pnm(filename);
28961           if (!cimg::strcmp(ftype,"bmp")) load_bmp(filename);
28962           if (!cimg::strcmp(ftype,"jpeg")) load_jpeg(filename);
28963           if (!cimg::strcmp(ftype,"pan")) load_pandore(filename);
28964           if (!cimg::strcmp(ftype,"png")) load_png(filename);
28965           if (!cimg::strcmp(ftype,"tiff")) load_tiff(filename);
28966           if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
28967         } catch (CImgException&) {
28968           try {
28969             load_other(filename);
28970           } catch (CImgException&) {
28971             assign();
28972           }
28973         }
28974       }
28975       cimg::exception_mode() = odebug;
28976       if (is_empty())
28977         throw CImgIOException("CImg<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
28978       return *this;
28979     }
28980 
28981     static CImg<T> get_load(const char *const filename) {
28982       return CImg<T>().load(filename);
28983     }
28984 
28985     //! Load an image from an ASCII file.
28986     CImg<T>& load_ascii(const char *const filename) {
28987       return _load_ascii(0,filename);
28988     }
28989 
28990     static CImg<T> get_load_ascii(const char *const filename) {
28991       return CImg<T>().load_ascii(filename);
28992     }
28993 
28994     //! Load an image from an ASCII file.
28995     CImg<T>& load_ascii(cimg_std::FILE *const file) {
28996       return _load_ascii(file,0);
28997     }
28998 
28999     static CImg<T> get_load_ascii(cimg_std::FILE *const file) {
29000       return CImg<T>().load_ascii(file);
29001     }
29002 
29003     CImg<T>& _load_ascii(cimg_std::FILE *const file, const char *const filename) {
29004       if (!filename && !file)
29005         throw CImgArgumentException("CImg<%s>::load_ascii() : Cannot load (null) filename.",
29006                                     pixel_type());
29007       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29008       char line[256] = { 0 };
29009       int err = cimg_std::fscanf(nfile,"%*[^0-9]%255[^\n]",line);
29010       unsigned int off, dx = 0, dy = 1, dz = 1, dv = 1;
29011       cimg_std::sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dv);
29012       err = cimg_std::fscanf(nfile,"%*[^0-9.+-]");
29013       if (!dx || !dy || !dz || !dv) {
29014         if (!file) cimg::fclose(nfile);
29015         throw CImgIOException("CImg<%s>::load_ascii() : File '%s', invalid .ASC header, specified image dimensions are (%u,%u,%u,%u).",
29016                               pixel_type(),filename?filename:"(FILE*)",dx,dy,dz,dv);
29017       }
29018       assign(dx,dy,dz,dv);
29019       const unsigned long siz = size();
29020       double val;
29021       T *ptr = data;
29022       for (err = 1, off = 0; off<siz && err==1; ++off) {
29023         err = cimg_std::fscanf(nfile,"%lf%*[^0-9.+-]",&val);
29024         *(ptr++) = (T)val;
29025       }
29026       if (err!=1)
29027         cimg::warn("CImg<%s>::load_ascii() : File '%s', only %u/%lu values read.",
29028                    pixel_type(),filename?filename:"(FILE*)",off-1,siz);
29029       if (!file) cimg::fclose(nfile);
29030       return *this;
29031     }
29032 
29033     //! Load an image from a DLM file.
29034     CImg<T>& load_dlm(const char *const filename) {
29035       return _load_dlm(0,filename);
29036     }
29037 
29038     static CImg<T> get_load_dlm(const char *const filename) {
29039       return CImg<T>().load_dlm(filename);
29040     }
29041 
29042     //! Load an image from a DLM file.
29043     CImg<T>& load_dlm(cimg_std::FILE *const file) {
29044       return _load_dlm(file,0);
29045     }
29046 
29047     static CImg<T> get_load_dlm(cimg_std::FILE *const file) {
29048       return CImg<T>().load_dlm(file);
29049     }
29050 
29051     CImg<T>& _load_dlm(cimg_std::FILE *const file, const char *const filename) {
29052       if (!filename && !file)
29053         throw CImgArgumentException("CImg<%s>::load_dlm() : Cannot load (null) filename.",
29054                                     pixel_type());
29055       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
29056       assign(256,256);
29057       char c, delimiter[256] = { 0 }, tmp[256];
29058       unsigned int cdx = 0, dx = 0, dy = 0;
29059       int oerr = 0, err;
29060       double val;
29061       while ((err = cimg_std::fscanf(nfile,"%lf%255[^0-9.+-]",&val,delimiter))!=EOF) {
29062         oerr = err;
29063         if (err>0) (*this)(cdx++,dy) = (T)val;
29064         if (cdx>=width) resize(width+256,1,1,1,0);
29065         c = 0; if (!cimg_std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') {
29066           dx = cimg::max(cdx,dx);
29067           ++dy;
29068           if (dy>=height) resize(width,height+256,1,1,0);
29069           cdx = 0;
29070         }
29071       }
29072       if (cdx && oerr==1) { dx=cdx; ++dy; }
29073       if (!dx || !dy) {
29074         if (!file) cimg::fclose(nfile);
29075         throw CImgIOException("CImg<%s>::load_dlm() : File '%s', invalid DLM file, specified image dimensions are (%u,%u).",
29076                               pixel_type(),filename?filename:"(FILE*)",dx,dy);
29077       }
29078       resize(dx,dy,1,1,0);
29079       if (!file) cimg::fclose(nfile);
29080       return *this;
29081     }
29082 
29083     //! Load an image from a BMP file.
29084     CImg<T>& load_bmp(const char *const filename) {
29085       return _load_bmp(0,filename);
29086     }
29087 
29088     static CImg<T> get_load_bmp(const char *const filename) {
29089       return CImg<T>().load_bmp(filename);
29090     }
29091 
29092     //! Load an image from a BMP file.
29093     CImg<T>& load_bmp(cimg_std::FILE *const file) {
29094       return _load_bmp(file,0);
29095     }
29096 
29097     static CImg<T> get_load_bmp(cimg_std::FILE *const file) {
29098       return CImg<T>().load_bmp(file);
29099     }
29100 
29101     CImg<T>& _load_bmp(cimg_std::FILE *const file, const char *const filename) {
29102       if (!filename && !file)
29103         throw CImgArgumentException("CImg<%s>::load_bmp() : Cannot load (null) filename.",
29104                                     pixel_type());
29105       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29106       unsigned char header[64];
29107       cimg::fread(header,54,nfile);
29108       if (header[0]!='B' || header[1]!='M') {
29109         if (!file) cimg::fclose(nfile);
29110         throw CImgIOException("CImg<%s>::load_bmp() : Invalid valid BMP file (filename '%s').",
29111                               pixel_type(),filename?filename:"(FILE*)");
29112       }
29113       assign();
29114 
29115       // Read header and pixel buffer
29116       int
29117         file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24),
29118         offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24),
29119         dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24),
29120         dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24),
29121         compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24),
29122         nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24),
29123         bpp = header[0x1C] + (header[0x1D]<<8),
29124         *palette = 0;
29125       const int
29126         dx_bytes = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)),
29127         align = (4-dx_bytes%4)%4,
29128         buf_size = cimg::min(cimg::abs(dy)*(dx_bytes+align),file_size-offset);
29129 
29130       if (bpp<16) { if (!nb_colors) nb_colors=1<<bpp; } else nb_colors = 0;
29131       if (nb_colors) { palette = new int[nb_colors]; cimg::fread(palette,nb_colors,nfile); }
29132       const int xoffset = offset-54-4*nb_colors;
29133       if (xoffset>0) cimg_std::fseek(nfile,xoffset,SEEK_CUR);
29134       unsigned char *buffer = new unsigned char[buf_size], *ptrs = buffer;
29135       cimg::fread(buffer,buf_size,nfile);
29136       if (!file) cimg::fclose(nfile);
29137 
29138       // Decompress buffer (if necessary)
29139       if (compression) {
29140         delete[] buffer;
29141         if (file) {
29142           throw CImgIOException("CImg<%s>::load_bmp() : Not able to read a compressed BMP file using a *FILE input",
29143                                 pixel_type());
29144         } else return load_other(filename);
29145       }
29146 
29147       // Read pixel data
29148       assign(dx,cimg::abs(dy),1,3);
29149       switch (bpp) {
29150       case 1 : { // Monochrome
29151         for (int y=height-1; y>=0; --y) {
29152           unsigned char mask = 0x80, val = 0;
29153           cimg_forX(*this,x) {
29154             if (mask==0x80) val = *(ptrs++);
29155             const unsigned char *col = (unsigned char*)(palette+(val&mask?1:0));
29156             (*this)(x,y,2) = (T)*(col++);
29157             (*this)(x,y,1) = (T)*(col++);
29158             (*this)(x,y,0) = (T)*(col++);
29159             mask = cimg::ror(mask);
29160           } ptrs+=align; }
29161       } break;
29162       case 4 : { // 16 colors
29163         for (int y=height-1; y>=0; --y) {
29164           unsigned char mask = 0xF0, val = 0;
29165           cimg_forX(*this,x) {
29166             if (mask==0xF0) val = *(ptrs++);
29167             const unsigned char color = (unsigned char)((mask<16)?(val&mask):((val&mask)>>4));
29168             unsigned char *col = (unsigned char*)(palette+color);
29169             (*this)(x,y,2) = (T)*(col++);
29170             (*this)(x,y,1) = (T)*(col++);
29171             (*this)(x,y,0) = (T)*(col++);
29172             mask = cimg::ror(mask,4);
29173           } ptrs+=align; }
29174       } break;
29175       case 8 : { //  256 colors
29176         for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
29177           const unsigned char *col = (unsigned char*)(palette+*(ptrs++));
29178           (*this)(x,y,2) = (T)*(col++);
29179           (*this)(x,y,1) = (T)*(col++);
29180           (*this)(x,y,0) = (T)*(col++);
29181         } ptrs+=align; }
29182       } break;
29183       case 16 : { // 16 bits colors
29184         for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
29185           const unsigned char c1 = *(ptrs++), c2 = *(ptrs++);
29186           const unsigned short col = (unsigned short)(c1|(c2<<8));
29187           (*this)(x,y,2) = (T)(col&0x1F);
29188           (*this)(x,y,1) = (T)((col>>5)&0x1F);
29189           (*this)(x,y,0) = (T)((col>>10)&0x1F);
29190         } ptrs+=align; }
29191       } break;
29192       case 24 : { // 24 bits colors
29193         for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
29194           (*this)(x,y,2) = (T)*(ptrs++);
29195           (*this)(x,y,1) = (T)*(ptrs++);
29196           (*this)(x,y,0) = (T)*(ptrs++);
29197         } ptrs+=align; }
29198       } break;
29199       case 32 : { // 32 bits colors
29200         for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
29201           (*this)(x,y,2) = (T)*(ptrs++);
29202           (*this)(x,y,1) = (T)*(ptrs++);
29203           (*this)(x,y,0) = (T)*(ptrs++);
29204           ++ptrs;
29205         } ptrs+=align; }
29206       } break;
29207       }
29208       if (palette) delete[] palette;
29209       delete[] buffer;
29210       if (dy<0) mirror('y');
29211       return *this;
29212     }
29213 
29214     //! Load an image from a JPEG file.
29215     CImg<T>& load_jpeg(const char *const filename) {
29216       return _load_jpeg(0,filename);
29217     }
29218 
29219     static CImg<T> get_load_jpeg(const char *const filename) {
29220       return CImg<T>().load_jpeg(filename);
29221     }
29222 
29223     //! Load an image from a JPEG file.
29224     CImg<T>& load_jpeg(cimg_std::FILE *const file) {
29225       return _load_jpeg(file,0);
29226     }
29227 
29228     static CImg<T> get_load_jpeg(cimg_std::FILE *const file) {
29229       return CImg<T>().load_jpeg(file);
29230     }
29231 
29232     CImg<T>& _load_jpeg(cimg_std::FILE *const file, const char *const filename) {
29233       if (!filename && !file)
29234         throw CImgArgumentException("CImg<%s>::load_jpeg() : Cannot load (null) filename.",
29235                                     pixel_type());
29236 #ifndef cimg_use_jpeg
29237       if (file)
29238         throw CImgIOException("CImg<%s>::load_jpeg() : File '(FILE*)' cannot be read without using libjpeg.",
29239                               pixel_type());
29240       else return load_other(filename);
29241 #else
29242       struct jpeg_decompress_struct cinfo;
29243       struct jpeg_error_mgr jerr;
29244       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29245 
29246       cinfo.err = jpeg_std_error(&jerr);
29247       jpeg_create_decompress(&cinfo);
29248       jpeg_stdio_src(&cinfo,nfile);
29249       jpeg_read_header(&cinfo,TRUE);
29250       jpeg_start_decompress(&cinfo);
29251 
29252       if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) {
29253         cimg::warn("CImg<%s>::load_jpeg() : Don't know how to read image '%s' with libpeg, trying ImageMagick's convert",
29254                    pixel_type(),filename?filename:"(FILE*)");
29255         if (!file) return load_other(filename);
29256         else {
29257           if (!file) cimg::fclose(nfile);
29258           throw CImgIOException("CImg<%s>::load_jpeg() : Cannot read JPEG image '%s' using a *FILE input.",
29259                                 pixel_type(),filename?filename:"(FILE*)");
29260         }
29261       }
29262 
29263       const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
29264       unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components], *buf2 = buf;
29265       JSAMPROW row_pointer[1];
29266       while (cinfo.output_scanline < cinfo.output_height) {
29267         row_pointer[0] = &buf[cinfo.output_scanline*row_stride];
29268         jpeg_read_scanlines(&cinfo,row_pointer,1);
29269       }
29270       jpeg_finish_decompress(&cinfo);
29271       jpeg_destroy_decompress(&cinfo);
29272       if (!file) cimg::fclose(nfile);
29273 
29274       assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components);
29275       switch (dim) {
29276       case 1 : {
29277         T *ptr_g = data;
29278         cimg_forXY(*this,x,y) *(ptr_g++) = (T)*(buf2++);
29279       } break;
29280       case 3 : {
29281         T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
29282         cimg_forXY(*this,x,y) {
29283           *(ptr_r++) = (T)*(buf2++);
29284           *(ptr_g++) = (T)*(buf2++);
29285           *(ptr_b++) = (T)*(buf2++);
29286         }
29287       } break;
29288       case 4 : {
29289         T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1),
29290           *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3);
29291         cimg_forXY(*this,x,y) {
29292           *(ptr_r++) = (T)*(buf2++);
29293           *(ptr_g++) = (T)*(buf2++);
29294           *(ptr_b++) = (T)*(buf2++);
29295           *(ptr_a++) = (T)*(buf2++);
29296         }
29297       } break;
29298       }
29299       delete[] buf;
29300       return *this;
29301 #endif
29302     }
29303 
29304     //! Load an image from a file, using Magick++ library.
29305     // Added April/may 2006 by Christoph Hormann <chris_hormann@gmx.de>
29306     //   This is experimental code, not much tested, use with care.
29307     CImg<T>& load_magick(const char *const filename) {
29308       if (!filename)
29309         throw CImgArgumentException("CImg<%s>::load_magick() : Cannot load (null) filename.",
29310                                     pixel_type());
29311 #ifdef cimg_use_magick
29312       Magick::Image image(filename);
29313       const unsigned int W = image.size().width(), H = image.size().height();
29314       switch (image.type()) {
29315       case Magick::PaletteMatteType :
29316       case Magick::TrueColorMatteType :
29317       case Magick::ColorSeparationType : {
29318         assign(W,H,1,4);
29319         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);
29320         Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29321         for (unsigned int off = W*H; off; --off) {
29322           *(rdata++) = (T)(pixels->red);
29323           *(gdata++) = (T)(pixels->green);
29324           *(bdata++) = (T)(pixels->blue);
29325           *(adata++) = (T)(pixels->opacity);
29326           ++pixels;
29327         }
29328       } break;
29329       case Magick::PaletteType :
29330       case Magick::TrueColorType : {
29331         assign(W,H,1,3);
29332         T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
29333         Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29334         for (unsigned int off = W*H; off; --off) {
29335           *(rdata++) = (T)(pixels->red);
29336           *(gdata++) = (T)(pixels->green);
29337           *(bdata++) = (T)(pixels->blue);
29338           ++pixels;
29339         }
29340       } break;
29341       case Magick::GrayscaleMatteType : {
29342         assign(W,H,1,2);
29343         T *data = ptr(0,0,0,0), *adata = ptr(0,0,0,1);
29344         Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29345         for (unsigned int off = W*H; off; --off) {
29346           *(data++) = (T)(pixels->red);
29347           *(adata++) = (T)(pixels->opacity);
29348           ++pixels;
29349         }
29350       } break;
29351       default : {
29352         assign(W,H,1,1);
29353         T *data = ptr(0,0,0,0);
29354         Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29355         for (unsigned int off = W*H; off; --off) {
29356           *(data++) = (T)(pixels->red);
29357           ++pixels;
29358         }
29359       }
29360       }
29361 #else
29362       throw CImgIOException("CImg<%s>::load_magick() : File '%s', Magick++ library has not been linked.",
29363                             pixel_type(),filename);
29364 #endif
29365       return *this;
29366     }
29367 
29368     static CImg<T> get_load_magick(const char *const filename) {
29369       return CImg<T>().load_magick(filename);
29370     }
29371 
29372     //! Load an image from a PNG file.
29373     CImg<T>& load_png(const char *const filename) {
29374       return _load_png(0,filename);
29375     }
29376 
29377     static CImg<T> get_load_png(const char *const filename) {
29378       return CImg<T>().load_png(filename);
29379     }
29380 
29381     //! Load an image from a PNG file.
29382     CImg<T>& load_png(cimg_std::FILE *const file) {
29383       return _load_png(file,0);
29384     }
29385 
29386     static CImg<T> get_load_png(cimg_std::FILE *const file) {
29387       return CImg<T>().load_png(file);
29388     }
29389 
29390     // (Note : Most of this function has been written by Eric Fausett)
29391     CImg<T>& _load_png(cimg_std::FILE *const file, const char *const filename) {
29392       if (!filename && !file)
29393         throw CImgArgumentException("CImg<%s>::load_png() : Cannot load (null) filename.",
29394                                     pixel_type());
29395 #ifndef cimg_use_png
29396       if (file)
29397         throw CImgIOException("CImg<%s>::load_png() : File '(FILE*)' cannot be read without using libpng.",
29398                               pixel_type());
29399       else return load_other(filename);
29400 #else
29401       // Open file and check for PNG validity
29402       const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
29403       cimg_std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb");
29404 
29405       unsigned char pngCheck[8];
29406       cimg::fread(pngCheck,8,(cimg_std::FILE*)nfile);
29407       if (png_sig_cmp(pngCheck,0,8)) {
29408         if (!file) cimg::fclose(nfile);
29409         throw CImgIOException("CImg<%s>::load_png() : File '%s' is not a valid PNG file.",
29410                               pixel_type(),nfilename?nfilename:"(FILE*)");
29411       }
29412 
29413       // Setup PNG structures for read
29414       png_voidp user_error_ptr = 0;
29415       png_error_ptr user_error_fn = 0, user_warning_fn = 0;
29416       png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn);
29417       if (!png_ptr) {
29418         if (!file) cimg::fclose(nfile);
29419         throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'png_ptr' data structure.",
29420                               pixel_type(),nfilename?nfilename:"(FILE*)");
29421       }
29422       png_infop info_ptr = png_create_info_struct(png_ptr);
29423       if (!info_ptr) {
29424         if (!file) cimg::fclose(nfile);
29425         png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0);
29426         throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'info_ptr' data structure.",
29427                               pixel_type(),nfilename?nfilename:"(FILE*)");
29428       }
29429       png_infop end_info = png_create_info_struct(png_ptr);
29430       if (!end_info) {
29431         if (!file) cimg::fclose(nfile);
29432         png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0);
29433         throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'end_info' data structure.",
29434                               pixel_type(),nfilename?nfilename:"(FILE*)");
29435       }
29436 
29437       // Error handling callback for png file reading
29438       if (setjmp(png_jmpbuf(png_ptr))) {
29439         if (!file) cimg::fclose((cimg_std::FILE*)nfile);
29440         png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
29441         throw CImgIOException("CImg<%s>::load_png() : File '%s', unknown fatal error.",
29442                               pixel_type(),nfilename?nfilename:"(FILE*)");
29443       }
29444       png_init_io(png_ptr, nfile);
29445       png_set_sig_bytes(png_ptr, 8);
29446 
29447       // Get PNG Header Info up to data block
29448       png_read_info(png_ptr,info_ptr);
29449       png_uint_32 W, H;
29450       int bit_depth, color_type, interlace_type;
29451       png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,int_p_NULL,int_p_NULL);
29452       int new_bit_depth = bit_depth;
29453       int new_color_type = color_type;
29454 
29455       // Transforms to unify image data
29456       if (new_color_type == PNG_COLOR_TYPE_PALETTE){
29457         png_set_palette_to_rgb(png_ptr);
29458         new_color_type -= PNG_COLOR_MASK_PALETTE;
29459         new_bit_depth = 8;
29460       }
29461       if (new_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){
29462         png_set_gray_1_2_4_to_8(png_ptr);
29463         new_bit_depth = 8;
29464       }
29465       if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
29466         png_set_tRNS_to_alpha(png_ptr);
29467       if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){
29468         png_set_gray_to_rgb(png_ptr);
29469         new_color_type |= PNG_COLOR_MASK_COLOR;
29470       }
29471       if (new_color_type == PNG_COLOR_TYPE_RGB)
29472         png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);
29473       png_read_update_info(png_ptr,info_ptr);
29474       if (!(new_bit_depth==8 || new_bit_depth==16)) {
29475         if (!file) cimg::fclose(nfile);
29476         png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
29477         throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong bit coding (bit_depth=%u)",
29478                               pixel_type(),nfilename?nfilename:"(FILE*)",new_bit_depth);
29479       }
29480       const int byte_depth = new_bit_depth>>3;
29481 
29482       // Allocate Memory for Image Read
29483       png_bytep *imgData = new png_bytep[H];
29484       for (unsigned int row = 0; row<H; ++row) imgData[row] = new png_byte[byte_depth*4*W];
29485       png_read_image(png_ptr,imgData);
29486       png_read_end(png_ptr,end_info);
29487 
29488       // Read pixel data
29489       if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA)) {
29490         if (!file) cimg::fclose(nfile);
29491         png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);
29492         throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong color coding (new_color_type=%u)",
29493                               pixel_type(),nfilename?nfilename:"(FILE*)",new_color_type);
29494       }
29495       const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB);
29496       assign(W,H,1,no_alpha_channel?3:4);
29497       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);
29498       switch (new_bit_depth) {
29499       case 8 : {
29500         cimg_forY(*this,y){
29501           const unsigned char *ptrs = (unsigned char*)imgData[y];
29502           cimg_forX(*this,x){
29503             *(ptr1++) = (T)*(ptrs++);
29504             *(ptr2++) = (T)*(ptrs++);
29505             *(ptr3++) = (T)*(ptrs++);
29506             if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
29507           }
29508         }
29509       } break;
29510       case 16 : {
29511         cimg_forY(*this,y){
29512           const unsigned short *ptrs = (unsigned short*)(imgData[y]);
29513           if (!cimg::endianness()) cimg::invert_endianness(ptrs,4*width);
29514           cimg_forX(*this,x){
29515             *(ptr1++) = (T)*(ptrs++);
29516             *(ptr2++) = (T)*(ptrs++);
29517             *(ptr3++) = (T)*(ptrs++);
29518             if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
29519           }
29520         }
29521       } break;
29522       }
29523       png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
29524 
29525       // Deallocate Image Read Memory
29526       cimg_forY(*this,n) delete[] imgData[n];
29527       delete[] imgData;
29528       if (!file) cimg::fclose(nfile);
29529       return *this;
29530 #endif
29531     }
29532 
29533     //! Load an image from a PNM file.
29534     CImg<T>& load_pnm(const char *const filename) {
29535       return _load_pnm(0,filename);
29536     }
29537 
29538     static CImg<T> get_load_pnm(const char *const filename) {
29539       return CImg<T>().load_pnm(filename);
29540     }
29541 
29542     //! Load an image from a PNM file.
29543     CImg<T>& load_pnm(cimg_std::FILE *const file) {
29544       return _load_pnm(file,0);
29545     }
29546 
29547     static CImg<T> get_load_pnm(cimg_std::FILE *const file) {
29548       return CImg<T>().load_pnm(file);
29549     }
29550 
29551     CImg<T>& _load_pnm(cimg_std::FILE *const file, const char *const filename) {
29552       if (!filename && !file)
29553         throw CImgArgumentException("CImg<%s>::load_pnm() : Cannot load (null) filename.",
29554                                     pixel_type());
29555       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29556       unsigned int ppm_type, W, H, colormax = 255;
29557       char item[1024] = { 0 };
29558       int err, rval, gval, bval;
29559       const int cimg_iobuffer = 12*1024*1024;
29560       while ((err=cimg_std::fscanf(nfile,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
29561       if (cimg_std::sscanf(item," P%u",&ppm_type)!=1) {
29562         if (!file) cimg::fclose(nfile);
29563         throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PNM header 'P?' not found.",
29564                               pixel_type(),filename?filename:"(FILE*)");
29565       }
29566       while ((err=cimg_std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
29567       if ((err=cimg_std::sscanf(item," %u %u %u",&W,&H,&colormax))<2) {
29568         if (!file) cimg::fclose(nfile);
29569         throw CImgIOException("CImg<%s>::load_pnm() : File '%s', WIDTH and HEIGHT fields are not defined in PNM header.",
29570                               pixel_type(),filename?filename:"(FILE*)");
29571       }
29572       if (err==2) {
29573         while ((err=cimg_std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
29574         if (cimg_std::sscanf(item,"%u",&colormax)!=1)
29575           cimg::warn("CImg<%s>::load_pnm() : File '%s', COLORMAX field is not defined in PNM header.",
29576                      pixel_type(),filename?filename:"(FILE*)");
29577       }
29578       cimg_std::fgetc(nfile);
29579       assign();
29580 
29581       switch (ppm_type) {
29582       case 2 : { // Grey Ascii
29583         assign(W,H,1,1);
29584         T* rdata = data;
29585         cimg_foroff(*this,off) { if (cimg_std::fscanf(nfile,"%d",&rval)>0) *(rdata++) = (T)rval; else break; }
29586       } break;
29587       case 3 : { // Color Ascii
29588         assign(W,H,1,3);
29589         T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
29590         cimg_forXY(*this,x,y) {
29591           if (cimg_std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval)==3) { *(rdata++) = (T)rval; *(gdata++) = (T)gval; *(bdata++) = (T)bval; }
29592           else break;
29593         }
29594       } break;
29595       case 5 : { // Grey Binary
29596         if (colormax<256) { // 8 bits
29597           CImg<ucharT> raw;
29598           assign(W,H,1,1);
29599           T *ptrd = ptr(0,0,0,0);
29600           for (int toread = (int)size(); toread>0; ) {
29601             raw.assign(cimg::min(toread,cimg_iobuffer));
29602             cimg::fread(raw.data,raw.width,nfile);
29603             toread-=raw.width;
29604             const unsigned char *ptrs = raw.data;
29605             for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
29606           }
29607         } else { // 16 bits
29608           CImg<ushortT> raw;
29609           assign(W,H,1,1);
29610           T *ptrd = ptr(0,0,0,0);
29611           for (int toread = (int)size(); toread>0; ) {
29612             raw.assign(cimg::min(toread,cimg_iobuffer/2));
29613             cimg::fread(raw.data,raw.width,nfile);
29614             if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
29615             toread-=raw.width;
29616             const unsigned short *ptrs = raw.data;
29617             for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
29618           }
29619         }
29620       } break;
29621       case 6 : { // Color Binary
29622         if (colormax<256) { // 8 bits
29623           CImg<ucharT> raw;
29624           assign(W,H,1,3);
29625           T
29626             *ptr_r = ptr(0,0,0,0),
29627             *ptr_g = ptr(0,0,0,1),
29628             *ptr_b = ptr(0,0,0,2);
29629           for (int toread = (int)size(); toread>0; ) {
29630             raw.assign(cimg::min(toread,cimg_iobuffer));
29631             cimg::fread(raw.data,raw.width,nfile);
29632             toread-=raw.width;
29633             const unsigned char *ptrs = raw.data;
29634             for (unsigned int off = raw.width/3; off; --off) {
29635               *(ptr_r++) = (T)*(ptrs++);
29636               *(ptr_g++) = (T)*(ptrs++);
29637               *(ptr_b++) = (T)*(ptrs++);
29638             }
29639           }
29640         } else { // 16 bits
29641           CImg<ushortT> raw;
29642           assign(W,H,1,3);
29643           T
29644             *ptr_r = ptr(0,0,0,0),
29645             *ptr_g = ptr(0,0,0,1),
29646             *ptr_b = ptr(0,0,0,2);
29647           for (int toread = (int)size(); toread>0; ) {
29648             raw.assign(cimg::min(toread,cimg_iobuffer/2));
29649             cimg::fread(raw.data,raw.width,nfile);
29650             if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
29651             toread-=raw.width;
29652             const unsigned short *ptrs = raw.data;
29653             for (unsigned int off = raw.width/3; off; --off) {
29654               *(ptr_r++) = (T)*(ptrs++);
29655               *(ptr_g++) = (T)*(ptrs++);
29656               *(ptr_b++) = (T)*(ptrs++);
29657             }
29658           }
29659         }
29660       } break;
29661       default :
29662         if (!file) cimg::fclose(nfile);
29663         throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PPM type 'P%d' not supported.",
29664                               pixel_type(),filename?filename:"(FILE*)",ppm_type);
29665       }
29666       if (!file) cimg::fclose(nfile);
29667       return *this;
29668     }
29669 
29670     //! Load an image from a RGB file.
29671     CImg<T>& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
29672       return _load_rgb(0,filename,dimw,dimh);
29673     }
29674 
29675     static CImg<T> get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
29676       return CImg<T>().load_rgb(filename,dimw,dimh);
29677     }
29678 
29679     //! Load an image from a RGB file.
29680     CImg<T>& load_rgb(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
29681       return _load_rgb(file,0,dimw,dimh);
29682     }
29683 
29684     static CImg<T> get_load_rgb(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
29685       return CImg<T>().load_rgb(file,dimw,dimh);
29686     }
29687 
29688     CImg<T>& _load_rgb(cimg_std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
29689       if (!filename && !file)
29690         throw CImgArgumentException("CImg<%s>::load_rgb() : Cannot load (null) filename.",
29691                                     pixel_type());
29692       if (!dimw || !dimh) return assign();
29693       const int cimg_iobuffer = 12*1024*1024;
29694       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29695       CImg<ucharT> raw;
29696       assign(dimw,dimh,1,3);
29697       T
29698         *ptr_r = ptr(0,0,0,0),
29699         *ptr_g = ptr(0,0,0,1),
29700         *ptr_b = ptr(0,0,0,2);
29701       for (int toread = (int)size(); toread>0; ) {
29702         raw.assign(cimg::min(toread,cimg_iobuffer));
29703         cimg::fread(raw.data,raw.width,nfile);
29704         toread-=raw.width;
29705         const unsigned char *ptrs = raw.data;
29706         for (unsigned int off = raw.width/3; off; --off) {
29707           *(ptr_r++) = (T)*(ptrs++);
29708           *(ptr_g++) = (T)*(ptrs++);
29709           *(ptr_b++) = (T)*(ptrs++);
29710         }
29711       }
29712       if (!file) cimg::fclose(nfile);
29713       return *this;
29714     }
29715 
29716     //! Load an image from a RGBA file.
29717     CImg<T>& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
29718       return _load_rgba(0,filename,dimw,dimh);
29719     }
29720 
29721     static CImg<T> get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
29722       return CImg<T>().load_rgba(filename,dimw,dimh);
29723     }
29724 
29725     //! Load an image from a RGBA file.
29726     CImg<T>& load_rgba(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
29727       return _load_rgba(file,0,dimw,dimh);
29728     }
29729 
29730     static CImg<T> get_load_rgba(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
29731       return CImg<T>().load_rgba(file,dimw,dimh);
29732     }
29733 
29734     CImg<T>& _load_rgba(cimg_std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
29735       if (!filename && !file)
29736         throw CImgArgumentException("CImg<%s>::load_rgba() : Cannot load (null) filename.",
29737                                     pixel_type());
29738       if (!dimw || !dimh) return assign();
29739       const int cimg_iobuffer = 12*1024*1024;
29740       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29741       CImg<ucharT> raw;
29742       assign(dimw,dimh,1,4);
29743       T
29744         *ptr_r = ptr(0,0,0,0),
29745         *ptr_g = ptr(0,0,0,1),
29746         *ptr_b = ptr(0,0,0,2),
29747         *ptr_a = ptr(0,0,0,3);
29748       for (int toread = (int)size(); toread>0; ) {
29749         raw.assign(cimg::min(toread,cimg_iobuffer));
29750         cimg::fread(raw.data,raw.width,nfile);
29751         toread-=raw.width;
29752         const unsigned char *ptrs = raw.data;
29753         for (unsigned int off = raw.width/4; off; --off) {
29754           *(ptr_r++) = (T)*(ptrs++);
29755           *(ptr_g++) = (T)*(ptrs++);
29756           *(ptr_b++) = (T)*(ptrs++);
29757           *(ptr_a++) = (T)*(ptrs++);
29758         }
29759       }
29760       if (!file) cimg::fclose(nfile);
29761       return *this;
29762     }
29763 
29764     //! Load an image from a TIFF file.
29765     CImg<T>& load_tiff(const char *const filename,
29766                        const unsigned int first_frame=0, const unsigned int last_frame=~0U,
29767                        const unsigned int step_frame=1) {
29768       if (!filename)
29769         throw CImgArgumentException("CImg<%s>::load_tiff() : Cannot load (null) filename.",
29770                                     pixel_type());
29771       const unsigned int
29772         nfirst_frame = first_frame<last_frame?first_frame:last_frame,
29773         nstep_frame = step_frame?step_frame:1;
29774       unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
29775 
29776 #ifndef cimg_use_tiff
29777       if (nfirst_frame || nlast_frame!=~0U || nstep_frame>1)
29778         throw CImgArgumentException("CImg<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
29779                                     "('cimg_use_tiff' must be defined).",
29780                                     pixel_type(),filename);
29781       return load_other(filename);
29782 #else
29783       TIFF *tif = TIFFOpen(filename,"r");
29784       if (tif) {
29785         unsigned int nb_images = 0;
29786         do ++nb_images; while (TIFFReadDirectory(tif));
29787         if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
29788           cimg::warn("CImg<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
29789                      pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
29790         if (nfirst_frame>=nb_images) return assign();
29791         if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
29792         TIFFSetDirectory(tif,0);
29793         CImg<T> frame;
29794         for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) {
29795           frame._load_tiff(tif,l);
29796           if (l==nfirst_frame) assign(frame.width,frame.height,1+(nlast_frame-nfirst_frame)/nstep_frame,frame.dim);
29797           if (frame.width>width || frame.height>height || frame.dim>dim)
29798             resize(cimg::max(frame.width,width),cimg::max(frame.height,height),-100,cimg::max(frame.dim,dim),0);
29799           draw_image(0,0,(l-nfirst_frame)/nstep_frame,frame);
29800         }
29801         TIFFClose(tif);
29802       } else throw CImgException("CImg<%s>::load_tiff() : File '%s' cannot be opened.",
29803                                  pixel_type(),filename);
29804       return *this;
29805 #endif
29806     }
29807 
29808     static CImg<T> get_load_tiff(const char *const filename,
29809                                  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
29810                                  const unsigned int step_frame=1) {
29811       return CImg<T>().load_tiff(filename,first_frame,last_frame,step_frame);
29812     }
29813 
29814     // (Original contribution by Jerome Boulanger).
29815 #ifdef cimg_use_tiff
29816     CImg<T>& _load_tiff(TIFF *tif, const unsigned int directory) {
29817       if (!TIFFSetDirectory(tif,directory)) return assign();
29818       uint16 samplesperpixel, bitspersample;
29819       uint32 nx,ny;
29820       const char *const filename = TIFFFileName(tif);
29821       TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx);
29822       TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny);
29823       TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel);
29824       if (samplesperpixel!=1 && samplesperpixel!=3 && samplesperpixel!=4) {
29825         cimg::warn("CImg<%s>::load_tiff() : File '%s', unknow value for tag : TIFFTAG_SAMPLESPERPIXEL, will force it to 1.",
29826                    pixel_type(),filename);
29827         samplesperpixel = 1;
29828       }
29829       TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample);
29830       assign(nx,ny,1,samplesperpixel);
29831       if (bitspersample!=8 || !(samplesperpixel==3 || samplesperpixel==4)) {
29832         uint16 photo, config;
29833         TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config);
29834         TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo);
29835         if (TIFFIsTiled(tif)) {
29836           uint32 tw, th;
29837           TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw);
29838           TIFFGetField(tif,TIFFTAG_TILELENGTH,&th);
29839           if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
29840             case 8 : {
29841               unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
29842               if (buf) {
29843                 for (unsigned int row = 0; row<ny; row+=th)
29844                   for (unsigned int col = 0; col<nx; col+=tw) {
29845                     if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
29846                       _TIFFfree(buf); TIFFClose(tif);
29847                       throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occurred while reading a tile.",
29848                                           pixel_type(),filename);
29849                     } else {
29850                       unsigned char *ptr = buf;
29851                       for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29852                         for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29853                           for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29854                             (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
29855                     }
29856                   }
29857                 _TIFFfree(buf);
29858               }
29859             } break;
29860             case 16 : {
29861               unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
29862               if (buf) {
29863                 for (unsigned int row = 0; row<ny; row+=th)
29864                   for (unsigned int col = 0; col<nx; col+=tw) {
29865                     if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
29866                       _TIFFfree(buf); TIFFClose(tif);
29867                       throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occurred while reading a tile.",
29868                                           pixel_type(),filename);
29869                     } else {
29870                       unsigned short *ptr = buf;
29871                       for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29872                         for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29873                           for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29874                             (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
29875                     }
29876                   }
29877                 _TIFFfree(buf);
29878               }
29879             } break;
29880             case 32 : {
29881               float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
29882               if (buf) {
29883                 for (unsigned int row = 0; row<ny; row+=th)
29884                   for (unsigned int col = 0; col<nx; col+=tw) {
29885                     if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
29886                       _TIFFfree(buf); TIFFClose(tif);
29887                       throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occurred while reading a tile.",
29888                                           pixel_type(),filename);
29889                     } else {
29890                       float *ptr = buf;
29891                       for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29892                         for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29893                           for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29894                             (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
29895                     }
29896                   }
29897                 _TIFFfree(buf);
29898               }
29899             } break;
29900             } else switch (bitspersample) {
29901             case 8 : {
29902               unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
29903               if (buf) {
29904                 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29905                   for (unsigned int row = 0; row<ny; row+=th)
29906                     for (unsigned int col = 0; col<nx; col+=tw) {
29907                       if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
29908                         _TIFFfree(buf); TIFFClose(tif);
29909                         throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occurred while reading a tile.",
29910                                             pixel_type(),filename);
29911                       } else {
29912                         unsigned char *ptr = buf;
29913                         for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29914                           for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29915                             (*this)(cc,rr,vv) = (T)(float)*(ptr++);
29916                       }
29917                     }
29918                 _TIFFfree(buf);
29919               }
29920             } break;
29921             case 16 : {
29922               unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
29923               if (buf) {
29924                 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29925                   for (unsigned int row = 0; row<ny; row+=th)
29926                     for (unsigned int col = 0; col<nx; col+=tw) {
29927                       if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
29928                         _TIFFfree(buf); TIFFClose(tif);
29929                         throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occurred while reading a tile.",
29930                                             pixel_type(),filename);
29931                       } else {
29932                         unsigned short *ptr = buf;
29933                         for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29934                           for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29935                             (*this)(cc,rr,vv) = (T)(float)*(ptr++);
29936                       }
29937                     }
29938                 _TIFFfree(buf);
29939               }
29940             } break;
29941             case 32 : {
29942               float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
29943               if (buf) {
29944                 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29945                   for (unsigned int row = 0; row<ny; row+=th)
29946                     for (unsigned int col = 0; col<nx; col+=tw) {
29947                       if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
29948                         _TIFFfree(buf); TIFFClose(tif);
29949                         throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occurred while reading a tile.",
29950                                             pixel_type(),filename);
29951                       } else {
29952                         float *ptr = buf;
29953                         for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29954                           for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29955                             (*this)(cc,rr,vv) = (T)(float)*(ptr++);
29956                       }
29957                     }
29958                 _TIFFfree(buf);
29959               }
29960             } break;
29961             }
29962         } else {
29963           if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
29964             case 8 : {
29965               unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
29966               if (buf) {
29967                 uint32 row, rowsperstrip = (uint32)-1;
29968                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
29969                 for (row = 0; row<ny; row+= rowsperstrip) {
29970                   uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
29971                   tstrip_t strip = TIFFComputeStrip(tif, row, 0);
29972                   if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
29973                     _TIFFfree(buf); TIFFClose(tif);
29974                     throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occurred while reading a strip.",
29975                                         pixel_type(),filename);
29976                   }
29977                   unsigned char *ptr = buf;
29978                   for (unsigned int rr = 0; rr<nrow; ++rr)
29979                     for (unsigned int cc = 0; cc<nx; ++cc)
29980                       for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
29981                 }
29982                 _TIFFfree(buf);
29983               }
29984             } break;
29985             case 16 : {
29986               unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
29987               if (buf) {
29988                 uint32 row, rowsperstrip = (uint32)-1;
29989                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
29990                 for (row = 0; row<ny; row+= rowsperstrip) {
29991                   uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
29992                   tstrip_t strip = TIFFComputeStrip(tif, row, 0);
29993                   if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
29994                     _TIFFfree(buf); TIFFClose(tif);
29995                     throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
29996                                         pixel_type(),filename);
29997                   }
29998                   unsigned short *ptr = buf;
29999                   for (unsigned int rr = 0; rr<nrow; ++rr)
30000                     for (unsigned int cc = 0; cc<nx; ++cc)
30001                       for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30002                 }
30003                 _TIFFfree(buf);
30004               }
30005             } break;
30006             case 32 : {
30007               float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
30008               if (buf) {
30009                 uint32 row, rowsperstrip = (uint32)-1;
30010                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30011                 for (row = 0; row<ny; row+= rowsperstrip) {
30012                   uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30013                   tstrip_t strip = TIFFComputeStrip(tif, row, 0);
30014                   if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30015                     _TIFFfree(buf); TIFFClose(tif);
30016                     throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
30017                                         pixel_type(),filename);
30018                   }
30019                   float *ptr = buf;
30020                   for (unsigned int rr = 0; rr<nrow; ++rr)
30021                     for (unsigned int cc = 0; cc<nx; ++cc)
30022                       for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30023                 }
30024                 _TIFFfree(buf);
30025               }
30026             } break;
30027             } else switch (bitspersample){
30028             case 8 : {
30029               unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
30030               if (buf) {
30031                 uint32 row, rowsperstrip = (uint32)-1;
30032                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30033                 for (unsigned int vv=0; vv<samplesperpixel; ++vv)
30034                   for (row = 0; row<ny; row+= rowsperstrip) {
30035                     uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30036                     tstrip_t strip = TIFFComputeStrip(tif, row, vv);
30037                     if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30038                       _TIFFfree(buf); TIFFClose(tif);
30039                       throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occurred while reading a strip.",
30040                                           pixel_type(),filename);
30041                     }
30042                     unsigned char *ptr = buf;
30043                     for (unsigned int rr = 0;rr<nrow; ++rr)
30044                       for (unsigned int cc = 0; cc<nx; ++cc)
30045                         (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30046                   }
30047                 _TIFFfree(buf);
30048               }
30049             } break;
30050             case 16 : {
30051               unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
30052               if (buf) {
30053                 uint32 row, rowsperstrip = (uint32)-1;
30054                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30055                 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30056                   for (row = 0; row<ny; row+= rowsperstrip) {
30057                     uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30058                     tstrip_t strip = TIFFComputeStrip(tif, row, vv);
30059                     if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30060                       _TIFFfree(buf); TIFFClose(tif);
30061                       throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
30062                                           pixel_type(),filename);
30063                     }
30064                     unsigned short *ptr = buf;
30065                     for (unsigned int rr = 0; rr<nrow; ++rr)
30066                       for (unsigned int cc = 0; cc<nx; ++cc)
30067                         (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30068                   }
30069                 _TIFFfree(buf);
30070               }
30071             } break;
30072             case 32 : {
30073               float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
30074               if (buf) {
30075                 uint32 row, rowsperstrip = (uint32)-1;
30076                 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30077                 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30078                   for (row = 0; row<ny; row+= rowsperstrip) {
30079                     uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30080                     tstrip_t strip = TIFFComputeStrip(tif, row, vv);
30081                     if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30082                       _TIFFfree(buf); TIFFClose(tif);
30083                       throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
30084                                           pixel_type(),filename);
30085                     }
30086                     float *ptr = buf;
30087                     for (unsigned int rr = 0; rr<nrow; ++rr)  for (unsigned int cc = 0; cc<nx; ++cc)
30088                         (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30089                   }
30090                 _TIFFfree(buf);
30091               }
30092             } break;
30093             }
30094         }
30095       } else {
30096         uint32* raster = (uint32*)_TIFFmalloc(nx * ny * sizeof (uint32));
30097         if (!raster) {
30098           _TIFFfree(raster); TIFFClose(tif);
30099           throw CImgException("CImg<%s>::load_tiff() : File '%s', not enough memory for buffer allocation.",
30100                               pixel_type(),filename);
30101         }
30102         TIFFReadRGBAImage(tif,nx,ny,raster,0);
30103         switch (samplesperpixel) {
30104         case 1 : {
30105           cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny-1-y)+x]+ 128) / 257);
30106         } break;
30107         case 3 : {
30108           cimg_forXY(*this,x,y) {
30109             (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
30110             (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
30111             (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
30112           }
30113         } break;
30114         case 4 : {
30115           cimg_forXY(*this,x,y) {
30116             (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
30117             (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
30118             (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
30119             (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny-1-y)+x]);
30120           }
30121         } break;
30122         }
30123         _TIFFfree(raster);
30124       }
30125       return *this;
30126     }
30127 #endif
30128 
30129     //! Load an image from an ANALYZE7.5/NIFTI file.
30130     CImg<T>& load_analyze(const char *const filename, float *const voxsize=0) {
30131       return _load_analyze(0,filename,voxsize);
30132     }
30133 
30134     static CImg<T> get_load_analyze(const char *const filename, float *const voxsize=0) {
30135       return CImg<T>().load_analyze(filename,voxsize);
30136     }
30137 
30138     //! Load an image from an ANALYZE7.5/NIFTI file.
30139     CImg<T>& load_analyze(cimg_std::FILE *const file, float *const voxsize=0) {
30140       return _load_analyze(file,0,voxsize);
30141     }
30142 
30143     static CImg<T> get_load_analyze(cimg_std::FILE *const file, float *const voxsize=0) {
30144       return CImg<T>().load_analyze(file,voxsize);
30145     }
30146 
30147     CImg<T>& _load_analyze(cimg_std::FILE *const file, const char *const filename, float *const voxsize=0) {
30148       if (!filename && !file)
30149         throw CImgArgumentException("CImg<%s>::load_analyze() : Cannot load (null) filename.",
30150                                     pixel_type());
30151       cimg_std::FILE *nfile_header = 0, *nfile = 0;
30152       if (!file) {
30153         char body[1024];
30154         const char *ext = cimg::split_filename(filename,body);
30155         if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file.
30156           nfile_header = cimg::fopen(filename,"rb");
30157           cimg_std::sprintf(body+cimg::strlen(body),".img");
30158           nfile = cimg::fopen(body,"rb");
30159         } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file.
30160           nfile = cimg::fopen(filename,"rb");
30161           cimg_std::sprintf(body+cimg::strlen(body),".hdr");
30162           nfile_header = cimg::fopen(body,"rb");
30163         } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file.
30164       } else nfile_header = nfile = file; // File is a Niftii file.
30165       if (!nfile || !nfile_header)
30166         throw CImgIOException("CImg<%s>::load_analyze() : File '%s', not recognized as an Analyze7.5 or NIFTI file.",
30167                               pixel_type(),filename?filename:"(FILE*)");
30168 
30169       // Read header.
30170       bool endian = false;
30171       unsigned int header_size;
30172       cimg::fread(&header_size,1,nfile_header);
30173       if (!header_size)
30174         throw CImgIOException("CImg<%s>::load_analyze() : File '%s', zero-sized header found.",
30175                               pixel_type(),filename?filename:"(FILE*)");
30176       if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); }
30177       unsigned char *header = new unsigned char[header_size];
30178       cimg::fread(header+4,header_size-4,nfile_header);
30179       if (!file && nfile_header!=nfile) cimg::fclose(nfile_header);
30180       if (endian) {
30181         cimg::invert_endianness((short*)(header+40),5);
30182         cimg::invert_endianness((short*)(header+70),1);
30183         cimg::invert_endianness((short*)(header+72),1);
30184         cimg::invert_endianness((float*)(header+76),4);
30185         cimg::invert_endianness((float*)(header+112),1);
30186       }
30187       unsigned short *dim = (unsigned short*)(header+40), dimx = 1, dimy = 1, dimz = 1, dimv = 1;
30188       if (!dim[0])
30189         cimg::warn("CImg<%s>::load_analyze() : File '%s', tells that image has zero dimensions.",
30190                    pixel_type(),filename?filename:"(FILE*)");
30191       if (dim[0]>4)
30192         cimg::warn("CImg<%s>::load_analyze() : File '%s', number of image dimension is %u, reading only the 4 first dimensions",
30193                    pixel_type(),filename?filename:"(FILE*)",dim[0]);
30194       if (dim[0]>=1) dimx = dim[1];
30195       if (dim[0]>=2) dimy = dim[2];
30196       if (dim[0]>=3) dimz = dim[3];
30197       if (dim[0]>=4) dimv = dim[4];
30198       float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
30199       const unsigned short datatype = *(short*)(header+70);
30200       if (voxsize) {
30201         const float *vsize = (float*)(header+76);
30202         voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3];
30203       }
30204       delete[] header;
30205 
30206       // Read pixel data.
30207       assign(dimx,dimy,dimz,dimv);
30208       switch (datatype) {
30209       case 2 : {
30210         unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
30211         cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30212         cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30213         delete[] buffer;
30214       } break;
30215       case 4 : {
30216         short *buffer = new short[dimx*dimy*dimz*dimv];
30217         cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30218         if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30219         cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30220         delete[] buffer;
30221       } break;
30222       case 8 : {
30223         int *buffer = new int[dimx*dimy*dimz*dimv];
30224         cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30225         if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30226         cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30227         delete[] buffer;
30228       } break;
30229       case 16 : {
30230         float *buffer = new float[dimx*dimy*dimz*dimv];
30231         cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30232         if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30233         cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30234         delete[] buffer;
30235       } break;
30236       case 64 : {
30237         double *buffer = new double[dimx*dimy*dimz*dimv];
30238         cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30239         if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30240         cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30241         delete[] buffer;
30242       } break;
30243       default :
30244         if (!file) cimg::fclose(nfile);
30245         throw CImgIOException("CImg<%s>::load_analyze() : File '%s', cannot read images with 'datatype = %d'",
30246                               pixel_type(),filename?filename:"(FILE*)",datatype);
30247       }
30248       if (!file) cimg::fclose(nfile);
30249       return *this;
30250     }
30251 
30252     //! Load an image (list) from a .cimg file.
30253     CImg<T>& load_cimg(const char *const filename, const char axis='z', const char align='p') {
30254       CImgList<T> list;
30255       list.load_cimg(filename);
30256       if (list.size==1) return list[0].transfer_to(*this);
30257       return assign(list.get_append(axis,align));
30258     }
30259 
30260     static CImg<T> get_load_cimg(const char *const filename, const char axis='z', const char align='p') {
30261       return CImg<T>().load_cimg(filename,axis,align);
30262     }
30263 
30264     //! Load an image (list) from a .cimg file.
30265     CImg<T>& load_cimg(cimg_std::FILE *const file, const char axis='z', const char align='p') {
30266       CImgList<T> list;
30267       list.load_cimg(file);
30268       if (list.size==1) return list[0].transfer_to(*this);
30269       return assign(list.get_append(axis,align));
30270     }
30271 
30272     static CImg<T> get_load_cimg(cimg_std::FILE *const file, const char axis='z', const char align='p') {
30273       return CImg<T>().load_cimg(file,axis,align);
30274     }
30275 
30276     //! Load a sub-image (list) from a .cimg file.
30277     CImg<T>& load_cimg(const char *const filename,
30278                        const unsigned int n0, const unsigned int n1,
30279                        const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30280                        const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30281                        const char axis='z', const char align='p') {
30282       CImgList<T> list;
30283       list.load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
30284       if (list.size==1) return list[0].transfer_to(*this);
30285       return assign(list.get_append(axis,align));
30286     }
30287 
30288     static CImg<T> get_load_cimg(const char *const filename,
30289                                  const unsigned int n0, const unsigned int n1,
30290                                  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30291                                  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30292                                  const char axis='z', const char align='p') {
30293       return CImg<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
30294     }
30295 
30296     //! Load a sub-image (list) from a non-compressed .cimg file.
30297     CImg<T>& load_cimg(cimg_std::FILE *const file,
30298                        const unsigned int n0, const unsigned int n1,
30299                        const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30300                        const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30301                        const char axis='z', const char align='p') {
30302       CImgList<T> list;
30303       list.load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
30304       if (list.size==1) return list[0].transfer_to(*this);
30305       return assign(list.get_append(axis,align));
30306     }
30307 
30308     static CImg<T> get_load_cimg(cimg_std::FILE *const file,
30309                                  const unsigned int n0, const unsigned int n1,
30310                                  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30311                                  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30312                                  const char axis='z', const char align='p') {
30313       return CImg<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
30314     }
30315 
30316     //! Load an image from an INRIMAGE-4 file.
30317     CImg<T>& load_inr(const char *const filename, float *const voxsize=0) {
30318       return _load_inr(0,filename,voxsize);
30319     }
30320 
30321     static CImg<T> get_load_inr(const char *const filename, float *const voxsize=0) {
30322       return CImg<T>().load_inr(filename,voxsize);
30323     }
30324 
30325     //! Load an image from an INRIMAGE-4 file.
30326     CImg<T>& load_inr(cimg_std::FILE *const file, float *const voxsize=0) {
30327       return _load_inr(file,0,voxsize);
30328     }
30329 
30330     static CImg<T> get_load_inr(cimg_std::FILE *const file, float *voxsize=0) {
30331       return CImg<T>().load_inr(file,voxsize);
30332     }
30333 
30334     // Load an image from an INRIMAGE-4 file (internal).
30335     static void _load_inr_header(cimg_std::FILE *file, int out[8], float *const voxsize) {
30336       char item[1024], tmp1[64], tmp2[64];
30337       out[0] = cimg_std::fscanf(file,"%63s",item);
30338       out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1;
30339       if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0)
30340         throw CImgIOException("CImg<%s>::load_inr() : File does not appear to be a valid INR file.\n"
30341                               "(INRIMAGE-4 identifier not found)",
30342                               pixel_type());
30343       while (cimg_std::fscanf(file," %63[^\n]%*c",item)!=EOF && cimg::strncmp(item,"##}",3)) {
30344         cimg_std::sscanf(item," XDIM%*[^0-9]%d",out);
30345         cimg_std::sscanf(item," YDIM%*[^0-9]%d",out+1);
30346         cimg_std::sscanf(item," ZDIM%*[^0-9]%d",out+2);
30347         cimg_std::sscanf(item," VDIM%*[^0-9]%d",out+3);
30348         cimg_std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6);
30349         if (voxsize) {
30350           cimg_std::sscanf(item," VX%*[^0-9.+-]%f",voxsize);
30351           cimg_std::sscanf(item," VY%*[^0-9.+-]%f",voxsize+1);
30352           cimg_std::sscanf(item," VZ%*[^0-9.+-]%f",voxsize+2);
30353         }
30354         if (cimg_std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1;
30355         switch (cimg_std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
30356         case 0 : break;
30357         case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; cimg_std::strcpy(tmp1,tmp2);
30358         case 1 :
30359           if (!cimg::strncasecmp(tmp1,"int",3)   || !cimg::strncasecmp(tmp1,"fixed",5))  out[4] = 0;
30360           if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1;
30361           if (!cimg::strncasecmp(tmp1,"packed",6))                                       out[4] = 2;
30362           if (out[4]>=0) break;
30363         default :
30364           throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2);
30365         }
30366       }
30367       if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
30368         throw CImgIOException("CImg<%s>::load_inr() : Bad dimensions in .inr file = ( %d , %d , %d , %d )",
30369                               pixel_type(),out[0],out[1],out[2],out[3]);
30370       if(out[4]<0 || out[5]<0)
30371         throw CImgIOException("CImg<%s>::load_inr() : TYPE is not fully defined",
30372                               pixel_type());
30373       if(out[6]<0)
30374         throw CImgIOException("CImg<%s>::load_inr() : PIXSIZE is not fully defined",
30375                               pixel_type());
30376       if(out[7]<0)
30377         throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type is not defined",
30378                               pixel_type());
30379     }
30380 
30381     CImg<T>& _load_inr(cimg_std::FILE *const file, const char *const filename, float *const voxsize) {
30382 #define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \
30383      if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \
30384         Ts *xval, *val = new Ts[fopt[0]*fopt[3]]; \
30385         cimg_forYZ(*this,y,z) { \
30386             cimg::fread(val,fopt[0]*fopt[3],nfile); \
30387             if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \
30388             xval = val; cimg_forX(*this,x) cimg_forV(*this,k) (*this)(x,y,z,k) = (T)*(xval++); \
30389           } \
30390         delete[] val; \
30391         loaded = true; \
30392       }
30393 
30394       if (!filename && !file)
30395         throw CImgArgumentException("CImg<%s>::load_inr() : Cannot load (null) filename.",
30396                                     pixel_type());
30397       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
30398       int fopt[8], endian=cimg::endianness()?1:0;
30399       bool loaded = false;
30400       if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1;
30401       _load_inr_header(nfile,fopt,voxsize);
30402       assign(fopt[0],fopt[1],fopt[2],fopt[3]);
30403       _cimg_load_inr_case(0,0,8, unsigned char);
30404       _cimg_load_inr_case(0,1,8, char);
30405       _cimg_load_inr_case(0,0,16,unsigned short);
30406       _cimg_load_inr_case(0,1,16,short);
30407       _cimg_load_inr_case(0,0,32,unsigned int);
30408       _cimg_load_inr_case(0,1,32,int);
30409       _cimg_load_inr_case(1,0,32,float);
30410       _cimg_load_inr_case(1,1,32,float);
30411       _cimg_load_inr_case(1,0,64,double);
30412       _cimg_load_inr_case(1,1,64,double);
30413       if (!loaded) {
30414         if (!file) cimg::fclose(nfile);
30415         throw CImgIOException("CImg<%s>::load_inr() : File '%s', cannot read images of the type specified in the file",
30416                               pixel_type(),filename?filename:"(FILE*)");
30417       }
30418       if (!file) cimg::fclose(nfile);
30419       return *this;
30420     }
30421 
30422     //! Load an image from a PANDORE file.
30423     CImg<T>& load_pandore(const char *const filename) {
30424       return _load_pandore(0,filename);
30425     }
30426 
30427     static CImg<T> get_load_pandore(const char *const filename) {
30428       return CImg<T>().load_pandore(filename);
30429     }
30430 
30431     //! Load an image from a PANDORE file.
30432     CImg<T>& load_pandore(cimg_std::FILE *const file) {
30433       return _load_pandore(file,0);
30434     }
30435 
30436     static CImg<T> get_load_pandore(cimg_std::FILE *const file) {
30437       return CImg<T>().load_pandore(file);
30438     }
30439 
30440     CImg<T>& _load_pandore(cimg_std::FILE *const file, const char *const filename) {
30441 #define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \
30442         cimg::fread(dims,nbdim,nfile); \
30443         if (endian) cimg::invert_endianness(dims,nbdim); \
30444         assign(nwidth,nheight,ndepth,ndim); \
30445         const unsigned int siz = size(); \
30446         stype *buffer = new stype[siz]; \
30447         cimg::fread(buffer,siz,nfile); \
30448         if (endian) cimg::invert_endianness(buffer,siz); \
30449         T *ptrd = data; \
30450         cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \
30451         buffer-=siz; \
30452         delete[] buffer
30453 
30454 #define _cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1,stype2,stype3,ltype) { \
30455         if (sizeof(stype1)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1); } \
30456         else if (sizeof(stype2)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype2); } \
30457         else if (sizeof(stype3)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype3); } \
30458         else throw CImgIOException("CImg<%s>::load_pandore() : File '%s' cannot be read, datatype not supported on this architecture.", \
30459                                    pixel_type(),filename?filename:"(FILE*)"); }
30460 
30461       if (!filename && !file)
30462         throw CImgArgumentException("CImg<%s>::load_pandore() : Cannot load (null) filename.",
30463                                     pixel_type());
30464       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
30465       typedef unsigned char uchar;
30466       typedef unsigned short ushort;
30467       typedef unsigned int uint;
30468       typedef unsigned long ulong;
30469       char header[32];
30470       cimg::fread(header,12,nfile);
30471       if (cimg::strncasecmp("PANDORE",header,7)) {
30472         if (!file) cimg::fclose(nfile);
30473         throw CImgIOException("CImg<%s>::load_pandore() : File '%s' is not a valid PANDORE file, "
30474                               "(PANDORE identifier not found).",
30475                               pixel_type(),filename?filename:"(FILE*)");
30476       }
30477       unsigned int imageid, dims[8];
30478       cimg::fread(&imageid,1,nfile);
30479       const bool endian = (imageid>255);
30480       if (endian) cimg::invert_endianness(imageid);
30481       cimg::fread(header,20,nfile);
30482 
30483       switch (imageid) {
30484       case 2: _cimg_load_pandore_case(2,dims[1],1,1,1,uchar,uchar,uchar,1); break;
30485       case 3: _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break;
30486       case 4: _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break;
30487       case 5: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,uchar,uchar,uchar,1); break;
30488       case 6: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break;
30489       case 7: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break;
30490       case 8: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,uchar,uchar,uchar,1); break;
30491       case 9: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break;
30492       case 10: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break;
30493       case 11 : { // Region 1D
30494         cimg::fread(dims,3,nfile);
30495         if (endian) cimg::invert_endianness(dims,3);
30496         assign(dims[1],1,1,1);
30497         const unsigned siz = size();
30498         if (dims[2]<256) {
30499           unsigned char *buffer = new unsigned char[siz];
30500           cimg::fread(buffer,siz,nfile);
30501           T *ptrd = data;
30502           cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30503           buffer-=siz;
30504           delete[] buffer;
30505         } else {
30506           if (dims[2]<65536) {
30507             unsigned short *buffer = new unsigned short[siz];
30508             cimg::fread(buffer,siz,nfile);
30509             if (endian) cimg::invert_endianness(buffer,siz);
30510             T *ptrd = data;
30511             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30512             buffer-=siz;
30513             delete[] buffer;
30514           } else {
30515             unsigned int *buffer = new unsigned int[siz];
30516             cimg::fread(buffer,siz,nfile);
30517             if (endian) cimg::invert_endianness(buffer,siz);
30518             T *ptrd = data;
30519             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30520             buffer-=siz;
30521             delete[] buffer;
30522           }
30523         }
30524       }
30525         break;
30526       case 12 : { // Region 2D
30527         cimg::fread(dims,4,nfile);
30528         if (endian) cimg::invert_endianness(dims,4);
30529         assign(dims[2],dims[1],1,1);
30530         const unsigned int siz = size();
30531         if (dims[3]<256) {
30532           unsigned char *buffer = new unsigned char[siz];
30533           cimg::fread(buffer,siz,nfile);
30534           T *ptrd = data;
30535           cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30536           buffer-=siz;
30537           delete[] buffer;
30538         } else {
30539           if (dims[3]<65536) {
30540             unsigned short *buffer = new unsigned short[siz];
30541             cimg::fread(buffer,siz,nfile);
30542             if (endian) cimg::invert_endianness(buffer,siz);
30543             T *ptrd = data;
30544             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30545             buffer-=siz;
30546             delete[] buffer;
30547           } else {
30548             unsigned long *buffer = new unsigned long[siz];
30549             cimg::fread(buffer,siz,nfile);
30550             if (endian) cimg::invert_endianness(buffer,siz);
30551             T *ptrd = data;
30552             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30553             buffer-=siz;
30554             delete[] buffer;
30555           }
30556         }
30557       }
30558         break;
30559       case 13 : { // Region 3D
30560         cimg::fread(dims,5,nfile);
30561         if (endian) cimg::invert_endianness(dims,5);
30562         assign(dims[3],dims[2],dims[1],1);
30563         const unsigned int siz = size();
30564         if (dims[4]<256) {
30565           unsigned char *buffer = new unsigned char[siz];
30566           cimg::fread(buffer,siz,nfile);
30567           T *ptrd = data;
30568           cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30569           buffer-=siz;
30570           delete[] buffer;
30571         } else {
30572           if (dims[4]<65536) {
30573             unsigned short *buffer = new unsigned short[siz];
30574             cimg::fread(buffer,siz,nfile);
30575             if (endian) cimg::invert_endianness(buffer,siz);
30576             T *ptrd = data;
30577             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30578             buffer-=siz;
30579             delete[] buffer;
30580           } else {
30581             unsigned int *buffer = new unsigned int[siz];
30582             cimg::fread(buffer,siz,nfile);
30583             if (endian) cimg::invert_endianness(buffer,siz);
30584             T *ptrd = data;
30585             cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30586             buffer-=siz;
30587             delete[] buffer;
30588           }
30589         }
30590       }
30591         break;
30592       case 16: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,uchar,uchar,uchar,1); break;
30593       case 17: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break;
30594       case 18: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break;
30595       case 19: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,uchar,uchar,uchar,1); break;
30596       case 20: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break;
30597       case 21: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break;
30598       case 22: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],uchar,uchar,uchar,1); break;
30599       case 23: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4);
30600       case 24: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],ulong,uint,ushort,4); break;
30601       case 25: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break;
30602       case 26: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],uchar,uchar,uchar,1); break;
30603       case 27: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break;
30604       case 28: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],ulong,uint,ushort,4); break;
30605       case 29: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break;
30606       case 30: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],uchar,uchar,uchar,1); break;
30607       case 31: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break;
30608       case 32: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],ulong,uint,ushort,4); break;
30609       case 33: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break;
30610       case 34 : { // Points 1D
30611         int ptbuf[4];
30612         cimg::fread(ptbuf,1,nfile);
30613         if (endian) cimg::invert_endianness(ptbuf,1);
30614         assign(1); (*this)(0) = (T)ptbuf[0];
30615       } break;
30616       case 35 : { // Points 2D
30617         int ptbuf[4];
30618         cimg::fread(ptbuf,2,nfile);
30619         if (endian) cimg::invert_endianness(ptbuf,2);
30620         assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0];
30621       } break;
30622       case 36 : { // Points 3D
30623         int ptbuf[4];
30624         cimg::fread(ptbuf,3,nfile);
30625         if (endian) cimg::invert_endianness(ptbuf,3);
30626         assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0];
30627       } break;
30628       default :
30629         if (!file) cimg::fclose(nfile);
30630         throw CImgIOException("CImg<%s>::load_pandore() : File '%s', cannot read images with ID_type = %u",
30631                               pixel_type(),filename?filename:"(FILE*)",imageid);
30632       }
30633       if (!file) cimg::fclose(nfile);
30634       return *this;
30635     }
30636 
30637     //! Load an image from a PAR-REC (Philips) file.
30638     CImg<T>& load_parrec(const char *const filename, const char axis='v', const char align='p') {
30639       CImgList<T> list;
30640       list.load_parrec(filename);
30641       if (list.size==1) return list[0].transfer_to(*this);
30642       return assign(list.get_append(axis,align));
30643     }
30644 
30645     static CImg<T> get_load_parrec(const char *const filename, const char axis='v', const char align='p') {
30646       return CImg<T>().load_parrec(filename,axis,align);
30647     }
30648 
30649     //! Load an image from a .RAW file.
30650     CImg<T>& load_raw(const char *const filename,
30651                       const unsigned int sizex, const unsigned int sizey=1,
30652                       const unsigned int sizez=1, const unsigned int sizev=1,
30653                       const bool multiplexed=false, const bool invert_endianness=false) {
30654       return _load_raw(0,filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30655     }
30656 
30657     static CImg<T> get_load_raw(const char *const filename,
30658                                 const unsigned int sizex, const unsigned int sizey=1,
30659                                 const unsigned int sizez=1, const unsigned int sizev=1,
30660                                 const bool multiplexed=false, const bool invert_endianness=false) {
30661       return CImg<T>().load_raw(filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30662     }
30663 
30664     //! Load an image from a .RAW file.
30665     CImg<T>& load_raw(cimg_std::FILE *const file,
30666                       const unsigned int sizex, const unsigned int sizey=1,
30667                       const unsigned int sizez=1, const unsigned int sizev=1,
30668                       const bool multiplexed=false, const bool invert_endianness=false) {
30669       return _load_raw(file,0,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30670     }
30671 
30672     static CImg<T> get_load_raw(cimg_std::FILE *const file,
30673                                 const unsigned int sizex, const unsigned int sizey=1,
30674                                 const unsigned int sizez=1, const unsigned int sizev=1,
30675                                 const bool multiplexed=false, const bool invert_endianness=false) {
30676       return CImg<T>().load_raw(file,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30677     }
30678 
30679     CImg<T>& _load_raw(cimg_std::FILE *const file, const char *const filename,
30680                        const unsigned int sizex, const unsigned int sizey,
30681                        const unsigned int sizez, const unsigned int sizev,
30682                        const bool multiplexed, const bool invert_endianness) {
30683       if (!filename && !file)
30684         throw CImgArgumentException("CImg<%s>::load_raw() : Cannot load (null) filename.",
30685                                     pixel_type());
30686       assign(sizex,sizey,sizez,sizev,0);
30687       const unsigned int siz = size();
30688       if (siz) {
30689         cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
30690         if (!multiplexed) {
30691           cimg::fread(data,siz,nfile);
30692           if (invert_endianness) cimg::invert_endianness(data,siz);
30693         }
30694         else {
30695           CImg<T> buf(1,1,1,sizev);
30696           cimg_forXYZ(*this,x,y,z) {
30697             cimg::fread(buf.data,sizev,nfile);
30698             if (invert_endianness) cimg::invert_endianness(buf.data,sizev);
30699             set_vector_at(buf,x,y,z); }
30700         }
30701         if (!file) cimg::fclose(nfile);
30702       }
30703       return *this;
30704     }
30705 
30706     //! Load a video sequence using FFMPEG av's libraries.
30707     CImg<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30708                          const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
30709                          const char axis='z', const char align='p') {
30710       return get_load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume,axis,align).transfer_to(*this);
30711     }
30712 
30713     static CImg<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30714                                    const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
30715                                    const char axis='z', const char align='p') {
30716       return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume).get_append(axis,align);
30717     }
30718 
30719     //! Load an image sequence from a YUV file.
30720     CImg<T>& load_yuv(const char *const filename,
30721                       const unsigned int sizex, const unsigned int sizey=1,
30722                       const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30723                       const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
30724       return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
30725     }
30726 
30727     static CImg<T> get_load_yuv(const char *const filename,
30728                                 const unsigned int sizex, const unsigned int sizey=1,
30729                                 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30730                                 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
30731       return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
30732     }
30733 
30734     //! Load an image sequence from a YUV file.
30735     CImg<T>& load_yuv(cimg_std::FILE *const file,
30736                       const unsigned int sizex, const unsigned int sizey=1,
30737                       const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30738                       const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
30739       return get_load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
30740     }
30741 
30742     static CImg<T> get_load_yuv(cimg_std::FILE *const file,
30743                                 const unsigned int sizex, const unsigned int sizey=1,
30744                                 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30745                                 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
30746       return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
30747     }
30748 
30749     //! Load a 3D object from a .OFF file.
30750     template<typename tf, typename tc>
30751     CImg<T>& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
30752       return _load_off(0,filename,primitives,colors,invert_faces);
30753     }
30754 
30755     template<typename tf, typename tc>
30756     static CImg<T> get_load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors,
30757                                 const bool invert_faces=false) {
30758       return CImg<T>().load_off(filename,primitives,colors,invert_faces);
30759     }
30760 
30761     //! Load a 3D object from a .OFF file.
30762     template<typename tf, typename tc>
30763     CImg<T>& load_off(cimg_std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
30764       return _load_off(file,0,primitives,colors,invert_faces);
30765     }
30766 
30767     template<typename tf, typename tc>
30768     static CImg<T> get_load_off(cimg_std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors,
30769                                 const bool invert_faces=false) {
30770       return CImg<T>().load_off(file,primitives,colors,invert_faces);
30771     }
30772 
30773     template<typename tf, typename tc>
30774     CImg<T>& _load_off(cimg_std::FILE *const file, const char *const filename,
30775                        CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces) {
30776       if (!filename && !file)
30777         throw CImgArgumentException("CImg<%s>::load_off() : Cannot load (null) filename.",
30778                                     pixel_type());
30779       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
30780       unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0;
30781       char line[256] = { 0 };
30782       int err;
30783 
30784       // Skip comments, and read magic string OFF
30785       do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
30786       if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) {
30787         if (!file) cimg::fclose(nfile);
30788         throw CImgIOException("CImg<%s>::load_off() : File '%s', keyword 'OFF' not found.",
30789                               pixel_type(),filename?filename:"(FILE*)");
30790       }
30791       do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
30792       if ((err = cimg_std::sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) {
30793         if (!file) cimg::fclose(nfile);
30794         throw CImgIOException("CImg<%s>::load_off() : File '%s', invalid vertices/primitives numbers.",
30795                               pixel_type(),filename?filename:"(FILE*)");
30796       }
30797 
30798       // Read points data
30799       assign(nb_points,3);
30800       float X = 0, Y = 0, Z = 0;
30801       cimg_forX(*this,l) {
30802         do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
30803         if ((err = cimg_std::sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) {
30804           if (!file) cimg::fclose(nfile);
30805           throw CImgIOException("CImg<%s>::load_off() : File '%s', cannot read point %u/%u.\n",
30806                                 pixel_type(),filename?filename:"(FILE*)",l+1,nb_points);
30807         }
30808         (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z;
30809       }
30810 
30811       // Read primitive data
30812       primitives.assign();
30813       colors.assign();
30814       bool stopflag = false;
30815       while (!stopflag) {
30816         float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f;
30817         unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
30818         line[0]='\0';
30819         if ((err = cimg_std::fscanf(nfile,"%u",&prim))!=1) stopflag=true;
30820         else {
30821           ++nb_read;
30822           switch (prim) {
30823           case 1 : {
30824             if ((err = cimg_std::fscanf(nfile,"%u%255[^\n] ",&i0,line))<2) {
30825               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30826                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30827               err = cimg_std::fscanf(nfile,"%*[^\n] ");
30828             } else {
30829               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30830               primitives.insert(CImg<tf>::vector(i0));
30831               colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
30832             }
30833           } break;
30834           case 2 : {
30835             if ((err = cimg_std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line))<2) {
30836               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30837                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30838               err = cimg_std::fscanf(nfile,"%*[^\n] ");
30839             } else {
30840               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30841               primitives.insert(CImg<tf>::vector(i0,i1));
30842               colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
30843             }
30844           } break;
30845           case 3 : {
30846             if ((err = cimg_std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line))<3) {
30847               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30848                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30849               err = cimg_std::fscanf(nfile,"%*[^\n] ");
30850             } else {
30851               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30852               if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2));
30853               else primitives.insert(CImg<tf>::vector(i0,i2,i1));
30854               colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
30855             }
30856           } break;
30857           case 4 : {
30858             if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line))<4) {
30859               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30860                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30861               err = cimg_std::fscanf(nfile,"%*[^\n] ");
30862             } else {
30863               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30864               if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
30865               else primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
30866               colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
30867             }
30868           } break;
30869           case 5 : {
30870             if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line))<5) {
30871               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30872                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30873               err = cimg_std::fscanf(nfile,"%*[^\n] ");
30874             } else {
30875               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30876               if (invert_faces) {
30877                 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
30878                 primitives.insert(CImg<tf>::vector(i0,i3,i4));
30879               }
30880               else {
30881                 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
30882                 primitives.insert(CImg<tf>::vector(i0,i4,i3));
30883               }
30884               colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
30885               ++nb_primitives;
30886             }
30887           } break;
30888           case 6 : {
30889             if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line))<6) {
30890               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30891                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30892               err = cimg_std::fscanf(nfile,"%*[^\n] ");
30893             } else {
30894               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30895               if (invert_faces) {
30896                 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
30897                 primitives.insert(CImg<tf>::vector(i0,i3,i4,i5));
30898               }
30899               else {
30900                 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
30901                 primitives.insert(CImg<tf>::vector(i0,i5,i4,i3));
30902               }
30903               colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
30904               ++nb_primitives;
30905             }
30906           } break;
30907           case 7 : {
30908             if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line))<7) {
30909               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30910                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30911               err = cimg_std::fscanf(nfile,"%*[^\n] ");
30912             } else {
30913               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30914               if (invert_faces) {
30915                 primitives.insert(CImg<tf>::vector(i0,i1,i3,i4));
30916                 primitives.insert(CImg<tf>::vector(i0,i4,i5,i6));
30917                 primitives.insert(CImg<tf>::vector(i1,i2,i3));
30918               }
30919               else {
30920                 primitives.insert(CImg<tf>::vector(i0,i4,i3,i1));
30921                 primitives.insert(CImg<tf>::vector(i0,i6,i5,i4));
30922                 primitives.insert(CImg<tf>::vector(i3,i2,i1));
30923               }
30924               colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
30925               ++(++nb_primitives);
30926             }
30927           } break;
30928           case 8 : {
30929             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) {
30930               cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30931                          pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30932               err = cimg_std::fscanf(nfile,"%*[^\n] ");
30933             } else {
30934               err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30935               if (invert_faces) {
30936                 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
30937                 primitives.insert(CImg<tf>::vector(i0,i3,i4,i5));
30938                 primitives.insert(CImg<tf>::vector(i0,i5,i6,i7));
30939               }
30940               else {
30941                 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
30942                 primitives.insert(CImg<tf>::vector(i0,i5,i4,i3));
30943                 primitives.insert(CImg<tf>::vector(i0,i7,i6,i5));
30944               }
30945               colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
30946               ++(++nb_primitives);
30947             }
30948           } break;
30949           default :
30950             cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u (%u vertices).",
30951                        pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives,prim);
30952             err = cimg_std::fscanf(nfile,"%*[^\n] ");
30953           }
30954         }
30955       }
30956       if (!file) cimg::fclose(nfile);
30957       if (primitives.size!=nb_primitives)
30958         cimg::warn("CImg<%s>::load_off() : File '%s', read only %u primitives instead of %u as claimed in the header.",
30959                    pixel_type(),filename?filename:"(FILE*)",primitives.size,nb_primitives);
30960       return *this;
30961     }
30962 
30963     //! Load a video sequence using FFMPEG's external tool 'ffmpeg'.
30964     CImg<T>& load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
30965       return get_load_ffmpeg_external(filename,axis,align).transfer_to(*this);
30966     }
30967 
30968     static CImg<T> get_load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
30969       return CImgList<T>().load_ffmpeg_external(filename).get_append(axis,align);
30970     }
30971 
30972     //! Load an image using GraphicsMagick's external tool 'gm'.
30973     CImg<T>& load_graphicsmagick_external(const char *const filename) {
30974       if (!filename)
30975         throw CImgArgumentException("CImg<%s>::load_graphicsmagick_external() : Cannot load (null) filename.",
30976                                     pixel_type());
30977       char command[1024], filetmp[512];
30978       cimg_std::FILE *file = 0;
30979 #if cimg_OS==1
30980       cimg_std::sprintf(command,"%s convert \"%s\" ppm:-",cimg::graphicsmagick_path(),filename);
30981       file = popen(command,"r");
30982       if (file) { load_pnm(file); pclose(file); return *this; }
30983 #endif
30984       do {
30985         cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
30986         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
30987       } while (file);
30988       cimg_std::sprintf(command,"%s convert \"%s\" %s",cimg::graphicsmagick_path(),filename,filetmp);
30989       cimg::system(command,cimg::graphicsmagick_path());
30990       if (!(file = cimg_std::fopen(filetmp,"rb"))) {
30991         cimg::fclose(cimg::fopen(filename,"r"));
30992         throw CImgIOException("CImg<%s>::load_graphicsmagick_external() : Failed to open image '%s'.\n\n"
30993                               "Path of 'GraphicsMagick's gm' : \"%s\"\n"
30994                               "Path of temporary filename : \"%s\"",
30995                               pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
30996       } else cimg::fclose(file);
30997       load_pnm(filetmp);
30998       cimg_std::remove(filetmp);
30999       return *this;
31000     }
31001 
31002     static CImg<T> get_load_graphicsmagick_external(const char *const filename) {
31003       return CImg<T>().load_graphicsmagick_external(filename);
31004     }
31005 
31006     //! Load a gzipped image file, using external tool 'gunzip'.
31007     CImg<T>& load_gzip_external(const char *const filename) {
31008       if (!filename)
31009         throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
31010                               pixel_type());
31011       char command[1024], filetmp[512], body[512];
31012       const char
31013         *ext = cimg::split_filename(filename,body),
31014         *ext2 = cimg::split_filename(body,0);
31015       cimg_std::FILE *file = 0;
31016       do {
31017         if (!cimg::strcasecmp(ext,"gz")) {
31018           if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
31019                                   cimg::filenamerand(),ext2);
31020           else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
31021                                   cimg::filenamerand());
31022         } else {
31023            if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
31024                                   cimg::filenamerand(),ext);
31025            else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
31026                              cimg::filenamerand());
31027         }
31028         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
31029       } while (file);
31030       cimg_std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
31031       cimg::system(command);
31032       if (!(file = cimg_std::fopen(filetmp,"rb"))) {
31033         cimg::fclose(cimg::fopen(filename,"r"));
31034         throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
31035                               pixel_type(),filename);
31036       } else cimg::fclose(file);
31037       load(filetmp);
31038       cimg_std::remove(filetmp);
31039       return *this;
31040     }
31041 
31042     static CImg<T> get_load_gzip_external(const char *const filename) {
31043       return CImg<T>().load_gzip_external(filename);
31044     }
31045 
31046     //! Load an image using ImageMagick's external tool 'convert'.
31047     CImg<T>& load_imagemagick_external(const char *const filename) {
31048       if (!filename)
31049         throw CImgArgumentException("CImg<%s>::load_imagemagick_external() : Cannot load (null) filename.",
31050                                     pixel_type());
31051       char command[1024], filetmp[512];
31052       cimg_std::FILE *file = 0;
31053 #if cimg_OS==1
31054       cimg_std::sprintf(command,"%s \"%s\" ppm:-",cimg::imagemagick_path(),filename);
31055       file = popen(command,"r");
31056       if (file) { load_pnm(file); pclose(file); return *this; }
31057 #endif
31058       do {
31059         cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
31060         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
31061       } while (file);
31062       cimg_std::sprintf(command,"%s \"%s\" %s",cimg::imagemagick_path(),filename,filetmp);
31063       cimg::system(command,cimg::imagemagick_path());
31064       if (!(file = cimg_std::fopen(filetmp,"rb"))) {
31065         cimg::fclose(cimg::fopen(filename,"r"));
31066         throw CImgIOException("CImg<%s>::load_imagemagick_external() : Failed to open image '%s'.\n\n"
31067                               "Path of 'ImageMagick's convert' : \"%s\"\n"
31068                               "Path of temporary filename : \"%s\"",
31069                               pixel_type(),filename,cimg::imagemagick_path(),filetmp);
31070       } else cimg::fclose(file);
31071       load_pnm(filetmp);
31072       cimg_std::remove(filetmp);
31073       return *this;
31074     }
31075 
31076     static CImg<T> get_load_imagemagick_external(const char *const filename) {
31077       return CImg<T>().load_imagemagick_external(filename);
31078     }
31079 
31080     //! Load a DICOM image file, using XMedcon's external tool 'medcon'.
31081     CImg<T>& load_medcon_external(const char *const filename) {
31082       if (!filename)
31083         throw CImgArgumentException("CImg<%s>::load_medcon_external() : Cannot load (null) filename.",
31084                                     pixel_type());
31085       char command[1024], filetmp[512], body[512];
31086       cimg::fclose(cimg::fopen(filename,"r"));
31087       cimg_std::FILE *file = 0;
31088       do {
31089         cimg_std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
31090         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
31091       } while (file);
31092       cimg_std::sprintf(command,"%s -w -c anlz -o %s -f %s",cimg::medcon_path(),filetmp,filename);
31093       cimg::system(command);
31094       cimg::split_filename(filetmp,body);
31095       cimg_std::sprintf(command,"m000-%s.hdr",body);
31096       file = cimg_std::fopen(command,"rb");
31097       if (!file) {
31098         throw CImgIOException("CImg<%s>::load_medcon_external() : Failed to open image '%s'.\n\n"
31099                               "Path of 'medcon' : \"%s\"\n"
31100                               "Path of temporary filename : \"%s\"",
31101                               pixel_type(),filename,cimg::medcon_path(),filetmp);
31102       } else cimg::fclose(file);
31103       load_analyze(command);
31104       cimg_std::remove(command);
31105       cimg_std::sprintf(command,"m000-%s.img",body);
31106       cimg_std::remove(command);
31107       return *this;
31108     }
31109 
31110     static CImg<T> get_load_medcon_external(const char *const filename) {
31111       return CImg<T>().load_medcon_external(filename);
31112     }
31113 
31114     //! Load a RAW Color Camera image file, using external tool 'dcraw'.
31115     CImg<T>& load_dcraw_external(const char *const filename) {
31116       if (!filename)
31117         throw CImgArgumentException("CImg<%s>::load_dcraw_external() : Cannot load (null) filename.",
31118                                     pixel_type());
31119       char command[1024], filetmp[512];
31120       cimg_std::FILE *file = 0;
31121 #if cimg_OS==1
31122       cimg_std::sprintf(command,"%s -4 -c \"%s\"",cimg::dcraw_path(),filename);
31123       file = popen(command,"r");
31124       if (file) { load_pnm(file); pclose(file); return *this; }
31125 #endif
31126       do {
31127         cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
31128         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
31129       } while (file);
31130       cimg_std::sprintf(command,"%s -4 -c \"%s\" > %s",cimg::dcraw_path(),filename,filetmp);
31131       cimg::system(command,cimg::dcraw_path());
31132       if (!(file = cimg_std::fopen(filetmp,"rb"))) {
31133         cimg::fclose(cimg::fopen(filename,"r"));
31134         throw CImgIOException("CImg<%s>::load_dcraw_external() : Failed to open image '%s'.\n\n"
31135                               "Path of 'dcraw' : \"%s\"\n"
31136                               "Path of temporary filename : \"%s\"",
31137                               pixel_type(),filename,cimg::dcraw_path(),filetmp);
31138       } else cimg::fclose(file);
31139       load_pnm(filetmp);
31140       cimg_std::remove(filetmp);
31141       return *this;
31142     }
31143 
31144     static CImg<T> get_load_dcraw_external(const char *const filename) {
31145       return CImg<T>().load_dcraw_external(filename);
31146     }
31147 
31148     //! Load an image using ImageMagick's or GraphicsMagick's executables.
31149     CImg<T>& load_other(const char *const filename) {
31150       if (!filename)
31151         throw CImgArgumentException("CImg<%s>::load_other() : Cannot load (null) filename.",
31152                                     pixel_type());
31153       const unsigned int odebug = cimg::exception_mode();
31154       cimg::exception_mode() = 0;
31155       try { load_magick(filename); }
31156       catch (CImgException&) {
31157         try { load_imagemagick_external(filename); }
31158         catch (CImgException&) {
31159           try { load_graphicsmagick_external(filename); }
31160           catch (CImgException&) {
31161             assign();
31162           }
31163         }
31164       }
31165       cimg::exception_mode() = odebug;
31166       if (is_empty())
31167         throw CImgIOException("CImg<%s>::load_other() : File '%s' cannot be opened.",
31168                               pixel_type(),filename);
31169       return *this;
31170     }
31171 
31172     static CImg<T> get_load_other(const char *const filename) {
31173       return CImg<T>().load_other(filename);
31174     }
31175 
31176     //@}
31177     //---------------------------
31178     //
31179     //! \name Image File Saving
31180     //@{
31181     //---------------------------
31182 
31183     //! Save the image as a file.
31184     /**
31185        The used file format is defined by the file extension in the filename \p filename.
31186        Parameter \p number can be used to add a 6-digit number to the filename before saving.
31187     **/
31188     const CImg<T>& save(const char *const filename, const int number=-1) const {
31189       if (is_empty())
31190         throw CImgInstanceException("CImg<%s>::save() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31191                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
31192       if (!filename)
31193         throw CImgArgumentException("CImg<%s>::save() : Instance image (%u,%u,%u,%u,%p) cannot be saved as a (null) filename.",
31194                                     pixel_type(),width,height,depth,dim,data);
31195       const char *ext = cimg::split_filename(filename);
31196       char nfilename[1024];
31197       const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
31198 #ifdef cimg_save_plugin
31199       cimg_save_plugin(fn);
31200 #endif
31201 #ifdef cimg_save_plugin1
31202       cimg_save_plugin1(fn);
31203 #endif
31204 #ifdef cimg_save_plugin2
31205       cimg_save_plugin2(fn);
31206 #endif
31207 #ifdef cimg_save_plugin3
31208       cimg_save_plugin3(fn);
31209 #endif
31210 #ifdef cimg_save_plugin4
31211       cimg_save_plugin4(fn);
31212 #endif
31213 #ifdef cimg_save_plugin5
31214       cimg_save_plugin5(fn);
31215 #endif
31216 #ifdef cimg_save_plugin6
31217       cimg_save_plugin6(fn);
31218 #endif
31219 #ifdef cimg_save_plugin7
31220       cimg_save_plugin7(fn);
31221 #endif
31222 #ifdef cimg_save_plugin8
31223       cimg_save_plugin8(fn);
31224 #endif
31225       // ASCII formats
31226       if (!cimg::strcasecmp(ext,"asc")) return save_ascii(fn);
31227       if (!cimg::strcasecmp(ext,"dlm") ||
31228           !cimg::strcasecmp(ext,"txt")) return save_dlm(fn);
31229       if (!cimg::strcasecmp(ext,"cpp") ||
31230           !cimg::strcasecmp(ext,"hpp") ||
31231           !cimg::strcasecmp(ext,"h") ||
31232           !cimg::strcasecmp(ext,"c")) return save_cpp(fn);
31233 
31234       // 2D binary formats
31235       if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(fn);
31236       if (!cimg::strcasecmp(ext,"jpg") ||
31237           !cimg::strcasecmp(ext,"jpeg") ||
31238           !cimg::strcasecmp(ext,"jpe") ||
31239           !cimg::strcasecmp(ext,"jfif") ||
31240           !cimg::strcasecmp(ext,"jif")) return save_jpeg(fn);
31241       if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(fn);
31242       if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(fn);
31243       if (!cimg::strcasecmp(ext,"png")) return save_png(fn);
31244       if (!cimg::strcasecmp(ext,"pgm") ||
31245           !cimg::strcasecmp(ext,"ppm") ||
31246           !cimg::strcasecmp(ext,"pnm")) return save_pnm(fn);
31247       if (!cimg::strcasecmp(ext,"tif") ||
31248           !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
31249 
31250       // 3D binary formats
31251       if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
31252       if (!cimg::strcasecmp(ext,"cimg") || ext[0]=='\0') return save_cimg(fn,false);
31253       if (!cimg::strcasecmp(ext,"dcm")) return save_medcon_external(fn);
31254       if (!cimg::strcasecmp(ext,"hdr") ||
31255           !cimg::strcasecmp(ext,"nii")) return save_analyze(fn);
31256       if (!cimg::strcasecmp(ext,"inr")) return save_inr(fn);
31257       if (!cimg::strcasecmp(ext,"pan")) return save_pandore(fn);
31258       if (!cimg::strcasecmp(ext,"raw")) return save_raw(fn);
31259 
31260       // Archive files
31261       if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
31262 
31263       // Image sequences
31264       if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
31265       if (!cimg::strcasecmp(ext,"avi") ||
31266           !cimg::strcasecmp(ext,"mov") ||
31267           !cimg::strcasecmp(ext,"asf") ||
31268           !cimg::strcasecmp(ext,"divx") ||
31269           !cimg::strcasecmp(ext,"flv") ||
31270           !cimg::strcasecmp(ext,"mpg") ||
31271           !cimg::strcasecmp(ext,"m1v") ||
31272           !cimg::strcasecmp(ext,"m2v") ||
31273           !cimg::strcasecmp(ext,"m4v") ||
31274           !cimg::strcasecmp(ext,"mjp") ||
31275           !cimg::strcasecmp(ext,"mkv") ||
31276           !cimg::strcasecmp(ext,"mpe") ||
31277           !cimg::strcasecmp(ext,"movie") ||
31278           !cimg::strcasecmp(ext,"ogm") ||
31279           !cimg::strcasecmp(ext,"qt") ||
31280           !cimg::strcasecmp(ext,"rm") ||
31281           !cimg::strcasecmp(ext,"vob") ||
31282           !cimg::strcasecmp(ext,"wmv") ||
31283           !cimg::strcasecmp(ext,"xvid") ||
31284           !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
31285       return save_other(fn);
31286     }
31287 
31288     // Save the image as an ASCII file (ASCII Raw + simple header) (internal).
31289     const CImg<T>& _save_ascii(cimg_std::FILE *const file, const char *const filename) const {
31290       if (is_empty())
31291         throw CImgInstanceException("CImg<%s>::save_ascii() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31292                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31293       if (!file && !filename)
31294         throw CImgArgumentException("CImg<%s>::save_ascii() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31295                                     pixel_type(),width,height,depth,dim,data);
31296       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
31297       cimg_std::fprintf(nfile,"%u %u %u %u\n",width,height,depth,dim);
31298       const T* ptrs = data;
31299       cimg_forYZV(*this,y,z,v) {
31300         cimg_forX(*this,x) cimg_std::fprintf(nfile,"%g ",(double)*(ptrs++));
31301         cimg_std::fputc('\n',nfile);
31302       }
31303       if (!file) cimg::fclose(nfile);
31304       return *this;
31305     }
31306 
31307     //! Save the image as an ASCII file (ASCII Raw + simple header).
31308     const CImg<T>& save_ascii(const char *const filename) const {
31309       return _save_ascii(0,filename);
31310     }
31311 
31312     //! Save the image as an ASCII file (ASCII Raw + simple header).
31313     const CImg<T>& save_ascii(cimg_std::FILE *const file) const {
31314       return _save_ascii(file,0);
31315     }
31316 
31317     // Save the image as a C or CPP source file (internal).
31318     const CImg<T>& _save_cpp(cimg_std::FILE *const file, const char *const filename) const {
31319       if (!file && !filename)
31320         throw CImgArgumentException("CImg<%s>::save_cpp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31321                                     pixel_type(),width,height,depth,dim,data);
31322       if (is_empty())
31323         throw CImgInstanceException("CImg<%s>::save_cpp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31324                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31325       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
31326       char varname[1024] = { 0 };
31327       if (filename) cimg_std::sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname);
31328       if (varname[0]=='\0') cimg_std::sprintf(varname,"unnamed");
31329       cimg_std::fprintf(nfile,
31330                    "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n"
31331                    "%s data_%s[] = { \n  ",
31332                    varname,width,height,depth,dim,pixel_type(),pixel_type(),varname);
31333       for (unsigned long off = 0, siz = size()-1; off<=siz; ++off) {
31334         cimg_std::fprintf(nfile,cimg::type<T>::format(),cimg::type<T>::format((*this)[off]));
31335         if (off==siz) cimg_std::fprintf(nfile," };\n");
31336         else if (!((off+1)%16)) cimg_std::fprintf(nfile,",\n  ");
31337         else cimg_std::fprintf(nfile,", ");
31338       }
31339       if (!file) cimg::fclose(nfile);
31340       return *this;
31341     }
31342 
31343     //! Save the image as a CPP source file.
31344     const CImg<T>& save_cpp(const char *const filename) const {
31345       return _save_cpp(0,filename);
31346     }
31347 
31348     //! Save the image as a CPP source file.
31349     const CImg<T>& save_cpp(cimg_std::FILE *const file) const {
31350       return _save_cpp(file,0);
31351     }
31352 
31353     // Save the image as a DLM file (internal).
31354     const CImg<T>& _save_dlm(cimg_std::FILE *const file, const char *const filename) const {
31355       if (is_empty())
31356         throw CImgInstanceException("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31357                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31358       if (!file && !filename)
31359         throw CImgArgumentException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31360                                     pixel_type(),width,height,depth,dim,data);
31361       if (depth>1)
31362         cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Pixel values along Z will be unrolled.",
31363                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31364       if (dim>1)
31365         cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. "
31366                    "Pixel values along V will be unrolled.",
31367                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31368 
31369       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
31370       const T* ptrs = data;
31371       cimg_forYZV(*this,y,z,v) {
31372         cimg_forX(*this,x) cimg_std::fprintf(nfile,"%g%s",(double)*(ptrs++),(x==dimx()-1)?"":",");
31373         cimg_std::fputc('\n',nfile);
31374       }
31375       if (!file) cimg::fclose(nfile);
31376       return *this;
31377     }
31378 
31379     //! Save the image as a DLM file.
31380     const CImg<T>& save_dlm(const char *const filename) const {
31381       return _save_dlm(0,filename);
31382     }
31383 
31384     //! Save the image as a DLM file.
31385     const CImg<T>& save_dlm(cimg_std::FILE *const file) const {
31386       return _save_dlm(file,0);
31387     }
31388 
31389    // Save the image as a BMP file (internal).
31390     const CImg<T>& _save_bmp(cimg_std::FILE *const file, const char *const filename) const {
31391       if (is_empty())
31392         throw CImgInstanceException("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31393                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31394       if (!file && !filename)
31395         throw CImgArgumentException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31396                                     pixel_type(),width,height,depth,dim,data);
31397       if (depth>1)
31398         cimg::warn("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
31399                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31400       if (dim>3)
31401         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.",
31402                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31403 
31404       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
31405       unsigned char header[54] = { 0 }, align_buf[4] = { 0 };
31406       const unsigned int
31407         align = (4 - (3*width)%4)%4,
31408         buf_size = (3*width+align)*dimy(),
31409         file_size = 54 + buf_size;
31410       header[0] = 'B'; header[1] = 'M';
31411       header[0x02] = file_size&0xFF;
31412       header[0x03] = (file_size>>8)&0xFF;
31413       header[0x04] = (file_size>>16)&0xFF;
31414       header[0x05] = (file_size>>24)&0xFF;
31415       header[0x0A] = 0x36;
31416       header[0x0E] = 0x28;
31417       header[0x12] = width&0xFF;
31418       header[0x13] = (width>>8)&0xFF;
31419       header[0x14] = (width>>16)&0xFF;
31420       header[0x15] = (width>>24)&0xFF;
31421       header[0x16] = height&0xFF;
31422       header[0x17] = (height>>8)&0xFF;
31423       header[0x18] = (height>>16)&0xFF;
31424       header[0x19] = (height>>24)&0xFF;
31425       header[0x1A] = 1;
31426       header[0x1B] = 0;
31427       header[0x1C] = 24;
31428       header[0x1D] = 0;
31429       header[0x22] = buf_size&0xFF;
31430       header[0x23] = (buf_size>>8)&0xFF;
31431       header[0x24] = (buf_size>>16)&0xFF;
31432       header[0x25] = (buf_size>>24)&0xFF;
31433       header[0x27] = 0x1;
31434       header[0x2B] = 0x1;
31435       cimg::fwrite(header,54,nfile);
31436 
31437       const T
31438         *pR = ptr(0,height-1,0,0),
31439         *pG = (dim>=2)?ptr(0,height-1,0,1):0,
31440         *pB = (dim>=3)?ptr(0,height-1,0,2):0;
31441 
31442       switch (dim) {
31443       case 1 : {
31444         cimg_forY(*this,y) { cimg_forX(*this,x) {
31445           const unsigned char val = (unsigned char)*(pR++);
31446           cimg_std::fputc(val,nfile); cimg_std::fputc(val,nfile); cimg_std::fputc(val,nfile);
31447         }
31448         cimg::fwrite(align_buf,align,nfile);
31449         pR-=2*width;
31450         }} break;
31451       case 2 : {
31452         cimg_forY(*this,y) { cimg_forX(*this,x) {
31453           cimg_std::fputc(0,nfile);
31454           cimg_std::fputc((unsigned char)(*(pG++)),nfile);
31455           cimg_std::fputc((unsigned char)(*(pR++)),nfile);
31456         }
31457         cimg::fwrite(align_buf,align,nfile);
31458         pR-=2*width; pG-=2*width;
31459         }} break;
31460       default : {
31461         cimg_forY(*this,y) { cimg_forX(*this,x) {
31462           cimg_std::fputc((unsigned char)(*(pB++)),nfile);
31463           cimg_std::fputc((unsigned char)(*(pG++)),nfile);
31464           cimg_std::fputc((unsigned char)(*(pR++)),nfile);
31465         }
31466         cimg::fwrite(align_buf,align,nfile);
31467         pR-=2*width; pG-=2*width; pB-=2*width;
31468         }
31469       }
31470       }
31471       if (!file) cimg::fclose(nfile);
31472       return *this;
31473     }
31474 
31475     //! Save the image as a BMP file.
31476     const CImg<T>& save_bmp(const char *const filename) const {
31477       return _save_bmp(0,filename);
31478     }
31479 
31480     //! Save the image as a BMP file.
31481     const CImg<T>& save_bmp(cimg_std::FILE *const file) const {
31482       return _save_bmp(file,0);
31483     }
31484 
31485     // Save a file in JPEG format (internal).
31486     const CImg<T>& _save_jpeg(cimg_std::FILE *const file, const char *const filename, const unsigned int quality) const {
31487       if (is_empty())
31488         throw CImgInstanceException("CImg<%s>::save_jpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31489                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31490       if (!file && !filename)
31491         throw CImgArgumentException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
31492                                     pixel_type(),width,height,depth,dim,data);
31493       if (depth>1)
31494         cimg::warn("CImg<%s>::save_jpeg() : File '%s, instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
31495                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31496 #ifndef cimg_use_jpeg
31497       if (!file) return save_other(filename,quality);
31498       else throw CImgIOException("CImg<%s>::save_jpeg() : Cannot save a JPEG image in a *FILE output. Use libjpeg instead.",
31499                                  pixel_type());
31500 #else
31501       // Fill pixel buffer
31502       unsigned char *buf;
31503       unsigned int dimbuf = 0;
31504       J_COLOR_SPACE colortype = JCS_RGB;
31505       switch (dim) {
31506       case 1 : { // Greyscale images
31507         unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=1)];
31508         colortype = JCS_GRAYSCALE;
31509         const T *ptr_g = data;
31510         cimg_forXY(*this,x,y) *(buf2++) = (unsigned char)*(ptr_g++);
31511       } break;
31512       case 2 : { // RG images
31513         unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
31514         const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1);
31515         colortype = JCS_RGB;
31516         cimg_forXY(*this,x,y) {
31517           *(buf2++) = (unsigned char)*(ptr_r++);
31518           *(buf2++) = (unsigned char)*(ptr_g++);
31519           *(buf2++) = 0;
31520         }
31521       } break;
31522       case 3 : { // RGB images
31523         unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
31524         const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
31525         colortype = JCS_RGB;
31526         cimg_forXY(*this,x,y) {
31527           *(buf2++) = (unsigned char)*(ptr_r++);
31528           *(buf2++) = (unsigned char)*(ptr_g++);
31529           *(buf2++) = (unsigned char)*(ptr_b++);
31530         }
31531       } break;
31532       default : { // CMYK images
31533         unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=4)];
31534         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);
31535         colortype = JCS_CMYK;
31536         cimg_forXY(*this,x,y) {
31537           *(buf2++) = (unsigned char)*(ptr_r++);
31538           *(buf2++) = (unsigned char)*(ptr_g++);
31539           *(buf2++) = (unsigned char)*(ptr_b++);
31540           *(buf2++) = (unsigned char)*(ptr_a++);
31541         }
31542       }
31543       }
31544 
31545       // Call libjpeg functions
31546       struct jpeg_compress_struct cinfo;
31547       struct jpeg_error_mgr jerr;
31548       cinfo.err = jpeg_std_error(&jerr);
31549       jpeg_create_compress(&cinfo);
31550       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
31551       jpeg_stdio_dest(&cinfo,nfile);
31552       cinfo.image_width = width;
31553       cinfo.image_height = height;
31554       cinfo.input_components = dimbuf;
31555       cinfo.in_color_space = colortype;
31556       jpeg_set_defaults(&cinfo);
31557       jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
31558       jpeg_start_compress(&cinfo,TRUE);
31559 
31560       const unsigned int row_stride = width*dimbuf;
31561       JSAMPROW row_pointer[1];
31562       while (cinfo.next_scanline < cinfo.image_height) {
31563         row_pointer[0] = &buf[cinfo.next_scanline*row_stride];
31564         jpeg_write_scanlines(&cinfo,row_pointer,1);
31565       }
31566       jpeg_finish_compress(&cinfo);
31567 
31568       delete[] buf;
31569       if (!file) cimg::fclose(nfile);
31570       jpeg_destroy_compress(&cinfo);
31571       return *this;
31572 #endif
31573     }
31574 
31575     //! Save a file in JPEG format.
31576     const CImg<T>& save_jpeg(const char *const filename, const unsigned int quality=100) const {
31577       return _save_jpeg(0,filename,quality);
31578     }
31579 
31580     //! Save a file in JPEG format.
31581     const CImg<T>& save_jpeg(cimg_std::FILE *const file, const unsigned int quality=100) const {
31582       return _save_jpeg(file,0,quality);
31583     }
31584 
31585     //! Save the image using built-in ImageMagick++ library.
31586     const CImg<T>& save_magick(const char *const filename) const {
31587       if (is_empty())
31588         throw CImgInstanceException("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31589                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
31590       if (!filename)
31591         throw CImgArgumentException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31592                                     pixel_type(),width,height,depth,dim,data);
31593 #ifdef cimg_use_magick
31594       Magick::Image image(Magick::Geometry(width,height),"black");
31595       image.type(Magick::TrueColorType);
31596       const T
31597         *rdata = ptr(0,0,0,0),
31598         *gdata = dim>1?ptr(0,0,0,1):0,
31599         *bdata = dim>2?ptr(0,0,0,2):0;
31600       Magick::PixelPacket *pixels = image.getPixels(0,0,width,height);
31601       switch (dim) {
31602       case 1 : // Scalar images
31603         for (unsigned int off = width*height; off; --off) {
31604           pixels->red = pixels->green = pixels->blue = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
31605           ++pixels;
31606         }
31607         break;
31608       case 2 : // RG images
31609         for (unsigned int off = width*height; off; --off) {
31610           pixels->red = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
31611           pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
31612           pixels->blue = 0;
31613           ++pixels;
31614         }
31615         break;
31616       default : // RGB images
31617         for (unsigned int off = width*height; off; --off) {
31618           pixels->red = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
31619           pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
31620           pixels->blue = Magick::Color::scaleDoubleToQuantum(*(bdata++)/255.0);
31621           ++pixels;
31622         }
31623       }
31624       image.syncPixels();
31625       image.write(filename);
31626 #else
31627       throw CImgIOException("CImg<%s>::save_magick() : File '%s', Magick++ library has not been linked.",
31628                             pixel_type(),filename);
31629 #endif
31630       return *this;
31631     }
31632 
31633     // Save an image to a PNG file (internal).
31634     // Most of this function has been written by Eric Fausett
31635     const CImg<T>& _save_png(cimg_std::FILE *const file, const char *const filename) const {
31636       if (is_empty())
31637         throw CImgInstanceException("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31638                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31639       if (!filename)
31640         throw CImgArgumentException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
31641                                     pixel_type(),width,height,depth,dim,data);
31642       if (depth>1)
31643         cimg::warn("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
31644                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31645 #ifndef cimg_use_png
31646       if (!file) return save_other(filename);
31647       else throw CImgIOException("CImg<%s>::save_png() : Cannot save a PNG image in a *FILE output. You must use 'libpng' to do this instead.",
31648                                  pixel_type());
31649 #else
31650       const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
31651       cimg_std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb");
31652 
31653       // Setup PNG structures for write
31654       png_voidp user_error_ptr = 0;
31655       png_error_ptr user_error_fn = 0, user_warning_fn = 0;
31656       png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn, user_warning_fn);
31657       if(!png_ptr){
31658         if (!file) cimg::fclose(nfile);
31659         throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'png_ptr' data structure.",
31660                               pixel_type(),nfilename?nfilename:"(FILE*)");
31661       }
31662       png_infop info_ptr = png_create_info_struct(png_ptr);
31663       if (!info_ptr) {
31664         png_destroy_write_struct(&png_ptr,(png_infopp)0);
31665         if (!file) cimg::fclose(nfile);
31666         throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'info_ptr' data structure.",
31667                               pixel_type(),nfilename?nfilename:"(FILE*)");
31668       }
31669       if (setjmp(png_jmpbuf(png_ptr))) {
31670         png_destroy_write_struct(&png_ptr, &info_ptr);
31671         if (!file) cimg::fclose(nfile);
31672         throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
31673                               pixel_type(),nfilename?nfilename:"(FILE*)");
31674       }
31675       png_init_io(png_ptr, nfile);
31676       png_uint_32 width = dimx(), height = dimy();
31677       float vmin, vmax = (float)maxmin(vmin);
31678       const int bit_depth = (vmin<0 || vmax>=256)?16:8;
31679       int color_type;
31680       switch (dimv()) {
31681       case 1 : color_type = PNG_COLOR_TYPE_GRAY; break;
31682       case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
31683       case 3 : color_type = PNG_COLOR_TYPE_RGB; break;
31684       default : color_type = PNG_COLOR_TYPE_RGB_ALPHA;
31685       }
31686       const int interlace_type = PNG_INTERLACE_NONE;
31687       const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
31688       const int filter_method = PNG_FILTER_TYPE_DEFAULT;
31689       png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type,compression_type, filter_method);
31690       png_write_info(png_ptr, info_ptr);
31691       const int byte_depth = bit_depth>>3;
31692       const int numChan = dimv()>4?4:dimv();
31693       const int pixel_bit_depth_flag = numChan * (bit_depth-1);
31694 
31695       // Allocate Memory for Image Save and Fill pixel data
31696       png_bytep *imgData = new png_byte*[height];
31697       for (unsigned int row = 0; row<height; ++row) imgData[row] = new png_byte[byte_depth*numChan*width];
31698       const T *pC0 = ptr(0,0,0,0);
31699       switch (pixel_bit_depth_flag) {
31700       case 7 :  { // Gray 8-bit
31701         cimg_forY(*this,y) {
31702           unsigned char *ptrd = imgData[y];
31703           cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++);
31704         }
31705       } break;
31706       case 14 : { // Gray w/ Alpha 8-bit
31707         const T *pC1 = ptr(0,0,0,1);
31708         cimg_forY(*this,y) {
31709           unsigned char *ptrd = imgData[y];
31710           cimg_forX(*this,x) {
31711             *(ptrd++) = (unsigned char)*(pC0++);
31712             *(ptrd++) = (unsigned char)*(pC1++);
31713           }
31714         }
31715       } break;
31716       case 21 :  { // RGB 8-bit
31717         const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
31718         cimg_forY(*this,y) {
31719           unsigned char *ptrd = imgData[y];
31720           cimg_forX(*this,x) {
31721             *(ptrd++) = (unsigned char)*(pC0++);
31722             *(ptrd++) = (unsigned char)*(pC1++);
31723             *(ptrd++) = (unsigned char)*(pC2++);
31724           }
31725         }
31726       } break;
31727       case 28 : { // RGB x/ Alpha 8-bit
31728         const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
31729         cimg_forY(*this,y){
31730           unsigned char *ptrd = imgData[y];
31731           cimg_forX(*this,x){
31732             *(ptrd++) = (unsigned char)*(pC0++);
31733             *(ptrd++) = (unsigned char)*(pC1++);
31734             *(ptrd++) = (unsigned char)*(pC2++);
31735             *(ptrd++) = (unsigned char)*(pC3++);
31736           }
31737         }
31738       } break;
31739       case 15 : { // Gray 16-bit
31740         cimg_forY(*this,y){
31741           unsigned short *ptrd = (unsigned short*)(imgData[y]);
31742           cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++);
31743           if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],width);
31744         }
31745       } break;
31746       case 30 : { // Gray w/ Alpha 16-bit
31747         const T *pC1 = ptr(0,0,0,1);
31748         cimg_forY(*this,y){
31749           unsigned short *ptrd = (unsigned short*)(imgData[y]);
31750           cimg_forX(*this,x) {
31751             *(ptrd++) = (unsigned short)*(pC0++);
31752             *(ptrd++) = (unsigned short)*(pC1++);
31753           }
31754           if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*width);
31755         }
31756       } break;
31757       case 45 : { // RGB 16-bit
31758         const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
31759         cimg_forY(*this,y) {
31760           unsigned short *ptrd = (unsigned short*)(imgData[y]);
31761           cimg_forX(*this,x) {
31762             *(ptrd++) = (unsigned short)*(pC0++);
31763             *(ptrd++) = (unsigned short)*(pC1++);
31764             *(ptrd++) = (unsigned short)*(pC2++);
31765           }
31766           if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*width);
31767         }
31768       } break;
31769       case 60 : { // RGB w/ Alpha 16-bit
31770         const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
31771         cimg_forY(*this,y) {
31772           unsigned short *ptrd = (unsigned short*)(imgData[y]);
31773           cimg_forX(*this,x) {
31774             *(ptrd++) = (unsigned short)*(pC0++);
31775             *(ptrd++) = (unsigned short)*(pC1++);
31776             *(ptrd++) = (unsigned short)*(pC2++);
31777             *(ptrd++) = (unsigned short)*(pC3++);
31778           }
31779           if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*width);
31780         }
31781       } break;
31782       default :
31783         if (!file) cimg::fclose(nfile);
31784         throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
31785                               pixel_type(),nfilename?nfilename:"(FILE*)");
31786       }
31787       png_write_image(png_ptr, imgData);
31788       png_write_end(png_ptr, info_ptr);
31789       png_destroy_write_struct(&png_ptr, &info_ptr);
31790 
31791       // Deallocate Image Write Memory
31792       cimg_forY(*this,n) delete[] imgData[n];
31793       delete[] imgData;
31794       if (!file) cimg::fclose(nfile);
31795       return *this;
31796 #endif
31797     }
31798 
31799     //! Save a file in PNG format
31800     const CImg<T>& save_png(const char *const filename) const {
31801       return _save_png(0,filename);
31802     }
31803 
31804     //! Save a file in PNG format
31805     const CImg<T>& save_png(cimg_std::FILE *const file) const {
31806       return _save_png(file,0);
31807     }
31808 
31809     // Save the image as a PNM file (internal function).
31810     const CImg<T>& _save_pnm(cimg_std::FILE *const file, const char *const filename) const {
31811       if (!file && !filename)
31812         throw CImgArgumentException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31813                                     pixel_type(),width,height,depth,dim,data);
31814       if (is_empty())
31815         throw CImgInstanceException("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31816                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31817       double stmin, stmax = (double)maxmin(stmin);
31818       if (depth>1)
31819         cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
31820                  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31821       if (dim>3)
31822         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.",
31823                  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31824       if (stmin<0 || stmax>65535)
31825         cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) has pixel values in [%g,%g]. Probable type overflow.",
31826                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data,stmin,stmax);
31827       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
31828       const T
31829         *ptrR = ptr(0,0,0,0),
31830         *ptrG = (dim>=2)?ptr(0,0,0,1):0,
31831         *ptrB = (dim>=3)?ptr(0,0,0,2):0;
31832       const unsigned int buf_size = width*height*(dim==1?1:3);
31833 
31834       cimg_std::fprintf(nfile,"P%c\n# CREATOR: CImg Library (original size = %ux%ux%ux%u)\n%u %u\n%u\n",
31835                    (dim==1?'5':'6'),width,height,depth,dim,width,height,stmax<256?255:(stmax<4096?4095:65535));
31836 
31837       switch (dim) {
31838       case 1 : { // Scalar image
31839         if (stmax<256) { // Binary PGM 8 bits
31840           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
31841           cimg_forXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++);
31842           cimg::fwrite(ptrd,buf_size,nfile);
31843           delete[] ptrd;
31844         } else {             // Binary PGM 16 bits
31845           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
31846           cimg_forXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++);
31847           if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
31848           cimg::fwrite(ptrd,buf_size,nfile);
31849           delete[] ptrd;
31850         }
31851       } break;
31852       case 2 : { // RG image
31853         if (stmax<256) { // Binary PPM 8 bits
31854           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
31855           cimg_forXY(*this,x,y) {
31856             *(xptrd++) = (unsigned char)*(ptrR++);
31857             *(xptrd++) = (unsigned char)*(ptrG++);
31858             *(xptrd++) = 0;
31859           }
31860           cimg::fwrite(ptrd,buf_size,nfile);
31861           delete[] ptrd;
31862         } else {             // Binary PPM 16 bits
31863           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
31864           cimg_forXY(*this,x,y) {
31865             *(xptrd++) = (unsigned short)*(ptrR++);
31866             *(xptrd++) = (unsigned short)*(ptrG++);
31867             *(xptrd++) = 0;
31868           }
31869           if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
31870           cimg::fwrite(ptrd,buf_size,nfile);
31871           delete[] ptrd;
31872         }
31873       } break;
31874       default : { // RGB image
31875         if (stmax<256) { // Binary PPM 8 bits
31876           unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
31877           cimg_forXY(*this,x,y) {
31878             *(xptrd++) = (unsigned char)*(ptrR++);
31879             *(xptrd++) = (unsigned char)*(ptrG++);
31880             *(xptrd++) = (unsigned char)*(ptrB++);
31881           }
31882           cimg::fwrite(ptrd,buf_size,nfile);
31883           delete[] ptrd;
31884         } else {             // Binary PPM 16 bits
31885           unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
31886           cimg_forXY(*this,x,y) {
31887             *(xptrd++) = (unsigned short)*(ptrR++);
31888             *(xptrd++) = (unsigned short)*(ptrG++);
31889             *(xptrd++) = (unsigned short)*(ptrB++);
31890           }
31891           if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
31892           cimg::fwrite(ptrd,buf_size,nfile);
31893           delete[] ptrd;
31894         }
31895       }
31896       }
31897       if (!file) cimg::fclose(nfile);
31898       return *this;
31899     }
31900 
31901     //! Save the image as a PNM file.
31902     const CImg<T>& save_pnm(const char *const filename) const {
31903       return _save_pnm(0,filename);
31904     }
31905 
31906     //! Save the image as a PNM file.
31907     const CImg<T>& save_pnm(cimg_std::FILE *const file) const {
31908       return _save_pnm(file,0);
31909     }
31910 
31911     // Save the image as a RGB file (internal).
31912     const CImg<T>& _save_rgb(cimg_std::FILE *const file, const char *const filename) const {
31913       if (is_empty())
31914         throw CImgInstanceException("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31915                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31916       if (!file && !filename)
31917         throw CImgArgumentException("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31918                                     pixel_type(),width,height,depth,dim,data);
31919       if (dim!=3)
31920         cimg::warn("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) has not exactly 3 channels.",
31921                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31922       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
31923       const unsigned int wh = width*height;
31924       unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer;
31925       const T
31926         *ptr1 = ptr(0,0,0,0),
31927         *ptr2 = dim>1?ptr(0,0,0,1):0,
31928         *ptr3 = dim>2?ptr(0,0,0,2):0;
31929       switch (dim) {
31930       case 1 : { // Scalar image
31931         for (unsigned int k=0; k<wh; ++k) {
31932           const unsigned char val = (unsigned char)*(ptr1++);
31933           *(nbuffer++) = val;
31934           *(nbuffer++) = val;
31935           *(nbuffer++) = val;
31936         }} break;
31937       case 2 : { // RG image
31938         for (unsigned int k=0; k<wh; ++k) {
31939           *(nbuffer++) = (unsigned char)(*(ptr1++));
31940           *(nbuffer++) = (unsigned char)(*(ptr2++));
31941           *(nbuffer++) = 0;
31942         }} break;
31943       default : { // RGB image
31944         for (unsigned int k=0; k<wh; ++k) {
31945           *(nbuffer++) = (unsigned char)(*(ptr1++));
31946           *(nbuffer++) = (unsigned char)(*(ptr2++));
31947           *(nbuffer++) = (unsigned char)(*(ptr3++));
31948         }
31949       }
31950       }
31951       cimg::fwrite(buffer,3*wh,nfile);
31952       if (!file) cimg::fclose(nfile);
31953       delete[] buffer;
31954       return *this;
31955     }
31956 
31957     //! Save the image as a RGB file.
31958     const CImg<T>& save_rgb(const char *const filename) const {
31959       return _save_rgb(0,filename);
31960     }
31961 
31962     //! Save the image as a RGB file.
31963     const CImg<T>& save_rgb(cimg_std::FILE *const file) const {
31964       return _save_rgb(file,0);
31965     }
31966 
31967     // Save the image as a RGBA file (internal).
31968     const CImg<T>& _save_rgba(cimg_std::FILE *const file, const char *const filename) const {
31969       if (is_empty())
31970         throw CImgInstanceException("CImg<%s>::save_rgba() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31971                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31972       if (!file && !filename)
31973         throw CImgArgumentException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31974                                     pixel_type(),width,height,depth,dim,data);
31975       if (dim!=4)
31976         cimg::warn("CImg<%s>::save_rgba() : File '%s, instance image (%u,%u,%u,%u,%p) has not exactly 4 channels.",
31977                    pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31978       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
31979       const unsigned int wh = width*height;
31980       unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer;
31981       const T
31982         *ptr1 = ptr(0,0,0,0),
31983         *ptr2 = dim>1?ptr(0,0,0,1):0,
31984         *ptr3 = dim>2?ptr(0,0,0,2):0,
31985         *ptr4 = dim>3?ptr(0,0,0,3):0;
31986       switch (dim) {
31987       case 1 : { // Scalar images
31988         for (unsigned int k=0; k<wh; ++k) {
31989           const unsigned char val = (unsigned char)*(ptr1++);
31990           *(nbuffer++) = val;
31991           *(nbuffer++) = val;
31992           *(nbuffer++) = val;
31993           *(nbuffer++) = 255;
31994         }} break;
31995       case 2 : { // RG images
31996         for (unsigned int k=0; k<wh; ++k) {
31997           *(nbuffer++) = (unsigned char)(*(ptr1++));
31998           *(nbuffer++) = (unsigned char)(*(ptr2++));
31999           *(nbuffer++) = 0;
32000           *(nbuffer++) = 255;
32001         }} break;
32002       case 3 : { // RGB images
32003         for (unsigned int k=0; k<wh; ++k) {
32004           *(nbuffer++) = (unsigned char)(*(ptr1++));
32005           *(nbuffer++) = (unsigned char)(*(ptr2++));
32006           *(nbuffer++) = (unsigned char)(*(ptr3++));
32007           *(nbuffer++) = 255;
32008         }} break;
32009       default : { // RGBA images
32010         for (unsigned int k=0; k<wh; ++k) {
32011           *(nbuffer++) = (unsigned char)(*(ptr1++));
32012           *(nbuffer++) = (unsigned char)(*(ptr2++));
32013           *(nbuffer++) = (unsigned char)(*(ptr3++));
32014           *(nbuffer++) = (unsigned char)(*(ptr4++));
32015         }
32016       }
32017       }
32018       cimg::fwrite(buffer,4*wh,nfile);
32019       if (!file) cimg::fclose(nfile);
32020       delete[] buffer;
32021       return *this;
32022     }
32023 
32024     //! Save the image as a RGBA file.
32025     const CImg<T>& save_rgba(const char *const filename) const {
32026       return _save_rgba(0,filename);
32027     }
32028 
32029     //! Save the image as a RGBA file.
32030     const CImg<T>& save_rgba(cimg_std::FILE *const file) const {
32031       return _save_rgba(file,0);
32032     }
32033 
32034     // Save a plane into a tiff file
32035 #ifdef cimg_use_tiff
32036     const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory) const {
32037       if (is_empty() || !tif) return *this;
32038       const char *const filename = TIFFFileName(tif);
32039       uint32 rowsperstrip = (uint32)-1;
32040       uint16 spp = dim, bpp = sizeof(T)*8, photometric, compression = COMPRESSION_NONE;
32041       if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB;
32042       else photometric = PHOTOMETRIC_MINISBLACK;
32043       TIFFSetDirectory(tif,directory);
32044       TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,width);
32045       TIFFSetField(tif,TIFFTAG_IMAGELENGTH,height);
32046       TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
32047       TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp);
32048       if (cimg::type<T>::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3);
32049       else if (cimg::type<T>::min()==0) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,1);
32050       else TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,2);
32051       TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp);
32052       TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
32053       TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric);
32054       TIFFSetField(tif,TIFFTAG_COMPRESSION,compression);
32055       rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip);
32056       TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip);
32057       TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB);
32058       TIFFSetField(tif,TIFFTAG_SOFTWARE,"CImg");
32059       T *buf = (T*)_TIFFmalloc(TIFFStripSize(tif));
32060       if (buf){
32061         for (unsigned int row = 0; row<height; row+=rowsperstrip) {
32062           uint32 nrow = (row+rowsperstrip>height?height-row:rowsperstrip);
32063           tstrip_t strip = TIFFComputeStrip(tif,row,0);
32064           tsize_t i = 0;
32065           for (unsigned int rr = 0; rr<nrow; ++rr)
32066             for (unsigned int cc = 0; cc<width; ++cc)
32067               for (unsigned int vv = 0; vv<spp; ++vv)
32068                 buf[i++] = (*this)(cc,row+rr,vv);
32069           if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(T))<0)
32070             throw CImgException("CImg<%s>::save_tiff() : File '%s', an error has occurred while writing a strip.",
32071                                 pixel_type(),filename?filename:"(FILE*)");
32072         }
32073         _TIFFfree(buf);
32074       }
32075       TIFFWriteDirectory(tif);
32076       return (*this);
32077     }
32078 #endif
32079 
32080     //! Save a file in TIFF format.
32081     const CImg<T>& save_tiff(const char *const filename) const {
32082       if (is_empty())
32083         throw CImgInstanceException("CImg<%s>::save_tiff() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32084                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32085       if (!filename)
32086         throw CImgArgumentException("CImg<%s>::save_tiff() : Specified filename is (null) for instance image (%u,%u,%u,%u,%p).",
32087                                     pixel_type(),width,height,depth,dim,data);
32088 #ifdef cimg_use_tiff
32089       TIFF *tif = TIFFOpen(filename,"w");
32090       if (tif) {
32091         cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z);
32092         TIFFClose(tif);
32093       } else throw CImgException("CImg<%s>::save_tiff() : File '%s', error while opening file stream for writing.",
32094                                  pixel_type(),filename);
32095 #else
32096       return save_other(filename);
32097 #endif
32098       return *this;
32099     }
32100 
32101     //! Save the image as an ANALYZE7.5 or NIFTI file.
32102     const CImg<T>& save_analyze(const char *const filename, const float *const voxsize=0) const {
32103       if (is_empty())
32104         throw CImgInstanceException("CImg<%s>::save_analyze() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32105                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32106       if (!filename)
32107         throw CImgArgumentException("CImg<%s>::save_analyze() :  Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32108                                     pixel_type(),width,height,depth,dim,data);
32109       cimg_std::FILE *file;
32110       char header[348], hname[1024], iname[1024];
32111       const char *ext = cimg::split_filename(filename);
32112       short datatype=-1;
32113       cimg_std::memset(header,0,348);
32114       if (!ext[0]) { cimg_std::sprintf(hname,"%s.hdr",filename); cimg_std::sprintf(iname,"%s.img",filename); }
32115       if (!cimg::strncasecmp(ext,"hdr",3)) {
32116         cimg_std::strcpy(hname,filename); cimg_std::strcpy(iname,filename); cimg_std::sprintf(iname+cimg::strlen(iname)-3,"img");
32117       }
32118       if (!cimg::strncasecmp(ext,"img",3)) {
32119         cimg_std::strcpy(hname,filename); cimg_std::strcpy(iname,filename); cimg_std::sprintf(hname+cimg::strlen(iname)-3,"hdr");
32120       }
32121       if (!cimg::strncasecmp(ext,"nii",3)) {
32122         cimg_std::strcpy(hname,filename); iname[0] = 0;
32123       }
32124       ((int*)(header))[0] = 348;
32125       cimg_std::sprintf(header+4,"CImg");
32126       cimg_std::sprintf(header+14," ");
32127       ((short*)(header+36))[0] = 4096;
32128       ((char*)(header+38))[0] = 114;
32129       ((short*)(header+40))[0] = 4;
32130       ((short*)(header+40))[1] = width;
32131       ((short*)(header+40))[2] = height;
32132       ((short*)(header+40))[3] = depth;
32133       ((short*)(header+40))[4] = dim;
32134       if (!cimg::strcasecmp(pixel_type(),"bool"))           datatype = 2;
32135       if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  datatype = 2;
32136       if (!cimg::strcasecmp(pixel_type(),"char"))           datatype = 2;
32137       if (!cimg::strcasecmp(pixel_type(),"unsigned short")) datatype = 4;
32138       if (!cimg::strcasecmp(pixel_type(),"short"))          datatype = 4;
32139       if (!cimg::strcasecmp(pixel_type(),"unsigned int"))   datatype = 8;
32140       if (!cimg::strcasecmp(pixel_type(),"int"))            datatype = 8;
32141       if (!cimg::strcasecmp(pixel_type(),"unsigned long"))  datatype = 8;
32142       if (!cimg::strcasecmp(pixel_type(),"long"))           datatype = 8;
32143       if (!cimg::strcasecmp(pixel_type(),"float"))          datatype = 16;
32144       if (!cimg::strcasecmp(pixel_type(),"double"))         datatype = 64;
32145       if (datatype<0)
32146         throw CImgIOException("CImg<%s>::save_analyze() : Cannot save image '%s' since pixel type (%s)"
32147                               "is not handled in Analyze7.5 specifications.\n",
32148                               pixel_type(),filename,pixel_type());
32149       ((short*)(header+70))[0] = datatype;
32150       ((short*)(header+72))[0] = sizeof(T);
32151       ((float*)(header+112))[0] = 1;
32152       ((float*)(header+76))[0] = 0;
32153       if (voxsize) {
32154         ((float*)(header+76))[1] = voxsize[0];
32155         ((float*)(header+76))[2] = voxsize[1];
32156         ((float*)(header+76))[3] = voxsize[2];
32157       } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1;
32158       file = cimg::fopen(hname,"wb");
32159       cimg::fwrite(header,348,file);
32160       if (iname[0]) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); }
32161       cimg::fwrite(data,size(),file);
32162       cimg::fclose(file);
32163       return *this;
32164     }
32165 
32166     //! Save the image as a .cimg file.
32167     const CImg<T>& save_cimg(const char *const filename, const bool compress=false) const {
32168       CImgList<T>(*this,true).save_cimg(filename,compress);
32169       return *this;
32170     }
32171 
32172     // Save the image as a .cimg file.
32173     const CImg<T>& save_cimg(cimg_std::FILE *const file, const bool compress=false) const {
32174       CImgList<T>(*this,true).save_cimg(file,compress);
32175       return *this;
32176     }
32177 
32178     //! Insert the image into an existing .cimg file, at specified coordinates.
32179     const CImg<T>& save_cimg(const char *const filename,
32180                              const unsigned int n0,
32181                              const unsigned int x0, const unsigned int y0,
32182                              const unsigned int z0, const unsigned int v0) const {
32183       CImgList<T>(*this,true).save_cimg(filename,n0,x0,y0,z0,v0);
32184       return *this;
32185     }
32186 
32187     //! Insert the image into an existing .cimg file, at specified coordinates.
32188     const CImg<T>& save_cimg(cimg_std::FILE *const file,
32189                              const unsigned int n0,
32190                              const unsigned int x0, const unsigned int y0,
32191                              const unsigned int z0, const unsigned int v0) const {
32192       CImgList<T>(*this,true).save_cimg(file,n0,x0,y0,z0,v0);
32193       return *this;
32194     }
32195 
32196     //! Save an empty .cimg file with specified dimensions.
32197     static void save_empty_cimg(const char *const filename,
32198                                 const unsigned int dx, const unsigned int dy=1,
32199                                 const unsigned int dz=1, const unsigned int dv=1) {
32200       return CImgList<T>::save_empty_cimg(filename,1,dx,dy,dz,dv);
32201     }
32202 
32203     //! Save an empty .cimg file with specified dimensions.
32204     static void save_empty_cimg(cimg_std::FILE *const file,
32205                                 const unsigned int dx, const unsigned int dy=1,
32206                                 const unsigned int dz=1, const unsigned int dv=1) {
32207       return CImgList<T>::save_empty_cimg(file,1,dx,dy,dz,dv);
32208     }
32209 
32210     // Save the image as an INRIMAGE-4 file (internal).
32211     const CImg<T>& _save_inr(cimg_std::FILE *const file, const char *const filename, const float *const voxsize) const {
32212       if (is_empty())
32213         throw CImgInstanceException("CImg<%s>::save_inr() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32214                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32215       if (!filename)
32216         throw CImgArgumentException("CImg<%s>::save_inr() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32217                                     pixel_type(),width,height,depth,dim,data);
32218       int inrpixsize=-1;
32219       const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0";
32220       if (!cimg::strcasecmp(pixel_type(),"unsigned char"))  { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
32221       if (!cimg::strcasecmp(pixel_type(),"char"))           { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
32222       if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; }
32223       if (!cimg::strcasecmp(pixel_type(),"short"))          { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; }
32224       if (!cimg::strcasecmp(pixel_type(),"unsigned int"))   { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; }
32225       if (!cimg::strcasecmp(pixel_type(),"int"))            { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; }
32226       if (!cimg::strcasecmp(pixel_type(),"float"))          { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; }
32227       if (!cimg::strcasecmp(pixel_type(),"double"))         { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; }
32228       if (inrpixsize<=0)
32229         throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of '%s'",
32230                               pixel_type(),pixel_type());
32231       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
32232       char header[257];
32233       int err = cimg_std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim);
32234       if (voxsize) err += cimg_std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]);
32235       err += cimg_std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm");
32236       cimg_std::memset(header+err,'\n',252-err);
32237       cimg_std::memcpy(header+252,"##}\n",4);
32238       cimg::fwrite(header,256,nfile);
32239       cimg_forXYZ(*this,x,y,z) cimg_forV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),1,nfile);
32240       if (!file) cimg::fclose(nfile);
32241       return *this;
32242     }
32243 
32244     //! Save the image as an INRIMAGE-4 file.
32245     const CImg<T>& save_inr(const char *const filename, const float *const voxsize=0) const {
32246       return _save_inr(0,filename,voxsize);
32247     }
32248 
32249     //! Save the image as an INRIMAGE-4 file.
32250     const CImg<T>& save_inr(cimg_std::FILE *const file, const float *const voxsize=0) const {
32251       return _save_inr(file,0,voxsize);
32252     }
32253 
32254     // Save the image as a PANDORE-5 file (internal).
32255     unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const {
32256       unsigned int nbdims = 0;
32257       if (id==2 || id==3 || id==4)    { dims[0] = 1;   dims[1] = width;  nbdims = 2; }
32258       if (id==5 || id==6 || id==7)    { dims[0] = 1;   dims[1] = height; dims[2] = width;  nbdims=3; }
32259       if (id==8 || id==9 || id==10)   { dims[0] = dim; dims[1] = depth;  dims[2] = height; dims[3] = width; nbdims = 4; }
32260       if (id==16 || id==17 || id==18) { dims[0] = 3;   dims[1] = height; dims[2] = width;  dims[3] = colorspace; nbdims = 4; }
32261       if (id==19 || id==20 || id==21) { dims[0] = 3;   dims[1] = depth;  dims[2] = height; dims[3] = width; dims[4] = colorspace; nbdims = 5; }
32262       if (id==22 || id==23 || id==25) { dims[0] = dim; dims[1] = width;  nbdims = 2; }
32263       if (id==26 || id==27 || id==29) { dims[0] = dim; dims[1] = height; dims[2] = width;  nbdims=3; }
32264       if (id==30 || id==31 || id==33) { dims[0] = dim; dims[1] = depth;  dims[2] = height; dims[3] = width; nbdims = 4; }
32265       return nbdims;
32266     }
32267 
32268     const CImg<T>& _save_pandore(cimg_std::FILE *const file, const char *const filename, const unsigned int colorspace) const {
32269       typedef unsigned char uchar;
32270       typedef unsigned short ushort;
32271       typedef unsigned int uint;
32272       typedef unsigned long ulong;
32273 
32274 #define __cimg_save_pandore_case(dtype) \
32275        dtype *buffer = new dtype[size()]; \
32276        const T *ptrs = data; \
32277        cimg_foroff(*this,off) *(buffer++) = (dtype)(*(ptrs++)); \
32278        buffer-=size(); \
32279        cimg::fwrite(buffer,size(),nfile); \
32280        delete[] buffer
32281 
32282 #define _cimg_save_pandore_case(sy,sz,sv,stype,id) \
32283       if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !cimg::strcmp(stype,pixel_type())) { \
32284         unsigned int *iheader = (unsigned int*)(header+12); \
32285         nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \
32286         cimg::fwrite(header,36,nfile); \
32287         if (sizeof(ulong)==4) { ulong ndims[5]; for (int d = 0; d<5; ++d) ndims[d] = (ulong)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
32288         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); } \
32289         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); } \
32290         else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
32291                                    "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
32292                                    depth,dim,data); \
32293         if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
32294           __cimg_save_pandore_case(uchar); \
32295         } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
32296           if (sizeof(ulong)==4) { __cimg_save_pandore_case(ulong); } \
32297           else if (sizeof(uint)==4) { __cimg_save_pandore_case(uint); } \
32298           else if (sizeof(ushort)==4) { __cimg_save_pandore_case(ushort); } \
32299           else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
32300                                      "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
32301                                      depth,dim,data); \
32302         } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
32303           if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \
32304           else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \
32305           else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
32306                                      "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
32307                                      depth,dim,data); \
32308         } \
32309         saved = true; \
32310       }
32311 
32312       if (is_empty())
32313         throw CImgInstanceException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32314                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32315       if (!file && !filename)
32316         throw CImgArgumentException("CImg<%s>::save_pandore() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32317                                     pixel_type(),width,height,depth,dim,data);
32318       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
32319       unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
32320                                    0,0,0,0,'C','I','m','g',0,0,0,0,0,'N','o',' ','d','a','t','e',0,0,0,0 };
32321       unsigned int nbdims, dims[5];
32322       bool saved = false;
32323       _cimg_save_pandore_case(1,1,1,"unsigned char",2);
32324       _cimg_save_pandore_case(1,1,1,"char",3);
32325       _cimg_save_pandore_case(1,1,1,"short",3);
32326       _cimg_save_pandore_case(1,1,1,"unsigned short",3);
32327       _cimg_save_pandore_case(1,1,1,"unsigned int",3);
32328       _cimg_save_pandore_case(1,1,1,"int",3);
32329       _cimg_save_pandore_case(1,1,1,"unsigned long",4);
32330       _cimg_save_pandore_case(1,1,1,"long",3);
32331       _cimg_save_pandore_case(1,1,1,"float",4);
32332       _cimg_save_pandore_case(1,1,1,"double",4);
32333 
32334       _cimg_save_pandore_case(0,1,1,"unsigned char",5);
32335       _cimg_save_pandore_case(0,1,1,"char",6);
32336       _cimg_save_pandore_case(0,1,1,"short",6);
32337       _cimg_save_pandore_case(0,1,1,"unsigned short",6);
32338       _cimg_save_pandore_case(0,1,1,"unsigned int",6);
32339       _cimg_save_pandore_case(0,1,1,"int",6);
32340       _cimg_save_pandore_case(0,1,1,"unsigned long",7);
32341       _cimg_save_pandore_case(0,1,1,"long",6);
32342       _cimg_save_pandore_case(0,1,1,"float",7);
32343       _cimg_save_pandore_case(0,1,1,"double",7);
32344 
32345       _cimg_save_pandore_case(0,0,1,"unsigned char",8);
32346       _cimg_save_pandore_case(0,0,1,"char",9);
32347       _cimg_save_pandore_case(0,0,1,"short",9);
32348       _cimg_save_pandore_case(0,0,1,"unsigned short",9);
32349       _cimg_save_pandore_case(0,0,1,"unsigned int",9);
32350       _cimg_save_pandore_case(0,0,1,"int",9);
32351       _cimg_save_pandore_case(0,0,1,"unsigned long",10);
32352       _cimg_save_pandore_case(0,0,1,"long",9);
32353       _cimg_save_pandore_case(0,0,1,"float",10);
32354       _cimg_save_pandore_case(0,0,1,"double",10);
32355 
32356       _cimg_save_pandore_case(0,1,3,"unsigned char",16);
32357       _cimg_save_pandore_case(0,1,3,"char",17);
32358       _cimg_save_pandore_case(0,1,3,"short",17);
32359       _cimg_save_pandore_case(0,1,3,"unsigned short",17);
32360       _cimg_save_pandore_case(0,1,3,"unsigned int",17);
32361       _cimg_save_pandore_case(0,1,3,"int",17);
32362       _cimg_save_pandore_case(0,1,3,"unsigned long",18);
32363       _cimg_save_pandore_case(0,1,3,"long",17);
32364       _cimg_save_pandore_case(0,1,3,"float",18);
32365       _cimg_save_pandore_case(0,1,3,"double",18);
32366 
32367       _cimg_save_pandore_case(0,0,3,"unsigned char",19);
32368       _cimg_save_pandore_case(0,0,3,"char",20);
32369       _cimg_save_pandore_case(0,0,3,"short",20);
32370       _cimg_save_pandore_case(0,0,3,"unsigned short",20);
32371       _cimg_save_pandore_case(0,0,3,"unsigned int",20);
32372       _cimg_save_pandore_case(0,0,3,"int",20);
32373       _cimg_save_pandore_case(0,0,3,"unsigned long",21);
32374       _cimg_save_pandore_case(0,0,3,"long",20);
32375       _cimg_save_pandore_case(0,0,3,"float",21);
32376       _cimg_save_pandore_case(0,0,3,"double",21);
32377 
32378       _cimg_save_pandore_case(1,1,0,"unsigned char",22);
32379       _cimg_save_pandore_case(1,1,0,"char",23);
32380       _cimg_save_pandore_case(1,1,0,"short",23);
32381       _cimg_save_pandore_case(1,1,0,"unsigned short",23);
32382       _cimg_save_pandore_case(1,1,0,"unsigned int",23);
32383       _cimg_save_pandore_case(1,1,0,"int",23);
32384       _cimg_save_pandore_case(1,1,0,"unsigned long",25);
32385       _cimg_save_pandore_case(1,1,0,"long",23);
32386       _cimg_save_pandore_case(1,1,0,"float",25);
32387       _cimg_save_pandore_case(1,1,0,"double",25);
32388 
32389       _cimg_save_pandore_case(0,1,0,"unsigned char",26);
32390       _cimg_save_pandore_case(0,1,0,"char",27);
32391       _cimg_save_pandore_case(0,1,0,"short",27);
32392       _cimg_save_pandore_case(0,1,0,"unsigned short",27);
32393       _cimg_save_pandore_case(0,1,0,"unsigned int",27);
32394       _cimg_save_pandore_case(0,1,0,"int",27);
32395       _cimg_save_pandore_case(0,1,0,"unsigned long",29);
32396       _cimg_save_pandore_case(0,1,0,"long",27);
32397       _cimg_save_pandore_case(0,1,0,"float",29);
32398       _cimg_save_pandore_case(0,1,0,"double",29);
32399 
32400       _cimg_save_pandore_case(0,0,0,"unsigned char",30);
32401       _cimg_save_pandore_case(0,0,0,"char",31);
32402       _cimg_save_pandore_case(0,0,0,"short",31);
32403       _cimg_save_pandore_case(0,0,0,"unsigned short",31);
32404       _cimg_save_pandore_case(0,0,0,"unsigned int",31);
32405       _cimg_save_pandore_case(0,0,0,"int",31);
32406       _cimg_save_pandore_case(0,0,0,"unsigned long",33);
32407       _cimg_save_pandore_case(0,0,0,"long",31);
32408       _cimg_save_pandore_case(0,0,0,"float",33);
32409       _cimg_save_pandore_case(0,0,0,"double",33);
32410 
32411       if (!file) cimg::fclose(nfile);
32412       return *this;
32413     }
32414 
32415     //! Save the image as a PANDORE-5 file.
32416     const CImg<T>& save_pandore(const char *const filename, const unsigned int colorspace=0) const {
32417       return _save_pandore(0,filename,colorspace);
32418     }
32419 
32420     //! Save the image as a PANDORE-5 file.
32421     const CImg<T>& save_pandore(cimg_std::FILE *const file, const unsigned int colorspace=0) const {
32422       return _save_pandore(file,0,colorspace);
32423     }
32424 
32425    // Save the image as a RAW file (internal).
32426     const CImg<T>& _save_raw(cimg_std::FILE *const file, const char *const filename, const bool multiplexed) const {
32427       if (is_empty())
32428         throw CImgInstanceException("CImg<%s>::save_raw() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32429                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32430       if (!file && !filename)
32431         throw CImgArgumentException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32432                                     pixel_type(),width,height,depth,dim,data);
32433       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
32434       if (!multiplexed) cimg::fwrite(data,size(),nfile);
32435       else {
32436         CImg<T> buf(dim);
32437         cimg_forXYZ(*this,x,y,z) {
32438           cimg_forV(*this,k) buf[k] = (*this)(x,y,z,k);
32439           cimg::fwrite(buf.data,dim,nfile);
32440         }
32441       }
32442       if (!file) cimg::fclose(nfile);
32443       return *this;
32444     }
32445 
32446     //! Save the image as a RAW file.
32447     const CImg<T>& save_raw(const char *const filename, const bool multiplexed=false) const {
32448       return _save_raw(0,filename,multiplexed);
32449     }
32450 
32451     //! Save the image as a RAW file.
32452     const CImg<T>& save_raw(cimg_std::FILE *const file, const bool multiplexed=false) const {
32453       return _save_raw(file,0,multiplexed);
32454     }
32455 
32456     //! Save the image as a video sequence file, using FFMPEG library.
32457     const CImg<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
32458                                const unsigned int fps=25) const {
32459       if (is_empty())
32460         throw CImgInstanceException("CImg<%s>::save_ffmpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32461                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32462       if (!filename)
32463         throw CImgArgumentException("CImg<%s>::save_ffmpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32464                                     pixel_type(),width,height,depth,dim,data);
32465       if (!fps)
32466         throw CImgArgumentException("CImg<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
32467                                     pixel_type(),filename);
32468 #ifndef cimg_use_ffmpeg
32469       return save_ffmpeg_external(filename,first_frame,last_frame);
32470 #else
32471       get_split('z').save_ffmpeg(filename,first_frame,last_frame,fps);
32472 #endif
32473       return *this;
32474     }
32475 
32476     //! Save the image as a YUV video sequence file.
32477     const CImg<T>& save_yuv(const char *const filename, const bool rgb2yuv=true) const {
32478       get_split('z').save_yuv(filename,rgb2yuv);
32479       return *this;
32480     }
32481 
32482     //! Save the image as a YUV video sequence file.
32483     const CImg<T>& save_yuv(cimg_std::FILE *const file, const bool rgb2yuv=true) const {
32484       get_split('z').save_yuv(file,rgb2yuv);
32485       return *this;
32486     }
32487 
32488    // Save OFF files (internal).
32489     template<typename tf, typename tc>
32490     const CImg<T>& _save_off(cimg_std::FILE *const file, const char *const filename,
32491                              const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces) const {
32492       if (is_empty())
32493         throw CImgInstanceException("CImg<%s>::save_off() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32494                                     pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32495       if (!file && !filename)
32496         throw CImgArgumentException("CImg<%s>::save_off() : Specified filename is (null).",
32497                                     pixel_type());
32498       if (height<3) return get_resize(-100,3,1,1,0)._save_off(file,filename,primitives,colors,invert_faces);
32499       CImgList<tc> _colors;
32500       if (!colors) _colors.insert(primitives.size,CImg<tc>::vector(200,200,200));
32501       const CImgList<tc>& ncolors = colors?colors:_colors;
32502 
32503       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
32504       cimg_std::fprintf(nfile,"OFF\n%u %u %u\n",width,primitives.size,3*primitives.size);
32505       cimg_forX(*this,i) cimg_std::fprintf(nfile,"%f %f %f\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2)));
32506       cimglist_for(primitives,l) {
32507         const unsigned int prim = primitives[l].size();
32508         const bool textured = (prim>4);
32509         const CImg<tc>& color = ncolors[l];
32510         const unsigned int s = textured?color.dimv():color.size();
32511         const float
32512           r = textured?(s>0?(float)(color.get_shared_channel(0).mean()/255.0f):1.0f):(s>0?(float)(color(0)/255.0f):1.0f),
32513           g = textured?(s>1?(float)(color.get_shared_channel(1).mean()/255.0f):r)   :(s>1?(float)(color(1)/255.0f):r),
32514           b = textured?(s>2?(float)(color.get_shared_channel(2).mean()/255.0f):r)   :(s>2?(float)(color(2)/255.0f):r);
32515 
32516         switch (prim) {
32517         case 1 :
32518           cimg_std::fprintf(nfile,"1 %u %f %f %f\n",(unsigned int)primitives(l,0),r,g,b);
32519           break;
32520         case 2 : case 6 :
32521           cimg_std::fprintf(nfile,"2 %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b);
32522           break;
32523         case 3 : case 9 :
32524           if (invert_faces)
32525             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);
32526           else
32527             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);
32528           break;
32529         case 4 : case 12 :
32530           if (invert_faces)
32531             cimg_std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
32532                          (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),(unsigned int)primitives(l,2),(unsigned int)primitives(l,3),r,g,b);
32533           else
32534             cimg_std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
32535                          (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),(unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b);
32536           break;
32537         }
32538       }
32539       if (!file) cimg::fclose(nfile);
32540       return *this;
32541     }
32542 
32543     //! Save OFF files.
32544     template<typename tf, typename tc>
32545     const CImg<T>& save_off(const char *const filename,
32546                             const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
32547       return _save_off(0,filename,primitives,colors,invert_faces);
32548     }
32549 
32550     //! Save OFF files.
32551     template<typename tf, typename tc>
32552     const CImg<T>& save_off(cimg_std::FILE *const file,
32553                             const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
32554       return _save_off(file,0,primitives,colors,invert_faces);
32555     }
32556 
32557     //! Save the image as a video sequence file, using the external tool 'ffmpeg'.
32558     const CImg<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
32559                                         const char *const codec="mpeg2video") const {
32560       if (is_empty())
32561         throw CImgInstanceException("CImg<%s>::save_ffmpeg_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32562                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32563       if (!filename)
32564         throw CImgArgumentException("CImg<%s>::save_ffmpeg_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32565                                     pixel_type(),width,height,depth,dim,data);
32566       get_split('z').save_ffmpeg_external(filename,first_frame,last_frame,codec);
32567       return *this;
32568     }
32569 
32570     //! Save the image using GraphicsMagick's gm.
32571     /** Function that saves the image for other file formats that are not natively handled by CImg,
32572         using the tool 'gm' from the GraphicsMagick package.\n
32573         This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
32574         the GraphicsMagick package in order to get
32575         this function working properly (see http://www.graphicsmagick.org ).
32576     **/
32577     const CImg<T>& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const {
32578       if (is_empty())
32579         throw CImgInstanceException("CImg<%s>::save_graphicsmagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32580                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32581       if (!filename)
32582         throw CImgArgumentException("CImg<%s>::save_graphicsmagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32583                                     pixel_type(),width,height,depth,dim,data);
32584       char command[1024],filetmp[512];
32585       cimg_std::FILE *file;
32586       do {
32587         if (dim==1) cimg_std::sprintf(filetmp,"%s%s%s.pgm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
32588         else cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
32589         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
32590       } while (file);
32591       save_pnm(filetmp);
32592       cimg_std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::graphicsmagick_path(),quality,filetmp,filename);
32593       cimg::system(command);
32594       file = cimg_std::fopen(filename,"rb");
32595       if (!file)
32596         throw CImgIOException("CImg<%s>::save_graphicsmagick_external() : Failed to save image '%s'.\n\n"
32597                               "Path of 'gm' : \"%s\"\n"
32598                               "Path of temporary filename : \"%s\"\n",
32599                               pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
32600       if (file) cimg::fclose(file);
32601       cimg_std::remove(filetmp);
32602       return *this;
32603     }
32604 
32605     //! Save an image as a gzipped file, using external tool 'gzip'.
32606     const CImg<T>& save_gzip_external(const char *const filename) const {
32607       if (!filename)
32608         throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
32609                               pixel_type());
32610       char command[1024], filetmp[512], body[512];
32611       const char
32612         *ext = cimg::split_filename(filename,body),
32613         *ext2 = cimg::split_filename(body,0);
32614       cimg_std::FILE *file;
32615       do {
32616         if (!cimg::strcasecmp(ext,"gz")) {
32617           if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
32618                                   cimg::filenamerand(),ext2);
32619           else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
32620                             cimg::filenamerand());
32621         } else {
32622           if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
32623                                  cimg::filenamerand(),ext);
32624           else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
32625                                  cimg::filenamerand());
32626         }
32627         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
32628       } while (file);
32629       save(filetmp);
32630       cimg_std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
32631       cimg::system(command);
32632       file = cimg_std::fopen(filename,"rb");
32633       if (!file)
32634         throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
32635                               pixel_type(),filename);
32636       else cimg::fclose(file);
32637       cimg_std::remove(filetmp);
32638       return *this;
32639     }
32640 
32641     //! Save the image using ImageMagick's convert.
32642     /** Function that saves the image for other file formats that are not natively handled by CImg,
32643         using the tool 'convert' from the ImageMagick package.\n
32644         This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
32645         the ImageMagick package in order to get
32646         this function working properly (see http://www.imagemagick.org ).
32647     **/
32648     const CImg<T>& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const {
32649       if (is_empty())
32650         throw CImgInstanceException("CImg<%s>::save_imagemagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32651                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32652       if (!filename)
32653         throw CImgArgumentException("CImg<%s>::save_imagemagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32654                                     pixel_type(),width,height,depth,dim,data);
32655       char command[1024], filetmp[512];
32656       cimg_std::FILE *file;
32657       do {
32658         cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand(),dim==1?"pgm":"ppm");
32659         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
32660       } while (file);
32661       save_pnm(filetmp);
32662       cimg_std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::imagemagick_path(),quality,filetmp,filename);
32663       cimg::system(command);
32664       file = cimg_std::fopen(filename,"rb");
32665       if (!file)
32666         throw CImgIOException("CImg<%s>::save_imagemagick_external() : Failed to save image '%s'.\n\n"
32667                               "Path of 'convert' : \"%s\"\n"
32668                               "Path of temporary filename : \"%s\"\n",
32669                               pixel_type(),filename,cimg::imagemagick_path(),filetmp);
32670       if (file) cimg::fclose(file);
32671       cimg_std::remove(filetmp);
32672       return *this;
32673     }
32674 
32675     //! Save an image as a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net )
32676     const CImg<T>& save_medcon_external(const char *const filename) const {
32677       if (is_empty())
32678         throw CImgInstanceException("CImg<%s>::save_medcon_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32679                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32680       if (!filename)
32681         throw CImgArgumentException("CImg<%s>::save_medcon_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32682                                     pixel_type(),width,height,depth,dim,data);
32683 
32684       char command[1024], filetmp[512], body[512];
32685       cimg_std::FILE *file;
32686       do {
32687         cimg_std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
32688         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
32689       } while (file);
32690       save_analyze(filetmp);
32691       cimg_std::sprintf(command,"%s -w -c dicom -o %s -f %s",cimg::medcon_path(),filename,filetmp);
32692       cimg::system(command);
32693       cimg_std::remove(filetmp);
32694       cimg::split_filename(filetmp,body);
32695       cimg_std::sprintf(filetmp,"%s.img",body);
32696       cimg_std::remove(filetmp);
32697       cimg_std::sprintf(command,"m000-%s",filename);
32698       file = cimg_std::fopen(command,"rb");
32699       if (!file) {
32700         cimg::fclose(cimg::fopen(filename,"r"));
32701         throw CImgIOException("CImg<%s>::save_medcon_external() : Failed to save image '%s'.\n\n"
32702                               "Path of 'medcon' : \"%s\"\n"
32703                               "Path of temporary filename : \"%s\"",
32704                               pixel_type(),filename,cimg::medcon_path(),filetmp);
32705       } else cimg::fclose(file);
32706       cimg_std::rename(command,filename);
32707       return *this;
32708     }
32709 
32710     // Try to save the image if other extension is provided.
32711     const CImg<T>& save_other(const char *const filename, const unsigned int quality=100) const {
32712       if (is_empty())
32713         throw CImgInstanceException("CImg<%s>::save_other() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32714                                     pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32715       if (!filename)
32716         throw CImgIOException("CImg<%s>::save_other() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32717                               pixel_type());
32718       const unsigned int odebug = cimg::exception_mode();
32719       bool is_saved = true;
32720       cimg::exception_mode() = 0;
32721       try { save_magick(filename); }
32722       catch (CImgException&) {
32723         try { save_imagemagick_external(filename,quality); }
32724         catch (CImgException&) {
32725           try { save_graphicsmagick_external(filename,quality); }
32726           catch (CImgException&) {
32727             is_saved = false;
32728           }
32729         }
32730       }
32731       cimg::exception_mode() = odebug;
32732       if (!is_saved)
32733         throw CImgIOException("CImg<%s>::save_other() : File '%s' cannot be saved.\n"
32734                               "Check you have either the ImageMagick or GraphicsMagick package installed.",
32735                               pixel_type(),filename);
32736       return *this;
32737     }
32738 
32739     // Get a 40x38 color logo of a 'danger' item (internal).
32740     static CImg<T> logo40x38() {
32741       static bool first_time = true;
32742       CImg<T> res(40,38,1,3);
32743       if (first_time) {
32744         const unsigned char *ptrs = cimg::logo40x38;
32745         T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2);
32746         for (unsigned int off = 0; off<res.width*res.height;) {
32747           const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++);
32748           for (unsigned int l=0; l<n; ++off, ++l) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; }
32749         }
32750         first_time = false;
32751       }
32752       return res;
32753     }
32754 
32755   };
32756 
32757   /*
32758    #-----------------------------------------
32759    #
32760    #
32761    #
32762    # Definition of the CImgList<> structure
32763    #
32764    #
32765    #
32766    #------------------------------------------
32767    */
32768 
32769   //! Class representing list of images CImg<T>.
32770   template<typename T>
32771   struct CImgList {
32772 
32773     //! Size of the list (number of elements inside).
32774     unsigned int size;
32775 
32776     //! Allocation size of the list.
32777     unsigned int allocsize;
32778 
32779     //! Pointer to the first list element.
32780     CImg<T> *data;
32781 
32782     //! Define a CImgList<T>::iterator.
32783     typedef CImg<T>* iterator;
32784 
32785     //! Define a CImgList<T>::const_iterator.
32786     typedef const CImg<T>* const_iterator;
32787 
32788     //! Get value type.
32789     typedef T value_type;
32790 
32791     // Define common T-dependent types.
32792     typedef typename cimg::superset<T,bool>::type Tbool;
32793     typedef typename cimg::superset<T,unsigned char>::type Tuchar;
32794     typedef typename cimg::superset<T,char>::type Tchar;
32795     typedef typename cimg::superset<T,unsigned short>::type Tushort;
32796     typedef typename cimg::superset<T,short>::type Tshort;
32797     typedef typename cimg::superset<T,unsigned int>::type Tuint;
32798     typedef typename cimg::superset<T,int>::type Tint;
32799     typedef typename cimg::superset<T,unsigned long>::type Tulong;
32800     typedef typename cimg::superset<T,long>::type Tlong;
32801     typedef typename cimg::superset<T,float>::type Tfloat;
32802     typedef typename cimg::superset<T,double>::type Tdouble;
32803     typedef typename cimg::last<T,bool>::type boolT;
32804     typedef typename cimg::last<T,unsigned char>::type ucharT;
32805     typedef typename cimg::last<T,char>::type charT;
32806     typedef typename cimg::last<T,unsigned short>::type ushortT;
32807     typedef typename cimg::last<T,short>::type shortT;
32808     typedef typename cimg::last<T,unsigned int>::type uintT;
32809     typedef typename cimg::last<T,int>::type intT;
32810     typedef typename cimg::last<T,unsigned long>::type ulongT;
32811     typedef typename cimg::last<T,long>::type longT;
32812     typedef typename cimg::last<T,float>::type floatT;
32813     typedef typename cimg::last<T,double>::type doubleT;
32814 
32815     //@}
32816     //---------------------------
32817     //
32818     //! \name Plugins
32819     //@{
32820     //---------------------------
32821 #ifdef cimglist_plugin
32822 #include cimglist_plugin
32823 #endif
32824 #ifdef cimglist_plugin1
32825 #include cimglist_plugin1
32826 #endif
32827 #ifdef cimglist_plugin2
32828 #include cimglist_plugin2
32829 #endif
32830 #ifdef cimglist_plugin3
32831 #include cimglist_plugin3
32832 #endif
32833 #ifdef cimglist_plugin4
32834 #include cimglist_plugin4
32835 #endif
32836 #ifdef cimglist_plugin5
32837 #include cimglist_plugin5
32838 #endif
32839 #ifdef cimglist_plugin6
32840 #include cimglist_plugin6
32841 #endif
32842 #ifdef cimglist_plugin7
32843 #include cimglist_plugin7
32844 #endif
32845 #ifdef cimglist_plugin8
32846 #include cimglist_plugin8
32847 #endif
32848     //@}
32849 
32850     //------------------------------------------
32851     //
32852     //! \name Constructors - Destructor - Copy
32853     //@{
32854     //------------------------------------------
32855 
32856     //! Destructor.
32857     ~CImgList() {
32858       if (data) delete[] data;
32859     }
32860 
32861     //! Default constructor.
32862     CImgList():
32863       size(0),allocsize(0),data(0) {}
32864 
32865     //! Construct an image list containing n empty images.
32866     explicit CImgList(const unsigned int n):
32867       size(n) {
32868       data = new CImg<T>[allocsize = cimg::max(16UL,cimg::nearest_pow2(n))];
32869     }
32870 
32871     //! Default copy constructor.
32872     template<typename t>
32873     CImgList(const CImgList<t>& list):
32874       size(0),allocsize(0),data(0) {
32875       assign(list.size);
32876       cimglist_for(*this,l) data[l].assign(list[l],false);
32877     }
32878 
32879     CImgList(const CImgList<T>& list):
32880       size(0),allocsize(0),data(0) {
32881       assign(list.size);
32882       cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
32883     }
32884 
32885     //! Advanced copy constructor.
32886     template<typename t>
32887     CImgList(const CImgList<t>& list, const bool shared):
32888       size(0),allocsize(0),data(0) {
32889       assign(list.size);
32890       if (shared)
32891         throw CImgArgumentException("CImgList<%s>::CImgList() : Cannot construct a list instance with shared images from "
32892                                     "a CImgList<%s> (different pixel types).",
32893                                     pixel_type(),CImgList<t>::pixel_type());
32894       cimglist_for(*this,l) data[l].assign(list[l],false);
32895     }
32896 
32897     CImgList(const CImgList<T>& list, const bool shared):
32898       size(0),allocsize(0),data(0) {
32899       assign(list.size);
32900       cimglist_for(*this,l) data[l].assign(list[l],shared);
32901     }
32902 
32903     //! Construct an image list containing n images with specified size.
32904     CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1,
32905              const unsigned int depth=1, const unsigned int dim=1):
32906       size(0),allocsize(0),data(0) {
32907       assign(n);
32908       cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
32909     }
32910 
32911     //! Construct an image list containing n images with specified size, filled with specified value.
32912     CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
32913              const unsigned int depth, const unsigned int dim, const T val):
32914       size(0),allocsize(0),data(0) {
32915       assign(n);
32916       cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
32917     }
32918 
32919     //! Construct an image list containing n images with specified size and specified pixel values (int version).
32920     CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
32921              const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...):
32922       size(0),allocsize(0),data(0) {
32923 #define _CImgList_stdarg(t) { \
32924         assign(n,width,height,depth,dim); \
32925         const unsigned int siz = width*height*depth*dim, nsiz = siz*n; \
32926         T *ptrd = data->data; \
32927         va_list ap; \
32928         va_start(ap,val1); \
32929         for (unsigned int l=0, s=0, i=0; i<nsiz; ++i) { \
32930           *(ptrd++) = (T)(i==0?val0:(i==1?val1:va_arg(ap,t))); \
32931           if ((++s)==siz) { ptrd = data[++l].data; s=0; } \
32932         } \
32933         va_end(ap); \
32934       }
32935       _CImgList_stdarg(int);
32936     }
32937 
32938     //! Construct an image list containing n images with specified size and specified pixel values (double version).
32939     CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
32940              const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...):
32941       size(0),allocsize(0),data(0) {
32942       _CImgList_stdarg(double);
32943     }
32944 
32945     //! Construct a list containing n copies of the image img.
32946     template<typename t>
32947     CImgList(const unsigned int n, const CImg<t>& img):
32948       size(0),allocsize(0),data(0) {
32949       assign(n);
32950       cimglist_for(*this,l) data[l].assign(img,img.is_shared);
32951     }
32952 
32953     //! Construct a list containing n copies of the image img, forcing the shared state.
32954     template<typename t>
32955     CImgList(const unsigned int n, const CImg<t>& img, const bool shared):
32956       size(0),allocsize(0),data(0) {
32957       assign(n);
32958       cimglist_for(*this,l) data[l].assign(img,shared);
32959     }
32960 
32961     //! Construct an image list from one image.
32962     template<typename t>
32963     explicit CImgList(const CImg<t>& img):
32964       size(0),allocsize(0),data(0) {
32965       assign(1);
32966       data[0].assign(img,img.is_shared);
32967     }
32968 
32969     //! Construct an image list from one image, forcing the shared state.
32970     template<typename t>
32971     explicit CImgList(const CImg<t>& img, const bool shared):
32972       size(0),allocsize(0),data(0) {
32973       assign(1);
32974       data[0].assign(img,shared);
32975     }
32976 
32977     //! Construct an image list from two images.
32978     template<typename t1, typename t2>
32979     CImgList(const CImg<t1>& img1, const CImg<t2>& img2):
32980       size(0),allocsize(0),data(0) {
32981       assign(2);
32982       data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared);
32983     }
32984 
32985     //! Construct an image list from two images, forcing the shared state.
32986     template<typename t1, typename t2>
32987     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared):
32988       size(0),allocsize(0),data(0) {
32989       assign(2);
32990       data[0].assign(img1,shared); data[1].assign(img2,shared);
32991     }
32992 
32993     //! Construct an image list from three images.
32994     template<typename t1, typename t2, typename t3>
32995     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3):
32996       size(0),allocsize(0),data(0) {
32997       assign(3);
32998       data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared);
32999     }
33000 
33001     //! Construct an image list from three images, forcing the shared state.
33002     template<typename t1, typename t2, typename t3>
33003     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared):
33004       size(0),allocsize(0),data(0) {
33005       assign(3);
33006       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
33007     }
33008 
33009     //! Construct an image list from four images.
33010     template<typename t1, typename t2, typename t3, typename t4>
33011     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4):
33012       size(0),allocsize(0),data(0) {
33013       assign(4);
33014       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);
33015     }
33016 
33017     //! Construct an image list from four images, forcing the shared state.
33018     template<typename t1, typename t2, typename t3, typename t4>
33019     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const bool shared):
33020       size(0),allocsize(0),data(0) {
33021       assign(4);
33022       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33023     }
33024 
33025     //! Construct an image list from five images.
33026     template<typename t1, typename t2, typename t3, typename t4, typename t5>
33027     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33028              const CImg<t5>& img5):
33029       size(0),allocsize(0),data(0) {
33030       assign(5);
33031       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);
33032       data[4].assign(img5,img5.is_shared);
33033     }
33034 
33035     //! Construct an image list from five images, forcing the shared state.
33036     template<typename t1, typename t2, typename t3, typename t4, typename t5>
33037     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33038              const CImg<t5>& img5, const bool shared):
33039       size(0),allocsize(0),data(0) {
33040       assign(5);
33041       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33042       data[4].assign(img5,shared);
33043     }
33044 
33045     //! Construct an image list from six images.
33046     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
33047     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33048              const CImg<t5>& img5, const CImg<t6>& img6):
33049       size(0),allocsize(0),data(0) {
33050       assign(6);
33051       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);
33052       data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared);
33053     }
33054 
33055     //! Construct an image list from six images, forcing the shared state.
33056     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
33057     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33058              const CImg<t5>& img5, const CImg<t6>& img6, const bool shared):
33059       size(0),allocsize(0),data(0) {
33060       assign(6);
33061       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33062       data[4].assign(img5,shared); data[5].assign(img6,shared);
33063     }
33064 
33065     //! Construct an image list from seven images.
33066     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
33067     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33068              const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7):
33069       size(0),allocsize(0),data(0) {
33070       assign(7);
33071       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);
33072       data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared); data[6].assign(img7,img7.is_shared);
33073     }
33074 
33075     //! Construct an image list from seven images, forcing the shared state.
33076     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
33077     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33078              const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared):
33079       size(0),allocsize(0),data(0) {
33080       assign(7);
33081       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33082       data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
33083     }
33084 
33085     //! Construct an image list from eight images.
33086     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
33087     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33088              const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8):
33089       size(0),allocsize(0),data(0) {
33090       assign(8);
33091       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);
33092       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);
33093     }
33094 
33095     //! Construct an image list from eight images, forcing the shared state.
33096     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
33097     CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33098              const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared):
33099       size(0),allocsize(0),data(0) {
33100       assign(8);
33101       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33102       data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
33103     }
33104 
33105     //! Construct an image list from a filename.
33106     explicit CImgList(const char *const filename):
33107       size(0),allocsize(0),data(0) {
33108       assign(filename);
33109     }
33110 
33111     //! In-place version of the default constructor and default destructor.
33112     CImgList<T>& assign() {
33113       if (data) delete[] data;
33114       size = allocsize = 0;
33115       data = 0;
33116       return *this;
33117     }
33118 
33119     //! Equivalent to assign() (STL-compliant name).
33120     CImgList<T>& clear() {
33121       return assign();
33122     }
33123 
33124     //! In-place version of the corresponding constructor.
33125     CImgList<T>& assign(const unsigned int n) {
33126       if (n) {
33127         if (allocsize<n || allocsize>(n<<2)) {
33128           if (data) delete[] data;
33129           data = new CImg<T>[allocsize=cimg::max(16UL,cimg::nearest_pow2(n))];
33130         }
33131         size = n;
33132       } else assign();
33133       return *this;
33134     }
33135 
33136     //! In-place version of the corresponding constructor.
33137     CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height=1,
33138                         const unsigned int depth=1, const unsigned int dim=1) {
33139       assign(n);
33140       cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
33141       return *this;
33142     }
33143 
33144     //! In-place version of the corresponding constructor.
33145     CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
33146                         const unsigned int depth, const unsigned int dim, const T val) {
33147       assign(n);
33148       cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
33149       return *this;
33150     }
33151 
33152     //! In-place version of the corresponding constructor.
33153     CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
33154                         const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...) {
33155       _CImgList_stdarg(int);
33156       return *this;
33157     }
33158 
33159     //! In-place version of the corresponding constructor.
33160     CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
33161                         const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...) {
33162       _CImgList_stdarg(double);
33163       return *this;
33164     }
33165 
33166     //! In-place version of the copy constructor.
33167     template<typename t>
33168     CImgList<T>& assign(const CImgList<t>& list) {
33169       assign(list.size);
33170       cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
33171       return *this;
33172     }
33173 
33174     //! In-place version of the copy constructor.
33175     template<typename t>
33176     CImgList<T>& assign(const CImgList<t>& list, const bool shared) {
33177       assign(list.size);
33178       cimglist_for(*this,l) data[l].assign(list[l],shared);
33179       return *this;
33180     }
33181 
33182     //! In-place version of the corresponding constructor.
33183     template<typename t>
33184     CImgList<T>& assign(const unsigned int n, const CImg<t>& img, const bool shared=false) {
33185       assign(n);
33186       cimglist_for(*this,l) data[l].assign(img,shared);
33187       return *this;
33188     }
33189 
33190     //! In-place version of the corresponding constructor.
33191     template<typename t>
33192     CImgList<T>& assign(const CImg<t>& img, const bool shared=false) {
33193       assign(1);
33194       data[0].assign(img,shared);
33195       return *this;
33196     }
33197 
33198     //! In-place version of the corresponding constructor.
33199     template<typename t1, typename t2>
33200     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false) {
33201       assign(2);
33202       data[0].assign(img1,shared); data[1].assign(img2,shared);
33203       return *this;
33204     }
33205 
33206     //! In-place version of the corresponding constructor.
33207     template<typename t1, typename t2, typename t3>
33208     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false) {
33209       assign(3);
33210       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
33211       return *this;
33212     }
33213 
33214     //! In-place version of the corresponding constructor.
33215     template<typename t1, typename t2, typename t3, typename t4>
33216     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33217                         const bool shared=false) {
33218       assign(4);
33219       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33220       return *this;
33221     }
33222 
33223     //! In-place version of the corresponding constructor.
33224     template<typename t1, typename t2, typename t3, typename t4, typename t5>
33225     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33226                         const CImg<t5>& img5, const bool shared=false) {
33227       assign(5);
33228       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33229       data[4].assign(img5,shared);
33230       return *this;
33231     }
33232 
33233     //! In-place version of the corresponding constructor.
33234     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
33235     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33236                         const CImg<t5>& img5, const CImg<t6>& img6, const bool shared=false) {
33237       assign(6);
33238       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33239       data[4].assign(img5,shared); data[5].assign(img6,shared);
33240       return *this;
33241     }
33242 
33243     //! In-place version of the corresponding constructor.
33244     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
33245     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33246                         const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false) {
33247       assign(7);
33248       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33249       data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
33250       return *this;
33251     }
33252 
33253     //! In-place version of the corresponding constructor.
33254     template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
33255     CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33256                         const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false) {
33257       assign(8);
33258       data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33259       data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
33260       return *this;
33261     }
33262 
33263     //! In-place version of the corresponding constructor.
33264     CImgList<T>& assign(const char *const filename) {
33265       return load(filename);
33266     }
33267 
33268     //! Transfer the content of the instance image list into another one.
33269     template<typename t>
33270     CImgList<T>& transfer_to(CImgList<t>& list) {
33271       list.assign(*this);
33272       assign();
33273       return list;
33274     }
33275 
33276     CImgList<T>& transfer_to(CImgList<T>& list) {
33277       list.assign();
33278       return swap(list);
33279     }
33280 
33281     //! Swap all fields of two CImgList instances (use with care !)
33282     CImgList<T>& swap(CImgList<T>& list) {
33283       cimg::swap(size,list.size);
33284       cimg::swap(allocsize,list.allocsize);
33285       cimg::swap(data,list.data);
33286       return list;
33287     }
33288 
33289     //! Return a string describing the type of the image pixels in the list (template parameter \p T).
33290     static const char* pixel_type() {
33291       return cimg::type<T>::string();
33292     }
33293 
33294     //! Return \p true if list is empty.
33295     bool is_empty() const {
33296       return (!data || !size);
33297     }
33298 
33299     //! Return \p true if list is not empty.
33300     operator bool() const {
33301       return !is_empty();
33302     }
33303 
33304     //! Return \p true if list if of specified size.
33305     bool is_sameN(const unsigned int n) const {
33306       return (size==n);
33307     }
33308 
33309     //! Return \p true if list if of specified size.
33310     template<typename t>
33311     bool is_sameN(const CImgList<t>& list) const {
33312       return (size==list.size);
33313     }
33314 
33315     // Define useful dimension check functions.
33316     // (not documented because they are macro-generated).
33317 #define _cimglist_def_is_same1(axis) \
33318     bool is_same##axis(const unsigned int val) const { \
33319       bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis(val); return res; \
33320     } \
33321     bool is_sameN##axis(const unsigned int n, const unsigned int val) const { \
33322       return is_sameN(n) && is_same##axis(val); \
33323     } \
33324 
33325 #define _cimglist_def_is_same2(axis1,axis2) \
33326     bool is_same##axis1##axis2(const unsigned int val1, const unsigned int val2) const { \
33327       bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis1##axis2(val1,val2); return res; \
33328     } \
33329     bool is_sameN##axis1##axis2(const unsigned int n, const unsigned int val1, const unsigned int val2) const { \
33330       return is_sameN(n) && is_same##axis1##axis2(val1,val2); \
33331     } \
33332 
33333 #define _cimglist_def_is_same3(axis1,axis2,axis3) \
33334     bool is_same##axis1##axis2##axis3(const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
33335       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; \
33336     } \
33337     bool is_sameN##axis1##axis2##axis3(const unsigned int n, const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
33338       return is_sameN(n) && is_same##axis1##axis2##axis3(val1,val2,val3); \
33339     } \
33340 
33341 #define _cimglist_def_is_same(axis) \
33342     template<typename t> bool is_same##axis(const CImg<t>& img) const { \
33343       bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis(img); return res; \
33344     } \
33345     template<typename t> bool is_same##axis(const CImgList<t>& list) const { \
33346       const unsigned int lmin = cimg::min(size,list.size); \
33347       bool res = true; for (unsigned int l = 0; l<lmin && res; ++l) res = data[l].is_same##axis(list[l]); return res; \
33348     } \
33349     template<typename t> bool is_sameN##axis(const unsigned int n, const CImg<t>& img) const { \
33350       return (is_sameN(n) && is_same##axis(img)); \
33351     } \
33352     template<typename t> bool is_sameN##axis(const CImgList<t>& list) const { \
33353       return (is_sameN(list) && is_same##axis(list)); \
33354     }
33355 
33356     _cimglist_def_is_same(XY)
33357     _cimglist_def_is_same(XZ)
33358     _cimglist_def_is_same(XV)
33359     _cimglist_def_is_same(YZ)
33360     _cimglist_def_is_same(YV)
33361     _cimglist_def_is_same(XYZ)
33362     _cimglist_def_is_same(XYV)
33363     _cimglist_def_is_same(YZV)
33364     _cimglist_def_is_same(XYZV)
33365     _cimglist_def_is_same1(X)
33366     _cimglist_def_is_same1(Y)
33367     _cimglist_def_is_same1(Z)
33368     _cimglist_def_is_same1(V)
33369     _cimglist_def_is_same2(X,Y)
33370     _cimglist_def_is_same2(X,Z)
33371     _cimglist_def_is_same2(X,V)
33372     _cimglist_def_is_same2(Y,Z)
33373     _cimglist_def_is_same2(Y,V)
33374     _cimglist_def_is_same2(Z,V)
33375     _cimglist_def_is_same3(X,Y,Z)
33376     _cimglist_def_is_same3(X,Y,V)
33377     _cimglist_def_is_same3(X,Z,V)
33378     _cimglist_def_is_same3(Y,Z,V)
33379 
33380     bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
33381       bool res = true;
33382       for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_sameXYZV(dx,dy,dz,dv);
33383       return res;
33384     }
33385 
33386     bool is_sameNXYZV(const unsigned int n, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
33387       return is_sameN(n) && is_sameXYZV(dx,dy,dz,dv);
33388     }
33389 
33390     //! Return \c true if the list contains the pixel (n,x,y,z,v).
33391     bool containsNXYZV(const int n, const int x=0, const int y=0, const int z=0, const int v=0) const {
33392       if (is_empty()) return false;
33393       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();
33394     }
33395 
33396     //! Return \c true if the list contains the image (n).
33397     bool containsN(const int n) const {
33398       if (is_empty()) return false;
33399       return n>=0 && n<(int)size;
33400     }
33401 
33402     //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z,v).
33403     template<typename t>
33404     bool contains(const T& pixel, t& n, t& x, t&y, t& z, t& v) const {
33405       if (is_empty()) return false;
33406       cimglist_for(*this,l) if (data[l].contains(pixel,x,y,z,v)) { n = (t)l; return true; }
33407       return false;
33408     }
33409 
33410     //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z).
33411     template<typename t>
33412     bool contains(const T& pixel, t& n, t& x, t&y, t& z) const {
33413       t v;
33414       return contains(pixel,n,x,y,z,v);
33415     }
33416 
33417     //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y).
33418     template<typename t>
33419     bool contains(const T& pixel, t& n, t& x, t&y) const {
33420       t z,v;
33421       return contains(pixel,n,x,y,z,v);
33422     }
33423 
33424     //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x).
33425     template<typename t>
33426     bool contains(const T& pixel, t& n, t& x) const {
33427       t y,z,v;
33428       return contains(pixel,n,x,y,z,v);
33429     }
33430 
33431     //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n).
33432     template<typename t>
33433     bool contains(const T& pixel, t& n) const {
33434       t x,y,z,v;
33435       return contains(pixel,n,x,y,z,v);
33436     }
33437 
33438     //! Return \c true if one of the image list contains the specified referenced value.
33439     bool contains(const T& pixel) const {
33440       unsigned int n,x,y,z,v;
33441       return contains(pixel,n,x,y,z,v);
33442     }
33443 
33444     //! Return \c true if the list contains the image 'img'. If true, returns the position (n) of the image in the list.
33445     template<typename t>
33446     bool contains(const CImg<T>& img, t& n) const {
33447       if (is_empty()) return false;
33448       const CImg<T> *const ptr = &img;
33449       cimglist_for(*this,i) if (data+i==ptr) { n = (t)i; return true; }
33450       return false;
33451     }
33452 
33453     //! Return \c true if the list contains the image img.
33454     bool contains(const CImg<T>& img) const {
33455       unsigned int n;
33456       return contains(img,n);
33457     }
33458 
33459     //@}
33460     //------------------------------
33461     //
33462     //! \name Arithmetic Operators
33463     //@{
33464     //------------------------------
33465 
33466     //! Assignment operator
33467     template<typename t>
33468     CImgList<T>& operator=(const CImgList<t>& list) {
33469       return assign(list);
33470     }
33471 
33472     CImgList<T>& operator=(const CImgList<T>& list) {
33473       return assign(list);
33474     }
33475 
33476     //! Assignment operator.
33477     template<typename t>
33478     CImgList<T>& operator=(const CImg<t>& img) {
33479       cimglist_for(*this,l) data[l] = img;
33480       return *this;
33481     }
33482 
33483     //! Assignment operator.
33484     CImgList<T>& operator=(const T val) {
33485       cimglist_for(*this,l) data[l].fill(val);
33486       return *this;
33487     }
33488 
33489     //! Operator+.
33490     CImgList<T> operator+() const {
33491       return CImgList<T>(*this);
33492     }
33493 
33494     //! Operator+=.
33495 #ifdef cimg_use_visualcpp6
33496     CImgList<T>& operator+=(const T val)
33497 #else
33498     template<typename t>
33499     CImgList<T>& operator+=(const t val)
33500 #endif
33501     {
33502       cimglist_for(*this,l) (*this)[l]+=val;
33503       return *this;
33504     }
33505 
33506     //! Operator+=.
33507     template<typename t>
33508     CImgList<T>& operator+=(const CImgList<t>& list) {
33509       const unsigned int sizemax = cimg::min(size,list.size);
33510       for (unsigned int l=0; l<sizemax; ++l) (*this)[l]+=list[l];
33511       return *this;
33512     }
33513 
33514     //! Operator++ (prefix).
33515     CImgList<T>& operator++() {
33516       cimglist_for(*this,l) ++(*this)[l];
33517       return *this;
33518     }
33519 
33520     //! Operator++ (postfix).
33521     CImgList<T> operator++(int) {
33522       CImgList<T> copy(*this);
33523       ++*this;
33524       return copy;
33525     }
33526 
33527     //! Operator-.
33528     CImgList<T> operator-() const {
33529       CImgList<T> res(size);
33530       cimglist_for(res,l) res[l].assign(-data[l]);
33531       return res;
33532     }
33533 
33534     //! Operator-=.
33535 #ifdef cimg_use_visualcpp6
33536     CImgList<T>& operator-=(const T val)
33537 #else
33538       template<typename t>
33539     CImgList<T>& operator-=(const t val)
33540 #endif
33541     {
33542       cimglist_for(*this,l) (*this)[l]-=val;
33543       return *this;
33544     }
33545 
33546     //! Operator-=.
33547     template<typename t>
33548     CImgList<T>& operator-=(const CImgList<t>& list) {
33549       const unsigned int sizemax = min(size,list.size);
33550       for (unsigned int l=0; l<sizemax; ++l) (*this)[l]-=list[l];
33551       return *this;
33552     }
33553 
33554     //! Operator-- (prefix).
33555     CImgList<T>& operator--() {
33556       cimglist_for(*this,l) --(*this)[l];
33557       return *this;
33558     }
33559 
33560     //! Operator-- (postfix).
33561     CImgList<T> operator--(int) {
33562       CImgList<T> copy(*this);
33563       --*this;
33564       return copy;
33565     }
33566 
33567     //! Operator*=.
33568 #ifdef cimg_use_visualcpp6
33569     CImgList<T>& operator*=(const double val)
33570 #else
33571     template<typename t>
33572     CImgList<T>& operator*=(const t val)
33573 #endif
33574     {
33575       cimglist_for(*this,l) (*this)[l]*=val;
33576       return *this;
33577     }
33578 
33579     //! Operator*=.
33580     template<typename t>
33581     CImgList<T>& operator*=(const CImgList<t>& list) {
33582       const unsigned int N = cimg::min(size,list.size);
33583       for (unsigned int l=0; l<N; ++l) (*this)[l]*=list[l];
33584       return this;
33585     }
33586 
33587     //! Operator/=.
33588 #ifdef cimg_use_visualcpp6
33589     CImgList<T>& operator/=(const double val)
33590 #else
33591     template<typename t>
33592     CImgList<T>& operator/=(const t val)
33593 #endif
33594     {
33595       cimglist_for(*this,l) (*this)[l]/=val;
33596       return *this;
33597     }
33598 
33599     //! Operator/=.
33600     template<typename t>
33601     CImgList<T>& operator/=(const CImgList<t>& list) {
33602       const unsigned int N = cimg::min(size,list.size);
33603       for (unsigned int l=0; l<N; ++l) (*this)[l]/=list[l];
33604       return this;
33605     }
33606 
33607     //! Return a reference to the maximum pixel value of the instance list.
33608     const T& max() const {
33609       if (is_empty())
33610         throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
33611                                     pixel_type());
33612       const T *ptrmax = data->data;
33613       T max_value = *ptrmax;
33614       cimglist_for(*this,l) {
33615         const CImg<T>& img = data[l];
33616         cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
33617       }
33618       return *ptrmax;
33619     }
33620 
33621     //! Return a reference to the maximum pixel value of the instance list.
33622     T& max() {
33623       if (is_empty())
33624         throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
33625                                     pixel_type());
33626       T *ptrmax = data->data;
33627       T max_value = *ptrmax;
33628       cimglist_for(*this,l) {
33629         const CImg<T>& img = data[l];
33630         cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
33631       }
33632       return *ptrmax;
33633     }
33634 
33635     //! Return a reference to the minimum pixel value of the instance list.
33636     const T& min() const {
33637       if (is_empty())
33638         throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
33639                                     pixel_type());
33640       const T *ptrmin = data->data;
33641       T min_value = *ptrmin;
33642       cimglist_for(*this,l) {
33643         const CImg<T>& img = data[l];
33644         cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
33645       }
33646       return *ptrmin;
33647     }
33648 
33649     //! Return a reference to the minimum pixel value of the instance list.
33650     T& min() {
33651       if (is_empty())
33652         throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
33653                                     pixel_type());
33654       T *ptrmin = data->data;
33655       T min_value = *ptrmin;
33656       cimglist_for(*this,l) {
33657         const CImg<T>& img = data[l];
33658         cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
33659       }
33660       return *ptrmin;
33661     }
33662 
33663     //! Return a reference to the minimum pixel value of the instance list.
33664     template<typename t>
33665     const T& minmax(t& max_val) const {
33666       if (is_empty())
33667         throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
33668                                     pixel_type());
33669       const T *ptrmin = data->data;
33670       T min_value = *ptrmin, max_value = min_value;
33671       cimglist_for(*this,l) {
33672         const CImg<T>& img = data[l];
33673         cimg_for(img,ptr,T) {
33674           const T val = *ptr;
33675           if (val<min_value) { min_value = val; ptrmin = ptr; }
33676           if (val>max_value) max_value = val;
33677         }
33678       }
33679       max_val = (t)max_value;
33680       return *ptrmin;
33681     }
33682 
33683     //! Return a reference to the minimum pixel value of the instance list.
33684     template<typename t>
33685     T& minmax(t& max_val) {
33686       if (is_empty())
33687         throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
33688                                     pixel_type());
33689       T *ptrmin = data->data;
33690       T min_value = *ptrmin, max_value = min_value;
33691       cimglist_for(*this,l) {
33692         const CImg<T>& img = data[l];
33693         cimg_for(img,ptr,T) {
33694           const T val = *ptr;
33695           if (val<min_value) { min_value = val; ptrmin = ptr; }
33696           if (val>max_value) max_value = val;
33697         }
33698       }
33699       max_val = (t)max_value;
33700       return *ptrmin;
33701     }
33702 
33703     //! Return a reference to the minimum pixel value of the instance list.
33704     template<typename t>
33705     const T& maxmin(t& min_val) const {
33706       if (is_empty())
33707         throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
33708                                     pixel_type());
33709       const T *ptrmax = data->data;
33710       T min_value = *ptrmax, max_value = min_value;
33711       cimglist_for(*this,l) {
33712         const CImg<T>& img = data[l];
33713         cimg_for(img,ptr,T) {
33714           const T val = *ptr;
33715           if (val>max_value) { max_value = val; ptrmax = ptr; }
33716           if (val<min_value) min_value = val;
33717         }
33718       }
33719       min_val = (t)min_value;
33720       return *ptrmax;
33721     }
33722 
33723     //! Return a reference to the minimum pixel value of the instance list.
33724     template<typename t>
33725     T& maxmin(t& min_val) {
33726       if (is_empty())
33727         throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
33728                                     pixel_type());
33729       T *ptrmax = data->data;
33730       T min_value = *ptrmax, max_value = min_value;
33731       cimglist_for(*this,l) {
33732         const CImg<T>& img = data[l];
33733         cimg_for(img,ptr,T) {
33734           const T val = *ptr;
33735           if (val>max_value) { max_value = val; ptrmax = ptr; }
33736           if (val<min_value) min_value = val;
33737         }
33738       }
33739       min_val = (t)min_value;
33740       return *ptrmax;
33741     }
33742 
33743     //! Return the mean pixel value of the instance list.
33744     double mean() const {
33745       if (is_empty())
33746         throw CImgInstanceException("CImgList<%s>::mean() : Instance image list is empty.",
33747                                     pixel_type());
33748       double val = 0;
33749       unsigned int siz = 0;
33750       cimglist_for(*this,l) {
33751         const CImg<T>& img = data[l];
33752         cimg_for(img,ptr,T) val+=(double)*ptr;
33753         siz+=img.size();
33754       }
33755       return val/siz;
33756     }
33757 
33758     //! Return the variance of the instance list.
33759     double variance() {
33760       if (is_empty())
33761         throw CImgInstanceException("CImgList<%s>::variance() : Instance image list is empty.",
33762                                     pixel_type());
33763       double res = 0;
33764       unsigned int siz = 0;
33765       double S = 0, S2 = 0;
33766       cimglist_for(*this,l) {
33767         const CImg<T>& img = data[l];
33768         cimg_for(img,ptr,T) { const double val = (double)*ptr; S+=val;  S2+=val*val; }
33769         siz+=img.size();
33770       }
33771       res = (S2 - S*S/siz)/siz;
33772       return res;
33773     }
33774 
33775     //! Compute a list of statistics vectors (min,max,mean,variance,xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax).
33776     CImgList<T>& stats(const unsigned int variance_method=1) {
33777       if (is_empty()) return *this;
33778       cimglist_for(*this,l) data[l].stats(variance_method);
33779       return *this;
33780     }
33781 
33782     CImgList<Tfloat> get_stats(const unsigned int variance_method=1) const {
33783       CImgList<Tfloat> res(size);
33784       cimglist_for(*this,l) res[l] = data[l].get_stats(variance_method);
33785       return res;
33786     }
33787 
33788     //@}
33789     //-------------------------
33790     //
33791     //! \name List Manipulation
33792     //@{
33793     //-------------------------
33794 
33795     //! Return a reference to the i-th element of the image list.
33796     CImg<T>& operator[](const unsigned int pos) {
33797 #if cimg_debug>=3
33798       if (pos>=size) {
33799         cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
33800                    pixel_type(),pos,size);
33801         return *data;
33802       }
33803 #endif
33804       return data[pos];
33805     }
33806 
33807     const CImg<T>& operator[](const unsigned int pos) const {
33808 #if cimg_debug>=3
33809       if (pos>=size) {
33810         cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
33811                    pixel_type(),pos,size);
33812         return *data;
33813       }
33814 #endif
33815       return data[pos];
33816     }
33817 
33818     //! Equivalent to CImgList<T>::operator[]
33819     CImg<T>& operator()(const unsigned int pos) {
33820       return (*this)[pos];
33821     }
33822 
33823     const CImg<T>& operator()(const unsigned int pos) const {
33824       return (*this)[pos];
33825     }
33826 
33827     //! Return a reference to (x,y,z,v) pixel of the pos-th image of the list
33828     T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
33829                   const unsigned int z=0, const unsigned int v=0) {
33830       return (*this)[pos](x,y,z,v);
33831     }
33832     const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
33833                         const unsigned int z=0, const unsigned int v=0) const {
33834       return (*this)[pos](x,y,z,v);
33835     }
33836 
33837     // This function is only here for template tricks.
33838     T _display_object3d_at2(const int i, const int j) const {
33839       return atNXY(i,0,j,0,0,0);
33840     }
33841 
33842     //! Read an image in specified position.
33843     CImg<T>& at(const int pos) {
33844       if (is_empty())
33845         throw CImgInstanceException("CImgList<%s>::at() : Instance list is empty.",
33846                                     pixel_type());
33847       return data[pos<0?0:pos>=(int)size?(int)size-1:pos];
33848     }
33849 
33850     //! Read a pixel value with Dirichlet boundary conditions.
33851     T& atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
33852       return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXYZV(x,y,z,v,out_val);
33853     }
33854 
33855     T atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
33856       return (pos<0 || pos>=(int)size)?out_val:data[pos].atXYZV(x,y,z,v,out_val);
33857     }
33858 
33859     //! Read a pixel value with Neumann boundary conditions.
33860     T& atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
33861       if (is_empty())
33862         throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
33863                                     pixel_type());
33864       return _atNXYZV(pos,x,y,z,v);
33865     }
33866 
33867     T atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
33868       if (is_empty())
33869         throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
33870                                     pixel_type());
33871       return _atNXYZV(pos,x,y,z,v);
33872     }
33873 
33874     T& _atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
33875       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZV(x,y,z,v);
33876     }
33877 
33878     T _atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
33879       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZV(x,y,z,v);
33880     }
33881 
33882     //! Read a pixel value with Dirichlet boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z).
33883     T& atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
33884       return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXYZ(x,y,z,v,out_val);
33885     }
33886 
33887     T atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
33888       return (pos<0 || pos>=(int)size)?out_val:data[pos].atXYZ(x,y,z,v,out_val);
33889     }
33890 
33891     //! Read a pixel value with Neumann boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z).
33892     T& atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
33893       if (is_empty())
33894         throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
33895                                     pixel_type());
33896       return _atNXYZ(pos,x,y,z,v);
33897     }
33898 
33899     T atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
33900       if (is_empty())
33901         throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
33902                                     pixel_type());
33903       return _atNXYZ(pos,x,y,z,v);
33904     }
33905 
33906     T& _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
33907       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZ(x,y,z,v);
33908     }
33909 
33910     T _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
33911       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZ(x,y,z,v);
33912     }
33913 
33914     //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c pos, \c x,\c y).
33915     T& atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
33916       return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXY(x,y,z,v,out_val);
33917     }
33918 
33919     T atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
33920       return (pos<0 || pos>=(int)size)?out_val:data[pos].atXY(x,y,z,v,out_val);
33921     }
33922 
33923     //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c pos, \c x,\c y).
33924     T& atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
33925       if (is_empty())
33926         throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
33927                                     pixel_type());
33928       return _atNXY(pos,x,y,z,v);
33929     }
33930 
33931     T atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
33932       if (is_empty())
33933         throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
33934                                     pixel_type());
33935       return _atNXY(pos,x,y,z,v);
33936     }
33937 
33938     T& _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
33939       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXY(x,y,z,v);
33940     }
33941 
33942     T _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
33943       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXY(x,y,z,v);
33944     }
33945 
33946     //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c pos,\c x).
33947     T& atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
33948       return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atX(x,y,z,v,out_val);
33949     }
33950 
33951     T atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
33952       return (pos<0 || pos>=(int)size)?out_val:data[pos].atX(x,y,z,v,out_val);
33953     }
33954 
33955     //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c pos, \c x).
33956     T& atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
33957       if (is_empty())
33958         throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
33959                                     pixel_type());
33960       return _atNX(pos,x,y,z,v);
33961     }
33962 
33963     T atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
33964       if (is_empty())
33965         throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
33966                                     pixel_type());
33967       return _atNX(pos,x,y,z,v);
33968     }
33969 
33970     T& _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
33971       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atX(x,y,z,v);
33972     }
33973 
33974     T _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
33975       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atX(x,y,z,v);
33976     }
33977 
33978     //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c pos).
33979     T& atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
33980       return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):(*this)(pos,x,y,z,v);
33981     }
33982 
33983     T atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
33984       return (pos<0 || pos>=(int)size)?out_val:(*this)(pos,x,y,z,v);
33985     }
33986 
33987     //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c pos).
33988     T& atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
33989       if (is_empty())
33990         throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
33991                                     pixel_type());
33992       return _atN(pos,x,y,z,v);
33993     }
33994 
33995     T atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
33996       if (is_empty())
33997         throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
33998                                     pixel_type());
33999       return _atN(pos,x,y,z,v);
34000     }
34001 
34002     T& _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
34003       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)](x,y,z,v);
34004     }
34005 
34006     T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
34007       return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)](x,y,z,v);
34008     }
34009 
34010     //! Returns a reference to the last element.
34011     CImg<T>& back() {
34012       return (*this)(size-1);
34013     }
34014 
34015     const CImg<T>& back() const {
34016       return (*this)(size-1);
34017     }
34018 
34019     //! Returns a reference to the first element.
34020     CImg<T>& front() {
34021       return *data;
34022     }
34023 
34024     const CImg<T>& front() const {
34025       return *data;
34026     }
34027 
34028     //! Returns an iterator to the beginning of the vector.
34029     iterator begin() {
34030       return data;
34031     }
34032 
34033     const_iterator begin() const {
34034       return data;
34035     }
34036 
34037     //! Return a reference to the first image.
34038     const CImg<T>& first() const {
34039       return *data;
34040     }
34041 
34042     CImg<T>& first() {
34043       return *data;
34044     }
34045 
34046     //! Returns an iterator just past the last element.
34047     iterator end() {
34048       return data + size;
34049     }
34050 
34051     const_iterator end() const {
34052       return data + size;
34053     }
34054 
34055     //! Return a reference to the last image.
34056     const CImg<T>& last() const {
34057       return data[size - 1];
34058     }
34059 
34060     CImg<T>& last() {
34061       return data[size - 1];
34062     }
34063 
34064     //! Insert a copy of the image \p img into the current image list, at position \p pos.
34065     template<typename t>
34066     CImgList<T>& insert(const CImg<t>& img, const unsigned int pos, const bool shared) {
34067       const unsigned int npos = pos==~0U?size:pos;
34068       if (npos>size)
34069         throw CImgArgumentException("CImgList<%s>::insert() : Cannot insert at position %u into a list with %u elements",
34070                                     pixel_type(),npos,size);
34071       if (shared)
34072         throw CImgArgumentException("CImgList<%s>::insert(): Cannot insert a shared image CImg<%s> into a CImgList<%s>",
34073                                     pixel_type(),img.pixel_type(),pixel_type());
34074       CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
34075       if (!size || !data) {
34076         data = new_data;
34077         *data = img;
34078       } else {
34079         if (new_data) {
34080           if (npos) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
34081           if (npos!=size-1) cimg_std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
34082           cimg_std::memset(data,0,sizeof(CImg<T>)*(size-1));
34083           delete[] data;
34084           data = new_data;
34085         }
34086         else if (npos!=size-1) cimg_std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
34087         data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
34088         data[npos] = img;
34089       }
34090       return *this;
34091     }
34092 
34093     CImgList<T>& insert(const CImg<T>& img, const unsigned int pos, const bool shared) {
34094       const unsigned int npos = pos==~0U?size:pos;
34095       if (npos>size)
34096         throw CImgArgumentException("CImgList<%s>::insert() : Can't insert at position %u into a list with %u elements",
34097                                     pixel_type(),npos,size);
34098       if (&img>=data && &img<data+size) return insert(+img,pos,shared);
34099       CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
34100       if (!size || !data) {
34101         data = new_data;
34102         if (shared && img) {
34103           data->width = img.width; data->height = img.height; data->depth = img.depth; data->dim = img.dim;
34104           data->is_shared = true; data->data = img.data;
34105         } else *data = img;
34106       }
34107       else {
34108         if (new_data) {
34109           if (npos) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
34110           if (npos!=size-1) cimg_std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
34111           if (shared && img) {
34112             new_data[npos].width = img.width; new_data[npos].height = img.height; new_data[npos].depth = img.depth;
34113             new_data[npos].dim = img.dim; new_data[npos].is_shared = true; new_data[npos].data = img.data;
34114           } else {
34115             new_data[npos].width = new_data[npos].height = new_data[npos].depth = new_data[npos].dim = 0; new_data[npos].data = 0;
34116             new_data[npos] = img;
34117           }
34118           cimg_std::memset(data,0,sizeof(CImg<T>)*(size-1));
34119           delete[] data;
34120           data = new_data;
34121         } else {
34122           if (npos!=size-1) cimg_std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
34123           if (shared && img) {
34124             data[npos].width = img.width; data[npos].height = img.height; data[npos].depth = img.depth; data[npos].dim = img.dim;
34125             data[npos].is_shared = true; data[npos].data = img.data;
34126           } else {
34127             data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
34128             data[npos] = img;
34129           }
34130         }
34131       }
34132       return *this;
34133     }
34134 
34135     // The two functions below are necessary due to Visual C++ 6.0 function overloading bugs, when
34136     // default parameters are used in function signatures.
34137     template<typename t>
34138     CImgList<T>& insert(const CImg<t>& img, const unsigned int pos) {
34139       return insert(img,pos,false);
34140     }
34141 
34142     //! Insert a copy of the image \p img into the current image list, at position \p pos.
34143     template<typename t>
34144     CImgList<T>& insert(const CImg<t>& img) {
34145       return insert(img,~0U,false);
34146     }
34147 
34148     template<typename t>
34149     CImgList<T> get_insert(const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
34150       return (+*this).insert(img,pos,shared);
34151     }
34152 
34153     //! Insert n empty images img into the current image list, at position \p pos.
34154     CImgList<T>& insert(const unsigned int n, const unsigned int pos=~0U) {
34155       CImg<T> foo;
34156       if (!n) return *this;
34157       const unsigned int npos = pos==~0U?size:pos;
34158       for (unsigned int i=0; i<n; ++i) insert(foo,npos+i);
34159       return *this;
34160     }
34161 
34162     CImgList<T> get_insert(const unsigned int n, const unsigned int pos=~0U) const {
34163       return (+*this).insert(n,pos);
34164     }
34165 
34166     //! Insert n copies of the image \p img into the current image list, at position \p pos.
34167     template<typename t>
34168     CImgList<T>& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) {
34169       if (!n) return *this;
34170       const unsigned int npos = pos==~0U?size:pos;
34171       insert(img,npos,shared);
34172       for (unsigned int i=1; i<n; ++i) insert(data[npos],npos+i,shared);
34173       return *this;
34174     }
34175 
34176     template<typename t>
34177     CImgList<T> get_insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
34178       return (+*this).insert(n,img,pos,shared);
34179     }
34180 
34181     //! Insert a copy of the image list \p list into the current image list, starting from position \p pos.
34182     template<typename t>
34183     CImgList<T>& insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
34184       const unsigned int npos = pos==~0U?size:pos;
34185       if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos+l,shared);
34186       else insert(CImgList<T>(list),npos,shared);
34187       return *this;
34188     }
34189 
34190     template<typename t>
34191     CImgList<T> get_insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
34192       return (+*this).insert(list,pos,shared);
34193     }
34194 
34195     //! Insert n copies of the list \p list at position \p pos of the current list.
34196     template<typename t>
34197     CImgList<T>& insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
34198       if (!n) return *this;
34199       const unsigned int npos = pos==~0U?size:pos;
34200       for (unsigned int i=0; i<n; ++i) insert(list,npos,shared);
34201       return *this;
34202     }
34203 
34204     template<typename t>
34205     CImgList<T> get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
34206       return (+*this).insert(n,list,pos,shared);
34207     }
34208 
34209     //! Insert a copy of the image \p img at the end of the current image list.
34210     template<typename t>
34211     CImgList<T>& operator<<(const CImg<t>& img) {
34212       return insert(img);
34213     }
34214 
34215     //! Insert a copy of the image list \p list at the end of the current image list.
34216     template<typename t>
34217     CImgList<T>& operator<<(const CImgList<t>& list) {
34218       return insert(list);
34219     }
34220 
34221     //! Return a copy of the current image list, where the image \p img has been inserted at the end.
34222     template<typename t>
34223     CImgList<T>& operator>>(CImg<t>& img) const {
34224       typedef typename cimg::superset<T,t>::type Tt;
34225       return CImgList<Tt>(*this).insert(img);
34226     }
34227 
34228     //! Insert a copy of the current image list at the beginning of the image list \p list.
34229     template<typename t>
34230     CImgList<T>& operator>>(CImgList<t>& list) const {
34231       return list.insert(*this,0);
34232     }
34233 
34234     //! Remove the images at positions \p pos1 to \p pos2 from the image list.
34235     CImgList<T>& remove(const unsigned int pos1, const unsigned int pos2) {
34236       const unsigned int
34237         npos1 = pos1<pos2?pos1:pos2,
34238         tpos2 = pos1<pos2?pos2:pos1,
34239         npos2 = tpos2<size?tpos2:size-1;
34240       if (npos1>=size)
34241         cimg::warn("CImgList<%s>::remove() : Cannot remove images from a list (%p,%u), at positions %u->%u.",
34242                    pixel_type(),data,size,npos1,tpos2);
34243       else {
34244         if (tpos2>=size)
34245           cimg::warn("CImgList<%s>::remove() : Cannot remove all images from a list (%p,%u), at positions %u->%u.",
34246                      pixel_type(),data,size,npos1,tpos2);
34247         for (unsigned int k = npos1; k<=npos2; ++k) data[k].assign();
34248         const unsigned int nb = 1 + npos2 - npos1;
34249         if (!(size-=nb)) return assign();
34250         if (size>(allocsize>>2) || allocsize<=8) { // Removing items without reallocation.
34251           if (npos1!=size) cimg_std::memmove(data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
34252           cimg_std::memset(data+size,0,sizeof(CImg<T>)*nb);
34253         } else { // Removing items with reallocation.
34254           allocsize>>=2;
34255           while (allocsize>8 && size<(allocsize>>1)) allocsize>>=1;
34256           CImg<T> *new_data = new CImg<T>[allocsize];
34257           if (npos1) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos1);
34258           if (npos1!=size) cimg_std::memcpy(new_data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
34259           if (size!=allocsize) cimg_std::memset(new_data+size,0,sizeof(allocsize-size));
34260           cimg_std::memset(data,0,sizeof(CImg<T>)*(size+nb));
34261           delete[] data;
34262           data = new_data;
34263         }
34264       }
34265       return *this;
34266     }
34267 
34268     CImgList<T> get_remove(const unsigned int pos1, const unsigned int pos2) const {
34269       return (+*this).remove(pos1,pos2);
34270     }
34271 
34272     //! Remove the image at position \p pos from the image list.
34273     CImgList<T>& remove(const unsigned int pos) {
34274       return remove(pos,pos);
34275     }
34276 
34277     CImgList<T> get_remove(const unsigned int pos) const {
34278       return (+*this).remove(pos);
34279     }
34280 
34281     //! Remove the last image from the image list.
34282     CImgList<T>& remove() {
34283       if (size) return remove(size-1);
34284       else cimg::warn("CImgList<%s>::remove() : List is empty",
34285                       pixel_type());
34286       return *this;
34287     }
34288 
34289     CImgList<T> get_remove() const {
34290       return (+*this).remove();
34291     }
34292 
34293     //! Reverse list order.
34294     CImgList<T>& reverse() {
34295       for (unsigned int l=0; l<size/2; ++l) (*this)[l].swap((*this)[size-1-l]);
34296       return *this;
34297     }
34298 
34299     CImgList<T> get_reverse() const {
34300       return (+*this).reverse();
34301     }
34302 
34303     //! Get a sub-list.
34304     CImgList<T>& crop(const unsigned int i0, const unsigned int i1, const bool shared=false) {
34305       return get_crop(i0,i1,shared).transfer_to(*this);
34306     }
34307 
34308     CImgList<T> get_crop(const unsigned int i0, const unsigned int i1, const bool shared=false) const {
34309       if (i0>i1 || i1>=size)
34310         throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
34311                                     pixel_type(),i0,i1,size,data);
34312       CImgList<T> res(i1-i0+1);
34313       cimglist_for(res,l) res[l].assign((*this)[i0+l],shared);
34314       return res;
34315     }
34316 
34317     //! Get sub-images of a sublist.
34318     CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
34319                       const int x0, const int y0, const int z0, const int v0,
34320                       const int x1, const int y1, const int z1, const int v1) {
34321       return get_crop(i0,i1,x0,y0,z0,v0,x1,y1,z1,v1).transfer_to(*this);
34322     }
34323 
34324     CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
34325                          const int x0, const int y0, const int z0, const int v0,
34326                          const int x1, const int y1, const int z1, const int v1) const {
34327       if (i0>i1 || i1>=size)
34328         throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
34329                                     pixel_type(),i0,i1,size,data);
34330       CImgList<T> res(i1-i0+1);
34331       cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,v0,x1,y1,z1,v1);
34332       return res;
34333     }
34334 
34335     //! Get sub-images of a sublist.
34336     CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
34337                       const int x0, const int y0, const int z0,
34338                       const int x1, const int y1, const int z1) {
34339       return get_crop(i0,i1,x0,y0,z0,x1,y1,z1).transfer_to(*this);
34340     }
34341 
34342     CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
34343                          const int x0, const int y0, const int z0,
34344                          const int x1, const int y1, const int z1) const {
34345       if (i0>i1 || i1>=size)
34346         throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
34347                                     pixel_type(),i0,i1,size,data);
34348       CImgList<T> res(i1-i0+1);
34349       cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,x1,y1,z1);
34350       return res;
34351     }
34352 
34353     //! Get sub-images of a sublist.
34354     CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
34355                       const int x0, const int y0,
34356                       const int x1, const int y1) {
34357       return get_crop(i0,i1,x0,y0,x1,y1).transfer_to(*this);
34358     }
34359 
34360     CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
34361                          const int x0, const int y0,
34362                          const int x1, const int y1) const {
34363       if (i0>i1 || i1>=size)
34364         throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
34365                                     pixel_type(),i0,i1,size,data);
34366       CImgList<T> res(i1-i0+1);
34367       cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,x1,y1);
34368       return res;
34369     }
34370 
34371     //! Get sub-images of a sublist.
34372     CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
34373                       const int x0, const int x1) {
34374       return get_crop(i0,i1,x0,x1).transfer_to(*this);
34375     }
34376 
34377     CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
34378                          const int x0, const int x1) const {
34379       if (i0>i1 || i1>=size)
34380         throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
34381                                     pixel_type(),i0,i1,size,data);
34382       CImgList<T> res(i1-i0+1);
34383       cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,x1);
34384       return res;
34385     }
34386 
34387     //! Display an image list into a CImgDisplay.
34388     const CImgList<T>& operator>>(CImgDisplay& disp) const {
34389       return display(disp);
34390     }
34391 
34392     //! Insert image \p img at the end of the list.
34393     template<typename t>
34394     CImgList<T>& push_back(const CImg<t>& img) {
34395       return insert(img);
34396     }
34397 
34398     //! Insert image \p img at the front of the list.
34399     template<typename t>
34400     CImgList<T>& push_front(const CImg<t>& img) {
34401       return insert(img,0);
34402     }
34403 
34404     //! Insert list \p list at the end of the current list.
34405     template<typename t>
34406     CImgList<T>& push_back(const CImgList<t>& list) {
34407       return insert(list);
34408     }
34409 
34410     //! Insert list \p list at the front of the current list.
34411     template<typename t>
34412     CImgList<T>& push_front(const CImgList<t>& list) {
34413       return insert(list,0);
34414     }
34415 
34416     //! Remove last element of the list.
34417     CImgList<T>& pop_back() {
34418       return remove(size-1);
34419     }
34420 
34421     //! Remove first element of the list.
34422     CImgList<T>& pop_front() {
34423       return remove(0);
34424     }
34425 
34426     //! Remove the element pointed by iterator \p iter.
34427     CImgList<T>& erase(const iterator iter) {
34428       return remove(iter-data);
34429     }
34430 
34431     //@}
34432     //----------------------------
34433     //
34434     //! \name Fourier Transforms
34435     //@{
34436     //----------------------------
34437 
34438     //! Compute the Fast Fourier Transform (along the specified axis).
34439     CImgList<T>& FFT(const char axis, const bool invert=false) {
34440       if (is_empty())
34441         throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",
34442                                     pixel_type(),size,data);
34443       if (!data[0])
34444         throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) is empty",
34445                                                 pixel_type(),data[0].width,data[0].height,data[0].depth,data[0].dim,data[0].data);
34446       if (size>2)
34447         cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
34448                    pixel_type(),size,data);
34449       if (size==1) insert(CImg<T>(data[0].width,data[0].height,data[0].depth,data[0].dim,0));
34450       CImg<T> &Ir = data[0], &Ii = data[1];
34451       if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim)
34452         throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) and imaginary part (%u,%u,%u,%u,%p)"
34453                                     "have different dimensions",
34454                                     pixel_type(),Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data);
34455 
34456 #ifdef cimg_use_fftw3
34457       fftw_complex *data_in;
34458       fftw_plan data_plan;
34459 
34460       switch (cimg::uncase(axis)) {
34461       case 'x' : {
34462         data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Ir.width);
34463         data_plan = fftw_plan_dft_1d(Ir.width,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
34464         cimg_forYZV(Ir,y,z,k) {
34465           T *ptrr = Ir.ptr(0,y,z,k), *ptri = Ii.ptr(0,y,z,k);
34466           double *ptrd = (double*)data_in;
34467           cimg_forX(Ir,x) { *(ptrd++) = (double)*(ptrr++); *(ptrd++) = (double)*(ptri++); }
34468           fftw_execute(data_plan);
34469           const unsigned int fact = Ir.width;
34470           if (invert) { cimg_forX(Ir,x) { *(--ptri) = (T)(*(--ptrd)/fact); *(--ptrr) = (T)(*(--ptrd)/fact); }}
34471           else { cimg_forX(Ir,x) { *(--ptri) = (T)*(--ptrd); *(--ptrr) = (T)*(--ptrd); }}
34472         }
34473       } break;
34474 
34475       case 'y' : {
34476         data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.height);
34477         data_plan = fftw_plan_dft_1d(Ir.height,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
34478         const unsigned int off = Ir.width;
34479         cimg_forXZV(Ir,x,z,k) {
34480           T *ptrr = Ir.ptr(x,0,z,k), *ptri = Ii.ptr(x,0,z,k);
34481           double *ptrd = (double*)data_in;
34482           cimg_forY(Ir,y) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
34483           fftw_execute(data_plan);
34484           const unsigned int fact = Ir.height;
34485           if (invert) { cimg_forY(Ir,y) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
34486           else { cimg_forY(Ir,y) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
34487         }
34488       } break;
34489 
34490       case 'z' : {
34491         data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.depth);
34492         data_plan = fftw_plan_dft_1d(Ir.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
34493         const unsigned int off = Ir.width*Ir.height;
34494         cimg_forXYV(Ir,x,y,k) {
34495           T *ptrr = Ir.ptr(x,y,0,k), *ptri = Ii.ptr(x,y,0,k);
34496           double *ptrd = (double*)data_in;
34497           cimg_forZ(Ir,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
34498           fftw_execute(data_plan);
34499           const unsigned int fact = Ir.depth;
34500           if (invert) { cimg_forZ(Ir,z) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
34501           else { cimg_forZ(Ir,z) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
34502         }
34503       } break;
34504 
34505       case 'v' : {
34506         data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.dim);
34507         data_plan = fftw_plan_dft_1d(Ir.dim,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
34508         const unsigned int off = Ir.width*Ir.height*Ir.depth;
34509         cimg_forXYZ(Ir,x,y,z) {
34510           T *ptrr = Ir.ptr(x,y,z,0), *ptri = Ii.ptr(x,y,z,0);
34511           double *ptrd = (double*)data_in;
34512           cimg_forV(Ir,k) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
34513           fftw_execute(data_plan);
34514           const unsigned int fact = Ir.dim;
34515           if (invert) { cimg_forV(Ir,k) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
34516           else { cimg_forV(Ir,k) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
34517         }
34518       } break;
34519       }
34520 
34521       fftw_destroy_plan(data_plan);
34522       fftw_free(data_in);
34523 #else
34524       switch (cimg::uncase(axis)) {
34525       case 'x' : { // Fourier along X
34526         const unsigned int N = Ir.width, N2 = (N>>1);
34527         if (((N-1)&N) && N!=1)
34528           throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image along 'x' is %d != 2^N",
34529                                       pixel_type(),N);
34530         for (unsigned int i=0, j=0; i<N2; ++i) {
34531           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));
34532           if (j<N2) {
34533             const unsigned int ri = N-1-i, rj = N-1-j;
34534             cimg::swap(Ir(ri,y,z,v),Ir(rj,y,z,v)); cimg::swap(Ii(ri,y,z,v),Ii(rj,y,z,v));
34535           }}
34536           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
34537         }
34538         for (unsigned int delta=2; delta<=N; delta<<=1) {
34539           const unsigned int delta2 = (delta>>1);
34540           for (unsigned int i=0; i<N; i+=delta) {
34541             float wr = 1, wi = 0;
34542             const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
34543                         ca = (float)cimg_std::cos(angle),
34544                         sa = (float)cimg_std::sin(angle);
34545             for (unsigned int k=0; k<delta2; ++k) {
34546               const unsigned int j = i + k, nj = j + delta2;
34547               cimg_forYZV(Ir,y,z,k) {
34548                 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);
34549                 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
34550                 nir = (T)(ir - tmpr);
34551                 nii = (T)(ii - tmpi);
34552                 ir += (T)tmpr;
34553                 ii += (T)tmpi;
34554               }
34555               const float nwr = wr*ca-wi*sa;
34556               wi = wi*ca + wr*sa;
34557               wr = nwr;
34558             }
34559           }
34560         }
34561         if (invert) (*this)/=N;
34562       } break;
34563 
34564       case 'y' : { // Fourier along Y
34565         const unsigned int N = Ir.height, N2 = (N>>1);
34566         if (((N-1)&N) && N!=1)
34567           throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'y' is %d != 2^N",
34568                                       pixel_type(),N);
34569         for (unsigned int i=0, j=0; i<N2; ++i) {
34570           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));
34571           if (j<N2) {
34572             const unsigned int ri = N-1-i, rj = N-1-j;
34573             cimg::swap(Ir(x,ri,z,v),Ir(x,rj,z,v)); cimg::swap(Ii(x,ri,z,v),Ii(x,rj,z,v));
34574           }}
34575           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
34576         }
34577         for (unsigned int delta=2; delta<=N; delta<<=1) {
34578           const unsigned int delta2 = (delta>>1);
34579           for (unsigned int i=0; i<N; i+=delta) {
34580             float wr = 1, wi = 0;
34581             const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
34582                         ca = (float)cimg_std::cos(angle), sa = (float)cimg_std::sin(angle);
34583             for (unsigned int k=0; k<delta2; ++k) {
34584               const unsigned int j = i + k, nj = j + delta2;
34585               cimg_forXZV(Ir,x,z,k) {
34586                 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);
34587                 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
34588                 nir = (T)(ir - tmpr);
34589                 nii = (T)(ii - tmpi);
34590                 ir += (T)tmpr;
34591                 ii += (T)tmpi;
34592               }
34593               const float nwr = wr*ca-wi*sa;
34594               wi = wi*ca + wr*sa;
34595               wr = nwr;
34596             }
34597           }
34598         }
34599         if (invert) (*this)/=N;
34600       } break;
34601 
34602       case 'z' : { // Fourier along Z
34603         const unsigned int N = Ir.depth, N2 = (N>>1);
34604         if (((N-1)&N) && N!=1)
34605           throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'z' is %d != 2^N",
34606                                       pixel_type(),N);
34607         for (unsigned int i=0, j=0; i<N2; ++i) {
34608           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));
34609           if (j<N2) {
34610             const unsigned int ri = N-1-i, rj = N-1-j;
34611             cimg::swap(Ir(x,y,ri,v),Ir(x,y,rj,v)); cimg::swap(Ii(x,y,ri,v),Ii(x,y,rj,v));
34612           }}
34613           for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
34614         }
34615         for (unsigned int delta=2; delta<=N; delta<<=1) {
34616           const unsigned int delta2 = (delta>>1);
34617           for (unsigned int i=0; i<N; i+=delta) {
34618             float wr = 1, wi = 0;
34619             const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
34620                         ca = (float)cimg_std::cos(angle), sa = (float)cimg_std::sin(angle);
34621             for (unsigned int k=0; k<delta2; ++k) {
34622               const unsigned int j = i + k, nj = j + delta2;
34623               cimg_forXYV(Ir,x,y,k) {
34624                 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);
34625                 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
34626                 nir = (T)(ir - tmpr);
34627                 nii = (T)(ii - tmpi);
34628                 ir += (T)tmpr;
34629                 ii += (T)tmpi;
34630               }
34631               const float nwr = wr*ca-wi*sa;
34632               wi = wi*ca + wr*sa;
34633               wr = nwr;
34634             }
34635           }
34636         }
34637         if (invert) (*this)/=N;
34638       } break;
34639 
34640       default :
34641         throw CImgArgumentException("CImgList<%s>::FFT() : Invalid axis '%c', must be 'x','y' or 'z'.");
34642       }
34643 #endif
34644       return *this;
34645     }
34646 
34647     CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
34648       return CImgList<Tfloat>(*this).FFT(axis,invert);
34649     }
34650 
34651     //! Compute the Fast Fourier Transform of a complex image.
34652     CImgList<T>& FFT(const bool invert=false) {
34653       if (is_empty())
34654         throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",
34655                                     pixel_type(),size,data);
34656       if (size>2)
34657         cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
34658                    pixel_type(),size,data);
34659       if (size==1) insert(CImg<T>(data->width,data->height,data->depth,data->dim,0));
34660       CImg<T> &Ir = data[0], &Ii = data[1];
34661       if (Ii.width!=Ir.width || Ii.height!=Ir.height || Ii.depth!=Ir.depth || Ii.dim!=Ir.dim)
34662         throw CImgInstanceException("CImgList<%s>::FFT() : Real (%u,%u,%u,%u,%p) and Imaginary (%u,%u,%u,%u,%p) parts "
34663                                     "of the instance image have different dimensions",
34664                                     pixel_type(),Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,
34665                                     Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data);
34666 #ifdef cimg_use_fftw3
34667       fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.width*Ir.height*Ir.depth);
34668       fftw_plan data_plan;
34669       const unsigned int w = Ir.width, wh = w*Ir.height, whd = wh*Ir.depth;
34670       data_plan = fftw_plan_dft_3d(Ir.width,Ir.height,Ir.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
34671       cimg_forV(Ir,k) {
34672         T *ptrr = Ir.ptr(0,0,0,k), *ptri = Ii.ptr(0,0,0,k);
34673         double *ptrd = (double*)data_in;
34674         for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
34675           for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
34676             for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
34677               *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri;
34678             }
34679         fftw_execute(data_plan);
34680         ptrd = (double*)data_in;
34681         ptrr = Ir.ptr(0,0,0,k);
34682         ptri = Ii.ptr(0,0,0,k);
34683         if (!invert) for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
34684           for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
34685             for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
34686               *ptrr = (T)*(ptrd++); *ptri = (T)*(ptrd++);
34687             }
34688         else for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
34689           for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
34690             for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
34691               *ptrr = (T)(*(ptrd++)/whd); *ptri = (T)(*(ptrd++)/whd);
34692             }
34693       }
34694       fftw_destroy_plan(data_plan);
34695       fftw_free(data_in);
34696 #else
34697       if (Ir.depth>1)  FFT('z',invert);
34698       if (Ir.height>1) FFT('y',invert);
34699       if (Ir.width>1)  FFT('x',invert);
34700 #endif
34701       return *this;
34702     }
34703 
34704     CImgList<Tfloat> get_FFT(const bool invert=false) const {
34705       return CImgList<Tfloat>(*this).FFT(invert);
34706     }
34707 
34708     // Return a list where each image has been split along the specified axis.
34709     CImgList<T>& split(const char axis) {
34710       return get_split(axis).transfer_to(*this);
34711     }
34712 
34713     CImgList<T> get_split(const char axis) const {
34714       CImgList<T> res;
34715       cimglist_for(*this,l) {
34716         CImgList<T> tmp = data[l].get_split(axis);
34717         const unsigned int pos = res.size;
34718         res.insert(tmp.size);
34719         cimglist_for(tmp,i) tmp[i].transfer_to(data[pos+i]);
34720       }
34721       return res;
34722     }
34723 
34724     //! Return a single image which is the concatenation of all images of the current CImgList instance.
34725     /**
34726        \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
34727        \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
34728        \return A CImg<T> image corresponding to the concatenation is returned.
34729     **/
34730     CImg<T> get_append(const char axis, const char align='p') const {
34731       if (is_empty()) return CImg<T>();
34732       if (size==1) return +((*this)[0]);
34733       unsigned int dx = 0, dy = 0, dz = 0, dv = 0, pos = 0;
34734       CImg<T> res;
34735       switch (cimg::uncase(axis)) {
34736       case 'x' : {
34737         switch (cimg::uncase(align)) {
34738         case 'x' : { dy = dz = dv = 1; cimglist_for(*this,l) dx+=(*this)[l].size(); } break;
34739         case 'y' : { dx = size; dz = dv = 1; cimglist_for(*this,l) dy = cimg::max(dy,(unsigned int)(*this)[l].size()); } break;
34740         case 'z' : { dx = size; dy = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
34741         case 'v' : { dx = size; dy = dz = 1; cimglist_for(*this,l) dv = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
34742         default :
34743           cimglist_for(*this,l) {
34744             const CImg<T>& img = (*this)[l];
34745             dx += img.width;
34746             dy = cimg::max(dy,img.height);
34747             dz = cimg::max(dz,img.depth);
34748             dv = cimg::max(dv,img.dim);
34749           }
34750         }
34751         res.assign(dx,dy,dz,dv,0);
34752         switch (cimg::uncase(align)) {
34753         case 'x' : {
34754           cimglist_for(*this,l) {
34755             res.draw_image(pos,CImg<T>((*this)[l],true).unroll('x'));
34756             pos+=(*this)[l].size();
34757           }
34758         } break;
34759         case 'y' : {
34760           cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('y'));
34761         } break;
34762         case 'z' : {
34763           cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('z'));
34764         } break;
34765         case 'v' : {
34766           cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('v'));
34767         } break;
34768         case 'p' : {
34769           cimglist_for(*this,l) { res.draw_image(pos,(*this)[l]); pos+=(*this)[l].width; }
34770         } break;
34771         case 'n' : {
34772           cimglist_for(*this,l) {
34773             res.draw_image(pos,dy-(*this)[l].height,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
34774             pos+=(*this)[l].width;
34775           }
34776         } break;
34777         default : {
34778           cimglist_for(*this,l) {
34779             res.draw_image(pos,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
34780             pos+=(*this)[l].width;
34781           }
34782         } break;
34783         }
34784       } break;
34785 
34786       case 'y' : {
34787         switch (cimg::uncase(align)) {
34788         case 'x' : { dy = size; dz = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
34789         case 'y' : { dx = dz = dv = 1; cimglist_for(*this,l) dy+=(*this)[l].size(); } break;
34790         case 'z' : { dy = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
34791         case 'v' : { dy = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
34792         default :
34793           cimglist_for(*this,l) {
34794             const CImg<T>& img = (*this)[l];
34795             dx = cimg::max(dx,img.width);
34796             dy += img.height;
34797             dz = cimg::max(dz,img.depth);
34798             dv = cimg::max(dv,img.dim);
34799           }
34800         }
34801         res.assign(dx,dy,dz,dv,0);
34802         switch (cimg::uncase(align)) {
34803         case 'x' : {
34804           cimglist_for(*this,l) res.draw_image(0,++pos,CImg<T>((*this)[l],true).unroll('x'));
34805         } break;
34806         case 'y' : {
34807           cimglist_for(*this,l) {
34808             res.draw_image(0,pos,CImg<T>((*this)[l],true).unroll('y'));
34809             pos+=(*this)[l].size();
34810           }
34811         } break;
34812         case 'z' : {
34813           cimglist_for(*this,l) res.draw_image(0,pos++,CImg<T>((*this)[l],true).unroll('z'));
34814         } break;
34815         case 'v' : {
34816           cimglist_for(*this,l) res.draw_image(0,pos++,CImg<T>((*this)[l],true).unroll('v'));
34817         } break;
34818         case 'p' : {
34819           cimglist_for(*this,l) { res.draw_image(0,pos,(*this)[l]); pos+=(*this)[l].height; }
34820         } break;
34821         case 'n' : {
34822           cimglist_for(*this,l) {
34823             res.draw_image(dx-(*this)[l].width,pos,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
34824             pos+=(*this)[l].height;
34825           }
34826         } break;
34827         default : {
34828           cimglist_for(*this,l) {
34829             res.draw_image((dx-(*this)[l].width)/2,pos,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
34830           pos+=(*this)[l].height;
34831           }
34832         } break;
34833         }
34834       } break;
34835 
34836       case 'z' : {
34837         switch (cimg::uncase(align)) {
34838         case 'x' : { dz = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
34839         case 'y' : { dz = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
34840         case 'z' : { dx = dy = dv = 1; cimglist_for(*this,l) dz+=(*this)[l].size(); } break;
34841         case 'v' : { dz = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
34842         default :
34843           cimglist_for(*this,l) {
34844             const CImg<T>& img = (*this)[l];
34845             dx = cimg::max(dx,img.width);
34846             dy = cimg::max(dy,img.height);
34847             dz += img.depth;
34848             dv = cimg::max(dv,img.dim);
34849           }
34850         }
34851         res.assign(dx,dy,dz,dv,0);
34852         switch (cimg::uncase(align)) {
34853         case 'x' : {
34854           cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('x'));
34855         } break;
34856         case 'y' : {
34857           cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('y'));
34858         } break;
34859         case 'z' : {
34860           cimglist_for(*this,l) {
34861             res.draw_image(0,0,pos,CImg<T>((*this)[l],true).unroll('z'));
34862             pos+=(*this)[l].size();
34863           }
34864         } break;
34865         case 'v' : {
34866           cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('v'));
34867         } break;
34868         case 'p' : {
34869           cimglist_for(*this,l) { res.draw_image(0,0,pos,(*this)[l]); pos+=(*this)[l].depth; }
34870         } break;
34871         case 'n' : {
34872           cimglist_for(*this,l) {
34873             res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,pos,dv-(*this)[l].dim,(*this)[l]);
34874             pos+=(*this)[l].depth;
34875           }
34876         } break;
34877         case 'c' : {
34878           cimglist_for(*this,l) {
34879             res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,pos,(dv-(*this)[l].dim)/2,(*this)[l]);
34880             pos+=(*this)[l].depth;
34881           }
34882         } break;
34883         }
34884       } break;
34885 
34886       case 'v' : {
34887         switch (cimg::uncase(align)) {
34888         case 'x' : { dv = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
34889         case 'y' : { dv = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
34890         case 'z' : { dv = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
34891         case 'v' : { dx = dy = dz = 1; cimglist_for(*this,l) dv+=(*this)[l].size(); } break;
34892         default :
34893           cimglist_for(*this,l) {
34894             const CImg<T>& img = (*this)[l];
34895             dx = cimg::max(dx,img.width);
34896             dy = cimg::max(dy,img.height);
34897             dz = cimg::max(dz,img.depth);
34898             dv += img.dim;
34899           }
34900         }
34901         res.assign(dx,dy,dz,dv,0);
34902         switch (cimg::uncase(align)) {
34903         case 'x' : {
34904           cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('x'));
34905         } break;
34906         case 'y' : {
34907           cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('y'));
34908         } break;
34909         case 'z' : {
34910           cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('v'));
34911         } break;
34912         case 'v' : {
34913           cimglist_for(*this,l) {
34914             res.draw_image(0,0,0,pos,CImg<T>((*this)[l],true).unroll('z'));
34915             pos+=(*this)[l].size();
34916           }
34917         } break;
34918         case 'p' : {
34919           cimglist_for(*this,l) { res.draw_image(0,0,0,pos,(*this)[l]); pos+=(*this)[l].dim; }
34920         } break;
34921         case 'n' : {
34922           cimglist_for(*this,l) {
34923             res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,dz-(*this)[l].depth,pos,(*this)[l]);
34924             pos+=(*this)[l].dim;
34925           }
34926         } break;
34927         case 'c' : {
34928           cimglist_for(*this,l) {
34929             res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,pos,(*this)[l]);
34930             pos+=(*this)[l].dim;
34931           }
34932         } break;
34933         }
34934       } break;
34935       default :
34936         throw CImgArgumentException("CImgList<%s>::get_append() : unknow axis '%c', must be 'x','y','z' or 'v'",
34937                                     pixel_type(),axis);
34938       }
34939       return res;
34940     }
34941 
34942     //! Create an auto-cropped font (along the X axis) from a input font \p font.
34943     CImgList<T>& crop_font() {
34944       return get_crop_font().transfer_to(*this);
34945     }
34946 
34947     CImgList<T> get_crop_font() const {
34948       CImgList<T> res;
34949       cimglist_for(*this,l) {
34950         const CImg<T>& letter = (*this)[l];
34951         int xmin = letter.width, xmax = 0;
34952         cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
34953         if (xmin>xmax) res.insert(CImg<T>(letter.width,letter.height,1,letter.dim,0));
34954         else res.insert(letter.get_crop(xmin,0,xmax,letter.height-1));
34955       }
34956       res[' '].resize(res['f'].width);
34957       res[' '+256].resize(res['f'].width);
34958       return res;
34959     }
34960 
34961     //! Invert primitives orientation of a 3D object.
34962     CImgList<T>& invert_object3d() {
34963       cimglist_for(*this,l) {
34964         CImg<T>& p = data[l];
34965         const unsigned int siz = p.size();
34966         if (siz==2 || siz==3 || siz==6 || siz==9) cimg::swap(p[0],p[1]);
34967         else if (siz==4 || siz==12) cimg::swap(p[0],p[3],p[1],p[2]);
34968       }
34969       return *this;
34970     }
34971 
34972     CImgList<T> get_invert_object3d() const {
34973       return (+*this).invert_object3d();
34974     }
34975 
34976     //! Return a CImg pre-defined font with desired size.
34977     /**
34978        \param font_height = height of the desired font (can be 11,13,24,38 or 57)
34979        \param fixed_size = tell if the font has a fixed or variable width.
34980     **/
34981     static CImgList<T> font(const unsigned int font_width, const bool variable_size=true) {
34982       if (font_width<=11) {
34983         static CImgList<T> font7x11, nfont7x11;
34984         if (!variable_size && !font7x11)  font7x11 = _font(cimg::font7x11,7,11,1,0,false);
34985         if (variable_size  && !nfont7x11) nfont7x11 = _font(cimg::font7x11,7,11,1,0,true);
34986         return variable_size?nfont7x11:font7x11;
34987       }
34988       if (font_width<=13) {
34989         static CImgList<T> font10x13, nfont10x13;
34990         if (!variable_size && !font10x13)  font10x13 = _font(cimg::font10x13,10,13,1,0,false);
34991         if (variable_size  && !nfont10x13) nfont10x13 = _font(cimg::font10x13,10,13,1,0,true);
34992         return variable_size?nfont10x13:font10x13;
34993       }
34994       if (font_width<=17) {
34995         static CImgList<T> font8x17, nfont8x17;
34996         if (!variable_size && !font8x17)  font8x17 = _font(cimg::font8x17,8,17,1,0,false);
34997         if (variable_size  && !nfont8x17) nfont8x17 = _font(cimg::font8x17,8,17,1,0,true);
34998         return variable_size?nfont8x17:font8x17;
34999       }
35000       if (font_width<=19) {
35001         static CImgList<T> font10x19, nfont10x19;
35002         if (!variable_size && !font10x19)  font10x19 = _font(cimg::font10x19,10,19,2,0,false);
35003         if (variable_size  && !nfont10x19) nfont10x19 = _font(cimg::font10x19,10,19,2,0,true);
35004         return variable_size?nfont10x19:font10x19;
35005       }
35006       if (font_width<=24) {
35007         static CImgList<T> font12x24, nfont12x24;
35008         if (!variable_size && !font12x24)  font12x24 = _font(cimg::font12x24,12,24,2,0,false);
35009         if (variable_size  && !nfont12x24) nfont12x24 = _font(cimg::font12x24,12,24,2,0,true);
35010         return variable_size?nfont12x24:font12x24;
35011       }
35012       if (font_width<=32) {
35013         static CImgList<T> font16x32, nfont16x32;
35014         if (!variable_size && !font16x32)  font16x32 = _font(cimg::font16x32,16,32,2,0,false);
35015         if (variable_size  && !nfont16x32) nfont16x32 = _font(cimg::font16x32,16,32,2,0,true);
35016         return variable_size?nfont16x32:font16x32;
35017       }
35018       if (font_width<=38) {
35019         static CImgList<T> font19x38, nfont19x38;
35020         if (!variable_size && !font19x38)  font19x38 = _font(cimg::font19x38,19,38,3,0,false);
35021         if (variable_size  && !nfont19x38) nfont19x38 = _font(cimg::font19x38,19,38,3,0,true);
35022         return variable_size?nfont19x38:font19x38;
35023       }
35024       static CImgList<T> font29x57, nfont29x57;
35025       if (!variable_size && !font29x57)  font29x57 = _font(cimg::font29x57,29,57,5,0,false);
35026       if (variable_size  && !nfont29x57) nfont29x57 = _font(cimg::font29x57,29,57,5,0,true);
35027       return variable_size?nfont29x57:font29x57;
35028     }
35029 
35030     static CImgList<T> _font(const unsigned int *const font, const unsigned int w, const unsigned int h,
35031                              const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true) {
35032       CImgList<T> res = CImgList<T>(256,w,h,1,3).insert(CImgList<T>(256,w,h,1,1));
35033       const unsigned int *ptr = font;
35034       unsigned int m = 0, val = 0;
35035       for (unsigned int y=0; y<h; ++y)
35036         for (unsigned int x=0; x<256*w; ++x) {
35037           m>>=1; if (!m) { m = 0x80000000; val = *(ptr++); }
35038           CImg<T>& img = res[x/w], &mask = res[x/w+256];
35039           unsigned int xm = x%w;
35040           img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0);
35041         }
35042       if (variable_size) res.crop_font();
35043       if (paddingx || paddingy) cimglist_for(res,l) res[l].resize(res[l].dimx()+paddingx, res[l].dimy()+paddingy,1,-100,0);
35044       return res;
35045     }
35046 
35047     //! Display the current CImgList instance in an existing CImgDisplay window (by reference).
35048     /**
35049        This function displays the list images of the current CImgList instance into an existing CImgDisplay window.
35050        Images of the list are concatenated in a single temporarly image for visualization purposes.
35051        The function returns immediately.
35052        \param disp : reference to an existing CImgDisplay instance, where the current image list will be displayed.
35053        \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
35054        \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
35055        \return A reference to the current CImgList instance is returned.
35056     **/
35057     const CImgList<T>& display(CImgDisplay& disp, const char axis='x', const char align='p') const {
35058       get_append(axis,align).display(disp);
35059       return *this;
35060     }
35061 
35062     //! Display the current CImgList instance in a new display window.
35063     /**
35064        This function opens a new window with a specific title and displays the list images of the current CImgList instance into it.
35065        Images of the list are concatenated in a single temporarly image for visualization purposes.
35066        The function returns when a key is pressed or the display window is closed by the user.
35067        \param title : specify the title of the opening display window.
35068        \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
35069        \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
35070        \return A reference to the current CImgList instance is returned.
35071     **/
35072     const CImgList<T>& display(CImgDisplay &disp,
35073                                const bool display_info, const char axis='x', const char align='p') const {
35074       if (is_empty())
35075         throw CImgInstanceException("CImgList<%s>::display() : Instance list (%u,%u) is empty.",
35076                                     pixel_type(),size,data);
35077       const CImg<T> visu = get_append(axis,align);
35078       if (display_info) print(disp.title);
35079       visu.display(disp,false);
35080       return *this;
35081     }
35082 
35083     //! Display the current CImgList instance in a new display window.
35084     const CImgList<T>& display(const char *const title=0,
35085                                const bool display_info=true, const char axis='x', const char align='p') const {
35086       const CImg<T> visu = get_append(axis,align);
35087       char ntitle[64] = { 0 };
35088       if (!title) cimg_std::sprintf(ntitle,"CImgList<%s>",pixel_type());
35089       if (display_info) print(title?title:ntitle);
35090       visu.display(title?title:ntitle,false);
35091       return *this;
35092     }
35093 
35094     //@}
35095     //----------------------------------
35096     //
35097     //! \name Input-Output
35098     //@{
35099     //----------------------------------
35100 
35101     //! Return a C-string containing the values of all images in the instance list.
35102     CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
35103       if (is_empty()) return CImg<ucharT>(1,1,1,1,0);
35104       CImgList<charT> items;
35105       for (unsigned int l = 0; l<size-1; ++l) {
35106         CImg<charT> item = data[l].value_string(separator,0);
35107         item[item.size()-1] = separator;
35108         items.insert(item);
35109       }
35110       items.insert(data[size-1].value_string(separator,0));
35111       CImg<charT> res = items.get_append('x');
35112       if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
35113       return res;
35114     }
35115 
35116     //! Print informations about the list on the standard output.
35117     const CImgList<T>& print(const char* title=0, const bool display_stats=true) const {
35118       unsigned long msiz = 0;
35119       cimglist_for(*this,l) msiz += data[l].size();
35120       msiz*=sizeof(T);
35121       const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2);
35122       char ntitle[64] = { 0 };
35123       if (!title) cimg_std::sprintf(ntitle,"CImgList<%s>",pixel_type());
35124       cimg_std::fprintf(cimg_stdout,"%s: this = %p, size = %u [%lu %s], data = (CImg<%s>*)%p.\n",
35125                    title?title:ntitle,(void*)this,size,
35126                    mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
35127                    mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
35128                    pixel_type(),(void*)data);
35129       char tmp[16] = { 0 };
35130       cimglist_for(*this,ll) {
35131         cimg_std::sprintf(tmp,"[%d]",ll);
35132         cimg_std::fprintf(cimg_stdout,"  ");
35133         data[ll].print(tmp,display_stats);
35134         if (ll==3 && size>8) { ll = size-5; cimg_std::fprintf(cimg_stdout,"  ...\n"); }
35135       }
35136       return *this;
35137     }
35138 
35139     //! Load an image list from a file.
35140     CImgList<T>& load(const char *const filename) {
35141       const char *ext = cimg::split_filename(filename);
35142       const unsigned int odebug = cimg::exception_mode();
35143       cimg::exception_mode() = 0;
35144       assign();
35145       try {
35146 #ifdef cimglist_load_plugin
35147         cimglist_load_plugin(filename);
35148 #endif
35149 #ifdef cimglist_load_plugin1
35150         cimglist_load_plugin1(filename);
35151 #endif
35152 #ifdef cimglist_load_plugin2
35153         cimglist_load_plugin2(filename);
35154 #endif
35155 #ifdef cimglist_load_plugin3
35156         cimglist_load_plugin3(filename);
35157 #endif
35158 #ifdef cimglist_load_plugin4
35159         cimglist_load_plugin4(filename);
35160 #endif
35161 #ifdef cimglist_load_plugin5
35162         cimglist_load_plugin5(filename);
35163 #endif
35164 #ifdef cimglist_load_plugin6
35165         cimglist_load_plugin6(filename);
35166 #endif
35167 #ifdef cimglist_load_plugin7
35168         cimglist_load_plugin7(filename);
35169 #endif
35170 #ifdef cimglist_load_plugin8
35171         cimglist_load_plugin8(filename);
35172 #endif
35173         if (!cimg::strcasecmp(ext,"tif") ||
35174             !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
35175         if (!cimg::strcasecmp(ext,"cimg") ||
35176             !cimg::strcasecmp(ext,"cimgz") ||
35177             !ext[0]) load_cimg(filename);
35178         if (!cimg::strcasecmp(ext,"rec") ||
35179             !cimg::strcasecmp(ext,"par")) load_parrec(filename);
35180         if (!cimg::strcasecmp(ext,"avi") ||
35181             !cimg::strcasecmp(ext,"mov") ||
35182             !cimg::strcasecmp(ext,"asf") ||
35183             !cimg::strcasecmp(ext,"divx") ||
35184             !cimg::strcasecmp(ext,"flv") ||
35185             !cimg::strcasecmp(ext,"mpg") ||
35186             !cimg::strcasecmp(ext,"m1v") ||
35187             !cimg::strcasecmp(ext,"m2v") ||
35188             !cimg::strcasecmp(ext,"m4v") ||
35189             !cimg::strcasecmp(ext,"mjp") ||
35190             !cimg::strcasecmp(ext,"mkv") ||
35191             !cimg::strcasecmp(ext,"mpe") ||
35192             !cimg::strcasecmp(ext,"movie") ||
35193             !cimg::strcasecmp(ext,"ogm") ||
35194             !cimg::strcasecmp(ext,"qt") ||
35195             !cimg::strcasecmp(ext,"rm") ||
35196             !cimg::strcasecmp(ext,"vob") ||
35197             !cimg::strcasecmp(ext,"wmv") ||
35198             !cimg::strcasecmp(ext,"xvid") ||
35199             !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
35200         if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
35201         if (is_empty()) throw CImgIOException("CImgList<%s>::load()",pixel_type());
35202       } catch (CImgIOException& e) {
35203         if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
35204           cimg::exception_mode() = odebug;
35205           throw CImgIOException("CImgList<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
35206         } else try {
35207           assign(1);
35208           data->load(filename);
35209         } catch (CImgException&) {
35210           assign();
35211         }
35212       }
35213       cimg::exception_mode() = odebug;
35214       if (is_empty())
35215         throw CImgIOException("CImgList<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
35216       return *this;
35217     }
35218 
35219     static CImgList<T> get_load(const char *const filename) {
35220       return CImgList<T>().load(filename);
35221     }
35222 
35223     //! Load an image list from a .cimg file.
35224     CImgList<T>& load_cimg(const char *const filename) {
35225       return _load_cimg(0,filename);
35226     }
35227 
35228     static CImgList<T> get_load_cimg(const char *const filename) {
35229       return CImgList<T>().load_cimg(filename);
35230     }
35231 
35232     //! Load an image list from a .cimg file.
35233     CImgList<T>& load_cimg(cimg_std::FILE *const file) {
35234       return _load_cimg(file,0);
35235     }
35236 
35237     static CImgList<T> get_load_cimg(cimg_std::FILE *const file) {
35238       return CImgList<T>().load_cimg(file);
35239     }
35240 
35241     CImgList<T>& _load_cimg(cimg_std::FILE *const file, const char *const filename) {
35242 #ifdef cimg_use_zlib
35243 #define _cimgz_load_cimg_case(Tss) { \
35244    Bytef *const cbuf = new Bytef[csiz]; \
35245    cimg::fread(cbuf,csiz,nfile); \
35246    raw.assign(W,H,D,V); \
35247    unsigned long destlen = raw.size()*sizeof(T); \
35248    uncompress((Bytef*)raw.data,&destlen,cbuf,csiz); \
35249    delete[] cbuf; \
35250    const Tss *ptrs = raw.data; \
35251    for (unsigned int off = raw.size(); off; --off) *(ptrd++) = (T)*(ptrs++); \
35252 }
35253 #else
35254 #define _cimgz_load_cimg_case(Tss) \
35255    throw CImgIOException("CImgList<%s>::load_cimg() : File '%s' contains compressed data, zlib must be used",\
35256                          pixel_type(),filename?filename:"(FILE*)");
35257 #endif
35258 
35259 #define _cimg_load_cimg_case(Ts,Tss) \
35260       if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
35261         for (unsigned int l = 0; l<N; ++l) { \
35262           j = 0; while ((i=cimg_std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = '\0'; \
35263           W = H = D = V = 0; csiz = 0; \
35264           if ((err = cimg_std::sscanf(tmp,"%u %u %u %u #%u",&W,&H,&D,&V,&csiz))<4) \
35265             throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
35266                                   pixel_type(),filename?filename:("(FILE*)"),W,H,D,V); \
35267           if (W*H*D*V>0) { \
35268             CImg<Tss> raw; \
35269             CImg<T> &img = data[l]; \
35270             img.assign(W,H,D,V); \
35271             T *ptrd = img.data; \
35272             if (err==5) _cimgz_load_cimg_case(Tss) \
35273             else for (int toread = (int)img.size(); toread>0; ) { \
35274               raw.assign(cimg::min(toread,cimg_iobuffer)); \
35275               cimg::fread(raw.data,raw.width,nfile); \
35276               if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
35277               toread-=raw.width; \
35278               const Tss *ptrs = raw.data; \
35279               for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
35280             } \
35281           } \
35282         } \
35283         loaded = true; \
35284       }
35285 
35286       if (!filename && !file)
35287         throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
35288                                     pixel_type());
35289       typedef unsigned char uchar;
35290       typedef unsigned short ushort;
35291       typedef unsigned int uint;
35292       typedef unsigned long ulong;
35293       const int cimg_iobuffer = 12*1024*1024;
35294       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
35295       bool loaded = false, endian = cimg::endianness();
35296       char tmp[256], str_pixeltype[256], str_endian[256];
35297       unsigned int j, err, N = 0, W, H, D, V, csiz;
35298       int i;
35299       j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
35300       err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
35301       if (err<2) {
35302         if (!file) cimg::fclose(nfile);
35303         throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
35304                               pixel_type(),filename?filename:"(FILE*)");
35305       }
35306       if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
35307       else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
35308       assign(N);
35309       _cimg_load_cimg_case("bool",bool);
35310       _cimg_load_cimg_case("unsigned_char",uchar);
35311       _cimg_load_cimg_case("uchar",uchar);
35312       _cimg_load_cimg_case("char",char);
35313       _cimg_load_cimg_case("unsigned_short",ushort);
35314       _cimg_load_cimg_case("ushort",ushort);
35315       _cimg_load_cimg_case("short",short);
35316       _cimg_load_cimg_case("unsigned_int",uint);
35317       _cimg_load_cimg_case("uint",uint);
35318       _cimg_load_cimg_case("int",int);
35319       _cimg_load_cimg_case("unsigned_long",ulong);
35320       _cimg_load_cimg_case("ulong",ulong);
35321       _cimg_load_cimg_case("long",long);
35322       _cimg_load_cimg_case("float",float);
35323       _cimg_load_cimg_case("double",double);
35324       if (!loaded) {
35325         if (!file) cimg::fclose(nfile);
35326         throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
35327                               pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
35328       }
35329       if (!file) cimg::fclose(nfile);
35330       return *this;
35331     }
35332 
35333     //! Load a sub-image list from a non compressed .cimg file.
35334     CImgList<T>& load_cimg(const char *const filename,
35335                            const unsigned int n0, const unsigned int n1,
35336                            const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35337                            const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35338       return _load_cimg(0,filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35339     }
35340 
35341     static CImgList<T> get_load_cimg(const char *const filename,
35342                                      const unsigned int n0, const unsigned int n1,
35343                                      const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35344                                      const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35345       return CImgList<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35346     }
35347 
35348     //! Load a sub-image list from a non compressed .cimg file.
35349     CImgList<T>& load_cimg(cimg_std::FILE *const file,
35350                            const unsigned int n0, const unsigned int n1,
35351                            const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35352                            const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35353       return _load_cimg(file,0,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35354     }
35355 
35356     static CImgList<T> get_load_cimg(cimg_std::FILE *const file,
35357                                      const unsigned int n0, const unsigned int n1,
35358                                      const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35359                                      const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35360       return CImgList<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35361     }
35362 
35363     CImgList<T>& _load_cimg(cimg_std::FILE *const file, const char *const filename,
35364                             const unsigned int n0, const unsigned int n1,
35365                             const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35366                             const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35367 #define _cimg_load_cimg_case2(Ts,Tss) \
35368       if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
35369         for (unsigned int l = 0; l<=nn1; ++l) { \
35370           j = 0; while ((i=cimg_std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = '\0'; \
35371           W = H = D = V = 0; \
35372           if (cimg_std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
35373             throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
35374                                   pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
35375           if (W*H*D*V>0) { \
35376             if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) cimg_std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
35377             else { \
35378               const unsigned int \
35379                 nx1 = x1>=W?W-1:x1, \
35380                 ny1 = y1>=H?H-1:y1, \
35381                 nz1 = z1>=D?D-1:z1, \
35382                 nv1 = v1>=V?V-1:v1; \
35383               CImg<Tss> raw(1+nx1-x0); \
35384               CImg<T> &img = data[l-n0]; \
35385               img.assign(1+nx1-x0,1+ny1-y0,1+nz1-z0,1+nv1-v0); \
35386               T *ptrd = img.data; \
35387               const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
35388               if (skipvb) cimg_std::fseek(nfile,skipvb,SEEK_CUR); \
35389               for (unsigned int v=1+nv1-v0; v; --v) { \
35390                 const unsigned int skipzb = z0*W*H*sizeof(Tss); \
35391                 if (skipzb) cimg_std::fseek(nfile,skipzb,SEEK_CUR); \
35392                 for (unsigned int z=1+nz1-z0; z; --z) { \
35393                   const unsigned int skipyb = y0*W*sizeof(Tss); \
35394                   if (skipyb) cimg_std::fseek(nfile,skipyb,SEEK_CUR); \
35395                   for (unsigned int y=1+ny1-y0; y; --y) { \
35396                     const unsigned int skipxb = x0*sizeof(Tss); \
35397                     if (skipxb) cimg_std::fseek(nfile,skipxb,SEEK_CUR); \
35398                     cimg::fread(raw.data,raw.width,nfile); \
35399                     if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
35400                     const Tss *ptrs = raw.data; \
35401                     for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
35402                     const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
35403                     if (skipxe) cimg_std::fseek(nfile,skipxe,SEEK_CUR); \
35404                   } \
35405                   const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \
35406                   if (skipye) cimg_std::fseek(nfile,skipye,SEEK_CUR); \
35407                 } \
35408                 const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \
35409                 if (skipze) cimg_std::fseek(nfile,skipze,SEEK_CUR); \
35410               } \
35411               const unsigned int skipve = (V-1-nv1)*W*H*D*sizeof(Tss); \
35412               if (skipve) cimg_std::fseek(nfile,skipve,SEEK_CUR); \
35413             } \
35414           } \
35415         } \
35416         loaded = true; \
35417       }
35418 
35419       if (!filename && !file)
35420         throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
35421                                     pixel_type());
35422       typedef unsigned char uchar;
35423       typedef unsigned short ushort;
35424       typedef unsigned int uint;
35425       typedef unsigned long ulong;
35426       if (n1<n0 || x1<x0 || y1<y0 || z1<z0 || v1<v0)
35427         throw CImgArgumentException("CImgList<%s>::load_cimg() : File '%s', Bad sub-region coordinates [%u->%u] "
35428                                     "(%u,%u,%u,%u)->(%u,%u,%u,%u).",
35429                                     pixel_type(),filename?filename:"(FILE*)",
35430                                     n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35431       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
35432       bool loaded = false, endian = cimg::endianness();
35433       char tmp[256], str_pixeltype[256], str_endian[256];
35434       unsigned int j, err, N, W, H, D, V;
35435       int i;
35436       j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
35437       err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
35438       if (err<2) {
35439         if (!file) cimg::fclose(nfile);
35440         throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
35441                               pixel_type(),filename?filename:"(FILE*)");
35442       }
35443       if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
35444       else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
35445       const unsigned int nn1 = n1>=N?N-1:n1;
35446       assign(1+nn1-n0);
35447       _cimg_load_cimg_case2("bool",bool);
35448       _cimg_load_cimg_case2("unsigned_char",uchar);
35449       _cimg_load_cimg_case2("uchar",uchar);
35450       _cimg_load_cimg_case2("char",char);
35451       _cimg_load_cimg_case2("unsigned_short",ushort);
35452       _cimg_load_cimg_case2("ushort",ushort);
35453       _cimg_load_cimg_case2("short",short);
35454       _cimg_load_cimg_case2("unsigned_int",uint);
35455       _cimg_load_cimg_case2("uint",uint);
35456       _cimg_load_cimg_case2("int",int);
35457       _cimg_load_cimg_case2("unsigned_long",ulong);
35458       _cimg_load_cimg_case2("ulong",ulong);
35459       _cimg_load_cimg_case2("long",long);
35460       _cimg_load_cimg_case2("float",float);
35461       _cimg_load_cimg_case2("double",double);
35462       if (!loaded) {
35463         if (!file) cimg::fclose(nfile);
35464         throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
35465                               pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
35466       }
35467       if (!file) cimg::fclose(nfile);
35468       return *this;
35469     }
35470 
35471     //! Load an image list from a PAR/REC (Philips) file.
35472     CImgList<T>& load_parrec(const char *const filename) {
35473       if (!filename)
35474         throw CImgArgumentException("CImgList<%s>::load_parrec() : Cannot load (null) filename.",
35475                                     pixel_type());
35476       char body[1024], filenamepar[1024], filenamerec[1024];
35477       const char *ext = cimg::split_filename(filename,body);
35478       if (!cimg::strcmp(ext,"par")) { cimg_std::strcpy(filenamepar,filename); cimg_std::sprintf(filenamerec,"%s.rec",body); }
35479       if (!cimg::strcmp(ext,"PAR")) { cimg_std::strcpy(filenamepar,filename); cimg_std::sprintf(filenamerec,"%s.REC",body); }
35480       if (!cimg::strcmp(ext,"rec")) { cimg_std::strcpy(filenamerec,filename); cimg_std::sprintf(filenamepar,"%s.par",body); }
35481       if (!cimg::strcmp(ext,"REC")) { cimg_std::strcpy(filenamerec,filename); cimg_std::sprintf(filenamepar,"%s.PAR",body); }
35482       cimg_std::FILE *file = cimg::fopen(filenamepar,"r");
35483 
35484       // Parse header file
35485       CImgList<floatT> st_slices;
35486       CImgList<uintT> st_global;
35487       int err;
35488       char line[256] = { 0 };
35489       do { err=cimg_std::fscanf(file,"%255[^\n]%*c",line); } while (err!=EOF && (line[0]=='#' || line[0]=='.'));
35490       do {
35491         unsigned int sn,sizex,sizey,pixsize;
35492         float rs,ri,ss;
35493         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);
35494         if (err==7) {
35495           st_slices.insert(CImg<floatT>::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,
35496                                                ri,rs,ss,0));
35497           unsigned int i; for (i=0; i<st_global.size && sn<=st_global[i][2]; ++i) {}
35498           if (i==st_global.size) st_global.insert(CImg<uintT>::vector(sizex,sizey,sn));
35499           else {
35500             CImg<uintT> &vec = st_global[i];
35501             if (sizex>vec[0]) vec[0] = sizex;
35502             if (sizey>vec[1]) vec[1] = sizey;
35503             vec[2] = sn;
35504           }
35505           st_slices[st_slices.size-1][7] = (float)i;
35506         }
35507       } while (err==7);
35508 
35509       // Read data
35510       cimg_std::FILE *file2 = cimg::fopen(filenamerec,"rb");
35511       { cimglist_for(st_global,l) {
35512         const CImg<uintT>& vec = st_global[l];
35513         insert(CImg<T>(vec[0],vec[1],vec[2]));
35514       }}
35515 
35516       cimglist_for(st_slices,l) {
35517         const CImg<floatT>& vec = st_slices[l];
35518         const unsigned int
35519           sn = (unsigned int)vec[0]-1,
35520           pixsize = (unsigned int)vec[1],
35521           sizex = (unsigned int)vec[2],
35522           sizey = (unsigned int)vec[3],
35523           imn = (unsigned int)vec[7];
35524         const float ri = vec[4], rs = vec[5], ss = vec[6];
35525         switch (pixsize) {
35526         case 8 : {
35527           CImg<ucharT> buf(sizex,sizey);
35528           cimg::fread(buf.data,sizex*sizey,file2);
35529           if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
35530           CImg<T>& img = (*this)[imn];
35531           cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
35532         } break;
35533         case 16 : {
35534           CImg<ushortT> buf(sizex,sizey);
35535           cimg::fread(buf.data,sizex*sizey,file2);
35536           if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
35537           CImg<T>& img = (*this)[imn];
35538           cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
35539         } break;
35540         case 32 : {
35541           CImg<uintT> buf(sizex,sizey);
35542           cimg::fread(buf.data,sizex*sizey,file2);
35543           if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
35544           CImg<T>& img = (*this)[imn];
35545           cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
35546         } break;
35547         default :
35548           cimg::fclose(file);
35549           cimg::fclose(file2);
35550           throw CImgIOException("CImg<%s>::load_parrec() : File '%s', cannot handle image with pixsize = %d bits.",
35551                                 pixel_type(),filename,pixsize);
35552         }
35553       }
35554       cimg::fclose(file);
35555       cimg::fclose(file2);
35556       if (!size)
35557         throw CImgIOException("CImg<%s>::load_parrec() : File '%s' does not appear to be a valid PAR-REC file.",
35558                               pixel_type(),filename);
35559       return *this;
35560     }
35561 
35562     static CImgList<T> get_load_parrec(const char *const filename) {
35563       return CImgList<T>().load_parrec(filename);
35564     }
35565 
35566     //! Load an image sequence from a YUV file.
35567     CImgList<T>& load_yuv(const char *const filename,
35568                           const unsigned int sizex, const unsigned int sizey,
35569                           const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35570                           const unsigned int step_frame=1, const bool yuv2rgb=true) {
35571       return _load_yuv(0,filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35572     }
35573 
35574     static CImgList<T> get_load_yuv(const char *const filename,
35575                                     const unsigned int sizex, const unsigned int sizey=1,
35576                                     const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35577                                     const unsigned int step_frame=1, const bool yuv2rgb=true) {
35578       return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35579     }
35580 
35581     //! Load an image sequence from a YUV file.
35582     CImgList<T>& load_yuv(cimg_std::FILE *const file,
35583                           const unsigned int sizex, const unsigned int sizey,
35584                           const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35585                           const unsigned int step_frame=1, const bool yuv2rgb=true) {
35586       return _load_yuv(file,0,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35587     }
35588 
35589     static CImgList<T> get_load_yuv(cimg_std::FILE *const file,
35590                                     const unsigned int sizex, const unsigned int sizey=1,
35591                                     const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35592                                     const unsigned int step_frame=1, const bool yuv2rgb=true) {
35593       return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35594     }
35595 
35596     CImgList<T>& _load_yuv(cimg_std::FILE *const file, const char *const filename,
35597                            const unsigned int sizex, const unsigned int sizey,
35598                            const unsigned int first_frame, const unsigned int last_frame,
35599                            const unsigned int step_frame, const bool yuv2rgb) {
35600       if (!filename && !file)
35601         throw CImgArgumentException("CImgList<%s>::load_yuv() : Cannot load (null) filename.",
35602                                     pixel_type());
35603       if (sizex%2 || sizey%2)
35604         throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', image dimensions along X and Y must be "
35605                                     "even numbers (given are %ux%u)\n",
35606                                     pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35607       if (!sizex || !sizey)
35608         throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given image sequence size (%u,%u) is invalid",
35609                                     pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35610 
35611       const unsigned int
35612         nfirst_frame = first_frame<last_frame?first_frame:last_frame,
35613         nlast_frame = first_frame<last_frame?last_frame:first_frame,
35614         nstep_frame = step_frame?step_frame:1;
35615 
35616       CImg<ucharT> tmp(sizex,sizey,1,3), UV(sizex/2,sizey/2,1,2);
35617       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
35618       bool stopflag = false;
35619       int err;
35620       if (nfirst_frame) {
35621         err = cimg_std::fseek(nfile,nfirst_frame*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
35622         if (err) {
35623           if (!file) cimg::fclose(nfile);
35624           throw CImgIOException("CImgList<%s>::load_yuv() : File '%s' doesn't contain frame number %u "
35625                                 "(out of range error).",
35626                                 pixel_type(),filename?filename:"(FILE*)",nfirst_frame);
35627         }
35628       }
35629       unsigned int frame;
35630       for (frame = nfirst_frame; !stopflag && frame<=nlast_frame; frame+=nstep_frame) {
35631         tmp.fill(0);
35632         // *TRY* to read the luminance part, do not replace by cimg::fread !
35633         err = (int)cimg_std::fread((void*)(tmp.data),1,(size_t)(tmp.width*tmp.height),nfile);
35634         if (err!=(int)(tmp.width*tmp.height)) {
35635           stopflag = true;
35636           if (err>0)
35637             cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
35638                        " or given image dimensions (%u,%u) are incorrect.",
35639                        pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35640         } else {
35641           UV.fill(0);
35642           // *TRY* to read the luminance part, do not replace by cimg::fread !
35643           err = (int)cimg_std::fread((void*)(UV.data),1,(size_t)(UV.size()),nfile);
35644           if (err!=(int)(UV.size())) {
35645             stopflag = true;
35646             if (err>0)
35647               cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
35648                          " or given image dimensions (%u,%u) are incorrect.",
35649                          pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35650           } else {
35651             cimg_forXY(UV,x,y) {
35652               const int x2 = x*2, y2 = y*2;
35653               tmp(x2,y2,1) = tmp(x2+1,y2,1) = tmp(x2,y2+1,1) = tmp(x2+1,y2+1,1) = UV(x,y,0);
35654               tmp(x2,y2,2) = tmp(x2+1,y2,2) = tmp(x2,y2+1,2) = tmp(x2+1,y2+1,2) = UV(x,y,1);
35655             }
35656             if (yuv2rgb) tmp.YCbCrtoRGB();
35657             insert(tmp);
35658             if (nstep_frame>1) cimg_std::fseek(nfile,(nstep_frame-1)*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
35659           }
35660         }
35661       }
35662       if (stopflag && nlast_frame!=~0U && frame!=nlast_frame)
35663         cimg::warn("CImgList<%s>::load_yuv() : File '%s', frame %d not reached since only %u frames were found in the file.",
35664                    pixel_type(),filename?filename:"(FILE*)",nlast_frame,frame-1,filename);
35665       if (!file) cimg::fclose(nfile);
35666       return *this;
35667     }
35668 
35669     //! Load an image from a video file, using ffmpeg libraries.
35670     // This piece of code has been firstly created by David Starweather (starkdg(at)users(dot)sourceforge(dot)net)
35671     // I modified it afterwards for direct inclusion in the library core.
35672     CImgList<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35673                              const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false) {
35674       if (!filename)
35675         throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : Cannot load (null) filename.",
35676                                     pixel_type());
35677       const unsigned int
35678         nfirst_frame = first_frame<last_frame?first_frame:last_frame,
35679         nlast_frame = first_frame<last_frame?last_frame:first_frame,
35680         nstep_frame = step_frame?step_frame:1;
35681       assign();
35682 
35683 #ifndef cimg_use_ffmpeg
35684       if ((nfirst_frame || nlast_frame!=~0U || nstep_frame>1) || (resume && (pixel_format || !pixel_format)))
35685         throw CImgArgumentException("CImg<%s>::load_ffmpeg() : File '%s', reading sub-frames from a video file requires the use of ffmpeg.\n"
35686                                     "('cimg_use_ffmpeg' must be defined).",
35687                                     pixel_type(),filename);
35688       return load_ffmpeg_external(filename);
35689 #else
35690       const unsigned int ffmpeg_pixfmt = pixel_format?PIX_FMT_RGB24:PIX_FMT_GRAY8;
35691       avcodec_register_all();
35692       av_register_all();
35693       static AVFormatContext *format_ctx = 0;
35694       static AVCodecContext *codec_ctx = 0;
35695       static AVCodec *codec = 0;
35696       static AVFrame *avframe = avcodec_alloc_frame(), *converted_frame = avcodec_alloc_frame();
35697       static int vstream = 0;
35698 
35699       if (resume) {
35700         if (!format_ctx || !codec_ctx || !codec || !avframe || !converted_frame)
35701           throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : File '%s', cannot resume due to unallocated FFMPEG structures.",
35702                                       pixel_type(),filename);
35703       } else {
35704         // Open video file, find main video stream and codec.
35705         if (format_ctx) av_close_input_file(format_ctx);
35706         if (av_open_input_file(&format_ctx,filename,0,0,0)!=0)
35707           throw CImgIOException("CImgList<%s>::load_ffmpeg() : File '%s' cannot be opened.",
35708                                 pixel_type(),filename);
35709         if (!avframe || !converted_frame || av_find_stream_info(format_ctx)<0) {
35710           av_close_input_file(format_ctx); format_ctx = 0;
35711           cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve stream information.\n"
35712                      "Trying with external ffmpeg executable.",
35713                      pixel_type(),filename);
35714           return load_ffmpeg_external(filename);
35715         }
35716 #if cimg_debug>=3
35717         dump_format(format_ctx,0,0,0);
35718 #endif
35719 
35720         // Special command : Return informations on main video stream.
35721         // as a vector 1x4 containing : (nb_frames,width,height,fps).
35722         if (!first_frame && !last_frame && !step_frame) {
35723           for (vstream = 0; vstream<(int)(format_ctx->nb_streams); ++vstream)
35724             if (format_ctx->streams[vstream]->codec->codec_type==CODEC_TYPE_VIDEO) break;
35725           if (vstream==(int)format_ctx->nb_streams) assign();
35726           else {
35727             CImgList<doubleT> timestamps;
35728             int nb_frames;
35729             AVPacket packet;
35730             // Count frames and store timestamps.
35731             for (nb_frames = 0; av_read_frame(format_ctx,&packet)>=0; av_free_packet(&packet))
35732               if (packet.stream_index==vstream) {
35733                 timestamps.insert(CImg<doubleT>::vector((double)packet.pts));
35734                 ++nb_frames;
35735               }
35736             // Get frame with, height and fps.
35737             const int
35738               framew = format_ctx->streams[vstream]->codec->width,
35739               frameh = format_ctx->streams[vstream]->codec->height;
35740             const float
35741               num = (float)(format_ctx->streams[vstream]->r_frame_rate).num,
35742               den = (float)(format_ctx->streams[vstream]->r_frame_rate).den,
35743               fps = num/den;
35744             // Return infos as a list.
35745             assign(2);
35746             (*this)[0].assign(1,4).fill((T)nb_frames,(T)framew,(T)frameh,(T)fps);
35747             (*this)[1] = timestamps.get_append('y');
35748           }
35749           av_close_input_file(format_ctx); format_ctx = 0;
35750           return *this;
35751         }
35752 
35753         for (vstream = 0; vstream<(int)(format_ctx->nb_streams) &&
35754                format_ctx->streams[vstream]->codec->codec_type!=CODEC_TYPE_VIDEO; ) ++vstream;
35755         if (vstream==(int)format_ctx->nb_streams) {
35756           cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve video stream.\n"
35757                      "Trying with external ffmpeg executable.",
35758                      pixel_type(),filename);
35759           av_close_input_file(format_ctx); format_ctx = 0;
35760           return load_ffmpeg_external(filename);
35761         }
35762         codec_ctx = format_ctx->streams[vstream]->codec;
35763         codec = avcodec_find_decoder(codec_ctx->codec_id);
35764         if (!codec) {
35765           cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot find video codec.\n"
35766                      "Trying with external ffmpeg executable.",
35767                      pixel_type(),filename);
35768           return load_ffmpeg_external(filename);
35769         }
35770         if (avcodec_open(codec_ctx,codec)<0) { // Open codec
35771           cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot open video codec.\n"
35772                      "Trying with external ffmpeg executable.",
35773                      pixel_type(),filename);
35774           return load_ffmpeg_external(filename);
35775         }
35776       }
35777 
35778       // Read video frames
35779       const unsigned int numBytes = avpicture_get_size(ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
35780       uint8_t *const buffer = new uint8_t[numBytes];
35781       avpicture_fill((AVPicture *)converted_frame,buffer,ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
35782       const T foo = (T)0;
35783       AVPacket packet;
35784       for (unsigned int frame = 0, next_frame = nfirst_frame; frame<=nlast_frame && av_read_frame(format_ctx,&packet)>=0; ) {
35785         if (packet.stream_index==(int)vstream) {
35786           int decoded = 0;
35787           avcodec_decode_video(codec_ctx,avframe,&decoded,packet.data,packet.size);
35788           if (decoded) {
35789             if (frame==next_frame) {
35790               SwsContext *c = sws_getContext(codec_ctx->width,codec_ctx->height,codec_ctx->pix_fmt,codec_ctx->width,
35791                                              codec_ctx->height,ffmpeg_pixfmt,1,0,0,0);
35792               sws_scale(c,avframe->data,avframe->linesize,0,codec_ctx->height,converted_frame->data,converted_frame->linesize);
35793               if (ffmpeg_pixfmt==PIX_FMT_RGB24) {
35794                 CImg<ucharT> next_image(*converted_frame->data,3,codec_ctx->width,codec_ctx->height,1,true);
35795                 insert(next_image._get_permute_axes("yzvx",foo));
35796               } else {
35797                 CImg<ucharT> next_image(*converted_frame->data,1,codec_ctx->width,codec_ctx->height,1,true);
35798                 insert(next_image._get_permute_axes("yzvx",foo));
35799               }
35800               next_frame+=nstep_frame;
35801             }
35802             ++frame;
35803           }
35804           av_free_packet(&packet);
35805           if (next_frame>nlast_frame) break;
35806         }
35807       }
35808       delete[] buffer;
35809 #endif
35810       return *this;
35811     }
35812 
35813     static CImgList<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35814                                        const unsigned int step_frame=1, const bool pixel_format=true) {
35815       return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format);
35816     }
35817 
35818     //! Load an image from a video file (MPEG,AVI) using the external tool 'ffmpeg'.
35819     CImgList<T>& load_ffmpeg_external(const char *const filename) {
35820       if (!filename)
35821         throw CImgArgumentException("CImgList<%s>::load_ffmpeg_external() : Cannot load (null) filename.",
35822                                     pixel_type());
35823       char command[1024], filetmp[512], filetmp2[512];
35824       cimg_std::FILE *file = 0;
35825       do {
35826         cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
35827         cimg_std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
35828         if ((file=cimg_std::fopen(filetmp2,"rb"))!=0) cimg_std::fclose(file);
35829       } while (file);
35830       cimg_std::sprintf(filetmp2,"%s_%%6d.ppm",filetmp);
35831 #if cimg_OS!=2
35832       cimg_std::sprintf(command,"%s -i \"%s\" %s >/dev/null 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
35833 #else
35834       cimg_std::sprintf(command,"\"%s -i \"%s\" %s\" >NUL 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
35835 #endif
35836       cimg::system(command,0);
35837       const unsigned int odebug = cimg::exception_mode();
35838       cimg::exception_mode() = 0;
35839       assign();
35840       unsigned int i = 1;
35841       for (bool stopflag = false; !stopflag; ++i) {
35842         cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,i);
35843         CImg<T> img;
35844         try { img.load_pnm(filetmp2); }
35845         catch (CImgException&) { stopflag = true; }
35846         if (img) { insert(img); cimg_std::remove(filetmp2); }
35847       }
35848       cimg::exception_mode() = odebug;
35849       if (is_empty())
35850         throw CImgIOException("CImgList<%s>::load_ffmpeg_external() : Failed to open image sequence '%s'.\n"
35851                               "Check the filename and if the 'ffmpeg' tool is installed on your system.",
35852                               pixel_type(),filename);
35853       return *this;
35854     }
35855 
35856     static CImgList<T> get_load_ffmpeg_external(const char *const filename) {
35857       return CImgList<T>().load_ffmpeg_external(filename);
35858     }
35859 
35860     //! Load a gzipped list, using external tool 'gunzip'.
35861     CImgList<T>& load_gzip_external(const char *const filename) {
35862       if (!filename)
35863         throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
35864                               pixel_type());
35865       char command[1024], filetmp[512], body[512];
35866       const char
35867         *ext = cimg::split_filename(filename,body),
35868         *ext2 = cimg::split_filename(body,0);
35869       cimg_std::FILE *file = 0;
35870       do {
35871         if (!cimg::strcasecmp(ext,"gz")) {
35872           if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
35873                                   cimg::filenamerand(),ext2);
35874           else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
35875                                   cimg::filenamerand());
35876         } else {
35877            if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
35878                                   cimg::filenamerand(),ext);
35879            else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
35880                              cimg::filenamerand());
35881         }
35882         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
35883       } while (file);
35884       cimg_std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
35885       cimg::system(command);
35886       if (!(file = cimg_std::fopen(filetmp,"rb"))) {
35887         cimg::fclose(cimg::fopen(filename,"r"));
35888         throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
35889                               pixel_type(),filename);
35890       } else cimg::fclose(file);
35891       load(filetmp);
35892       cimg_std::remove(filetmp);
35893       return *this;
35894     }
35895 
35896     static CImgList<T> get_load_gzip_external(const char *const filename) {
35897       return CImgList<T>().load_gzip_external(filename);
35898     }
35899 
35900     //! Load a 3D object from a .OFF file.
35901     template<typename tf, typename tc>
35902     CImgList<T>& load_off(const char *const filename,
35903                           CImgList<tf>& primitives, CImgList<tc>& colors,
35904                           const bool invert_faces=false) {
35905       return get_load_off(filename,primitives,colors,invert_faces).transfer_to(*this);
35906     }
35907 
35908     template<typename tf, typename tc>
35909       static CImgList<T> get_load_off(const char *const filename,
35910                                       CImgList<tf>& primitives, CImgList<tc>& colors,
35911                                       const bool invert_faces=false) {
35912       return CImg<T>().load_off(filename,primitives,colors,invert_faces).get_split('x');
35913     }
35914 
35915     //! Load a TIFF file.
35916     CImgList<T>& load_tiff(const char *const filename,
35917                            const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35918                            const unsigned int step_frame=1) {
35919       const unsigned int
35920         nfirst_frame = first_frame<last_frame?first_frame:last_frame,
35921         nstep_frame = step_frame?step_frame:1;
35922       unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
35923 #ifndef cimg_use_tiff
35924       if (nfirst_frame || nlast_frame!=~0U || nstep_frame!=1)
35925         throw CImgArgumentException("CImgList<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
35926                                     "('cimg_use_tiff' must be defined).",
35927                                     pixel_type(),filename);
35928       return assign(CImg<T>::get_load_tiff(filename));
35929 #else
35930       TIFF *tif = TIFFOpen(filename,"r");
35931       if (tif) {
35932         unsigned int nb_images = 0;
35933         do ++nb_images; while (TIFFReadDirectory(tif));
35934         if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
35935           cimg::warn("CImgList<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
35936                      pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
35937         if (nfirst_frame>=nb_images) return assign();
35938         if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
35939         assign(1+(nlast_frame-nfirst_frame)/nstep_frame);
35940         TIFFSetDirectory(tif,0);
35941 #if cimg_debug>=3
35942         TIFFSetWarningHandler(0);
35943         TIFFSetErrorHandler(0);
35944 #endif
35945         cimglist_for(*this,l) data[l]._load_tiff(tif,nfirst_frame+l*nstep_frame);
35946         TIFFClose(tif);
35947       } else throw CImgException("CImgList<%s>::load_tiff() : File '%s' cannot be opened.",
35948                                  pixel_type(),filename);
35949       return *this;
35950 #endif
35951     }
35952 
35953     static CImgList<T> get_load_tiff(const char *const filename,
35954                                      const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35955                                      const unsigned int step_frame=1) {
35956       return CImgList<T>().load_tiff(filename,first_frame,last_frame,step_frame);
35957     }
35958 
35959     //! Save an image list into a file.
35960     /**
35961        Depending on the extension of the given filename, a file format is chosen for the output file.
35962     **/
35963     const CImgList<T>& save(const char *const filename, const int number=-1) const {
35964       if (is_empty())
35965         throw CImgInstanceException("CImgList<%s>::save() : File '%s, instance list (%u,%p) is empty.",
35966                                     pixel_type(),filename?filename:"(null)",size,data);
35967       if (!filename)
35968         throw CImgArgumentException("CImg<%s>::save() : Instance list (%u,%p), specified filename is (null).",
35969                                     pixel_type(),size,data);
35970       const char *ext = cimg::split_filename(filename);
35971       char nfilename[1024];
35972       const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
35973 #ifdef cimglist_save_plugin
35974       cimglist_save_plugin(fn);
35975 #endif
35976 #ifdef cimglist_save_plugin1
35977       cimglist_save_plugin1(fn);
35978 #endif
35979 #ifdef cimglist_save_plugin2
35980       cimglist_save_plugin2(fn);
35981 #endif
35982 #ifdef cimglist_save_plugin3
35983       cimglist_save_plugin3(fn);
35984 #endif
35985 #ifdef cimglist_save_plugin4
35986       cimglist_save_plugin4(fn);
35987 #endif
35988 #ifdef cimglist_save_plugin5
35989       cimglist_save_plugin5(fn);
35990 #endif
35991 #ifdef cimglist_save_plugin6
35992       cimglist_save_plugin6(fn);
35993 #endif
35994 #ifdef cimglist_save_plugin7
35995       cimglist_save_plugin7(fn);
35996 #endif
35997 #ifdef cimglist_save_plugin8
35998       cimglist_save_plugin8(fn);
35999 #endif
36000 #ifdef cimg_use_tiff
36001       if (!cimg::strcasecmp(ext,"tif") ||
36002           !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
36003 #endif
36004       if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
36005       if (!cimg::strcasecmp(ext,"cimg") || !ext[0]) return save_cimg(fn,false);
36006       if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
36007       if (!cimg::strcasecmp(ext,"avi") ||
36008           !cimg::strcasecmp(ext,"mov") ||
36009           !cimg::strcasecmp(ext,"asf") ||
36010           !cimg::strcasecmp(ext,"divx") ||
36011           !cimg::strcasecmp(ext,"flv") ||
36012           !cimg::strcasecmp(ext,"mpg") ||
36013           !cimg::strcasecmp(ext,"m1v") ||
36014           !cimg::strcasecmp(ext,"m2v") ||
36015           !cimg::strcasecmp(ext,"m4v") ||
36016           !cimg::strcasecmp(ext,"mjp") ||
36017           !cimg::strcasecmp(ext,"mkv") ||
36018           !cimg::strcasecmp(ext,"mpe") ||
36019           !cimg::strcasecmp(ext,"movie") ||
36020           !cimg::strcasecmp(ext,"ogm") ||
36021           !cimg::strcasecmp(ext,"qt") ||
36022           !cimg::strcasecmp(ext,"rm") ||
36023           !cimg::strcasecmp(ext,"vob") ||
36024           !cimg::strcasecmp(ext,"wmv") ||
36025           !cimg::strcasecmp(ext,"xvid") ||
36026           !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
36027       if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
36028       if (size==1) data[0].save(fn,-1); else cimglist_for(*this,l) data[l].save(fn,l);
36029       return *this;
36030     }
36031 
36032     //! Save an image sequence, using FFMPEG library.
36033     // This piece of code has been originally written by David. G. Starkweather.
36034     const CImgList<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
36035                                    const unsigned int fps=25) const {
36036       if (is_empty())
36037         throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', instance list (%u,%p) is empty.",
36038                                     pixel_type(),filename?filename:"(null)",size,data);
36039       if (!filename)
36040         throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : Instance list (%u,%p), specified filename is (null).",
36041                                     pixel_type(),size,data);
36042       if (!fps)
36043         throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
36044                                     pixel_type(),filename);
36045       const unsigned int nlast_frame = last_frame==~0U?size-1:last_frame;
36046       if (first_frame>=size || nlast_frame>=size)
36047         throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
36048                                     pixel_type(),filename,first_frame,last_frame,size);
36049       for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
36050         throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', images of the sequence have different dimensions.",
36051                                     pixel_type(),filename);
36052 
36053 #ifndef cimg_use_ffmpeg
36054       return save_ffmpeg_external(filename,first_frame,last_frame);
36055 #else
36056       avcodec_register_all();
36057       av_register_all();
36058       const int
36059         frame_dimx = data[first_frame].dimx(),
36060         frame_dimy = data[first_frame].dimy(),
36061         frame_dimv = data[first_frame].dimv();
36062       if (frame_dimv!=1 && frame_dimv!=3)
36063         throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', image[0] (%u,%u,%u,%u,%p) has not 1 or 3 channels.",
36064                                     pixel_type(),filename,data[0].width,data[0].height,data[0].depth,data[0].dim,data);
36065 
36066       PixelFormat dest_pxl_fmt = PIX_FMT_YUV420P;
36067       PixelFormat src_pxl_fmt  = (frame_dimv == 3)?PIX_FMT_RGB24:PIX_FMT_GRAY8;
36068 
36069       int sws_flags = SWS_FAST_BILINEAR; // Interpolation method (keeping same size images for now).
36070       AVOutputFormat *fmt = 0;
36071       fmt = guess_format(0,filename,0);
36072       if (!fmt) fmt = guess_format("mpeg",0,0); // Default format "mpeg".
36073       if (!fmt)
36074         throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', could not determine file format from filename.",
36075                                     pixel_type(),filename);
36076 
36077       AVFormatContext *oc = 0;
36078       oc = av_alloc_format_context();
36079       if (!oc) // Failed to allocate format context.
36080         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate structure for format context.",
36081                               pixel_type(),filename);
36082 
36083       AVCodec *codec = 0;
36084       AVFrame *picture = 0;
36085       AVFrame *tmp_pict = 0;
36086       oc->oformat = fmt;
36087       cimg_std::sprintf(oc->filename,"%s",filename);
36088 
36089       // Add video stream.
36090       int stream_index = 0;
36091       AVStream *video_str = 0;
36092       if (fmt->video_codec!=CODEC_ID_NONE) {
36093         video_str = av_new_stream(oc,stream_index);
36094         if (!video_str) { // Failed to allocate stream.
36095           av_free(oc);
36096           throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate video stream structure.",
36097                                 pixel_type(),filename);
36098         }
36099       } else { // No codec identified.
36100         av_free(oc);
36101         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no proper codec identified.",
36102                               pixel_type(),filename);
36103       }
36104 
36105       AVCodecContext *c = video_str->codec;
36106       c->codec_id = fmt->video_codec;
36107       c->codec_type = CODEC_TYPE_VIDEO;
36108       c->bit_rate = 400000;
36109       c->width = frame_dimx;
36110       c->height = frame_dimy;
36111       c->time_base.num = 1;
36112       c->time_base.den = fps;
36113       c->gop_size = 12;
36114       c->pix_fmt = dest_pxl_fmt;
36115       if (c->codec_id == CODEC_ID_MPEG2VIDEO) c->max_b_frames = 2;
36116       if (c->codec_id == CODEC_ID_MPEG1VIDEO) c->mb_decision = 2;
36117 
36118       if (av_set_parameters(oc,0)<0) { // Parameters not properly set.
36119         av_free(oc);
36120         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', parameters for avcodec not properly set.",
36121                               pixel_type(),filename);
36122       }
36123 
36124       // Open codecs and alloc buffers.
36125       codec = avcodec_find_encoder(c->codec_id);
36126       if (!codec) { // Failed to find codec.
36127         av_free(oc);
36128         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no codec found.",
36129                               pixel_type(),filename);
36130       }
36131       if (avcodec_open(c,codec)<0) // Failed to open codec.
36132         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to open codec.",
36133                               pixel_type(),filename);
36134       tmp_pict = avcodec_alloc_frame();
36135       if (!tmp_pict) { // Failed to allocate memory for tmp_pict frame.
36136         avcodec_close(video_str->codec);
36137         av_free(oc);
36138         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
36139                               pixel_type(),filename);
36140       }
36141       tmp_pict->linesize[0] = (src_pxl_fmt==PIX_FMT_RGB24)?3*frame_dimx:frame_dimx;
36142       tmp_pict->type = FF_BUFFER_TYPE_USER;
36143       int tmp_size = avpicture_get_size(src_pxl_fmt,frame_dimx,frame_dimy);
36144       uint8_t *tmp_buffer = (uint8_t*)av_malloc(tmp_size);
36145       if (!tmp_buffer) { // Failed to allocate memory for tmp buffer.
36146         av_free(tmp_pict);
36147         avcodec_close(video_str->codec);
36148         av_free(oc);
36149         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
36150                               pixel_type(),filename);
36151       }
36152 
36153       // Associate buffer with tmp_pict.
36154       avpicture_fill((AVPicture*)tmp_pict,tmp_buffer,src_pxl_fmt,frame_dimx,frame_dimy);
36155       picture = avcodec_alloc_frame();
36156       if (!picture) { // Failed to allocate picture frame.
36157         av_free(tmp_pict->data[0]);
36158         av_free(tmp_pict);
36159         avcodec_close(video_str->codec);
36160         av_free(oc);
36161         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame.",
36162                               pixel_type(),filename);
36163       }
36164 
36165       int size = avpicture_get_size(c->pix_fmt,frame_dimx,frame_dimy);
36166       uint8_t *buffer = (uint8_t*)av_malloc(size);
36167       if (!buffer) { // Failed to allocate picture frame buffer.
36168         av_free(picture);
36169         av_free(tmp_pict->data[0]);
36170         av_free(tmp_pict);
36171         avcodec_close(video_str->codec);
36172         av_free(oc);
36173         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame buffer.",
36174                               pixel_type(),filename);
36175       }
36176 
36177       // Associate the buffer with picture.
36178       avpicture_fill((AVPicture*)picture,buffer,c->pix_fmt,frame_dimx,frame_dimy);
36179 
36180       // Open file.
36181       if (!(fmt->flags&AVFMT_NOFILE)) {
36182         if (url_fopen(&oc->pb,filename,URL_WRONLY)<0)
36183           throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s' cannot be opened.",
36184                                 pixel_type(),filename);
36185       }
36186 
36187       if (av_write_header(oc)<0)
36188         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', could not write header.",
36189                               pixel_type(),filename);
36190       double video_pts;
36191       SwsContext *img_convert_context = 0;
36192       img_convert_context = sws_getContext(frame_dimx,frame_dimy,src_pxl_fmt,
36193                                            c->width,c->height,c->pix_fmt,sws_flags,0,0,0);
36194       if (!img_convert_context) { // Failed to get swscale context.
36195         // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
36196         av_free(picture->data);
36197         av_free(picture);
36198         av_free(tmp_pict->data[0]);
36199         av_free(tmp_pict);
36200         avcodec_close(video_str->codec);
36201         av_free(oc);
36202         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%', failed to get conversion context.",
36203                               pixel_type(),filename);
36204       }
36205       int ret = 0, out_size;
36206       uint8_t *video_outbuf = 0;
36207       int video_outbuf_size = 1000000;
36208       video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);
36209       if (!video_outbuf) {
36210         // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
36211         av_free(picture->data);
36212         av_free(picture);
36213         av_free(tmp_pict->data[0]);
36214         av_free(tmp_pict);
36215         avcodec_close(video_str->codec);
36216         av_free(oc);
36217         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', memory allocation error.",
36218                               pixel_type(),filename);
36219       }
36220 
36221       // Loop through each desired image in list.
36222       for (unsigned int i = first_frame; i<=nlast_frame; ++i) {
36223         CImg<uint8_t> currentIm = data[i], red, green, blue, gray;
36224         if (src_pxl_fmt == PIX_FMT_RGB24) {
36225           red = currentIm.get_shared_channel(0);
36226           green = currentIm.get_shared_channel(1);
36227           blue = currentIm.get_shared_channel(2);
36228           cimg_forXY(currentIm,X,Y) { // Assign pizel values to data buffer in interlaced RGBRGB ... format.
36229             tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X]     = red(X,Y);
36230             tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 1] = green(X,Y);
36231             tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 2] = blue(X,Y);
36232           }
36233         } else {
36234           gray = currentIm.get_shared_channel(0);
36235           cimg_forXY(currentIm,X,Y) tmp_pict->data[0][Y*tmp_pict->linesize[0] + X] = gray(X,Y);
36236         }
36237 
36238         if (video_str) video_pts = (video_str->pts.val * video_str->time_base.num)/(video_str->time_base.den);
36239         else video_pts = 0.0;
36240         if (!video_str) break;
36241         if (sws_scale(img_convert_context,tmp_pict->data,tmp_pict->linesize,0,c->height,picture->data,picture->linesize)<0) break;
36242         out_size = avcodec_encode_video(c,video_outbuf,video_outbuf_size,picture);
36243         if (out_size>0) {
36244           AVPacket pkt;
36245           av_init_packet(&pkt);
36246           pkt.pts = av_rescale_q(c->coded_frame->pts,c->time_base,video_str->time_base);
36247           if (c->coded_frame->key_frame) pkt.flags|=PKT_FLAG_KEY;
36248           pkt.stream_index = video_str->index;
36249           pkt.data = video_outbuf;
36250           pkt.size = out_size;
36251           ret = av_write_frame(oc,&pkt);
36252         } else if (out_size<0) break;
36253         if (ret) break; // Error occurred in writing frame.
36254       }
36255 
36256       // Close codec.
36257       if (video_str) {
36258         avcodec_close(video_str->codec);
36259         av_free(picture->data[0]);
36260         av_free(picture);
36261         av_free(tmp_pict->data[0]);
36262         av_free(tmp_pict);
36263       }
36264       if (av_write_trailer(oc)<0)
36265         throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to write trailer.",
36266                               pixel_type(),filename);
36267       av_freep(&oc->streams[stream_index]->codec);
36268       av_freep(&oc->streams[stream_index]);
36269       if (!(fmt->flags&AVFMT_NOFILE)) {
36270         /*if (url_fclose(oc->pb)<0)
36271           throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to close file.",
36272           pixel_type(),filename);
36273         */
36274       }
36275       av_free(oc);
36276       av_free(video_outbuf);
36277 #endif
36278       return *this;
36279     }
36280 
36281     // Save an image sequence into a YUV file (internal).
36282     const CImgList<T>& _save_yuv(cimg_std::FILE *const file, const char *const filename, const bool rgb2yuv) const {
36283       if (is_empty())
36284         throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', instance list (%u,%p) is empty.",
36285                                     pixel_type(),filename?filename:"(FILE*)",size,data);
36286       if (!file && !filename)
36287         throw CImgArgumentException("CImg<%s>::save_yuv() : Instance list (%u,%p), specified file is (null).",
36288                                     pixel_type(),size,data);
36289       if ((*this)[0].dimx()%2 || (*this)[0].dimy()%2)
36290         throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', image dimensions must be even numbers (current are %ux%u).",
36291                                     pixel_type(),filename?filename:"(FILE*)",(*this)[0].dimx(),(*this)[0].dimy());
36292 
36293       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
36294       cimglist_for(*this,l) {
36295         CImg<ucharT> YCbCr((*this)[l]);
36296         if (rgb2yuv) YCbCr.RGBtoYCbCr();
36297         cimg::fwrite(YCbCr.data,YCbCr.width*YCbCr.height,nfile);
36298         cimg::fwrite(YCbCr.get_resize(YCbCr.width/2, YCbCr.height/2,1,3,3).ptr(0,0,0,1),
36299                      YCbCr.width*YCbCr.height/2,nfile);
36300       }
36301       if (!file) cimg::fclose(nfile);
36302       return *this;
36303     }
36304 
36305     //! Save an image sequence into a YUV file.
36306     const CImgList<T>& save_yuv(const char *const filename=0, const bool rgb2yuv=true) const {
36307       return _save_yuv(0,filename,rgb2yuv);
36308     }
36309 
36310     //! Save an image sequence into a YUV file.
36311     const CImgList<T>& save_yuv(cimg_std::FILE *const file, const bool rgb2yuv=true) const {
36312       return _save_yuv(file,0,rgb2yuv);
36313     }
36314 
36315     //! Save an image list into a .cimg file.
36316     /**
36317        A CImg RAW file is a simple uncompressed binary file that may be used to save list of CImg<T> images.
36318        \param filename : name of the output file.
36319        \return A reference to the current CImgList instance is returned.
36320     **/
36321     const CImgList<T>& _save_cimg(cimg_std::FILE *const file, const char *const filename, const bool compression) const {
36322       if (is_empty())
36323         throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
36324                                     pixel_type(),filename?filename:"(FILE*)",size,data);
36325       if (!file && !filename)
36326         throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
36327                                     pixel_type(),size,data);
36328       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
36329       const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little";
36330       if (cimg_std::strstr(ptype,"unsigned")==ptype) cimg_std::fprintf(nfile,"%u unsigned_%s %s_endian\n",size,ptype+9,etype);
36331       else cimg_std::fprintf(nfile,"%u %s %s_endian\n",size,ptype,etype);
36332       cimglist_for(*this,l) {
36333         const CImg<T>& img = data[l];
36334         cimg_std::fprintf(nfile,"%u %u %u %u",img.width,img.height,img.depth,img.dim);
36335         if (img.data) {
36336           CImg<T> tmp;
36337           if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp.data,tmp.size()); }
36338           const CImg<T>& ref = cimg::endianness()?tmp:img;
36339           bool compressed = false;
36340           if (compression) {
36341 #ifdef cimg_use_zlib
36342             const unsigned long siz = sizeof(T)*ref.size();
36343             unsigned long csiz = siz + siz/10 + 16;
36344             Bytef *const cbuf = new Bytef[csiz];
36345             if (compress(cbuf,&csiz,(Bytef*)ref.data,siz)) {
36346               cimg::warn("CImgList<%s>::save_cimg() : File '%s', failed to save compressed data.\n Data will be saved uncompressed.",
36347                        pixel_type(),filename?filename:"(FILE*)");
36348               compressed = false;
36349             } else {
36350               cimg_std::fprintf(nfile," #%lu\n",csiz);
36351               cimg::fwrite(cbuf,csiz,nfile);
36352               delete[] cbuf;
36353               compressed = true;
36354             }
36355 #else
36356             cimg::warn("CImgList<%s>::save_cimg() : File '%s', cannot save compressed data unless zlib is used "
36357                        "('cimg_use_zlib' must be defined).\n Data will be saved uncompressed.",
36358                        pixel_type(),filename?filename:"(FILE*)");
36359             compressed = false;
36360 #endif
36361           }
36362           if (!compressed) {
36363             cimg_std::fputc('\n',nfile);
36364             cimg::fwrite(ref.data,ref.size(),nfile);
36365           }
36366         } else cimg_std::fputc('\n',nfile);
36367       }
36368       if (!file) cimg::fclose(nfile);
36369       return *this;
36370     }
36371 
36372     //! Save an image list into a CImg file (RAW binary file + simple header)
36373     const CImgList<T>& save_cimg(cimg_std::FILE *file, const bool compress=false) const {
36374       return _save_cimg(file,0,compress);
36375     }
36376 
36377     //! Save an image list into a CImg file (RAW binary file + simple header)
36378     const CImgList<T>& save_cimg(const char *const filename, const bool compress=false) const {
36379       return _save_cimg(0,filename,compress);
36380     }
36381 
36382     // Insert the instance image into an existing .cimg file, at specified coordinates.
36383     const CImgList<T>& _save_cimg(cimg_std::FILE *const file, const char *const filename,
36384                                  const unsigned int n0,
36385                                  const unsigned int x0, const unsigned int y0,
36386                                  const unsigned int z0, const unsigned int v0) const {
36387 #define _cimg_save_cimg_case(Ts,Tss) \
36388       if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \
36389         for (unsigned int l=0; l<lmax; ++l) { \
36390           j = 0; while((i=cimg_std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j]='\0'; \
36391           W = H = D = V = 0; \
36392           if (cimg_std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
36393             throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
36394                                   pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
36395           if (W*H*D*V>0) { \
36396             if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) cimg_std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
36397             else { \
36398               const CImg<T>& img = (*this)[l-n0]; \
36399               const T *ptrs = img.data; \
36400               const unsigned int \
36401                 x1 = x0 + img.width - 1, \
36402                 y1 = y0 + img.height - 1, \
36403                 z1 = z0 + img.depth - 1, \
36404                 v1 = v0 + img.dim - 1, \
36405                 nx1 = x1>=W?W-1:x1, \
36406                 ny1 = y1>=H?H-1:y1, \
36407                 nz1 = z1>=D?D-1:z1, \
36408                 nv1 = v1>=V?V-1:v1; \
36409               CImg<Tss> raw(1+nx1-x0); \
36410               const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
36411               if (skipvb) cimg_std::fseek(nfile,skipvb,SEEK_CUR); \
36412               for (unsigned int v=1+nv1-v0; v; --v) { \
36413                 const unsigned int skipzb = z0*W*H*sizeof(Tss); \
36414                 if (skipzb) cimg_std::fseek(nfile,skipzb,SEEK_CUR); \
36415                 for (unsigned int z=1+nz1-z0; z; --z) { \
36416                   const unsigned int skipyb = y0*W*sizeof(Tss); \
36417                   if (skipyb) cimg_std::fseek(nfile,skipyb,SEEK_CUR); \
36418                   for (unsigned int y=1+ny1-y0; y; --y) { \
36419                     const unsigned int skipxb = x0*sizeof(Tss); \
36420                     if (skipxb) cimg_std::fseek(nfile,skipxb,SEEK_CUR); \
36421                     raw.assign(ptrs, raw.width); \
36422                     ptrs+=img.width; \
36423                     if (endian) cimg::invert_endianness(raw.data,raw.width); \
36424                     cimg::fwrite(raw.data,raw.width,nfile); \
36425                     const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
36426                     if (skipxe) cimg_std::fseek(nfile,skipxe,SEEK_CUR); \
36427                   } \
36428                   const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \
36429                   if (skipye) cimg_std::fseek(nfile,skipye,SEEK_CUR); \
36430                 } \
36431                 const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \
36432                 if (skipze) cimg_std::fseek(nfile,skipze,SEEK_CUR); \
36433               } \
36434               const unsigned int skipve = (V-1-nv1)*W*H*D*sizeof(Tss); \
36435               if (skipve) cimg_std::fseek(nfile,skipve,SEEK_CUR); \
36436             } \
36437           } \
36438         } \
36439         saved = true; \
36440       }
36441       if (is_empty())
36442         throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
36443                                     pixel_type(),filename?filename:"(FILE*)",size,data);
36444       if (!file && !filename)
36445         throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
36446                                     pixel_type(),size,data);
36447       typedef unsigned char uchar;
36448       typedef unsigned short ushort;
36449       typedef unsigned int uint;
36450       typedef unsigned long ulong;
36451       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+");
36452       bool saved = false, endian = cimg::endianness();
36453       char tmp[256], str_pixeltype[256], str_endian[256];
36454       unsigned int j, err, N, W, H, D, V;
36455       int i;
36456       j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
36457       err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
36458       if (err<2) {
36459         if (!file) cimg::fclose(nfile);
36460         throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Unknow CImg RAW header.",
36461                               pixel_type(),filename?filename:"(FILE*)");
36462       }
36463       if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
36464       else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
36465       const unsigned int lmax = cimg::min(N,n0+size);
36466       _cimg_save_cimg_case("bool",bool);
36467       _cimg_save_cimg_case("unsigned_char",uchar);
36468       _cimg_save_cimg_case("uchar",uchar);
36469       _cimg_save_cimg_case("char",char);
36470       _cimg_save_cimg_case("unsigned_short",ushort);
36471       _cimg_save_cimg_case("ushort",ushort);
36472       _cimg_save_cimg_case("short",short);
36473       _cimg_save_cimg_case("unsigned_int",uint);
36474       _cimg_save_cimg_case("uint",uint);
36475       _cimg_save_cimg_case("int",int);
36476       _cimg_save_cimg_case("unsigned_long",ulong);
36477       _cimg_save_cimg_case("ulong",ulong);
36478       _cimg_save_cimg_case("long",long);
36479       _cimg_save_cimg_case("float",float);
36480       _cimg_save_cimg_case("double",double);
36481       if (!saved) {
36482         if (!file) cimg::fclose(nfile);
36483         throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', cannot save images of pixels coded as '%s'.",
36484                               pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
36485       }
36486       if (!file) cimg::fclose(nfile);
36487       return *this;
36488     }
36489 
36490     //! Insert the instance image into an existing .cimg file, at specified coordinates.
36491     const CImgList<T>& save_cimg(const char *const filename,
36492                                  const unsigned int n0,
36493                                  const unsigned int x0, const unsigned int y0,
36494                                  const unsigned int z0, const unsigned int v0) const {
36495       return _save_cimg(0,filename,n0,x0,y0,z0,v0);
36496     }
36497 
36498     //! Insert the instance image into an existing .cimg file, at specified coordinates.
36499     const CImgList<T>& save_cimg(cimg_std::FILE *const file,
36500                                  const unsigned int n0,
36501                                  const unsigned int x0, const unsigned int y0,
36502                                  const unsigned int z0, const unsigned int v0) const {
36503       return _save_cimg(file,0,n0,x0,y0,z0,v0);
36504     }
36505 
36506     // Create an empty .cimg file with specified dimensions (internal)
36507     static void _save_empty_cimg(cimg_std::FILE *const file, const char *const filename,
36508                                 const unsigned int nb,
36509                                 const unsigned int dx, const unsigned int dy,
36510                                 const unsigned int dz, const unsigned int dv) {
36511       cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
36512       const unsigned int siz = dx*dy*dz*dv*sizeof(T);
36513       cimg_std::fprintf(nfile,"%u %s\n",nb,pixel_type());
36514       for (unsigned int i=nb; i; --i) {
36515         cimg_std::fprintf(nfile,"%u %u %u %u\n",dx,dy,dz,dv);
36516         for (unsigned int off=siz; off; --off) cimg_std::fputc(0,nfile);
36517       }
36518       if (!file) cimg::fclose(nfile);
36519     }
36520 
36521     //! Create an empty .cimg file with specified dimensions.
36522     static void save_empty_cimg(const char *const filename,
36523                                 const unsigned int nb,
36524                                 const unsigned int dx, const unsigned int dy=1,
36525                                 const unsigned int dz=1, const unsigned int dv=1) {
36526       return _save_empty_cimg(0,filename,nb,dx,dy,dz,dv);
36527     }
36528 
36529     //! Create an empty .cimg file with specified dimensions.
36530     static void save_empty_cimg(cimg_std::FILE *const file,
36531                                 const unsigned int nb,
36532                                 const unsigned int dx, const unsigned int dy=1,
36533                                 const unsigned int dz=1, const unsigned int dv=1) {
36534       return _save_empty_cimg(file,0,nb,dx,dy,dz,dv);
36535     }
36536 
36537     //! Save a file in TIFF format.
36538 #ifdef cimg_use_tiff
36539     const CImgList<T>& save_tiff(const char *const filename) const {
36540       if (is_empty())
36541         throw CImgInstanceException("CImgList<%s>::save_tiff() : File '%s', instance list (%u,%p) is empty.",
36542                                     pixel_type(),filename?filename:"(null)",size,data);
36543       if (!filename)
36544         throw CImgArgumentException("CImgList<%s>::save_tiff() : Specified filename is (null) for instance list (%u,%p).",
36545                                     pixel_type(),size,data);
36546       TIFF *tif = TIFFOpen(filename,"w");
36547       if (tif) {
36548         for (unsigned int dir=0, l=0; l<size; ++l) {
36549           const CImg<T>& img = (*this)[l];
36550           if (img) {
36551             if (img.depth==1) img._save_tiff(tif,dir++);
36552             else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++);
36553           }
36554         }
36555         TIFFClose(tif);
36556       } else
36557         throw CImgException("CImgList<%s>::save_tiff() : File '%s', error while opening stream for tiff file.",
36558                             pixel_type(),filename);
36559       return *this;
36560     }
36561 #endif
36562 
36563     //! Save an image list as a gzipped file, using external tool 'gzip'.
36564     const CImgList<T>& save_gzip_external(const char *const filename) const {
36565       if (!filename)
36566         throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
36567                               pixel_type());
36568       char command[1024], filetmp[512], body[512];
36569       const char
36570         *ext = cimg::split_filename(filename,body),
36571         *ext2 = cimg::split_filename(body,0);
36572       cimg_std::FILE *file;
36573       do {
36574         if (!cimg::strcasecmp(ext,"gz")) {
36575           if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
36576                                   cimg::filenamerand(),ext2);
36577           else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
36578                             cimg::filenamerand());
36579         } else {
36580           if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
36581                                  cimg::filenamerand(),ext);
36582           else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
36583                                  cimg::filenamerand());
36584         }
36585         if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
36586       } while (file);
36587       save(filetmp);
36588       cimg_std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
36589       cimg::system(command);
36590       file = cimg_std::fopen(filename,"rb");
36591       if (!file)
36592         throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
36593                               pixel_type(),filename);
36594       else cimg::fclose(file);
36595       cimg_std::remove(filetmp);
36596       return *this;
36597     }
36598 
36599     //! Save an image list into a OFF file.
36600     template<typename tf, typename tc>
36601     const CImgList<T>& save_off(const char *const filename,
36602                                 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
36603       get_append('x','y').save_off(filename,primitives,colors,invert_faces);
36604       return *this;
36605     }
36606 
36607     //! Save an image list into a OFF file.
36608     template<typename tf, typename tc>
36609     const CImgList<T>& save_off(cimg_std::FILE *const file,
36610                                 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
36611       get_append('x','y').save_off(file,primitives,colors,invert_faces);
36612       return *this;
36613     }
36614 
36615     //! Save an image sequence using the external tool 'ffmpeg'.
36616     const CImgList<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
36617                                             const char *const codec="mpeg2video") const {
36618       if (is_empty())
36619         throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', instance list (%u,%p) is empty.",
36620                                     pixel_type(),filename?filename:"(null)",size,data);
36621       if (!filename)
36622         throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : Instance list (%u,%p), specified filename is (null).",
36623                                     pixel_type(),size,data);
36624       char command[1024], filetmp[512], filetmp2[512];
36625       cimg_std::FILE *file = 0;
36626       const unsigned int nlast_frame = last_frame==~0U?size-1:last_frame;
36627       if (first_frame>=size || nlast_frame>=size)
36628         throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
36629                                     pixel_type(),filename,first_frame,last_frame,size);
36630       for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
36631         throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', all images of the sequence must be of the same dimension.",
36632                                     pixel_type(),filename);
36633       do {
36634         cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
36635         cimg_std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
36636         if ((file=cimg_std::fopen(filetmp2,"rb"))!=0) cimg_std::fclose(file);
36637       } while (file);
36638       for (unsigned int l = first_frame; l<=nlast_frame; ++l) {
36639         cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,l+1);
36640         if (data[l].depth>1 || data[l].dim!=3) data[l].get_resize(-100,-100,1,3).save_pnm(filetmp2);
36641         else data[l].save_pnm(filetmp2);
36642       }
36643 #if cimg_OS!=2
36644       cimg_std::sprintf(command,"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\" >/dev/null 2>&1",filetmp,codec,filename);
36645 #else
36646       cimg_std::sprintf(command,"\"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\"\" >NUL 2>&1",filetmp,codec,filename);
36647 #endif
36648       cimg::system(command);
36649       file = cimg_std::fopen(filename,"rb");
36650       if (!file)
36651         throw CImgIOException("CImg<%s>::save_ffmpeg_external() : Failed to save image sequence '%s'.\n\n",
36652                               pixel_type(),filename);
36653       else cimg::fclose(file);
36654       cimglist_for(*this,lll) { cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,lll+1); cimg_std::remove(filetmp2); }
36655       return *this;
36656     }
36657 
36658    };
36659 
36660   /*
36661    #---------------------------------------------
36662    #
36663    # Completion of previously declared functions
36664    #
36665    #----------------------------------------------
36666   */
36667 
36668 namespace cimg {
36669 
36670   //! Display a dialog box, where a user can click standard buttons.
36671   /**
36672      Up to 6 buttons can be defined in the dialog window.
36673      This function returns when a user clicked one of the button or closed the dialog window.
36674      \param title = Title of the dialog window.
36675      \param msg = Main message displayed inside the dialog window.
36676      \param button1_txt = Label of the 1st button.
36677      \param button2_txt = Label of the 2nd button.
36678      \param button3_txt = Label of the 3rd button.
36679      \param button4_txt = Label of the 4th button.
36680      \param button5_txt = Label of the 5th button.
36681      \param button6_txt = Label of the 6th button.
36682      \param logo = Logo image displayed at the left of the main message. This parameter is optional.
36683      \param centering = Tell to center the dialog window on the screen.
36684      \return The button number (from 0 to 5), or -1 if the dialog window has been closed by the user.
36685      \note If a button text is set to 0, then the corresponding button (and the followings) won't appear in
36686      the dialog box. At least one button is necessary.
36687   **/
36688 
36689   template<typename t>
36690   inline int dialog(const char *title, const char *msg,
36691                     const char *button1_txt, const char *button2_txt,
36692                     const char *button3_txt, const char *button4_txt,
36693                     const char *button5_txt, const char *button6_txt,
36694                     const CImg<t>& logo, const bool centering = false) {
36695 #if cimg_display!=0
36696     const unsigned char
36697       black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };
36698 
36699       // Create buttons and canvas graphics
36700       CImgList<unsigned char> buttons, cbuttons, sbuttons;
36701       if (button1_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button1_txt,black,gray,1,13));
36702       if (button2_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button2_txt,black,gray,1,13));
36703       if (button3_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button3_txt,black,gray,1,13));
36704       if (button4_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button4_txt,black,gray,1,13));
36705       if (button5_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button5_txt,black,gray,1,13));
36706       if (button6_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button6_txt,black,gray,1,13));
36707       }}}}}}
36708       if (!buttons.size)
36709         throw CImgArgumentException("cimg::dialog() : No buttons have been defined. At least one is necessary");
36710 
36711       unsigned int bw = 0, bh = 0;
36712       cimglist_for(buttons,l) { bw = cimg::max(bw,buttons[l].width); bh = cimg::max(bh,buttons[l].height); }
36713       bw+=8; bh+=8;
36714       if (bw<64) bw=64;
36715       if (bw>128) bw=128;
36716       if (bh<24) bh=24;
36717       if (bh>48) bh=48;
36718 
36719       CImg<unsigned char> button(bw,bh,1,3);
36720       button.draw_rectangle(0,0,bw-1,bh-1,gray);
36721       button.draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white);
36722       button.draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black);
36723       button.draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2);
36724       CImg<unsigned char> sbutton(bw,bh,1,3);
36725       sbutton.draw_rectangle(0,0,bw-1,bh-1,gray);
36726       sbutton.draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black);
36727       sbutton.draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black);
36728       sbutton.draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white);
36729       sbutton.draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black);
36730       sbutton.draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2);
36731       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);
36732       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);
36733       CImg<unsigned char> cbutton(bw,bh,1,3);
36734       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);
36735       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);
36736       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);
36737 
36738       cimglist_for(buttons,ll) {
36739         cbuttons.insert(CImg<unsigned char>(cbutton).draw_image(1+(bw-buttons[ll].dimx())/2,1+(bh-buttons[ll].dimy())/2,buttons[ll]));
36740         sbuttons.insert(CImg<unsigned char>(sbutton).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]));
36741         buttons[ll] = CImg<unsigned char>(button).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]);
36742       }
36743 
36744       CImg<unsigned char> canvas;
36745       if (msg) canvas = CImg<unsigned char>().draw_text(0,0,msg,black,gray,1,13);
36746       const unsigned int
36747         bwall = (buttons.size-1)*(12+bw) + bw,
36748         w = cimg::max(196U,36+logo.width+canvas.width, 24+bwall),
36749         h = cimg::max(96U,36+canvas.height+bh,36+logo.height+bh),
36750         lx = 12 + (canvas.data?0:((w-24-logo.width)/2)),
36751         ly = (h-12-bh-logo.height)/2,
36752         tx = lx+logo.width+12,
36753         ty = (h-12-bh-canvas.height)/2,
36754         bx = (w-bwall)/2,
36755         by = h-12-bh;
36756 
36757       if (canvas.data)
36758         canvas = CImg<unsigned char>(w,h,1,3).
36759           draw_rectangle(0,0,w-1,h-1,gray).
36760           draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
36761           draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black).
36762           draw_image(tx,ty,canvas);
36763       else
36764         canvas = CImg<unsigned char>(w,h,1,3).
36765           draw_rectangle(0,0,w-1,h-1,gray).
36766           draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
36767           draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black);
36768       if (logo.data) canvas.draw_image(lx,ly,logo);
36769 
36770       unsigned int xbuttons[6];
36771       cimglist_for(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(xbuttons[lll],by,buttons[lll]); }
36772 
36773       // Open window and enter events loop
36774       CImgDisplay disp(canvas,title?title:" ",0,false,centering?true:false);
36775       if (centering) disp.move((CImgDisplay::screen_dimx()-disp.dimx())/2,
36776                                (CImgDisplay::screen_dimy()-disp.dimy())/2);
36777       bool stopflag = false, refresh = false;
36778       int oselected = -1, oclicked = -1, selected = -1, clicked = -1;
36779       while (!disp.is_closed && !stopflag) {
36780         if (refresh) {
36781           if (clicked>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[clicked],by,cbuttons[clicked]).display(disp);
36782           else {
36783             if (selected>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[selected],by,sbuttons[selected]).display(disp);
36784             else canvas.display(disp);
36785           }
36786           refresh = false;
36787         }
36788         disp.wait(15);
36789         if (disp.is_resized) disp.resize(disp);
36790 
36791         if (disp.button&1)  {
36792           oclicked = clicked;
36793           clicked = -1;
36794           cimglist_for(buttons,l)
36795             if (disp.mouse_y>=(int)by && disp.mouse_y<(int)(by+bh) &&
36796                 disp.mouse_x>=(int)xbuttons[l] && disp.mouse_x<(int)(xbuttons[l]+bw)) {
36797               clicked = selected = l;
36798               refresh = true;
36799             }
36800           if (clicked!=oclicked) refresh = true;
36801         } else if (clicked>=0) stopflag = true;
36802 
36803         if (disp.key) {
36804           oselected = selected;
36805           switch (disp.key) {
36806           case cimg::keyESC : selected=-1; stopflag=true; break;
36807           case cimg::keyENTER : if (selected<0) selected = 0; stopflag = true; break;
36808           case cimg::keyTAB :
36809           case cimg::keyARROWRIGHT :
36810           case cimg::keyARROWDOWN : selected = (selected+1)%buttons.size; break;
36811           case cimg::keyARROWLEFT :
36812           case cimg::keyARROWUP : selected = (selected+buttons.size-1)%buttons.size; break;
36813           }
36814           disp.key = 0;
36815           if (selected!=oselected) refresh = true;
36816         }
36817       }
36818       if (!disp) selected = -1;
36819       return selected;
36820 #else
36821       cimg_std::fprintf(cimg_stdout,"<%s>\n\n%s\n\n",title,msg);
36822       return -1+0*(int)(button1_txt-button2_txt+button3_txt-button4_txt+button5_txt-button6_txt+logo.width+(int)centering);
36823 #endif
36824   }
36825 
36826   inline int dialog(const char *title, const char *msg,
36827                     const char *button1_txt, const char *button2_txt, const char *button3_txt,
36828                     const char *button4_txt, const char *button5_txt, const char *button6_txt,
36829                     const bool centering) {
36830     return dialog(title,msg,button1_txt,button2_txt,button3_txt,button4_txt,button5_txt,button6_txt,
36831                   CImg<unsigned char>::logo40x38(),centering);
36832   }
36833 
36834   // End of cimg:: namespace
36835 }
36836 
36837   // End of cimg_library:: namespace
36838 }
36839 
36840 } // namespace Digikam
36841 
36842 #ifdef _cimg_redefine_min
36843 #define min(a,b) (((a)<(b))?(a):(b))
36844 #endif
36845 #ifdef _cimg_redefine_max
36846 #define max(a,b) (((a)>(b))?(a):(b))
36847 #endif
36848 
36849 #endif
36850 // Local Variables:
36851 // mode: c++
36852 // End:
36853