Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CImg.h
Go to the documentation of this file.
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 #ifndef cimg_version
56 #define cimg_version 132
57 
58 /*-----------------------------------------------------------
59  #
60  # Test/auto-set CImg configuration variables
61  # and include required headers.
62  #
63  # If you find that default configuration variables are
64  # not adapted, you can override their values before including
65  # the header file "CImg.h" (using the #define directive).
66  #
67  ------------------------------------------------------------*/
68 
69 // Include required standard C++ headers.
70 #include <cstdio>
71 #include <cstdlib>
72 #include <cstdarg>
73 #include <cstring>
74 #include <cmath>
75 #include <ctime>
76 
77 // Operating system configuration.
78 //
79 // Define 'cimg_OS' to : 0 for an unknown OS (will try to minize library dependancies).
80 // 1 for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...).
81 // 2 for Microsoft Windows.
82 #ifndef cimg_OS
83 #if defined(unix) || defined(__unix) || defined(__unix__) \
84  || defined(linux) || defined(__linux) || defined(__linux__) \
85  || defined(sun) || defined(__sun) \
86  || defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) \
87  || defined(__FreeBSD__) || defined __DragonFly__ \
88  || defined(sgi) || defined(__sgi) \
89  || defined(__MACOSX__) || defined(__APPLE__) \
90  || defined(__CYGWIN__)
91 #define cimg_OS 1
92 #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
93  || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
94 #define cimg_OS 2
95 #else
96 #define cimg_OS 0
97 #endif
98 #elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2)
99 #error CImg Library : Configuration variable 'cimg_OS' is badly defined.
100 #error (valid values are '0=unknown OS', '1=Unix-like OS', '2=Microsoft Windows').
101 #endif
102 
103 // Compiler configuration.
104 //
105 // Try to detect Microsoft VC++ compilers.
106 // (lot of workarounds are needed afterwards to
107 // make CImg working, particularly with VC++ 6.0).
108 #ifdef _MSC_VER
109 #pragma warning(push)
110 #pragma warning(disable:4311)
111 #pragma warning(disable:4312)
112 #pragma warning(disable:4800)
113 #pragma warning(disable:4804)
114 #pragma warning(disable:4996)
115 #define _CRT_SECURE_NO_DEPRECATE 1
116 #define _CRT_NONSTDC_NO_DEPRECATE 1
117 #endif
118 
119 // Include OS-specific headers.
120 #if cimg_OS==1
121 #include <sys/time.h>
122 #include <unistd.h>
123 #elif cimg_OS==2
124 #include <windows.h>
125 #ifndef _WIN32_IE
126 #define _WIN32_IE 0x0400
127 #endif
128 #include <shlobj.h>
129 #endif
130 
131 // Define default pipe for output messages.
132 //
133 // Define 'cimg_stdout' to : stdout to print CImg messages on the standard output.
134 // stderr to print CImg messages on the standart error output (default behavior).
135 #ifndef cimg_stdout
136 #define cimg_stdout stderr
137 #endif
138 
139 // Define default filename separator.
140 #ifndef cimg_file_separator
141 #if cimg_OS==2
142 #define cimg_file_separator '\\'
143 #else
144 #define cimg_file_separator '/'
145 #endif
146 #endif
147 
148 // Output messages configuration.
149 //
150 // Define 'cimg_debug' to : 0 to hide debug messages (quiet mode, but exceptions are still thrown).
151 // 1 to display debug messages on the console.
152 // 2 to display debug messages with dialog windows (default behavior).
153 // 3 to do as 1 + add extra warnings (may slow down the code !).
154 // 4 to do as 2 + add extra warnings (may slow down the code !).
155 //
156 // Define 'cimg_strict_warnings' to replace warning messages by exception throwns.
157 //
158 // Define 'cimg_use_vt100' to allow output of color messages (require VT100-compatible terminal).
159 #ifndef cimg_debug
160 #define cimg_debug 2
161 #elif !(cimg_debug==0 || cimg_debug==1 || cimg_debug==2 || cimg_debug==3 || cimg_debug==4)
162 #error CImg Library : Configuration variable 'cimg_debug' is badly defined.
163 #error (valid values are '0=quiet', '1=console', '2=dialog', '3=console+warnings', '4=dialog+warnings').
164 #endif
165 
166 // Display framework configuration.
167 //
168 // Define 'cimg_display' to : 0 to disable display capabilities.
169 // 1 to use X-Window framework (X11).
170 // 2 to use Microsoft GDI32 framework.
171 // 3 to use Apple Carbon framework.
172 #define cimg_display 0
173 #ifndef cimg_display
174 #if cimg_OS==0
175 #define cimg_display 0
176 #elif cimg_OS==1
177 #if defined(__MACOSX__) || defined(__APPLE__)
178 #define cimg_display 1
179 #else
180 #define cimg_display 1
181 #endif
182 #elif cimg_OS==2
183 #define cimg_display 2
184 #endif
185 #elif !(cimg_display==0 || cimg_display==1 || cimg_display==2 || cimg_display==3)
186 #error CImg Library : Configuration variable 'cimg_display' is badly defined.
187 #error (valid values are '0=disable', '1=X-Window (X11)', '2=Microsoft GDI32', '3=Apple Carbon').
188 #endif
189 
190 // Include display-specific headers.
191 #if cimg_display==1
192 #include <X11/Xlib.h>
193 #include <X11/Xutil.h>
194 #include <X11/keysym.h>
195 #include <pthread.h>
196 #ifdef cimg_use_xshm
197 #include <sys/ipc.h>
198 #include <sys/shm.h>
199 #include <X11/extensions/XShm.h>
200 #endif
201 #ifdef cimg_use_xrandr
202 #include <X11/extensions/Xrandr.h>
203 #endif
204 #elif cimg_display==3
205 #include <Carbon/Carbon.h>
206 #include <pthread.h>
207 #endif
208 
209 // OpenMP configuration.
210 // (http://www.openmp.org)
211 //
212 // Define 'cimg_use_openmp' to enable OpenMP support.
213 //
214 // OpenMP directives can be used in few CImg functions to get
215 // advantages of multi-core CPUs. Using OpenMP is not mandatory.
216 #ifdef cimg_use_openmp
217 #include "omp.h"
218 #endif
219 
220 // LibPNG configuration.
221 // (http://www.libpng.org)
222 //
223 // Define 'cimg_use_png' to enable LibPNG support.
224 //
225 // LibPNG can be used in functions 'CImg<T>::{load,save}_png()'
226 // to get a builtin support of PNG files. Using LibPNG is not mandatory.
227 #ifdef cimg_use_png
228 extern "C" {
229 #include "png.h"
230 }
231 #endif
232 
233 // LibJPEG configuration.
234 // (http://en.wikipedia.org/wiki/Libjpeg)
235 //
236 // Define 'cimg_use_jpeg' to enable LibJPEG support.
237 //
238 // LibJPEG can be used in functions 'CImg<T>::{load,save}_jpeg()'
239 // to get a builtin support of JPEG files. Using LibJPEG is not mandatory.
240 #ifdef cimg_use_jpeg
241 extern "C" {
242 #include "jpeglib.h"
243 }
244 #endif
245 
246 // LibTIFF configuration.
247 // (http://www.libtiff.org)
248 //
249 // Define 'cimg_use_tiff' to enable LibTIFF support.
250 //
251 // LibTIFF can be used in functions 'CImg[List]<T>::{load,save}_tiff()'
252 // to get a builtin support of TIFF files. Using LibTIFF is not mandatory.
253 #ifdef cimg_use_tiff
254 extern "C" {
255 #include "tiffio.h"
256 }
257 #endif
258 
259 // FFMPEG Avcodec and Avformat libraries configuration.
260 // (http://www.ffmpeg.org)
261 //
262 // Define 'cimg_use_ffmpeg' to enable FFMPEG lib support.
263 //
264 // Avcodec and Avformat libraries can be used in functions
265 // 'CImg[List]<T>::load_ffmpeg()' to get a builtin
266 // support of various image sequences files.
267 // Using FFMPEG libraries is not mandatory.
268 #ifdef cimg_use_ffmpeg
269 extern "C" {
270 #include "avformat.h"
271 #include "avcodec.h"
272 #include "swscale.h"
273 }
274 #endif
275 
276 // Zlib configuration
277 // (http://www.zlib.net)
278 //
279 // Define 'cimg_use_zlib' to enable Zlib support.
280 //
281 // Zlib can be used in functions 'CImg[List]<T>::{load,save}_cimg()'
282 // to allow compressed data in '.cimg' files. Using Zlib is not mandatory.
283 #ifdef cimg_use_zlib
284 extern "C" {
285 #include "zlib.h"
286 }
287 #endif
288 
289 // Magick++ configuration.
290 // (http://www.imagemagick.org/Magick++)
291 //
292 // Define 'cimg_use_magick' to enable Magick++ support.
293 //
294 // Magick++ library can be used in functions 'CImg<T>::{load,save}()'
295 // to get a builtin support of various image formats (PNG,JPEG,TIFF,...).
296 // Using Magick++ is not mandatory.
297 #ifdef cimg_use_magick
298 #include "Magick++.h"
299 #endif
300 
301 // FFTW3 configuration.
302 // (http://www.fftw.org)
303 //
304 // Define 'cimg_use_fftw3' to enable libFFTW3 support.
305 //
306 // FFTW3 library can be used in functions 'CImg[List]<T>::FFT()' to
307 // efficiently compile the Fast Fourier Transform of image data.
308 #ifdef cimg_use_fftw3
309 extern "C" {
310 #include "fftw3.h"
311 }
312 #endif
313 
314 // Board configuration
315 // (http://libboard.sourceforge.net/)
316 //
317 // Define 'cimg_use_board' to enable Board support.
318 //
319 // Board library can be used in functions 'CImg<T>::draw_object3d()'
320 // to draw objects 3D in vector-graphics canvas that can be saved
321 // as .PS or .SVG files afterwards.
322 #ifdef cimg_use_board
323 #ifdef None
324 #undef None
325 #define _cimg_redefine_None
326 #endif
327 #include "Board.h"
328 #endif
329 
330 // Lapack configuration.
331 // (http://www.netlib.org/lapack)
332 //
333 // Define 'cimg_use_lapack' to enable LAPACK support.
334 //
335 // Lapack can be used in various CImg functions dealing with
336 // matrix computation and algorithms (eigenvalues, inverse, ...).
337 // Using Lapack is not mandatory.
338 #ifdef cimg_use_lapack
339 extern "C" {
340  extern void sgetrf_(int*, int*, float*, int*, int*, int*);
341  extern void sgetri_(int*, float*, int*, int*, float*, int*, int*);
342  extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*);
343  extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*);
344  extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*);
345  extern void dgetrf_(int*, int*, double*, int*, int*, int*);
346  extern void dgetri_(int*, double*, int*, int*, double*, int*, int*);
347  extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*);
348  extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*, int*, double*, int*, double*, int*, int*);
349  extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*);
350 }
351 #endif
352 
353 // Check if min/max macros are defined.
354 //
355 // CImg does not compile if macros 'min' or 'max' are defined,
356 // because min() and max() functions are also defined in the cimg:: namespace.
357 // so it '#undef' these macros if necessary, and restore them to reasonable
358 // values at the end of the file.
359 #ifdef min
360 #undef min
361 #define _cimg_redefine_min
362 #endif
363 #ifdef max
364 #undef max
365 #define _cimg_redefine_max
366 #endif
367 
368 // Set the current working directory for native MacOSX bundled applications.
369 //
370 // By default, MacOS bundled applications set the cwd at the root directory '/',
371 // the code below allows to set it to the current exec directory instead when
372 // a CImg-based program is executed.
373 #if cimg_OS==1 && cimg_display==3
374 static struct _cimg_macosx_setcwd {
375  _cimg_macosx_setcwd() {
376  FSRef location;
377  ProcessSerialNumber psn;
378  char filePath[512] = { 0 };
379  if (GetCurrentProcess(&psn)!=noErr) return;
380  if (GetProcessBundleLocation(&psn,&location)!=noErr) return;
381  FSRefMakePath(&location,(UInt8*)filePath,sizeof(filePath)-1);
382  unsigned int p = std::strlen(filePath);
383  while (filePath[p] != '/') --p;
384  filePath[p] = 0;
385  chdir(filePath);
386  }
387 } cimg_macosx_setcwd;
388 #endif
389 
390 /*------------------------------------------------------------------------------
391  #
392  # Define user-friendly macros.
393  #
394  # User macros are prefixed by 'cimg_' and can be used in your own code.
395  # They are particularly useful for option parsing, and image loops creation.
396  #
397  ------------------------------------------------------------------------------*/
398 
399 // Define the program usage, and retrieve command line arguments.
400 #define cimg_usage(usage) cimg_library::cimg::option((char*)0,argc,argv,(char*)0,usage)
401 #define cimg_help(str) cimg_library::cimg::option((char*)0,argc,argv,str,(char*)0)
402 #define cimg_option(name,defaut,usage) cimg_library::cimg::option(name,argc,argv,defaut,usage)
403 #define cimg_argument(pos) cimg_library::cimg::argument(pos,argc,argv)
404 #define cimg_argument1(pos,s0) cimg_library::cimg::argument(pos,argc,argv,1,s0)
405 #define cimg_argument2(pos,s0,s1) cimg_library::cimg::argument(pos,argc,argv,2,s0,s1)
406 #define cimg_argument3(pos,s0,s1,s2) cimg_library::cimg::argument(pos,argc,argv,3,s0,s1,s2)
407 #define cimg_argument4(pos,s0,s1,s2,s3) cimg_library::cimg::argument(pos,argc,argv,4,s0,s1,s2,s3)
408 #define cimg_argument5(pos,s0,s1,s2,s3,s4) cimg_library::cimg::argument(pos,argc,argv,5,s0,s1,s2,s3,s4)
409 #define cimg_argument6(pos,s0,s1,s2,s3,s4,s5) cimg_library::cimg::argument(pos,argc,argv,6,s0,s1,s2,s3,s4,s5)
410 #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)
411 #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)
412 #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)
413 
414 // Define and manipulate local neighborhoods.
415 #define CImg_2x2(I,T) T I[4]; \
416  T& I##cc = I[0]; T& I##nc = I[1]; \
417  T& I##cn = I[2]; T& I##nn = I[3]; \
418  I##cc = I##nc = \
419  I##cn = I##nn = 0
420 
421 #define CImg_3x3(I,T) T I[9]; \
422  T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \
423  T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \
424  T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \
425  I##pp = I##cp = I##np = \
426  I##pc = I##cc = I##nc = \
427  I##pn = I##cn = I##nn = 0
428 
429 #define CImg_4x4(I,T) T I[16]; \
430  T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \
431  T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \
432  T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \
433  T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \
434  I##pp = I##cp = I##np = I##ap = \
435  I##pc = I##cc = I##nc = I##ac = \
436  I##pn = I##cn = I##nn = I##an = \
437  I##pa = I##ca = I##na = I##aa = 0
438 
439 #define CImg_5x5(I,T) T I[25]; \
440  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]; \
441  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]; \
442  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]; \
443  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]; \
444  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]; \
445  I##bb = I##pb = I##cb = I##nb = I##ab = \
446  I##bp = I##pp = I##cp = I##np = I##ap = \
447  I##bc = I##pc = I##cc = I##nc = I##ac = \
448  I##bn = I##pn = I##cn = I##nn = I##an = \
449  I##ba = I##pa = I##ca = I##na = I##aa = 0
450 
451 #define CImg_2x2x2(I,T) T I[8]; \
452  T& I##ccc = I[0]; T& I##ncc = I[1]; \
453  T& I##cnc = I[2]; T& I##nnc = I[3]; \
454  T& I##ccn = I[4]; T& I##ncn = I[5]; \
455  T& I##cnn = I[6]; T& I##nnn = I[7]; \
456  I##ccc = I##ncc = \
457  I##cnc = I##nnc = \
458  I##ccn = I##ncn = \
459  I##cnn = I##nnn = 0
460 
461 #define CImg_3x3x3(I,T) T I[27]; \
462  T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \
463  T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \
464  T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \
465  T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \
466  T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \
467  T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \
468  T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \
469  T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \
470  T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \
471  I##ppp = I##cpp = I##npp = \
472  I##pcp = I##ccp = I##ncp = \
473  I##pnp = I##cnp = I##nnp = \
474  I##ppc = I##cpc = I##npc = \
475  I##pcc = I##ccc = I##ncc = \
476  I##pnc = I##cnc = I##nnc = \
477  I##ppn = I##cpn = I##npn = \
478  I##pcn = I##ccn = I##ncn = \
479  I##pnn = I##cnn = I##nnn = 0
480 
481 #define cimg_get2x2(img,x,y,z,v,I) \
482  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)
483 
484 #define cimg_get3x3(img,x,y,z,v,I) \
485  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), \
486  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), \
487  I[8] = (img)(_n1##x,_n1##y,z,v)
488 
489 #define cimg_get4x4(img,x,y,z,v,I) \
490  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), \
491  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), \
492  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), \
493  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)
494 
495 #define cimg_get5x5(img,x,y,z,v,I) \
496  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), \
497  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), \
498  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), \
499  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), \
500  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), \
501  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), \
502  I[24] = (img)(_n2##x,_n2##y,z,v)
503 
504 #define cimg_get6x6(img,x,y,z,v,I) \
505  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), \
506  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), \
507  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), \
508  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), \
509  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), \
510  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), \
511  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), \
512  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), \
513  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)
514 
515 #define cimg_get7x7(img,x,y,z,v,I) \
516  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), \
517  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), \
518  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), \
519  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), \
520  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), \
521  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), \
522  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), \
523  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), \
524  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), \
525  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), \
526  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), \
527  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), \
528  I[48] = (img)(_n3##x,_n3##y,z,v)
529 
530 #define cimg_get8x8(img,x,y,z,v,I) \
531  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), \
532  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), \
533  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), \
534  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), \
535  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), \
536  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), \
537  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), \
538  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), \
539  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), \
540  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), \
541  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), \
542  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), \
543  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), \
544  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), \
545  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), \
546  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);
547 
548 #define cimg_get9x9(img,x,y,z,v,I) \
549  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), \
550  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), \
551  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), \
552  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), \
553  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), \
554  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), \
555  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), \
556  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), \
557  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), \
558  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), \
559  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), \
560  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), \
561  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), \
562  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), \
563  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), \
564  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), \
565  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), \
566  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), \
567  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), \
568  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), \
569  I[80] = (img)(_n4##x,_n4##y,z,v)
570 
571 #define cimg_get2x2x2(img,x,y,z,v,I) \
572  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), \
573  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)
574 
575 #define cimg_get3x3x3(img,x,y,z,v,I) \
576  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), \
577  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), \
578  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), \
579  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), \
580  I[12] = (img)(_p1##x,y,z,v), I[13] = (img)(x,y,z,v), I[14] = (img)(_n1##x,y,z,v), \
581  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), \
582  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), \
583  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), \
584  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)
585 
586 // Define various image loops.
587 //
588 // These macros generally avoid the use of iterators, but you are not forced to used them !
589 #define cimg_for(img,ptr,T_ptr) for (T_ptr *ptr = (img).data + (img).size(); (ptr--)>(img).data; )
590 #define cimg_foroff(img,off) for (unsigned int off = 0, _max##off = (unsigned int)(img).size(); off<_max##off; ++off)
591 
592 #define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i)
593 #define cimg_forX(img,x) cimg_for1((img).width,x)
594 #define cimg_forY(img,y) cimg_for1((img).height,y)
595 #define cimg_forZ(img,z) cimg_for1((img).depth,z)
596 #define cimg_forV(img,v) cimg_for1((img).dim,v)
597 #define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x)
598 #define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x)
599 #define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y)
600 #define cimg_forXV(img,x,v) cimg_forV(img,v) cimg_forX(img,x)
601 #define cimg_forYV(img,y,v) cimg_forV(img,v) cimg_forY(img,y)
602 #define cimg_forZV(img,z,v) cimg_forV(img,v) cimg_forZ(img,z)
603 #define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y)
604 #define cimg_forXYV(img,x,y,v) cimg_forV(img,v) cimg_forXY(img,x,y)
605 #define cimg_forXZV(img,x,z,v) cimg_forV(img,v) cimg_forXZ(img,x,z)
606 #define cimg_forYZV(img,y,z,v) cimg_forV(img,v) cimg_forYZ(img,y,z)
607 #define cimg_forXYZV(img,x,y,z,v) cimg_forV(img,v) cimg_forXYZ(img,x,y,z)
608 
609 #define cimg_for_in1(bound,i0,i1,i) \
610  for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound)-1; i<=_max##i; ++i)
611 #define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img).width,x0,x1,x)
612 #define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img).height,y0,y1,y)
613 #define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img).depth,z0,z1,z)
614 #define cimg_for_inV(img,v0,v1,v) cimg_for_in1((img).dim,v0,v1,v)
615 #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)
616 #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)
617 #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)
618 #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)
619 #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)
620 #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)
621 #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)
622 #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)
623 #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)
624 #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)
625 #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)
626 #define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img).width-1-(n),x)
627 #define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img).height-1-(n),y)
628 #define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img).depth-1-(n),z)
629 #define cimg_for_insideV(img,v,n) cimg_for_inV(img,n,(img).dim-1-(n),v)
630 #define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
631 #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)
632 #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)
633 
634 #define cimg_for_out1(boundi,i0,i1,i) \
635  for (int i = (int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1)+1:i)
636 #define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \
637  for (int j = 0; j<(int)(boundj); ++j) \
638  for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
639  ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1)+1:i))
640 #define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \
641  for (int k = 0; k<(int)(boundk); ++k) \
642  for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
643  for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
644  ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1)+1:i))
645 #define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \
646  for (int l = 0; l<(int)(boundl); ++l) \
647  for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \
648  for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
649  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); \
650  ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1)+1:i))
651 #define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img).width,x0,x1,x)
652 #define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img).height,y0,y1,y)
653 #define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img).depth,z0,z1,z)
654 #define cimg_for_outV(img,v0,v1,v) cimg_for_out1((img).dim,v0,v1,v)
655 #define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img).width,(img).height,x0,y0,x1,y1,x,y)
656 #define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img).width,(img).depth,x0,z0,x1,z1,x,z)
657 #define cimg_for_outXV(img,x0,v0,x1,v1,x,v) cimg_for_out2((img).width,(img).dim,x0,v0,x1,v1,x,v)
658 #define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img).height,(img).depth,y0,z0,y1,z1,y,z)
659 #define cimg_for_outYV(img,y0,v0,y1,v1,y,v) cimg_for_out2((img).height,(img).dim,y0,v0,y1,v1,y,v)
660 #define cimg_for_outZV(img,z0,v0,z1,v1,z,v) cimg_for_out2((img).depth,(img).dim,z0,v0,z1,v1,z,v)
661 #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)
662 #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)
663 #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)
664 #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)
665 #define cimg_for_outXYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) \
666  cimg_for_out4((img).width,(img).height,(img).depth,(img).dim,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v)
667 #define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img).width-1-(n),x)
668 #define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img).height-1-(n),y)
669 #define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img).depth-1-(n),z)
670 #define cimg_for_borderV(img,v,n) cimg_for_outV(img,n,(img).dim-1-(n),v)
671 #define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
672 #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)
673 #define cimg_for_borderXYZV(img,x,y,z,v,n) \
674  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)
675 
676 #define cimg_for_spiralXY(img,x,y) \
677  for (int x = 0, y = 0, _n1##x = 1, _n1##y = (int)((img).width*(img).height); _n1##y; \
678  --_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)
679 
680 #define cimg_for_lineXY(x,y,x0,y0,x1,y1) \
681  for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \
682  _dx=(x1)>(x0)?(int)(x1)-(int)(x0):(_sx=-1,(int)(x0)-(int)(x1)), \
683  _dy=(y1)>(y0)?(int)(y1)-(int)(y0):(_sy=-1,(int)(y0)-(int)(y1)), \
684  _counter = _dx, \
685  _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \
686  _counter>=0; \
687  --_counter, x+=_steep? \
688  (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \
689  (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx))
690 
691 #define cimg_for2(bound,i) \
692  for (int i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1; \
693  _n1##i<(int)(bound) || i==--_n1##i; \
694  ++i, ++_n1##i)
695 #define cimg_for2X(img,x) cimg_for2((img).width,x)
696 #define cimg_for2Y(img,y) cimg_for2((img).height,y)
697 #define cimg_for2Z(img,z) cimg_for2((img).depth,z)
698 #define cimg_for2V(img,v) cimg_for2((img).dim,v)
699 #define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x)
700 #define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x)
701 #define cimg_for2XV(img,x,v) cimg_for2V(img,v) cimg_for2X(img,x)
702 #define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y)
703 #define cimg_for2YV(img,y,v) cimg_for2V(img,v) cimg_for2Y(img,y)
704 #define cimg_for2ZV(img,z,v) cimg_for2V(img,v) cimg_for2Z(img,z)
705 #define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y)
706 #define cimg_for2XZV(img,x,z,v) cimg_for2V(img,v) cimg_for2XZ(img,x,z)
707 #define cimg_for2YZV(img,y,z,v) cimg_for2V(img,v) cimg_for2YZ(img,y,z)
708 #define cimg_for2XYZV(img,x,y,z,v) cimg_for2V(img,v) cimg_for2XYZ(img,x,y,z)
709 
710 #define cimg_for_in2(bound,i0,i1,i) \
711  for (int i = (int)(i0)<0?0:(int)(i0), \
712  _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
713  i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
714  ++i, ++_n1##i)
715 #define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img).width,x0,x1,x)
716 #define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img).height,y0,y1,y)
717 #define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img).depth,z0,z1,z)
718 #define cimg_for_in2V(img,v0,v1,v) cimg_for_in2((img).dim,v0,v1,v)
719 #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)
720 #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)
721 #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)
722 #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)
723 #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)
724 #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)
725 #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)
726 #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)
727 #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)
728 #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)
729 
730 #define cimg_for3(bound,i) \
731  for (int i = 0, _p1##i = 0, \
732  _n1##i = 1>=(bound)?(int)(bound)-1:1; \
733  _n1##i<(int)(bound) || i==--_n1##i; \
734  _p1##i = i++, ++_n1##i)
735 #define cimg_for3X(img,x) cimg_for3((img).width,x)
736 #define cimg_for3Y(img,y) cimg_for3((img).height,y)
737 #define cimg_for3Z(img,z) cimg_for3((img).depth,z)
738 #define cimg_for3V(img,v) cimg_for3((img).dim,v)
739 #define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x)
740 #define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x)
741 #define cimg_for3XV(img,x,v) cimg_for3V(img,v) cimg_for3X(img,x)
742 #define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y)
743 #define cimg_for3YV(img,y,v) cimg_for3V(img,v) cimg_for3Y(img,y)
744 #define cimg_for3ZV(img,z,v) cimg_for3V(img,v) cimg_for3Z(img,z)
745 #define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y)
746 #define cimg_for3XZV(img,x,z,v) cimg_for3V(img,v) cimg_for3XZ(img,x,z)
747 #define cimg_for3YZV(img,y,z,v) cimg_for3V(img,v) cimg_for3YZ(img,y,z)
748 #define cimg_for3XYZV(img,x,y,z,v) cimg_for3V(img,v) cimg_for3XYZ(img,x,y,z)
749 
750 #define cimg_for_in3(bound,i0,i1,i) \
751  for (int i = (int)(i0)<0?0:(int)(i0), \
752  _p1##i = i-1<0?0:i-1, \
753  _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
754  i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
755  _p1##i = i++, ++_n1##i)
756 #define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img).width,x0,x1,x)
757 #define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img).height,y0,y1,y)
758 #define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img).depth,z0,z1,z)
759 #define cimg_for_in3V(img,v0,v1,v) cimg_for_in3((img).dim,v0,v1,v)
760 #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)
761 #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)
762 #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)
763 #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)
764 #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)
765 #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)
766 #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)
767 #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)
768 #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)
769 #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)
770 
771 #define cimg_for4(bound,i) \
772  for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1, \
773  _n2##i = 2>=(bound)?(int)(bound)-1:2; \
774  _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
775  _p1##i = i++, ++_n1##i, ++_n2##i)
776 #define cimg_for4X(img,x) cimg_for4((img).width,x)
777 #define cimg_for4Y(img,y) cimg_for4((img).height,y)
778 #define cimg_for4Z(img,z) cimg_for4((img).depth,z)
779 #define cimg_for4V(img,v) cimg_for4((img).dim,v)
780 #define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x)
781 #define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x)
782 #define cimg_for4XV(img,x,v) cimg_for4V(img,v) cimg_for4X(img,x)
783 #define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y)
784 #define cimg_for4YV(img,y,v) cimg_for4V(img,v) cimg_for4Y(img,y)
785 #define cimg_for4ZV(img,z,v) cimg_for4V(img,v) cimg_for4Z(img,z)
786 #define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y)
787 #define cimg_for4XZV(img,x,z,v) cimg_for4V(img,v) cimg_for4XZ(img,x,z)
788 #define cimg_for4YZV(img,y,z,v) cimg_for4V(img,v) cimg_for4YZ(img,y,z)
789 #define cimg_for4XYZV(img,x,y,z,v) cimg_for4V(img,v) cimg_for4XYZ(img,x,y,z)
790 
791 #define cimg_for_in4(bound,i0,i1,i) \
792  for (int i = (int)(i0)<0?0:(int)(i0), \
793  _p1##i = i-1<0?0:i-1, \
794  _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
795  _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
796  i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
797  _p1##i = i++, ++_n1##i, ++_n2##i)
798 #define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img).width,x0,x1,x)
799 #define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img).height,y0,y1,y)
800 #define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img).depth,z0,z1,z)
801 #define cimg_for_in4V(img,v0,v1,v) cimg_for_in4((img).dim,v0,v1,v)
802 #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)
803 #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)
804 #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)
805 #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)
806 #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)
807 #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)
808 #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)
809 #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)
810 #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)
811 #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)
812 
813 #define cimg_for5(bound,i) \
814  for (int i = 0, _p2##i = 0, _p1##i = 0, \
815  _n1##i = 1>=(bound)?(int)(bound)-1:1, \
816  _n2##i = 2>=(bound)?(int)(bound)-1:2; \
817  _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
818  _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
819 #define cimg_for5X(img,x) cimg_for5((img).width,x)
820 #define cimg_for5Y(img,y) cimg_for5((img).height,y)
821 #define cimg_for5Z(img,z) cimg_for5((img).depth,z)
822 #define cimg_for5V(img,v) cimg_for5((img).dim,v)
823 #define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x)
824 #define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x)
825 #define cimg_for5XV(img,x,v) cimg_for5V(img,v) cimg_for5X(img,x)
826 #define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y)
827 #define cimg_for5YV(img,y,v) cimg_for5V(img,v) cimg_for5Y(img,y)
828 #define cimg_for5ZV(img,z,v) cimg_for5V(img,v) cimg_for5Z(img,z)
829 #define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y)
830 #define cimg_for5XZV(img,x,z,v) cimg_for5V(img,v) cimg_for5XZ(img,x,z)
831 #define cimg_for5YZV(img,y,z,v) cimg_for5V(img,v) cimg_for5YZ(img,y,z)
832 #define cimg_for5XYZV(img,x,y,z,v) cimg_for5V(img,v) cimg_for5XYZ(img,x,y,z)
833 
834 #define cimg_for_in5(bound,i0,i1,i) \
835  for (int i = (int)(i0)<0?0:(int)(i0), \
836  _p2##i = i-2<0?0:i-2, \
837  _p1##i = i-1<0?0:i-1, \
838  _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
839  _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
840  i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
841  _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
842 #define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img).width,x0,x1,x)
843 #define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img).height,y0,y1,y)
844 #define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img).depth,z0,z1,z)
845 #define cimg_for_in5V(img,v0,v1,v) cimg_for_in5((img).dim,v0,v1,v)
846 #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)
847 #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)
848 #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)
849 #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)
850 #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)
851 #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)
852 #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)
853 #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)
854 #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)
855 #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)
856 
857 #define cimg_for6(bound,i) \
858  for (int i = 0, _p2##i = 0, _p1##i = 0, \
859  _n1##i = 1>=(bound)?(int)(bound)-1:1, \
860  _n2##i = 2>=(bound)?(int)(bound)-1:2, \
861  _n3##i = 3>=(bound)?(int)(bound)-1:3; \
862  _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
863  _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
864 #define cimg_for6X(img,x) cimg_for6((img).width,x)
865 #define cimg_for6Y(img,y) cimg_for6((img).height,y)
866 #define cimg_for6Z(img,z) cimg_for6((img).depth,z)
867 #define cimg_for6V(img,v) cimg_for6((img).dim,v)
868 #define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x)
869 #define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x)
870 #define cimg_for6XV(img,x,v) cimg_for6V(img,v) cimg_for6X(img,x)
871 #define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y)
872 #define cimg_for6YV(img,y,v) cimg_for6V(img,v) cimg_for6Y(img,y)
873 #define cimg_for6ZV(img,z,v) cimg_for6V(img,v) cimg_for6Z(img,z)
874 #define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y)
875 #define cimg_for6XZV(img,x,z,v) cimg_for6V(img,v) cimg_for6XZ(img,x,z)
876 #define cimg_for6YZV(img,y,z,v) cimg_for6V(img,v) cimg_for6YZ(img,y,z)
877 #define cimg_for6XYZV(img,x,y,z,v) cimg_for6V(img,v) cimg_for6XYZ(img,x,y,z)
878 
879 #define cimg_for_in6(bound,i0,i1,i) \
880  for (int i = (int)(i0)<0?0:(int)(i0), \
881  _p2##i = i-2<0?0:i-2, \
882  _p1##i = i-1<0?0:i-1, \
883  _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
884  _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
885  _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
886  i<=(int)(i1) && (_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_for_in6X(img,x0,x1,x) cimg_for_in6((img).width,x0,x1,x)
889 #define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img).height,y0,y1,y)
890 #define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img).depth,z0,z1,z)
891 #define cimg_for_in6V(img,v0,v1,v) cimg_for_in6((img).dim,v0,v1,v)
892 #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)
893 #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)
894 #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)
895 #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)
896 #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)
897 #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)
898 #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)
899 #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)
900 #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)
901 #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)
902 
903 #define cimg_for7(bound,i) \
904  for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
905  _n1##i = 1>=(bound)?(int)(bound)-1:1, \
906  _n2##i = 2>=(bound)?(int)(bound)-1:2, \
907  _n3##i = 3>=(bound)?(int)(bound)-1:3; \
908  _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
909  _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
910 #define cimg_for7X(img,x) cimg_for7((img).width,x)
911 #define cimg_for7Y(img,y) cimg_for7((img).height,y)
912 #define cimg_for7Z(img,z) cimg_for7((img).depth,z)
913 #define cimg_for7V(img,v) cimg_for7((img).dim,v)
914 #define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x)
915 #define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x)
916 #define cimg_for7XV(img,x,v) cimg_for7V(img,v) cimg_for7X(img,x)
917 #define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y)
918 #define cimg_for7YV(img,y,v) cimg_for7V(img,v) cimg_for7Y(img,y)
919 #define cimg_for7ZV(img,z,v) cimg_for7V(img,v) cimg_for7Z(img,z)
920 #define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y)
921 #define cimg_for7XZV(img,x,z,v) cimg_for7V(img,v) cimg_for7XZ(img,x,z)
922 #define cimg_for7YZV(img,y,z,v) cimg_for7V(img,v) cimg_for7YZ(img,y,z)
923 #define cimg_for7XYZV(img,x,y,z,v) cimg_for7V(img,v) cimg_for7XYZ(img,x,y,z)
924 
925 #define cimg_for_in7(bound,i0,i1,i) \
926  for (int i = (int)(i0)<0?0:(int)(i0), \
927  _p3##i = i-3<0?0:i-3, \
928  _p2##i = i-2<0?0:i-2, \
929  _p1##i = i-1<0?0:i-1, \
930  _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
931  _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
932  _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
933  i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
934  _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
935 #define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img).width,x0,x1,x)
936 #define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img).height,y0,y1,y)
937 #define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img).depth,z0,z1,z)
938 #define cimg_for_in7V(img,v0,v1,v) cimg_for_in7((img).dim,v0,v1,v)
939 #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)
940 #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)
941 #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)
942 #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)
943 #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)
944 #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)
945 #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)
946 #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)
947 #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)
948 #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)
949 
950 #define cimg_for8(bound,i) \
951  for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
952  _n1##i = 1>=(bound)?(int)(bound)-1:1, \
953  _n2##i = 2>=(bound)?(int)(bound)-1:2, \
954  _n3##i = 3>=(bound)?(int)(bound)-1:3, \
955  _n4##i = 4>=(bound)?(int)(bound)-1:4; \
956  _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
957  i==(_n4##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, ++_n4##i)
959 #define cimg_for8X(img,x) cimg_for8((img).width,x)
960 #define cimg_for8Y(img,y) cimg_for8((img).height,y)
961 #define cimg_for8Z(img,z) cimg_for8((img).depth,z)
962 #define cimg_for8V(img,v) cimg_for8((img).dim,v)
963 #define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x)
964 #define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x)
965 #define cimg_for8XV(img,x,v) cimg_for8V(img,v) cimg_for8X(img,x)
966 #define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y)
967 #define cimg_for8YV(img,y,v) cimg_for8V(img,v) cimg_for8Y(img,y)
968 #define cimg_for8ZV(img,z,v) cimg_for8V(img,v) cimg_for8Z(img,z)
969 #define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y)
970 #define cimg_for8XZV(img,x,z,v) cimg_for8V(img,v) cimg_for8XZ(img,x,z)
971 #define cimg_for8YZV(img,y,z,v) cimg_for8V(img,v) cimg_for8YZ(img,y,z)
972 #define cimg_for8XYZV(img,x,y,z,v) cimg_for8V(img,v) cimg_for8XYZ(img,x,y,z)
973 
974 #define cimg_for_in8(bound,i0,i1,i) \
975  for (int i = (int)(i0)<0?0:(int)(i0), \
976  _p3##i = i-3<0?0:i-3, \
977  _p2##i = i-2<0?0:i-2, \
978  _p1##i = i-1<0?0:i-1, \
979  _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
980  _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
981  _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
982  _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
983  i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
984  i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
985  _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
986 #define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img).width,x0,x1,x)
987 #define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img).height,y0,y1,y)
988 #define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img).depth,z0,z1,z)
989 #define cimg_for_in8V(img,v0,v1,v) cimg_for_in8((img).dim,v0,v1,v)
990 #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)
991 #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)
992 #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)
993 #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)
994 #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)
995 #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)
996 #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)
997 #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)
998 #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)
999 #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)
1000 
1001 #define cimg_for9(bound,i) \
1002  for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
1003  _n1##i = 1>=(int)(bound)?(int)(bound)-1:1, \
1004  _n2##i = 2>=(int)(bound)?(int)(bound)-1:2, \
1005  _n3##i = 3>=(int)(bound)?(int)(bound)-1:3, \
1006  _n4##i = 4>=(int)(bound)?(int)(bound)-1:4; \
1007  _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  _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1010 #define cimg_for9X(img,x) cimg_for9((img).width,x)
1011 #define cimg_for9Y(img,y) cimg_for9((img).height,y)
1012 #define cimg_for9Z(img,z) cimg_for9((img).depth,z)
1013 #define cimg_for9V(img,v) cimg_for9((img).dim,v)
1014 #define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x)
1015 #define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x)
1016 #define cimg_for9XV(img,x,v) cimg_for9V(img,v) cimg_for9X(img,x)
1017 #define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y)
1018 #define cimg_for9YV(img,y,v) cimg_for9V(img,v) cimg_for9Y(img,y)
1019 #define cimg_for9ZV(img,z,v) cimg_for9V(img,v) cimg_for9Z(img,z)
1020 #define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y)
1021 #define cimg_for9XZV(img,x,z,v) cimg_for9V(img,v) cimg_for9XZ(img,x,z)
1022 #define cimg_for9YZV(img,y,z,v) cimg_for9V(img,v) cimg_for9YZ(img,y,z)
1023 #define cimg_for9XYZV(img,x,y,z,v) cimg_for9V(img,v) cimg_for9XYZ(img,x,y,z)
1024 
1025 #define cimg_for_in9(bound,i0,i1,i) \
1026  for (int i = (int)(i0)<0?0:(int)(i0), \
1027  _p4##i = i-4<0?0:i-4, \
1028  _p3##i = i-3<0?0:i-3, \
1029  _p2##i = i-2<0?0:i-2, \
1030  _p1##i = i-1<0?0:i-1, \
1031  _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
1032  _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
1033  _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
1034  _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
1035  i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
1036  i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
1037  _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1038 #define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img).width,x0,x1,x)
1039 #define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img).height,y0,y1,y)
1040 #define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img).depth,z0,z1,z)
1041 #define cimg_for_in9V(img,v0,v1,v) cimg_for_in9((img).dim,v0,v1,v)
1042 #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)
1043 #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)
1044 #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)
1045 #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)
1046 #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)
1047 #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)
1048 #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)
1049 #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)
1050 #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)
1051 #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)
1052 
1053 #define cimg_for2x2(img,x,y,z,v,I) \
1054  cimg_for2((img).height,y) for (int x = 0, \
1055  _n1##x = (int)( \
1056  (I[0] = (img)(0,y,z,v)), \
1057  (I[2] = (img)(0,_n1##y,z,v)), \
1058  1>=(img).width?(int)((img).width)-1:1); \
1059  (_n1##x<(int)((img).width) && ( \
1060  (I[1] = (img)(_n1##x,y,z,v)), \
1061  (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1062  x==--_n1##x; \
1063  I[0] = I[1], \
1064  I[2] = I[3], \
1065  ++x, ++_n1##x)
1066 
1067 #define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,v,I) \
1068  cimg_for_in2((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1069  _n1##x = (int)( \
1070  (I[0] = (img)(x,y,z,v)), \
1071  (I[2] = (img)(x,_n1##y,z,v)), \
1072  x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1073  x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
1074  (I[1] = (img)(_n1##x,y,z,v)), \
1075  (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1076  x==--_n1##x); \
1077  I[0] = I[1], \
1078  I[2] = I[3], \
1079  ++x, ++_n1##x)
1080 
1081 #define cimg_for3x3(img,x,y,z,v,I) \
1082  cimg_for3((img).height,y) for (int x = 0, \
1083  _p1##x = 0, \
1084  _n1##x = (int)( \
1085  (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
1086  (I[3] = I[4] = (img)(0,y,z,v)), \
1087  (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
1088  1>=(img).width?(int)((img).width)-1:1); \
1089  (_n1##x<(int)((img).width) && ( \
1090  (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1091  (I[5] = (img)(_n1##x,y,z,v)), \
1092  (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1093  x==--_n1##x; \
1094  I[0] = I[1], I[1] = I[2], \
1095  I[3] = I[4], I[4] = I[5], \
1096  I[6] = I[7], I[7] = I[8], \
1097  _p1##x = x++, ++_n1##x)
1098 
1099 #define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,v,I) \
1100  cimg_for_in3((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1101  _p1##x = x-1<0?0:x-1, \
1102  _n1##x = (int)( \
1103  (I[0] = (img)(_p1##x,_p1##y,z,v)), \
1104  (I[3] = (img)(_p1##x,y,z,v)), \
1105  (I[6] = (img)(_p1##x,_n1##y,z,v)), \
1106  (I[1] = (img)(x,_p1##y,z,v)), \
1107  (I[4] = (img)(x,y,z,v)), \
1108  (I[7] = (img)(x,_n1##y,z,v)), \
1109  x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1110  x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
1111  (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1112  (I[5] = (img)(_n1##x,y,z,v)), \
1113  (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1114  x==--_n1##x); \
1115  I[0] = I[1], I[1] = I[2], \
1116  I[3] = I[4], I[4] = I[5], \
1117  I[6] = I[7], I[7] = I[8], \
1118  _p1##x = x++, ++_n1##x)
1119 
1120 #define cimg_for4x4(img,x,y,z,v,I) \
1121  cimg_for4((img).height,y) for (int x = 0, \
1122  _p1##x = 0, \
1123  _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1124  _n2##x = (int)( \
1125  (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
1126  (I[4] = I[5] = (img)(0,y,z,v)), \
1127  (I[8] = I[9] = (img)(0,_n1##y,z,v)), \
1128  (I[12] = I[13] = (img)(0,_n2##y,z,v)), \
1129  (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1130  (I[6] = (img)(_n1##x,y,z,v)), \
1131  (I[10] = (img)(_n1##x,_n1##y,z,v)), \
1132  (I[14] = (img)(_n1##x,_n2##y,z,v)), \
1133  2>=(img).width?(int)((img).width)-1:2); \
1134  (_n2##x<(int)((img).width) && ( \
1135  (I[3] = (img)(_n2##x,_p1##y,z,v)), \
1136  (I[7] = (img)(_n2##x,y,z,v)), \
1137  (I[11] = (img)(_n2##x,_n1##y,z,v)), \
1138  (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1139  _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
1140  I[0] = I[1], I[1] = I[2], I[2] = I[3], \
1141  I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1142  I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1143  I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1144  _p1##x = x++, ++_n1##x, ++_n2##x)
1145 
1146 #define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,v,I) \
1147  cimg_for_in4((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1148  _p1##x = x-1<0?0:x-1, \
1149  _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1150  _n2##x = (int)( \
1151  (I[0] = (img)(_p1##x,_p1##y,z,v)), \
1152  (I[4] = (img)(_p1##x,y,z,v)), \
1153  (I[8] = (img)(_p1##x,_n1##y,z,v)), \
1154  (I[12] = (img)(_p1##x,_n2##y,z,v)), \
1155  (I[1] = (img)(x,_p1##y,z,v)), \
1156  (I[5] = (img)(x,y,z,v)), \
1157  (I[9] = (img)(x,_n1##y,z,v)), \
1158  (I[13] = (img)(x,_n2##y,z,v)), \
1159  (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1160  (I[6] = (img)(_n1##x,y,z,v)), \
1161  (I[10] = (img)(_n1##x,_n1##y,z,v)), \
1162  (I[14] = (img)(_n1##x,_n2##y,z,v)), \
1163  x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
1164  x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
1165  (I[3] = (img)(_n2##x,_p1##y,z,v)), \
1166  (I[7] = (img)(_n2##x,y,z,v)), \
1167  (I[11] = (img)(_n2##x,_n1##y,z,v)), \
1168  (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1169  _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
1170  I[0] = I[1], I[1] = I[2], I[2] = I[3], \
1171  I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1172  I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1173  I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1174  _p1##x = x++, ++_n1##x, ++_n2##x)
1175 
1176 #define cimg_for5x5(img,x,y,z,v,I) \
1177  cimg_for5((img).height,y) for (int x = 0, \
1178  _p2##x = 0, _p1##x = 0, \
1179  _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1180  _n2##x = (int)( \
1181  (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
1182  (I[5] = I[6] = I[7] = (img)(0,_p1##y,z,v)), \
1183  (I[10] = I[11] = I[12] = (img)(0,y,z,v)), \
1184  (I[15] = I[16] = I[17] = (img)(0,_n1##y,z,v)), \
1185  (I[20] = I[21] = I[22] = (img)(0,_n2##y,z,v)), \
1186  (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1187  (I[8] = (img)(_n1##x,_p1##y,z,v)), \
1188  (I[13] = (img)(_n1##x,y,z,v)), \
1189  (I[18] = (img)(_n1##x,_n1##y,z,v)), \
1190  (I[23] = (img)(_n1##x,_n2##y,z,v)), \
1191  2>=(img).width?(int)((img).width)-1:2); \
1192  (_n2##x<(int)((img).width) && ( \
1193  (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1194  (I[9] = (img)(_n2##x,_p1##y,z,v)), \
1195  (I[14] = (img)(_n2##x,y,z,v)), \
1196  (I[19] = (img)(_n2##x,_n1##y,z,v)), \
1197  (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1198  _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
1199  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
1200  I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
1201  I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
1202  I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
1203  I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
1204  _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
1205 
1206 #define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,v,I) \
1207  cimg_for_in5((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1208  _p2##x = x-2<0?0:x-2, \
1209  _p1##x = x-1<0?0:x-1, \
1210  _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1211  _n2##x = (int)( \
1212  (I[0] = (img)(_p2##x,_p2##y,z,v)), \
1213  (I[5] = (img)(_p2##x,_p1##y,z,v)), \
1214  (I[10] = (img)(_p2##x,y,z,v)), \
1215  (I[15] = (img)(_p2##x,_n1##y,z,v)), \
1216  (I[20] = (img)(_p2##x,_n2##y,z,v)), \
1217  (I[1] = (img)(_p1##x,_p2##y,z,v)), \
1218  (I[6] = (img)(_p1##x,_p1##y,z,v)), \
1219  (I[11] = (img)(_p1##x,y,z,v)), \
1220  (I[16] = (img)(_p1##x,_n1##y,z,v)), \
1221  (I[21] = (img)(_p1##x,_n2##y,z,v)), \
1222  (I[2] = (img)(x,_p2##y,z,v)), \
1223  (I[7] = (img)(x,_p1##y,z,v)), \
1224  (I[12] = (img)(x,y,z,v)), \
1225  (I[17] = (img)(x,_n1##y,z,v)), \
1226  (I[22] = (img)(x,_n2##y,z,v)), \
1227  (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1228  (I[8] = (img)(_n1##x,_p1##y,z,v)), \
1229  (I[13] = (img)(_n1##x,y,z,v)), \
1230  (I[18] = (img)(_n1##x,_n1##y,z,v)), \
1231  (I[23] = (img)(_n1##x,_n2##y,z,v)), \
1232  x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
1233  x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
1234  (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1235  (I[9] = (img)(_n2##x,_p1##y,z,v)), \
1236  (I[14] = (img)(_n2##x,y,z,v)), \
1237  (I[19] = (img)(_n2##x,_n1##y,z,v)), \
1238  (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1239  _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
1240  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
1241  I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
1242  I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
1243  I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
1244  I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
1245  _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
1246 
1247 #define cimg_for6x6(img,x,y,z,v,I) \
1248  cimg_for6((img).height,y) for (int x = 0, \
1249  _p2##x = 0, _p1##x = 0, \
1250  _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1251  _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
1252  _n3##x = (int)( \
1253  (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
1254  (I[6] = I[7] = I[8] = (img)(0,_p1##y,z,v)), \
1255  (I[12] = I[13] = I[14] = (img)(0,y,z,v)), \
1256  (I[18] = I[19] = I[20] = (img)(0,_n1##y,z,v)), \
1257  (I[24] = I[25] = I[26] = (img)(0,_n2##y,z,v)), \
1258  (I[30] = I[31] = I[32] = (img)(0,_n3##y,z,v)), \
1259  (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1260  (I[9] = (img)(_n1##x,_p1##y,z,v)), \
1261  (I[15] = (img)(_n1##x,y,z,v)), \
1262  (I[21] = (img)(_n1##x,_n1##y,z,v)), \
1263  (I[27] = (img)(_n1##x,_n2##y,z,v)), \
1264  (I[33] = (img)(_n1##x,_n3##y,z,v)), \
1265  (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1266  (I[10] = (img)(_n2##x,_p1##y,z,v)), \
1267  (I[16] = (img)(_n2##x,y,z,v)), \
1268  (I[22] = (img)(_n2##x,_n1##y,z,v)), \
1269  (I[28] = (img)(_n2##x,_n2##y,z,v)), \
1270  (I[34] = (img)(_n2##x,_n3##y,z,v)), \
1271  3>=(img).width?(int)((img).width)-1:3); \
1272  (_n3##x<(int)((img).width) && ( \
1273  (I[5] = (img)(_n3##x,_p2##y,z,v)), \
1274  (I[11] = (img)(_n3##x,_p1##y,z,v)), \
1275  (I[17] = (img)(_n3##x,y,z,v)), \
1276  (I[23] = (img)(_n3##x,_n1##y,z,v)), \
1277  (I[29] = (img)(_n3##x,_n2##y,z,v)), \
1278  (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1279  _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \
1280  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
1281  I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1282  I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
1283  I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1284  I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
1285  I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
1286  _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1287 
1288 #define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,v,I) \
1289  cimg_for_in6((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \
1290  _p2##x = x-2<0?0:x-2, \
1291  _p1##x = x-1<0?0:x-1, \
1292  _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1293  _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
1294  _n3##x = (int)( \
1295  (I[0] = (img)(_p2##x,_p2##y,z,v)), \
1296  (I[6] = (img)(_p2##x,_p1##y,z,v)), \
1297  (I[12] = (img)(_p2##x,y,z,v)), \
1298  (I[18] = (img)(_p2##x,_n1##y,z,v)), \
1299  (I[24] = (img)(_p2##x,_n2##y,z,v)), \
1300  (I[30] = (img)(_p2##x,_n3##y,z,v)), \
1301  (I[1] = (img)(_p1##x,_p2##y,z,v)), \
1302  (I[7] = (img)(_p1##x,_p1##y,z,v)), \
1303  (I[13] = (img)(_p1##x,y,z,v)), \
1304  (I[19] = (img)(_p1##x,_n1##y,z,v)), \
1305  (I[25] = (img)(_p1##x,_n2##y,z,v)), \
1306  (I[31] = (img)(_p1##x,_n3##y,z,v)), \
1307  (I[2] = (img)(x,_p2##y,z,v)), \
1308  (I[8] = (img)(x,_p1##y,z,v)), \
1309  (I[14] = (img)(x,y,z,v)), \
1310  (I[20] = (img)(x,_n1##y,z,v)), \
1311  (I[26] = (img)(x,_n2##y,z,v)), \
1312  (I[32] = (img)(x,_n3##y,z,v)), \
1313  (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1314  (I[9] = (img)(_n1##x,_p1##y,z,v)), \
1315  (I[15] = (img)(_n1##x,y,z,v)), \
1316  (I[21] = (img)(_n1##x,_n1##y,z,v)), \
1317  (I[27] = (img)(_n1##x,_n2##y,z,v)), \
1318  (I[33] = (img)(_n1##x,_n3##y,z,v)), \
1319  (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1320  (I[10] = (img)(_n2##x,_p1##y,z,v)), \
1321  (I[16] = (img)(_n2##x,y,z,v)), \
1322  (I[22] = (img)(_n2##x,_n1##y,z,v)), \
1323  (I[28] = (img)(_n2##x,_n2##y,z,v)), \
1324  (I[34] = (img)(_n2##x,_n3##y,z,v)), \
1325  x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
1326  x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
1327  (I[5] = (img)(_n3##x,_p2##y,z,v)), \
1328  (I[11] = (img)(_n3##x,_p1##y,z,v)), \
1329  (I[17] = (img)(_n3##x,y,z,v)), \
1330  (I[23] = (img)(_n3##x,_n1##y,z,v)), \
1331  (I[29] = (img)(_n3##x,_n2##y,z,v)), \
1332  (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1333  _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \
1334  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
1335  I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1336  I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
1337  I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1338  I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
1339  I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
1340  _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1341 
1342 #define cimg_for7x7(img,x,y,z,v,I) \
1343  cimg_for7((img).height,y) for (int x = 0, \
1344  _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1345  _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1346  _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
1347  _n3##x = (int)( \
1348  (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
1349  (I[7] = I[8] = I[9] = I[10] = (img)(0,_p2##y,z,v)), \
1350  (I[14] = I[15] = I[16] = I[17] = (img)(0,_p1##y,z,v)), \
1351  (I[21] = I[22] = I[23] = I[24] = (img)(0,y,z,v)), \
1352  (I[28] = I[29] = I[30] = I[31] = (img)(0,_n1##y,z,v)), \
1353  (I[35] = I[36] = I[37] = I[38] = (img)(0,_n2##y,z,v)), \
1354  (I[42] = I[43] = I[44] = I[45] = (img)(0,_n3##y,z,v)), \
1355  (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1356  (I[11] = (img)(_n1##x,_p2##y,z,v)), \
1357  (I[18] = (img)(_n1##x,_p1##y,z,v)), \
1358  (I[25] = (img)(_n1##x,y,z,v)), \
1359  (I[32] = (img)(_n1##x,_n1##y,z,v)), \
1360  (I[39] = (img)(_n1##x,_n2##y,z,v)), \
1361  (I[46] = (img)(_n1##x,_n3##y,z,v)), \
1362  (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1363  (I[12] = (img)(_n2##x,_p2##y,z,v)), \
1364  (I[19] = (img)(_n2##x,_p1##y,z,v)), \
1365  (I[26] = (img)(_n2##x,y,z,v)), \
1366  (I[33] = (img)(_n2##x,_n1##y,z,v)), \
1367  (I[40] = (img)(_n2##x,_n2##y,z,v)), \
1368  (I[47] = (img)(_n2##x,_n3##y,z,v)), \
1369  3>=(img).width?(int)((img).width)-1:3); \
1370  (_n3##x<(int)((img).width) && ( \
1371  (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1372  (I[13] = (img)(_n3##x,_p2##y,z,v)), \
1373  (I[20] = (img)(_n3##x,_p1##y,z,v)), \
1374  (I[27] = (img)(_n3##x,y,z,v)), \
1375  (I[34] = (img)(_n3##x,_n1##y,z,v)), \
1376  (I[41] = (img)(_n3##x,_n2##y,z,v)), \
1377  (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1378  _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \
1379  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
1380  I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
1381  I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
1382  I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
1383  I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
1384  I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
1385  I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
1386  _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1387 
1388 #define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,v,I) \
1389  cimg_for_in7((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1390  _p3##x = x-3<0?0:x-3, \
1391  _p2##x = x-2<0?0:x-2, \
1392  _p1##x = x-1<0?0:x-1, \
1393  _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1394  _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
1395  _n3##x = (int)( \
1396  (I[0] = (img)(_p3##x,_p3##y,z,v)), \
1397  (I[7] = (img)(_p3##x,_p2##y,z,v)), \
1398  (I[14] = (img)(_p3##x,_p1##y,z,v)), \
1399  (I[21] = (img)(_p3##x,y,z,v)), \
1400  (I[28] = (img)(_p3##x,_n1##y,z,v)), \
1401  (I[35] = (img)(_p3##x,_n2##y,z,v)), \
1402  (I[42] = (img)(_p3##x,_n3##y,z,v)), \
1403  (I[1] = (img)(_p2##x,_p3##y,z,v)), \
1404  (I[8] = (img)(_p2##x,_p2##y,z,v)), \
1405  (I[15] = (img)(_p2##x,_p1##y,z,v)), \
1406  (I[22] = (img)(_p2##x,y,z,v)), \
1407  (I[29] = (img)(_p2##x,_n1##y,z,v)), \
1408  (I[36] = (img)(_p2##x,_n2##y,z,v)), \
1409  (I[43] = (img)(_p2##x,_n3##y,z,v)), \
1410  (I[2] = (img)(_p1##x,_p3##y,z,v)), \
1411  (I[9] = (img)(_p1##x,_p2##y,z,v)), \
1412  (I[16] = (img)(_p1##x,_p1##y,z,v)), \
1413  (I[23] = (img)(_p1##x,y,z,v)), \
1414  (I[30] = (img)(_p1##x,_n1##y,z,v)), \
1415  (I[37] = (img)(_p1##x,_n2##y,z,v)), \
1416  (I[44] = (img)(_p1##x,_n3##y,z,v)), \
1417  (I[3] = (img)(x,_p3##y,z,v)), \
1418  (I[10] = (img)(x,_p2##y,z,v)), \
1419  (I[17] = (img)(x,_p1##y,z,v)), \
1420  (I[24] = (img)(x,y,z,v)), \
1421  (I[31] = (img)(x,_n1##y,z,v)), \
1422  (I[38] = (img)(x,_n2##y,z,v)), \
1423  (I[45] = (img)(x,_n3##y,z,v)), \
1424  (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1425  (I[11] = (img)(_n1##x,_p2##y,z,v)), \
1426  (I[18] = (img)(_n1##x,_p1##y,z,v)), \
1427  (I[25] = (img)(_n1##x,y,z,v)), \
1428  (I[32] = (img)(_n1##x,_n1##y,z,v)), \
1429  (I[39] = (img)(_n1##x,_n2##y,z,v)), \
1430  (I[46] = (img)(_n1##x,_n3##y,z,v)), \
1431  (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1432  (I[12] = (img)(_n2##x,_p2##y,z,v)), \
1433  (I[19] = (img)(_n2##x,_p1##y,z,v)), \
1434  (I[26] = (img)(_n2##x,y,z,v)), \
1435  (I[33] = (img)(_n2##x,_n1##y,z,v)), \
1436  (I[40] = (img)(_n2##x,_n2##y,z,v)), \
1437  (I[47] = (img)(_n2##x,_n3##y,z,v)), \
1438  x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
1439  x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
1440  (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1441  (I[13] = (img)(_n3##x,_p2##y,z,v)), \
1442  (I[20] = (img)(_n3##x,_p1##y,z,v)), \
1443  (I[27] = (img)(_n3##x,y,z,v)), \
1444  (I[34] = (img)(_n3##x,_n1##y,z,v)), \
1445  (I[41] = (img)(_n3##x,_n2##y,z,v)), \
1446  (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1447  _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \
1448  I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
1449  I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
1450  I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
1451  I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
1452  I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
1453  I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
1454  I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
1455  _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1456 
1457 #define cimg_for8x8(img,x,y,z,v,I) \
1458  cimg_for8((img).height,y) for (int x = 0, \
1459  _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1460  _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
1461  _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
1462  _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
1463  _n4##x = (int)( \
1464  (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
1465  (I[8] = I[9] = I[10] = I[11] = (img)(0,_p2##y,z,v)), \
1466  (I[16] = I[17] = I[18] = I[19] = (img)(0,_p1##y,z,v)), \
1467  (I[24] = I[25] = I[26] = I[27] = (img)(0,y,z,v)), \
1468  (I[32] = I[33] = I[34] = I[35] = (img)(0,_n1##y,z,v)), \
1469  (I[40] = I[41] = I[42] = I[43] = (img)(0,_n2##y,z,v)), \
1470  (I[48] = I[49] = I[50] = I[51] = (img)(0,_n3##y,z,v)), \
1471  (I[56] = I[57] = I[58] = I[59] = (img)(0,_n4##y,z,v)), \
1472  (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1473  (I[12] = (img)(_n1##x,_p2##y,z,v)), \
1474  (I[20] = (img)(_n1##x,_p1##y,z,v)), \
1475  (I[28] = (img)(_n1##x,y,z,v)), \
1476  (I[36] = (img)(_n1##x,_n1##y,z,v)), \
1477  (I[44] = (img)(_n1##x,_n2##y,z,v)), \
1478  (I[52] = (img)(_n1##x,_n3##y,z,v)), \
1479  (I[60] = (img)(_n1##x,_n4##y,z,v)), \
1480  (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1481  (I[13] = (img)(_n2##x,_p2##y,z,v)), \
1482  (I[21] = (img)(_n2##x,_p1##y,z,v)), \
1483  (I[29] = (img)(_n2##x,y,z,v)), \
1484  (I[37] = (img)(_n2##x,_n1##y,z,v)), \
1485  (I[45] = (img)(_n2##x,_n2##y,z,v)), \
1486  (I[53] = (img)(_n2##x,_n3##y,z,v)), \
1487  (I[61] = (img)(_n2##x,_n4##y,z,v)), \
1488  (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1489  (I[14] = (img)(_n3##x,_p2##y,z,v)), \
1490  (I[22] = (img)(_n3##x,_p1##y,z,v)), \
1491  (I[30] = (img)(_n3##x,y,z,v)), \
1492  (I[38] = (img)(_n3##x,_n1##y,z,v)), \
1493  (I[46] = (img)(_n3##x,_n2##y,z,v)), \
1494  (I[54] = (img)(_n3##x,_n3##y,z,v)), \
1495  (I[62] = (img)(_n3##x,_n4##y,z,v)), \
1496  4>=((img).width)?(int)((img).width)-1:4); \
1497  (_n4##x<(int)((img).width) && ( \
1498  (I[7] = (img)(_n4##x,_p3##y,z,v)), \
1499  (I[15] = (img)(_n4##x,_p2##y,z,v)), \
1500  (I[23] = (img)(_n4##x,_p1##y,z,v)), \
1501  (I[31] = (img)(_n4##x,y,z,v)), \
1502  (I[39] = (img)(_n4##x,_n1##y,z,v)), \
1503  (I[47] = (img)(_n4##x,_n2##y,z,v)), \
1504  (I[55] = (img)(_n4##x,_n3##y,z,v)), \
1505  (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1506  _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
1507  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], \
1508  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], \
1509  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], \
1510  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], \
1511  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], \
1512  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], \
1513  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], \
1514  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], \
1515  _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1516 
1517 #define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,v,I) \
1518  cimg_for_in8((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1519  _p3##x = x-3<0?0:x-3, \
1520  _p2##x = x-2<0?0:x-2, \
1521  _p1##x = x-1<0?0:x-1, \
1522  _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
1523  _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
1524  _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
1525  _n4##x = (int)( \
1526  (I[0] = (img)(_p3##x,_p3##y,z,v)), \
1527  (I[8] = (img)(_p3##x,_p2##y,z,v)), \
1528  (I[16] = (img)(_p3##x,_p1##y,z,v)), \
1529  (I[24] = (img)(_p3##x,y,z,v)), \
1530  (I[32] = (img)(_p3##x,_n1##y,z,v)), \
1531  (I[40] = (img)(_p3##x,_n2##y,z,v)), \
1532  (I[48] = (img)(_p3##x,_n3##y,z,v)), \
1533  (I[56] = (img)(_p3##x,_n4##y,z,v)), \
1534  (I[1] = (img)(_p2##x,_p3##y,z,v)), \
1535  (I[9] = (img)(_p2##x,_p2##y,z,v)), \
1536  (I[17] = (img)(_p2##x,_p1##y,z,v)), \
1537  (I[25] = (img)(_p2##x,y,z,v)), \
1538  (I[33] = (img)(_p2##x,_n1##y,z,v)), \
1539  (I[41] = (img)(_p2##x,_n2##y,z,v)), \
1540  (I[49] = (img)(_p2##x,_n3##y,z,v)), \
1541  (I[57] = (img)(_p2##x,_n4##y,z,v)), \
1542  (I[2] = (img)(_p1##x,_p3##y,z,v)), \
1543  (I[10] = (img)(_p1##x,_p2##y,z,v)), \
1544  (I[18] = (img)(_p1##x,_p1##y,z,v)), \
1545  (I[26] = (img)(_p1##x,y,z,v)), \
1546  (I[34] = (img)(_p1##x,_n1##y,z,v)), \
1547  (I[42] = (img)(_p1##x,_n2##y,z,v)), \
1548  (I[50] = (img)(_p1##x,_n3##y,z,v)), \
1549  (I[58] = (img)(_p1##x,_n4##y,z,v)), \
1550  (I[3] = (img)(x,_p3##y,z,v)), \
1551  (I[11] = (img)(x,_p2##y,z,v)), \
1552  (I[19] = (img)(x,_p1##y,z,v)), \
1553  (I[27] = (img)(x,y,z,v)), \
1554  (I[35] = (img)(x,_n1##y,z,v)), \
1555  (I[43] = (img)(x,_n2##y,z,v)), \
1556  (I[51] = (img)(x,_n3##y,z,v)), \
1557  (I[59] = (img)(x,_n4##y,z,v)), \
1558  (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1559  (I[12] = (img)(_n1##x,_p2##y,z,v)), \
1560  (I[20] = (img)(_n1##x,_p1##y,z,v)), \
1561  (I[28] = (img)(_n1##x,y,z,v)), \
1562  (I[36] = (img)(_n1##x,_n1##y,z,v)), \
1563  (I[44] = (img)(_n1##x,_n2##y,z,v)), \
1564  (I[52] = (img)(_n1##x,_n3##y,z,v)), \
1565  (I[60] = (img)(_n1##x,_n4##y,z,v)), \
1566  (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1567  (I[13] = (img)(_n2##x,_p2##y,z,v)), \
1568  (I[21] = (img)(_n2##x,_p1##y,z,v)), \
1569  (I[29] = (img)(_n2##x,y,z,v)), \
1570  (I[37] = (img)(_n2##x,_n1##y,z,v)), \
1571  (I[45] = (img)(_n2##x,_n2##y,z,v)), \
1572  (I[53] = (img)(_n2##x,_n3##y,z,v)), \
1573  (I[61] = (img)(_n2##x,_n4##y,z,v)), \
1574  (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1575  (I[14] = (img)(_n3##x,_p2##y,z,v)), \
1576  (I[22] = (img)(_n3##x,_p1##y,z,v)), \
1577  (I[30] = (img)(_n3##x,y,z,v)), \
1578  (I[38] = (img)(_n3##x,_n1##y,z,v)), \
1579  (I[46] = (img)(_n3##x,_n2##y,z,v)), \
1580  (I[54] = (img)(_n3##x,_n3##y,z,v)), \
1581  (I[62] = (img)(_n3##x,_n4##y,z,v)), \
1582  x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
1583  x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
1584  (I[7] = (img)(_n4##x,_p3##y,z,v)), \
1585  (I[15] = (img)(_n4##x,_p2##y,z,v)), \
1586  (I[23] = (img)(_n4##x,_p1##y,z,v)), \
1587  (I[31] = (img)(_n4##x,y,z,v)), \
1588  (I[39] = (img)(_n4##x,_n1##y,z,v)), \
1589  (I[47] = (img)(_n4##x,_n2##y,z,v)), \
1590  (I[55] = (img)(_n4##x,_n3##y,z,v)), \
1591  (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1592  _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
1593  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], \
1594  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], \
1595  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], \
1596  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], \
1597  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], \
1598  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], \
1599  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], \
1600  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], \
1601  _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1602 
1603 #define cimg_for9x9(img,x,y,z,v,I) \
1604  cimg_for9((img).height,y) for (int x = 0, \
1605  _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1606  _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
1607  _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
1608  _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
1609  _n4##x = (int)( \
1610  (I[0] = I[1] = I[2] = I[3] = I[4] = (img)(0,_p4##y,z,v)), \
1611  (I[9] = I[10] = I[11] = I[12] = I[13] = (img)(0,_p3##y,z,v)), \
1612  (I[18] = I[19] = I[20] = I[21] = I[22] = (img)(0,_p2##y,z,v)), \
1613  (I[27] = I[28] = I[29] = I[30] = I[31] = (img)(0,_p1##y,z,v)), \
1614  (I[36] = I[37] = I[38] = I[39] = I[40] = (img)(0,y,z,v)), \
1615  (I[45] = I[46] = I[47] = I[48] = I[49] = (img)(0,_n1##y,z,v)), \
1616  (I[54] = I[55] = I[56] = I[57] = I[58] = (img)(0,_n2##y,z,v)), \
1617  (I[63] = I[64] = I[65] = I[66] = I[67] = (img)(0,_n3##y,z,v)), \
1618  (I[72] = I[73] = I[74] = I[75] = I[76] = (img)(0,_n4##y,z,v)), \
1619  (I[5] = (img)(_n1##x,_p4##y,z,v)), \
1620  (I[14] = (img)(_n1##x,_p3##y,z,v)), \
1621  (I[23] = (img)(_n1##x,_p2##y,z,v)), \
1622  (I[32] = (img)(_n1##x,_p1##y,z,v)), \
1623  (I[41] = (img)(_n1##x,y,z,v)), \
1624  (I[50] = (img)(_n1##x,_n1##y,z,v)), \
1625  (I[59] = (img)(_n1##x,_n2##y,z,v)), \
1626  (I[68] = (img)(_n1##x,_n3##y,z,v)), \
1627  (I[77] = (img)(_n1##x,_n4##y,z,v)), \
1628  (I[6] = (img)(_n2##x,_p4##y,z,v)), \
1629  (I[15] = (img)(_n2##x,_p3##y,z,v)), \
1630  (I[24] = (img)(_n2##x,_p2##y,z,v)), \
1631  (I[33] = (img)(_n2##x,_p1##y,z,v)), \
1632  (I[42] = (img)(_n2##x,y,z,v)), \
1633  (I[51] = (img)(_n2##x,_n1##y,z,v)), \
1634  (I[60] = (img)(_n2##x,_n2##y,z,v)), \
1635  (I[69] = (img)(_n2##x,_n3##y,z,v)), \
1636  (I[78] = (img)(_n2##x,_n4##y,z,v)), \
1637  (I[7] = (img)(_n3##x,_p4##y,z,v)), \
1638  (I[16] = (img)(_n3##x,_p3##y,z,v)), \
1639  (I[25] = (img)(_n3##x,_p2##y,z,v)), \
1640  (I[34] = (img)(_n3##x,_p1##y,z,v)), \
1641  (I[43] = (img)(_n3##x,y,z,v)), \
1642  (I[52] = (img)(_n3##x,_n1##y,z,v)), \
1643  (I[61] = (img)(_n3##x,_n2##y,z,v)), \
1644  (I[70] = (img)(_n3##x,_n3##y,z,v)), \
1645  (I[79] = (img)(_n3##x,_n4##y,z,v)), \
1646  4>=((img).width)?(int)((img).width)-1:4); \
1647  (_n4##x<(int)((img).width) && ( \
1648  (I[8] = (img)(_n4##x,_p4##y,z,v)), \
1649  (I[17] = (img)(_n4##x,_p3##y,z,v)), \
1650  (I[26] = (img)(_n4##x,_p2##y,z,v)), \
1651  (I[35] = (img)(_n4##x,_p1##y,z,v)), \
1652  (I[44] = (img)(_n4##x,y,z,v)), \
1653  (I[53] = (img)(_n4##x,_n1##y,z,v)), \
1654  (I[62] = (img)(_n4##x,_n2##y,z,v)), \
1655  (I[71] = (img)(_n4##x,_n3##y,z,v)), \
1656  (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1657  _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
1658  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], \
1659  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], \
1660  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], \
1661  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], \
1662  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], \
1663  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], \
1664  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], \
1665  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], \
1666  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], \
1667  _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1668 
1669 #define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,v,I) \
1670  cimg_for_in9((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1671  _p4##x = x-4<0?0:x-4, \
1672  _p3##x = x-3<0?0:x-3, \
1673  _p2##x = x-2<0?0:x-2, \
1674  _p1##x = x-1<0?0:x-1, \
1675  _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
1676  _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
1677  _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
1678  _n4##x = (int)( \
1679  (I[0] = (img)(_p4##x,_p4##y,z,v)), \
1680  (I[9] = (img)(_p4##x,_p3##y,z,v)), \
1681  (I[18] = (img)(_p4##x,_p2##y,z,v)), \
1682  (I[27] = (img)(_p4##x,_p1##y,z,v)), \
1683  (I[36] = (img)(_p4##x,y,z,v)), \
1684  (I[45] = (img)(_p4##x,_n1##y,z,v)), \
1685  (I[54] = (img)(_p4##x,_n2##y,z,v)), \
1686  (I[63] = (img)(_p4##x,_n3##y,z,v)), \
1687  (I[72] = (img)(_p4##x,_n4##y,z,v)), \
1688  (I[1] = (img)(_p3##x,_p4##y,z,v)), \
1689  (I[10] = (img)(_p3##x,_p3##y,z,v)), \
1690  (I[19] = (img)(_p3##x,_p2##y,z,v)), \
1691  (I[28] = (img)(_p3##x,_p1##y,z,v)), \
1692  (I[37] = (img)(_p3##x,y,z,v)), \
1693  (I[46] = (img)(_p3##x,_n1##y,z,v)), \
1694  (I[55] = (img)(_p3##x,_n2##y,z,v)), \
1695  (I[64] = (img)(_p3##x,_n3##y,z,v)), \
1696  (I[73] = (img)(_p3##x,_n4##y,z,v)), \
1697  (I[2] = (img)(_p2##x,_p4##y,z,v)), \
1698  (I[11] = (img)(_p2##x,_p3##y,z,v)), \
1699  (I[20] = (img)(_p2##x,_p2##y,z,v)), \
1700  (I[29] = (img)(_p2##x,_p1##y,z,v)), \
1701  (I[38] = (img)(_p2##x,y,z,v)), \
1702  (I[47] = (img)(_p2##x,_n1##y,z,v)), \
1703  (I[56] = (img)(_p2##x,_n2##y,z,v)), \
1704  (I[65] = (img)(_p2##x,_n3##y,z,v)), \
1705  (I[74] = (img)(_p2##x,_n4##y,z,v)), \
1706  (I[3] = (img)(_p1##x,_p4##y,z,v)), \
1707  (I[12] = (img)(_p1##x,_p3##y,z,v)), \
1708  (I[21] = (img)(_p1##x,_p2##y,z,v)), \
1709  (I[30] = (img)(_p1##x,_p1##y,z,v)), \
1710  (I[39] = (img)(_p1##x,y,z,v)), \
1711  (I[48] = (img)(_p1##x,_n1##y,z,v)), \
1712  (I[57] = (img)(_p1##x,_n2##y,z,v)), \
1713  (I[66] = (img)(_p1##x,_n3##y,z,v)), \
1714  (I[75] = (img)(_p1##x,_n4##y,z,v)), \
1715  (I[4] = (img)(x,_p4##y,z,v)), \
1716  (I[13] = (img)(x,_p3##y,z,v)), \
1717  (I[22] = (img)(x,_p2##y,z,v)), \
1718  (I[31] = (img)(x,_p1##y,z,v)), \
1719  (I[40] = (img)(x,y,z,v)), \
1720  (I[49] = (img)(x,_n1##y,z,v)), \
1721  (I[58] = (img)(x,_n2##y,z,v)), \
1722  (I[67] = (img)(x,_n3##y,z,v)), \
1723  (I[76] = (img)(x,_n4##y,z,v)), \
1724  (I[5] = (img)(_n1##x,_p4##y,z,v)), \
1725  (I[14] = (img)(_n1##x,_p3##y,z,v)), \
1726  (I[23] = (img)(_n1##x,_p2##y,z,v)), \
1727  (I[32] = (img)(_n1##x,_p1##y,z,v)), \
1728  (I[41] = (img)(_n1##x,y,z,v)), \
1729  (I[50] = (img)(_n1##x,_n1##y,z,v)), \
1730  (I[59] = (img)(_n1##x,_n2##y,z,v)), \
1731  (I[68] = (img)(_n1##x,_n3##y,z,v)), \
1732  (I[77] = (img)(_n1##x,_n4##y,z,v)), \
1733  (I[6] = (img)(_n2##x,_p4##y,z,v)), \
1734  (I[15] = (img)(_n2##x,_p3##y,z,v)), \
1735  (I[24] = (img)(_n2##x,_p2##y,z,v)), \
1736  (I[33] = (img)(_n2##x,_p1##y,z,v)), \
1737  (I[42] = (img)(_n2##x,y,z,v)), \
1738  (I[51] = (img)(_n2##x,_n1##y,z,v)), \
1739  (I[60] = (img)(_n2##x,_n2##y,z,v)), \
1740  (I[69] = (img)(_n2##x,_n3##y,z,v)), \
1741  (I[78] = (img)(_n2##x,_n4##y,z,v)), \
1742  (I[7] = (img)(_n3##x,_p4##y,z,v)), \
1743  (I[16] = (img)(_n3##x,_p3##y,z,v)), \
1744  (I[25] = (img)(_n3##x,_p2##y,z,v)), \
1745  (I[34] = (img)(_n3##x,_p1##y,z,v)), \
1746  (I[43] = (img)(_n3##x,y,z,v)), \
1747  (I[52] = (img)(_n3##x,_n1##y,z,v)), \
1748  (I[61] = (img)(_n3##x,_n2##y,z,v)), \
1749  (I[70] = (img)(_n3##x,_n3##y,z,v)), \
1750  (I[79] = (img)(_n3##x,_n4##y,z,v)), \
1751  x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
1752  x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
1753  (I[8] = (img)(_n4##x,_p4##y,z,v)), \
1754  (I[17] = (img)(_n4##x,_p3##y,z,v)), \
1755  (I[26] = (img)(_n4##x,_p2##y,z,v)), \
1756  (I[35] = (img)(_n4##x,_p1##y,z,v)), \
1757  (I[44] = (img)(_n4##x,y,z,v)), \
1758  (I[53] = (img)(_n4##x,_n1##y,z,v)), \
1759  (I[62] = (img)(_n4##x,_n2##y,z,v)), \
1760  (I[71] = (img)(_n4##x,_n3##y,z,v)), \
1761  (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1762  _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
1763  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], \
1764  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], \
1765  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], \
1766  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], \
1767  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], \
1768  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], \
1769  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], \
1770  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], \
1771  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], \
1772  _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1773 
1774 #define cimg_for2x2x2(img,x,y,z,v,I) \
1775  cimg_for2((img).depth,z) cimg_for2((img).height,y) for (int x = 0, \
1776  _n1##x = (int)( \
1777  (I[0] = (img)(0,y,z,v)), \
1778  (I[2] = (img)(0,_n1##y,z,v)), \
1779  (I[4] = (img)(0,y,_n1##z,v)), \
1780  (I[6] = (img)(0,_n1##y,_n1##z,v)), \
1781  1>=(img).width?(int)((img).width)-1:1); \
1782  (_n1##x<(int)((img).width) && ( \
1783  (I[1] = (img)(_n1##x,y,z,v)), \
1784  (I[3] = (img)(_n1##x,_n1##y,z,v)), \
1785  (I[5] = (img)(_n1##x,y,_n1##z,v)), \
1786  (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1787  x==--_n1##x; \
1788  I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
1789  ++x, ++_n1##x)
1790 
1791 #define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
1792  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), \
1793  _n1##x = (int)( \
1794  (I[0] = (img)(x,y,z,v)), \
1795  (I[2] = (img)(x,_n1##y,z,v)), \
1796  (I[4] = (img)(x,y,_n1##z,v)), \
1797  (I[6] = (img)(x,_n1##y,_n1##z,v)), \
1798  x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1799  x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
1800  (I[1] = (img)(_n1##x,y,z,v)), \
1801  (I[3] = (img)(_n1##x,_n1##y,z,v)), \
1802  (I[5] = (img)(_n1##x,y,_n1##z,v)), \
1803  (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1804  x==--_n1##x); \
1805  I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
1806  ++x, ++_n1##x)
1807 
1808 #define cimg_for3x3x3(img,x,y,z,v,I) \
1809  cimg_for3((img).depth,z) cimg_for3((img).height,y) for (int x = 0, \
1810  _p1##x = 0, \
1811  _n1##x = (int)( \
1812  (I[0] = I[1] = (img)(0,_p1##y,_p1##z,v)), \
1813  (I[3] = I[4] = (img)(0,y,_p1##z,v)), \
1814  (I[6] = I[7] = (img)(0,_n1##y,_p1##z,v)), \
1815  (I[9] = I[10] = (img)(0,_p1##y,z,v)), \
1816  (I[12] = I[13] = (img)(0,y,z,v)), \
1817  (I[15] = I[16] = (img)(0,_n1##y,z,v)), \
1818  (I[18] = I[19] = (img)(0,_p1##y,_n1##z,v)), \
1819  (I[21] = I[22] = (img)(0,y,_n1##z,v)), \
1820  (I[24] = I[25] = (img)(0,_n1##y,_n1##z,v)), \
1821  1>=(img).width?(int)((img).width)-1:1); \
1822  (_n1##x<(int)((img).width) && ( \
1823  (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
1824  (I[5] = (img)(_n1##x,y,_p1##z,v)), \
1825  (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
1826  (I[11] = (img)(_n1##x,_p1##y,z,v)), \
1827  (I[14] = (img)(_n1##x,y,z,v)), \
1828  (I[17] = (img)(_n1##x,_n1##y,z,v)), \
1829  (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
1830  (I[23] = (img)(_n1##x,y,_n1##z,v)), \
1831  (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1832  x==--_n1##x; \
1833  I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
1834  I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
1835  I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
1836  _p1##x = x++, ++_n1##x)
1837 
1838 #define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
1839  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), \
1840  _p1##x = x-1<0?0:x-1, \
1841  _n1##x = (int)( \
1842  (I[0] = (img)(_p1##x,_p1##y,_p1##z,v)), \
1843  (I[3] = (img)(_p1##x,y,_p1##z,v)), \
1844  (I[6] = (img)(_p1##x,_n1##y,_p1##z,v)), \
1845  (I[9] = (img)(_p1##x,_p1##y,z,v)), \
1846  (I[12] = (img)(_p1##x,y,z,v)), \
1847  (I[15] = (img)(_p1##x,_n1##y,z,v)), \
1848  (I[18] = (img)(_p1##x,_p1##y,_n1##z,v)), \
1849  (I[21] = (img)(_p1##x,y,_n1##z,v)), \
1850  (I[24] = (img)(_p1##x,_n1##y,_n1##z,v)), \
1851  (I[1] = (img)(x,_p1##y,_p1##z,v)), \
1852  (I[4] = (img)(x,y,_p1##z,v)), \
1853  (I[7] = (img)(x,_n1##y,_p1##z,v)), \
1854  (I[10] = (img)(x,_p1##y,z,v)), \
1855  (I[13] = (img)(x,y,z,v)), \
1856  (I[16] = (img)(x,_n1##y,z,v)), \
1857  (I[19] = (img)(x,_p1##y,_n1##z,v)), \
1858  (I[22] = (img)(x,y,_n1##z,v)), \
1859  (I[25] = (img)(x,_n1##y,_n1##z,v)), \
1860  x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1861  x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
1862  (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
1863  (I[5] = (img)(_n1##x,y,_p1##z,v)), \
1864  (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
1865  (I[11] = (img)(_n1##x,_p1##y,z,v)), \
1866  (I[14] = (img)(_n1##x,y,z,v)), \
1867  (I[17] = (img)(_n1##x,_n1##y,z,v)), \
1868  (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
1869  (I[23] = (img)(_n1##x,y,_n1##z,v)), \
1870  (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1871  x==--_n1##x); \
1872  I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
1873  I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
1874  I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
1875  _p1##x = x++, ++_n1##x)
1876 
1877 #define cimglist_for(list,l) for (int l = 0; l<(int)(list).width; ++l)
1878 #define cimglist_for_in(list,l0,l1,l) \
1879  for (int l = (int)(l0)<0?0:(int)(l0), _max##l = (unsigned int)l1<(list).width?(int)(l1):(int)(list).width-1; l<=_max##l; ++l)
1880 
1881 #define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn
1882 
1883 /*------------------------------------------------
1884  #
1885  #
1886  # Definition of the cimg_library:: namespace
1887  #
1888  #
1889  -------------------------------------------------*/
1891 
1902 namespace cimg_library {
1903 
1904  // Declare the only four classes of the CImg Library.
1905  template<typename T=float> struct CImg;
1906  template<typename T=float> struct CImgList;
1907  struct CImgDisplay;
1908  struct CImgException;
1909 
1910  // (Pre)declare the cimg namespace.
1911  // This is not the complete namespace declaration. It only contains some
1912  // necessary stuffs to ensure a correct declaration order of classes and functions
1913  // defined afterwards.
1914  namespace cimg {
1915 
1916 #ifdef cimg_use_vt100
1917  const char t_normal[] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', 0 };
1918  const char t_red[] = { 0x1b, '[', '4', ';', '3', '1', ';', '5', '9', 'm', 0 };
1919  const char t_bold[] = { 0x1b, '[', '1', 'm', 0 };
1920  const char t_purple[] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', 0 };
1921  const char t_green[] = { 0x1b, '[', '0', ';', '3', '2', ';', '5', '9', 'm', 0 };
1922 #else
1923  const char t_normal[] = { 0 };
1924  const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal,
1926 #endif
1927 
1928  inline void info();
1929 
1931 
1940  inline unsigned int& exception_mode() { static unsigned int mode = cimg_debug; return mode; }
1941 
1942  inline int dialog(const char *title, const char *msg, const char *button1_txt="OK",
1943  const char *button2_txt=0, const char *button3_txt=0,
1944  const char *button4_txt=0, const char *button5_txt=0,
1945  const char *button6_txt=0, const bool centering=false);
1946 
1948  inline double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double v=0);
1949  }
1950 
1951  /*----------------------------------------------
1952  #
1953  # Definition of the CImgException structures
1954  #
1955  ----------------------------------------------*/
1957 
2020  struct CImgException {
2021 #define _cimg_exception_err(etype,disp_flag) \
2022  std::va_list ap; va_start(ap,format); std::vsprintf(message,format,ap); va_end(ap); \
2023  switch (cimg::exception_mode()) { \
2024  case 0 : break; \
2025  case 2 : case 4 : try { cimg::dialog(etype,message,"Abort"); } catch (CImgException&) { \
2026  std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
2027  } break; \
2028  default : std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
2029  } \
2030  if (cimg::exception_mode()>=3) cimg_library::cimg::info();
2031 
2032  char message[16384];
2033  CImgException() { message[0] = 0; }
2034  CImgException(const char *format, ...) { _cimg_exception_err("CImgException",true); }
2035  };
2036 
2037  // The \ref CImgInstanceException class is used to throw an exception related
2038  // to a non suitable instance encountered in a library function call.
2040  CImgInstanceException(const char *format, ...) { _cimg_exception_err("CImgInstanceException",true); }
2041  };
2042 
2043  // The \ref CImgArgumentException class is used to throw an exception related
2044  // to invalid arguments encountered in a library function call.
2046  CImgArgumentException(const char *format, ...) { _cimg_exception_err("CImgArgumentException",true); }
2047  };
2048 
2049  // The \ref CImgIOException class is used to throw an exception related
2050  // to Input/Output file problems encountered in a library function call.
2052  CImgIOException(const char *format, ...) { _cimg_exception_err("CImgIOException",true); }
2053  };
2054 
2055  // The CImgDisplayException class is used to throw an exception related to display problems
2056  // encountered in a library function call.
2058  CImgDisplayException(const char *format, ...) { _cimg_exception_err("CImgDisplayException",false); }
2059  };
2060 
2061  // The CImgWarningException class is used to throw an exception for warnings
2062  // encountered in a library function call.
2064  CImgWarningException(const char *format, ...) { _cimg_exception_err("CImgWarningException",false); }
2065  };
2066 
2067  /*-------------------------------------
2068  #
2069  # Definition of the namespace 'cimg'
2070  #
2071  --------------------------------------*/
2073 
2080  namespace cimg {
2081 
2082  // Define the traits that will be used to determine the best data type to work with.
2083  //
2084  template<typename T> struct type {
2085  static const char* string() {
2086  static const char* s[] = { "unknown", "unknown8", "unknown16", "unknown24",
2087  "unknown32", "unknown40", "unknown48", "unknown56",
2088  "unknown64", "unknown72", "unknown80", "unknown88",
2089  "unknown96", "unknown104", "unknown112", "unknown120",
2090  "unknown128" };
2091  return s[(sizeof(T)<17)?sizeof(T):0];
2092  }
2093  static bool is_float() { return false; }
2094  static T min() { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); }
2095  static T max() { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); }
2096  static const char* format() { return "%s"; }
2097  static const char* format(const T val) { static const char *s = "unknown"; return s; }
2098  };
2099 
2100  template<> struct type<bool> {
2101  static const char* string() { static const char *const s = "bool"; return s; }
2102  static bool is_float() { return false; }
2103  static bool min() { return false; }
2104  static bool max() { return true; }
2105  static const char* format() { return "%s"; }
2106  static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; }
2107  };
2108 
2109  template<> struct type<unsigned char> {
2110  static const char* string() { static const char *const s = "unsigned char"; return s; }
2111  static bool is_float() { return false; }
2112  static unsigned char min() { return 0; }
2113  static unsigned char max() { return (unsigned char)~0U; }
2114  static const char* format() { return "%u"; }
2115  static unsigned int format(const unsigned char val) { return (unsigned int)val; }
2116  };
2117 
2118  template<> struct type<char> {
2119  static const char* string() { static const char *const s = "char"; return s; }
2120  static bool is_float() { return false; }
2121  static char min() { return (char)(-1L<<(8*sizeof(char)-1)); }
2122  static char max() { return ~((char)(-1L<<(8*sizeof(char)-1))); }
2123  static const char* format() { return "%d"; }
2124  static int format(const char val) { return (int)val; }
2125  };
2126 
2127  template<> struct type<signed char> {
2128  static const char* string() { static const char *const s = "signed char"; return s; }
2129  static bool is_float() { return false; }
2130  static signed char min() { return (signed char)(-1L<<(8*sizeof(signed char)-1)); }
2131  static signed char max() { return ~((signed char)(-1L<<(8*sizeof(signed char)-1))); }
2132  static const char* format() { return "%d"; }
2133  static unsigned int format(const signed char val) { return (int)val; }
2134  };
2135 
2136  template<> struct type<unsigned short> {
2137  static const char* string() { static const char *const s = "unsigned short"; return s; }
2138  static bool is_float() { return false; }
2139  static unsigned short min() { return 0; }
2140  static unsigned short max() { return (unsigned short)~0U; }
2141  static const char* format() { return "%u"; }
2142  static unsigned int format(const unsigned short val) { return (unsigned int)val; }
2143  };
2144 
2145  template<> struct type<short> {
2146  static const char* string() { static const char *const s = "short"; return s; }
2147  static bool is_float() { return false; }
2148  static short min() { return (short)(-1L<<(8*sizeof(short)-1)); }
2149  static short max() { return ~((short)(-1L<<(8*sizeof(short)-1))); }
2150  static const char* format() { return "%d"; }
2151  static int format(const short val) { return (int)val; }
2152  };
2153 
2154  template<> struct type<unsigned int> {
2155  static const char* string() { static const char *const s = "unsigned int"; return s; }
2156  static bool is_float() { return false; }
2157  static unsigned int min() { return 0; }
2158  static unsigned int max() { return (unsigned int)~0U; }
2159  static const char* format() { return "%u"; }
2160  static unsigned int format(const unsigned int val) { return val; }
2161  };
2162 
2163  template<> struct type<int> {
2164  static const char* string() { static const char *const s = "int"; return s; }
2165  static bool is_float() { return false; }
2166  static int min() { return (int)(-1L<<(8*sizeof(int)-1)); }
2167  static int max() { return ~((int)(-1L<<(8*sizeof(int)-1))); }
2168  static const char* format() { return "%d"; }
2169  static int format(const int val) { return val; }
2170  };
2171 
2172  template<> struct type<unsigned long> {
2173  static const char* string() { static const char *const s = "unsigned long"; return s; }
2174  static bool is_float() { return false; }
2175  static unsigned long min() { return 0; }
2176  static unsigned long max() { return (unsigned long)~0UL; }
2177  static const char* format() { return "%lu"; }
2178  static unsigned long format(const unsigned long val) { return val; }
2179  };
2180 
2181  template<> struct type<long> {
2182  static const char* string() { static const char *const s = "long"; return s; }
2183  static bool is_float() { return false; }
2184  static long min() { return (long)(-1L<<(8*sizeof(long)-1)); }
2185  static long max() { return ~((long)(-1L<<(8*sizeof(long)-1))); }
2186  static const char* format() { return "%ld"; }
2187  static long format(const long val) { return val; }
2188  };
2189 
2190  template<> struct type<float> {
2191  static const char* string() { static const char *const s = "float"; return s; }
2192  static bool is_float() { return true; }
2193  static float min() { return -3.4E38f; }
2194  static float max() { return 3.4E38f; }
2195  static const char* format() { return "%g"; }
2196  static double format(const float val) { return (double)val; }
2197  };
2198 
2199  template<> struct type<double> {
2200  static const char* string() { static const char *const s = "double"; return s; }
2201  static bool is_float() { return true; }
2202  static double min() { return -1.7E308; }
2203  static double max() { return 1.7E308; }
2204  static const char* format() { return "%g"; }
2205  static double format(const double val) { return val; }
2206  };
2207 
2208  template<typename T, typename t> struct superset { typedef T type; };
2209  template<> struct superset<bool,unsigned char> { typedef unsigned char type; };
2210  template<> struct superset<bool,char> { typedef char type; };
2211  template<> struct superset<bool,signed char> { typedef signed char type; };
2212  template<> struct superset<bool,unsigned short> { typedef unsigned short type; };
2213  template<> struct superset<bool,short> { typedef short type; };
2214  template<> struct superset<bool,unsigned int> { typedef unsigned int type; };
2215  template<> struct superset<bool,int> { typedef int type; };
2216  template<> struct superset<bool,unsigned long> { typedef unsigned long type; };
2217  template<> struct superset<bool,long> { typedef long type; };
2218  template<> struct superset<bool,float> { typedef float type; };
2219  template<> struct superset<bool,double> { typedef double type; };
2220  template<> struct superset<unsigned char,char> { typedef short type; };
2221  template<> struct superset<unsigned char,signed char> { typedef short type; };
2222  template<> struct superset<unsigned char,unsigned short> { typedef unsigned short type; };
2223  template<> struct superset<unsigned char,short> { typedef short type; };
2224  template<> struct superset<unsigned char,unsigned int> { typedef unsigned int type; };
2225  template<> struct superset<unsigned char,int> { typedef int type; };
2226  template<> struct superset<unsigned char,unsigned long> { typedef unsigned long type; };
2227  template<> struct superset<unsigned char,long> { typedef long type; };
2228  template<> struct superset<unsigned char,float> { typedef float type; };
2229  template<> struct superset<unsigned char,double> { typedef double type; };
2230  template<> struct superset<signed char,unsigned char> { typedef short type; };
2231  template<> struct superset<signed char,char> { typedef short type; };
2232  template<> struct superset<signed char,unsigned short> { typedef int type; };
2233  template<> struct superset<signed char,short> { typedef short type; };
2234  template<> struct superset<signed char,unsigned int> { typedef long type; };
2235  template<> struct superset<signed char,int> { typedef int type; };
2236  template<> struct superset<signed char,unsigned long> { typedef long type; };
2237  template<> struct superset<signed char,long> { typedef long type; };
2238  template<> struct superset<signed char,float> { typedef float type; };
2239  template<> struct superset<signed char,double> { typedef double type; };
2240  template<> struct superset<char,unsigned char> { typedef short type; };
2241  template<> struct superset<char,signed char> { typedef short type; };
2242  template<> struct superset<char,unsigned short> { typedef int type; };
2243  template<> struct superset<char,short> { typedef short type; };
2244  template<> struct superset<char,unsigned int> { typedef long type; };
2245  template<> struct superset<char,int> { typedef int type; };
2246  template<> struct superset<char,unsigned long> { typedef long type; };
2247  template<> struct superset<char,long> { typedef long type; };
2248  template<> struct superset<char,float> { typedef float type; };
2249  template<> struct superset<char,double> { typedef double type; };
2250  template<> struct superset<unsigned short,char> { typedef int type; };
2251  template<> struct superset<unsigned short,signed char> { typedef int type; };
2252  template<> struct superset<unsigned short,short> { typedef int type; };
2253  template<> struct superset<unsigned short,unsigned int> { typedef unsigned int type; };
2254  template<> struct superset<unsigned short,int> { typedef int type; };
2255  template<> struct superset<unsigned short,unsigned long> { typedef unsigned long type; };
2256  template<> struct superset<unsigned short,long> { typedef long type; };
2257  template<> struct superset<unsigned short,float> { typedef float type; };
2258  template<> struct superset<unsigned short,double> { typedef double type; };
2259  template<> struct superset<short,unsigned short> { typedef int type; };
2260  template<> struct superset<short,unsigned int> { typedef long type; };
2261  template<> struct superset<short,int> { typedef int type; };
2262  template<> struct superset<short,unsigned long> { typedef long type; };
2263  template<> struct superset<short,long> { typedef long type; };
2264  template<> struct superset<short,float> { typedef float type; };
2265  template<> struct superset<short,double> { typedef double type; };
2266  template<> struct superset<unsigned int,char> { typedef long type; };
2267  template<> struct superset<unsigned int,signed char> { typedef long type; };
2268  template<> struct superset<unsigned int,short> { typedef long type; };
2269  template<> struct superset<unsigned int,int> { typedef long type; };
2270  template<> struct superset<unsigned int,unsigned long> { typedef unsigned long type; };
2271  template<> struct superset<unsigned int,long> { typedef long type; };
2272  template<> struct superset<unsigned int,float> { typedef float type; };
2273  template<> struct superset<unsigned int,double> { typedef double type; };
2274  template<> struct superset<int,unsigned int> { typedef long type; };
2275  template<> struct superset<int,unsigned long> { typedef long type; };
2276  template<> struct superset<int,long> { typedef long type; };
2277  template<> struct superset<int,float> { typedef float type; };
2278  template<> struct superset<int,double> { typedef double type; };
2279  template<> struct superset<unsigned long,char> { typedef long type; };
2280  template<> struct superset<unsigned long,signed char> { typedef long type; };
2281  template<> struct superset<unsigned long,short> { typedef long type; };
2282  template<> struct superset<unsigned long,int> { typedef long type; };
2283  template<> struct superset<unsigned long,long> { typedef long type; };
2284  template<> struct superset<unsigned long,float> { typedef float type; };
2285  template<> struct superset<unsigned long,double> { typedef double type; };
2286  template<> struct superset<long,float> { typedef float type; };
2287  template<> struct superset<long,double> { typedef double type; };
2288  template<> struct superset<float,double> { typedef double type; };
2289 
2290  template<typename t1, typename t2, typename t3> struct superset2 {
2292  };
2293 
2294  template<typename t1, typename t2, typename t3, typename t4> struct superset3 {
2296  };
2297 
2298  template<typename t1, typename t2> struct last { typedef t2 type; };
2299 
2300 #define _cimg_Tt typename cimg::superset<T,t>::type
2301 #define _cimg_Tfloat typename cimg::superset<T,float>::type
2302 #define _cimg_Ttfloat typename cimg::superset2<T,t,float>::type
2303 
2304  // Define internal library variables.
2305 #if cimg_display==1
2306  struct X11info {
2307  volatile unsigned int nb_wins;
2308  pthread_t* event_thread;
2309  CImgDisplay* wins[1024];
2310  Display* display;
2311  unsigned int nb_bits;
2312  GC* gc;
2313  bool blue_first;
2314  bool byte_order;
2315  bool shm_enabled;
2316 #ifdef cimg_use_xrandr
2317  XRRScreenSize *resolutions;
2318  Rotation curr_rotation;
2319  unsigned int curr_resolution;
2320  unsigned int nb_resolutions;
2321 #endif
2322  X11info():nb_wins(0),event_thread(0),display(0),
2323  nb_bits(0),gc(0),blue_first(false),byte_order(false),shm_enabled(false) {
2324 #ifdef cimg_use_xrandr
2325  resolutions = 0;
2326  curr_rotation = 0;
2327  curr_resolution = nb_resolutions = 0;
2328 #endif
2329  }
2330  };
2331 #if defined(cimg_module)
2332  X11info& X11attr();
2333 #elif defined(cimg_main)
2334  X11info& X11attr() { static X11info val; return val; }
2335 #else
2336  inline X11info& X11attr() { static X11info val; return val; }
2337 #endif
2338 
2339 #elif cimg_display==2
2340  struct Win32info {
2341  HANDLE wait_event;
2342  Win32info() { wait_event = CreateEvent(0,FALSE,FALSE,0); }
2343  };
2344 #if defined(cimg_module)
2345  Win32info& Win32attr();
2346 #elif defined(cimg_main)
2347  Win32info& Win32attr() { static Win32info val; return val; }
2348 #else
2349  inline Win32info& Win32attr() { static Win32info val; return val; }
2350 #endif
2351 
2352 #elif cimg_display==3
2353  struct CarbonInfo {
2354  MPCriticalRegionID windowListCR; // Protects access to the list of windows
2355  int windowCount; // Count of displays used on the screen
2356  pthread_t event_thread; // The background event thread
2357  MPSemaphoreID sync_event; // Event used to perform tasks synchronizations
2358  MPSemaphoreID wait_event; // Event used to notify that new events occured on the display
2359  MPQueueID com_queue; // The message queue
2360  CarbonInfo(): windowCount(0),event_thread(0),sync_event(0),com_queue(0) {
2361  if (MPCreateCriticalRegion(&windowListCR) != noErr) // Create the critical region
2362  throw CImgDisplayException("MPCreateCriticalRegion failed.");
2363  if (MPCreateSemaphore(1, 0, &sync_event) != noErr) // Create the inter-thread sync object
2364  throw CImgDisplayException("MPCreateSemaphore failed.");
2365  if (MPCreateSemaphore(1, 0, &wait_event) != noErr) // Create the event sync object
2366  throw CImgDisplayException("MPCreateSemaphore failed.");
2367  if (MPCreateQueue(&com_queue) != noErr) // Create the shared queue
2368  throw CImgDisplayException("MPCreateQueue failed.");
2369  }
2370  ~CarbonInfo() {
2371  if (event_thread != 0) { // Terminates the resident thread, if needed
2372  pthread_cancel(event_thread);
2373  pthread_join(event_thread, NULL);
2374  event_thread = 0;
2375  }
2376  if (MPDeleteCriticalRegion(windowListCR) != noErr) // Delete the critical region
2377  throw CImgDisplayException("MPDeleteCriticalRegion failed.");
2378  if (MPDeleteSemaphore(wait_event) != noErr) // Delete the event sync event
2379  throw CImgDisplayException("MPDeleteEvent failed.");
2380  if (MPDeleteSemaphore(sync_event) != noErr) // Delete the inter-thread sync event
2381  throw CImgDisplayException("MPDeleteEvent failed.");
2382  if (MPDeleteQueue(com_queue) != noErr) // Delete the shared queue
2383  throw CImgDisplayException("MPDeleteQueue failed.");
2384  }
2385  };
2386 #if defined(cimg_module)
2387  CarbonInfo& CarbonAttr();
2388 #elif defined(cimg_main)
2389  CarbonInfo CarbonAttr() { static CarbonInfo val; return val; }
2390 #else
2391  inline CarbonInfo& CarbonAttr() { static CarbonInfo val; return val; }
2392 #endif
2393 #endif
2394 
2395 #if cimg_display==1
2396  // Keycodes for X11-based graphical systems.
2397  const unsigned int keyESC = XK_Escape;
2398  const unsigned int keyF1 = XK_F1;
2399  const unsigned int keyF2 = XK_F2;
2400  const unsigned int keyF3 = XK_F3;
2401  const unsigned int keyF4 = XK_F4;
2402  const unsigned int keyF5 = XK_F5;
2403  const unsigned int keyF6 = XK_F6;
2404  const unsigned int keyF7 = XK_F7;
2405  const unsigned int keyF8 = XK_F8;
2406  const unsigned int keyF9 = XK_F9;
2407  const unsigned int keyF10 = XK_F10;
2408  const unsigned int keyF11 = XK_F11;
2409  const unsigned int keyF12 = XK_F12;
2410  const unsigned int keyPAUSE = XK_Pause;
2411  const unsigned int key1 = XK_1;
2412  const unsigned int key2 = XK_2;
2413  const unsigned int key3 = XK_3;
2414  const unsigned int key4 = XK_4;
2415  const unsigned int key5 = XK_5;
2416  const unsigned int key6 = XK_6;
2417  const unsigned int key7 = XK_7;
2418  const unsigned int key8 = XK_8;
2419  const unsigned int key9 = XK_9;
2420  const unsigned int key0 = XK_0;
2421  const unsigned int keyBACKSPACE = XK_BackSpace;
2422  const unsigned int keyINSERT = XK_Insert;
2423  const unsigned int keyHOME = XK_Home;
2424  const unsigned int keyPAGEUP = XK_Page_Up;
2425  const unsigned int keyTAB = XK_Tab;
2426  const unsigned int keyQ = XK_q;
2427  const unsigned int keyW = XK_w;
2428  const unsigned int keyE = XK_e;
2429  const unsigned int keyR = XK_r;
2430  const unsigned int keyT = XK_t;
2431  const unsigned int keyY = XK_y;
2432  const unsigned int keyU = XK_u;
2433  const unsigned int keyI = XK_i;
2434  const unsigned int keyO = XK_o;
2435  const unsigned int keyP = XK_p;
2436  const unsigned int keyDELETE = XK_Delete;
2437  const unsigned int keyEND = XK_End;
2438  const unsigned int keyPAGEDOWN = XK_Page_Down;
2439  const unsigned int keyCAPSLOCK = XK_Caps_Lock;
2440  const unsigned int keyA = XK_a;
2441  const unsigned int keyS = XK_s;
2442  const unsigned int keyD = XK_d;
2443  const unsigned int keyF = XK_f;
2444  const unsigned int keyG = XK_g;
2445  const unsigned int keyH = XK_h;
2446  const unsigned int keyJ = XK_j;
2447  const unsigned int keyK = XK_k;
2448  const unsigned int keyL = XK_l;
2449  const unsigned int keyENTER = XK_Return;
2450  const unsigned int keySHIFTLEFT = XK_Shift_L;
2451  const unsigned int keyZ = XK_z;
2452  const unsigned int keyX = XK_x;
2453  const unsigned int keyC = XK_c;
2454  const unsigned int keyV = XK_v;
2455  const unsigned int keyB = XK_b;
2456  const unsigned int keyN = XK_n;
2457  const unsigned int keyM = XK_m;
2458  const unsigned int keySHIFTRIGHT = XK_Shift_R;
2459  const unsigned int keyARROWUP = XK_Up;
2460  const unsigned int keyCTRLLEFT = XK_Control_L;
2461  const unsigned int keyAPPLEFT = XK_Super_L;
2462  const unsigned int keyALT = XK_Alt_L;
2463  const unsigned int keySPACE = XK_space;
2464  const unsigned int keyALTGR = XK_Alt_R;
2465  const unsigned int keyAPPRIGHT = XK_Super_R;
2466  const unsigned int keyMENU = XK_Menu;
2467  const unsigned int keyCTRLRIGHT = XK_Control_R;
2468  const unsigned int keyARROWLEFT = XK_Left;
2469  const unsigned int keyARROWDOWN = XK_Down;
2470  const unsigned int keyARROWRIGHT = XK_Right;
2471  const unsigned int keyPAD0 = XK_KP_0;
2472  const unsigned int keyPAD1 = XK_KP_1;
2473  const unsigned int keyPAD2 = XK_KP_2;
2474  const unsigned int keyPAD3 = XK_KP_3;
2475  const unsigned int keyPAD4 = XK_KP_4;
2476  const unsigned int keyPAD5 = XK_KP_5;
2477  const unsigned int keyPAD6 = XK_KP_6;
2478  const unsigned int keyPAD7 = XK_KP_7;
2479  const unsigned int keyPAD8 = XK_KP_8;
2480  const unsigned int keyPAD9 = XK_KP_9;
2481  const unsigned int keyPADADD = XK_KP_Add;
2482  const unsigned int keyPADSUB = XK_KP_Subtract;
2483  const unsigned int keyPADMUL = XK_KP_Multiply;
2484  const unsigned int keyPADDIV = XK_KP_Divide;
2485 
2486 #elif cimg_display==2
2487  // Keycodes for Windows.
2488  const unsigned int keyESC = VK_ESCAPE;
2489  const unsigned int keyF1 = VK_F1;
2490  const unsigned int keyF2 = VK_F2;
2491  const unsigned int keyF3 = VK_F3;
2492  const unsigned int keyF4 = VK_F4;
2493  const unsigned int keyF5 = VK_F5;
2494  const unsigned int keyF6 = VK_F6;
2495  const unsigned int keyF7 = VK_F7;
2496  const unsigned int keyF8 = VK_F8;
2497  const unsigned int keyF9 = VK_F9;
2498  const unsigned int keyF10 = VK_F10;
2499  const unsigned int keyF11 = VK_F11;
2500  const unsigned int keyF12 = VK_F12;
2501  const unsigned int keyPAUSE = VK_PAUSE;
2502  const unsigned int key1 = '1';
2503  const unsigned int key2 = '2';
2504  const unsigned int key3 = '3';
2505  const unsigned int key4 = '4';
2506  const unsigned int key5 = '5';
2507  const unsigned int key6 = '6';
2508  const unsigned int key7 = '7';
2509  const unsigned int key8 = '8';
2510  const unsigned int key9 = '9';
2511  const unsigned int key0 = '0';
2512  const unsigned int keyBACKSPACE = VK_BACK;
2513  const unsigned int keyINSERT = VK_INSERT;
2514  const unsigned int keyHOME = VK_HOME;
2515  const unsigned int keyPAGEUP = VK_PRIOR;
2516  const unsigned int keyTAB = VK_TAB;
2517  const unsigned int keyQ = 'Q';
2518  const unsigned int keyW = 'W';
2519  const unsigned int keyE = 'E';
2520  const unsigned int keyR = 'R';
2521  const unsigned int keyT = 'T';
2522  const unsigned int keyY = 'Y';
2523  const unsigned int keyU = 'U';
2524  const unsigned int keyI = 'I';
2525  const unsigned int keyO = 'O';
2526  const unsigned int keyP = 'P';
2527  const unsigned int keyDELETE = VK_DELETE;
2528  const unsigned int keyEND = VK_END;
2529  const unsigned int keyPAGEDOWN = VK_NEXT;
2530  const unsigned int keyCAPSLOCK = VK_CAPITAL;
2531  const unsigned int keyA = 'A';
2532  const unsigned int keyS = 'S';
2533  const unsigned int keyD = 'D';
2534  const unsigned int keyF = 'F';
2535  const unsigned int keyG = 'G';
2536  const unsigned int keyH = 'H';
2537  const unsigned int keyJ = 'J';
2538  const unsigned int keyK = 'K';
2539  const unsigned int keyL = 'L';
2540  const unsigned int keyENTER = VK_RETURN;
2541  const unsigned int keySHIFTLEFT = VK_SHIFT;
2542  const unsigned int keyZ = 'Z';
2543  const unsigned int keyX = 'X';
2544  const unsigned int keyC = 'C';
2545  const unsigned int keyV = 'V';
2546  const unsigned int keyB = 'B';
2547  const unsigned int keyN = 'N';
2548  const unsigned int keyM = 'M';
2549  const unsigned int keySHIFTRIGHT = VK_SHIFT;
2550  const unsigned int keyARROWUP = VK_UP;
2551  const unsigned int keyCTRLLEFT = VK_CONTROL;
2552  const unsigned int keyAPPLEFT = VK_LWIN;
2553  const unsigned int keyALT = VK_LMENU;
2554  const unsigned int keySPACE = VK_SPACE;
2555  const unsigned int keyALTGR = VK_CONTROL;
2556  const unsigned int keyAPPRIGHT = VK_RWIN;
2557  const unsigned int keyMENU = VK_APPS;
2558  const unsigned int keyCTRLRIGHT = VK_CONTROL;
2559  const unsigned int keyARROWLEFT = VK_LEFT;
2560  const unsigned int keyARROWDOWN = VK_DOWN;
2561  const unsigned int keyARROWRIGHT = VK_RIGHT;
2562  const unsigned int keyPAD0 = 0x60;
2563  const unsigned int keyPAD1 = 0x61;
2564  const unsigned int keyPAD2 = 0x62;
2565  const unsigned int keyPAD3 = 0x63;
2566  const unsigned int keyPAD4 = 0x64;
2567  const unsigned int keyPAD5 = 0x65;
2568  const unsigned int keyPAD6 = 0x66;
2569  const unsigned int keyPAD7 = 0x67;
2570  const unsigned int keyPAD8 = 0x68;
2571  const unsigned int keyPAD9 = 0x69;
2572  const unsigned int keyPADADD = VK_ADD;
2573  const unsigned int keyPADSUB = VK_SUBTRACT;
2574  const unsigned int keyPADMUL = VK_MULTIPLY;
2575  const unsigned int keyPADDIV = VK_DIVIDE;
2576 
2577 #elif cimg_display==3
2578  // Keycodes for MacOSX, when using the Carbon framework.
2579  const unsigned int keyESC = kEscapeCharCode;
2580  const unsigned int keyF1 = 2U;
2581  const unsigned int keyF2 = 3U;
2582  const unsigned int keyF3 = 4U;
2583  const unsigned int keyF4 = 5U;
2584  const unsigned int keyF5 = 6U;
2585  const unsigned int keyF6 = 7U;
2586  const unsigned int keyF7 = 8U;
2587  const unsigned int keyF8 = 9U;
2588  const unsigned int keyF9 = 10U;
2589  const unsigned int keyF10 = 11U;
2590  const unsigned int keyF11 = 12U;
2591  const unsigned int keyF12 = 13U;
2592  const unsigned int keyPAUSE = 14U;
2593  const unsigned int key1 = '1';
2594  const unsigned int key2 = '2';
2595  const unsigned int key3 = '3';
2596  const unsigned int key4 = '4';
2597  const unsigned int key5 = '5';
2598  const unsigned int key6 = '6';
2599  const unsigned int key7 = '7';
2600  const unsigned int key8 = '8';
2601  const unsigned int key9 = '9';
2602  const unsigned int key0 = '0';
2603  const unsigned int keyBACKSPACE = kBackspaceCharCode;
2604  const unsigned int keyINSERT = 26U;
2605  const unsigned int keyHOME = kHomeCharCode;
2606  const unsigned int keyPAGEUP = kPageUpCharCode;
2607  const unsigned int keyTAB = kTabCharCode;
2608  const unsigned int keyQ = 'q';
2609  const unsigned int keyW = 'w';
2610  const unsigned int keyE = 'e';
2611  const unsigned int keyR = 'r';
2612  const unsigned int keyT = 't';
2613  const unsigned int keyY = 'y';
2614  const unsigned int keyU = 'u';
2615  const unsigned int keyI = 'i';
2616  const unsigned int keyO = 'o';
2617  const unsigned int keyP = 'p';
2618  const unsigned int keyDELETE = kDeleteCharCode;
2619  const unsigned int keyEND = kEndCharCode;
2620  const unsigned int keyPAGEDOWN = kPageDownCharCode;
2621  const unsigned int keyCAPSLOCK = 43U;
2622  const unsigned int keyA = 'a';
2623  const unsigned int keyS = 's';
2624  const unsigned int keyD = 'd';
2625  const unsigned int keyF = 'f';
2626  const unsigned int keyG = 'g';
2627  const unsigned int keyH = 'h';
2628  const unsigned int keyJ = 'j';
2629  const unsigned int keyK = 'k';
2630  const unsigned int keyL = 'l';
2631  const unsigned int keyENTER = kEnterCharCode;
2632  const unsigned int keySHIFTLEFT = 54U; //Macintosh modifier key, emulated
2633  const unsigned int keyZ = 'z';
2634  const unsigned int keyX = 'x';
2635  const unsigned int keyC = 'c';
2636  const unsigned int keyV = 'v';
2637  const unsigned int keyB = 'b';
2638  const unsigned int keyN = 'n';
2639  const unsigned int keyM = 'm';
2640  const unsigned int keySHIFTRIGHT = 62U; //Macintosh modifier key, emulated
2641  const unsigned int keyARROWUP = kUpArrowCharCode;
2642  const unsigned int keyCTRLLEFT = 64U; //Macintosh modifier key, emulated
2643  const unsigned int keyAPPLEFT = 65U; //Macintosh modifier key, emulated
2644  const unsigned int keyALT = 66U;
2645  const unsigned int keySPACE = kSpaceCharCode;
2646  const unsigned int keyALTGR = 67U; //Macintosh modifier key, emulated
2647  const unsigned int keyAPPRIGHT = 68U; //Aliased on keyAPPLEFT
2648  const unsigned int keyMENU = 69U;
2649  const unsigned int keyCTRLRIGHT = 70U; //Macintosh modifier key, emulated
2650  const unsigned int keyARROWLEFT = kLeftArrowCharCode;
2651  const unsigned int keyARROWDOWN = kDownArrowCharCode;
2652  const unsigned int keyARROWRIGHT = kRightArrowCharCode;
2653  const unsigned int keyPAD0 = 74U;
2654  const unsigned int keyPAD1 = 75U;
2655  const unsigned int keyPAD2 = 76U;
2656  const unsigned int keyPAD3 = 77U;
2657  const unsigned int keyPAD4 = 78U;
2658  const unsigned int keyPAD5 = 79U;
2659  const unsigned int keyPAD6 = 80U;
2660  const unsigned int keyPAD7 = 81U;
2661  const unsigned int keyPAD8 = 82U;
2662  const unsigned int keyPAD9 = 83U;
2663  const unsigned int keyPADADD = 84U;
2664  const unsigned int keyPADSUB = 85U;
2665  const unsigned int keyPADMUL = 86U;
2666  const unsigned int keyPADDIV = 87U;
2667 
2668 #else
2669  // Define unknow keycodes when no display are available.
2670  // (should rarely be used then !).
2671  const unsigned int keyESC = 1U;
2672  const unsigned int keyF1 = 2U;
2673  const unsigned int keyF2 = 3U;
2674  const unsigned int keyF3 = 4U;
2675  const unsigned int keyF4 = 5U;
2676  const unsigned int keyF5 = 6U;
2677  const unsigned int keyF6 = 7U;
2678  const unsigned int keyF7 = 8U;
2679  const unsigned int keyF8 = 9U;
2680  const unsigned int keyF9 = 10U;
2681  const unsigned int keyF10 = 11U;
2682  const unsigned int keyF11 = 12U;
2683  const unsigned int keyF12 = 13U;
2684  const unsigned int keyPAUSE = 14U;
2685  const unsigned int key1 = 15U;
2686  const unsigned int key2 = 16U;
2687  const unsigned int key3 = 17U;
2688  const unsigned int key4 = 18U;
2689  const unsigned int key5 = 19U;
2690  const unsigned int key6 = 20U;
2691  const unsigned int key7 = 21U;
2692  const unsigned int key8 = 22U;
2693  const unsigned int key9 = 23U;
2694  const unsigned int key0 = 24U;
2695  const unsigned int keyBACKSPACE = 25U;
2696  const unsigned int keyINSERT = 26U;
2697  const unsigned int keyHOME = 27U;
2698  const unsigned int keyPAGEUP = 28U;
2699  const unsigned int keyTAB = 29U;
2700  const unsigned int keyQ = 30U;
2701  const unsigned int keyW = 31U;
2702  const unsigned int keyE = 32U;
2703  const unsigned int keyR = 33U;
2704  const unsigned int keyT = 34U;
2705  const unsigned int keyY = 35U;
2706  const unsigned int keyU = 36U;
2707  const unsigned int keyI = 37U;
2708  const unsigned int keyO = 38U;
2709  const unsigned int keyP = 39U;
2710  const unsigned int keyDELETE = 40U;
2711  const unsigned int keyEND = 41U;
2712  const unsigned int keyPAGEDOWN = 42U;
2713  const unsigned int keyCAPSLOCK = 43U;
2714  const unsigned int keyA = 44U;
2715  const unsigned int keyS = 45U;
2716  const unsigned int keyD = 46U;
2717  const unsigned int keyF = 47U;
2718  const unsigned int keyG = 48U;
2719  const unsigned int keyH = 49U;
2720  const unsigned int keyJ = 50U;
2721  const unsigned int keyK = 51U;
2722  const unsigned int keyL = 52U;
2723  const unsigned int keyENTER = 53U;
2724  const unsigned int keySHIFTLEFT = 54U;
2725  const unsigned int keyZ = 55U;
2726  const unsigned int keyX = 56U;
2727  const unsigned int keyC = 57U;
2728  const unsigned int keyV = 58U;
2729  const unsigned int keyB = 59U;
2730  const unsigned int keyN = 60U;
2731  const unsigned int keyM = 61U;
2732  const unsigned int keySHIFTRIGHT = 62U;
2733  const unsigned int keyARROWUP = 63U;
2734  const unsigned int keyCTRLLEFT = 64U;
2735  const unsigned int keyAPPLEFT = 65U;
2736  const unsigned int keyALT = 66U;
2737  const unsigned int keySPACE = 67U;
2738  const unsigned int keyALTGR = 68U;
2739  const unsigned int keyAPPRIGHT = 69U;
2740  const unsigned int keyMENU = 70U;
2741  const unsigned int keyCTRLRIGHT = 71U;
2742  const unsigned int keyARROWLEFT = 72U;
2743  const unsigned int keyARROWDOWN = 73U;
2744  const unsigned int keyARROWRIGHT = 74U;
2745  const unsigned int keyPAD0 = 75U;
2746  const unsigned int keyPAD1 = 76U;
2747  const unsigned int keyPAD2 = 77U;
2748  const unsigned int keyPAD3 = 78U;
2749  const unsigned int keyPAD4 = 79U;
2750  const unsigned int keyPAD5 = 80U;
2751  const unsigned int keyPAD6 = 81U;
2752  const unsigned int keyPAD7 = 82U;
2753  const unsigned int keyPAD8 = 83U;
2754  const unsigned int keyPAD9 = 84U;
2755  const unsigned int keyPADADD = 85U;
2756  const unsigned int keyPADSUB = 86U;
2757  const unsigned int keyPADMUL = 87U;
2758  const unsigned int keyPADDIV = 88U;
2759 #endif
2760 
2761  const double valuePI = 3.14159265358979323846;
2762 
2763  // Definition of a 7x11 font, used to return a default font for drawing text.
2764  const unsigned int font7x11[7*11*256/32] = {
2765  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,
2766  0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x7f0000,0x40000,0x0,0x0,0x4010c0a4,0x82000040,0x11848402,0x18480050,0x80430292,0x8023,0x9008000,
2767  0x40218140,0x4000040,0x21800402,0x18000051,0x1060500,0x8083,0x10000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x24002,0x4031,0x80000000,0x10000,
2768  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c0400,0x40020000,0x80070080,0x40440e00,0x0,0x0,0x1,0x88180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2769  0x0,0x200000,0x0,0x0,0x80000,0x0,0x0,0x20212140,0x5000020,0x22400204,0x240000a0,0x40848500,0x4044,0x80010038,0x20424285,0xa000020,
2770  0x42428204,0x2428e0a0,0x82090a14,0x4104,0x85022014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10240a7,0x88484040,0x40800000,0x270c3,0x87811e0e,
2771  0x7c70e000,0x78,0x3c23c1ef,0x1f3e1e89,0xf1c44819,0xa23cf0f3,0xc3cff120,0xc18307f4,0x4040400,0x20000,0x80080080,0x40200,0x0,
2772  0x40000,0x2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8188,0x50603800,0xf3c00000,0x1c004003,0xc700003e,0x18180,0xc993880,0x10204081,
2773  0x2071ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x7d1224,0x48906048,0x0,0x4000000,0x0,0x9000,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,
2774  0x0,0x10240aa,0x14944080,0x23610000,0x68940,0x40831010,0x8891306,0x802044,0x44522208,0x90202088,0x40448819,0xb242890a,0x24011111,
2775  0x49448814,0x4040a00,0xe2c3c7,0x8e3f3cb9,0xc1c44216,0xee38b0f2,0xe78f9120,0xc18507e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2776  0x101c207,0x88a04001,0x9c00000,0x2200a041,0x8200113a,0x8240,0x50a3110,0x2850a142,0x850c2081,0x2040204,0x8104592,0x142850a1,
2777  0x42cd1224,0x4888bc48,0x70e1c387,0xe3b3c70,0xe1c38e1c,0x38707171,0xc3870e1c,0x10791224,0x48906c41,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2778  0x10003ee,0x15140080,0x21810000,0x48840,0x40851020,0x8911306,0x31fd804,0x9c522408,0x90204088,0x4045081a,0xba42890a,0x24011111,
2779  0x49285024,0x2041b00,0x132408,0x910844c8,0x4044821b,0x7244c913,0x24041111,0x49488822,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2780  0x28204,0x85006001,0x6a414000,0x3a004043,0xc700113a,0x8245,0x50a3a00,0x2850a142,0x850c4081,0x2040204,0x81045d2,0x142850a1,
2781  0x24951224,0x48852250,0x8102040,0x81054089,0x12244204,0x8108992,0x24489122,0x991224,0x4888b222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2782  0x1000143,0xa988080,0x2147c01f,0x88840,0x83091c2c,0x1070f000,0xc000608,0xa48bc408,0x9e3c46f8,0x40460816,0xaa42f10b,0xc3811111,
2783  0x35102044,0x1041100,0xf22408,0x9f084488,0x40470212,0x62448912,0x6041111,0x55308846,0x8061c80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2784  0x1028704,0x8f805801,0x4be28fdf,0x220001f0,0x111a,0x60000182,0x82c5c710,0x44891224,0x489640f1,0xe3c78204,0x810e552,0x142850a1,
2785  0x18a51224,0x48822250,0x78f1e3c7,0x8f1f40f9,0xf3e7c204,0x8108912,0x24489122,0x7ea91224,0x4888a222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2786  0x10007e2,0x85648080,0x20010000,0x88841,0x8f8232,0x20881000,0xc1fc610,0xbefa2408,0x90204288,0x40450816,0xa642810a,0x4041110a,
2787  0x36282084,0x1042080,0x1122408,0x90084488,0x40450212,0x62448912,0x184110a,0x55305082,0x8042700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2788  0x1028207,0x82004801,0x68050040,0x1c000040,0x110a,0x60000001,0x45484d10,0x7cf9f3e7,0xcf944081,0x2040204,0x8104532,0x142850a1,
2789  0x18a51224,0x48822248,0x89122448,0x91244081,0x2040204,0x8108912,0x24489122,0xc91224,0x48852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x282,
2790  0x89630080,0x20010c00,0x30108842,0x810222,0x20882306,0x3001800,0x408a2208,0x90202288,0x40448814,0xa642810a,0x2041110a,0x26442104,
2791  0x840000,0x1122408,0x90084488,0x40448212,0x62448912,0x84130a,0x36485102,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x101c208,0x4f802801,
2792  0x8028040,0x40,0x130a,0x2,0x85e897a0,0x44891224,0x489c2081,0x2040204,0x8104532,0x142850a1,0x24cd1224,0x48823c44,0x89122448,
2793  0x91244081,0x2040204,0x8108912,0x24489122,0xc93264,0xc9852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100028f,0x109f0080,0x20010c00,
2794  0x303071f3,0xc7011c1c,0x4071c306,0x802010,0x3907c1ef,0x1f201e89,0xf3844f90,0xa23c80f2,0x17810e04,0x228223f4,0x840000,0xfbc3c7,
2795  0x8f083c88,0x40444212,0x6238f0f2,0x7039d04,0x228423e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1008780,0x2201800,0xf0014000,0x1f0,
2796  0x1d0a,0x5,0x851e140,0x83060c18,0x30671ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x42f8e1c3,0x8702205c,0x7cf9f3e7,0xcf9b3c78,0xf1e3c204,
2797  0x8107111,0xc3870e1c,0x10f1d3a7,0x4e823c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x40,0x40000400,0x200000,0x0,0x2,0x0,0x0,0x0,0x0,0x18,
2798  0x0,0x4,0x44007f,0x0,0x400,0x400000,0x8010,0x0,0x6002,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x200800,0x0,0x0,0x100a,
2799  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,
2800  0x400000,0x0,0x4,0x0,0x0,0x0,0x0,0xc,0x0,0x7,0x3c0000,0x0,0x3800,0x3800000,0x8010,0x0,0x1c001,0x881c0000,0x0,0x0,0x0,0x0,0x0,0x0,
2801  0x0,0x0,0x207000,0x0,0x0,0x100a,0xc00000,0x3c,0x0,0xc00,0x0,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x0,0x1c2070
2802  };
2803 
2804  // Definition of a 10x13 font (used in dialog boxes).
2805  const unsigned int font10x13[256*10*13/32] = {
2806  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2807  0x0,0x0,0x0,0x0,0x0,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,
2808  0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2809  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2810  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,
2811  0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2812  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,
2813  0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2814  0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001,
2815  0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801,
2816  0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0,
2817  0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0,
2818  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010,
2819  0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480,
2820  0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,
2821  0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010,
2822  0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008,
2823  0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006,
2824  0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088,
2825  0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000,
2826  0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220,
2827  0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208,
2828  0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040,
2829  0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508,
2830  0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088,
2831  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018,
2832  0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220,
2833  0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2834  0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484,
2835  0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808,
2836  0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264,
2837  0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010,
2838  0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100,
2839  0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800,
2840  0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,
2841  0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822,
2842  0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200,
2843  0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000,
2844  0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2845  0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8,
2846  0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008,
2847  0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000,
2848  0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220,
2849  0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402,
2850  0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980,
2851  0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421,
2852  0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0,
2853  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020,
2854  0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701,
2855  0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,
2856  0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c,
2857  0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0,
2858  0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000,
2859  0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000,
2860  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0,
2861  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,
2862  0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000,
2863  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,
2864  0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040
2865  };
2866 
2867  // Definition of a 8x17 font.
2868  const unsigned int font8x17[8*17*256/32] = {
2869  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2870  0x0,0x0,0x0,0x2400,0x2400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20081834,0x1c0000,0x20081800,0x20081800,0x342008,
2871  0x18340000,0x200818,0x80000,0x0,0x180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4200000,0x0,0x0,
2872  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x380000,0x4000,0x2000c00,0x40100840,0x70000000,0x0,0x0,0x1c,0x10700000,0x7,0x0,
2873  0x1800,0x1800,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1010242c,0x14140000,0x10102414,0x10102414,0x2c1010,0x242c1400,
2874  0x101024,0x14100038,0x0,0x240000,0x0,0x0,0x30000000,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x8100000,0x0,
2875  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x80000,0x10004000,0x2001000,0x40000040,0x10000000,0x0,0x0,0x10,0x10100000,0x4,
2876  0x0,0x18000000,0x0,0x0,0x0,0x34002400,0x2400,0x0,0x0,0x0,0x3c,0x0,0x8000000,0x0,0x60607800,0x0,0x140000,0x0,0x0,0x0,0x0,0x0,
2877  0x44,0x10081834,0x240000,0x10081800,0x10081800,0x1c341008,0x18340000,0x100818,0x84000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102812,
2878  0x8601c10,0x8100800,0x2,0x1c383e3e,0x67e1e7f,0x3e3c0000,0x38,0x1e087e1e,0x7c7f7f1e,0x417c1c42,0x4063611c,0x7e1c7e3e,0xfe414181,
2879  0x63827f10,0x40081000,0x8004000,0x2001000,0x40000040,0x10000000,0x0,0x10000000,0x10,0x10100000,0x3c000008,0x0,0x24003e00,
2880  0x3f007f00,0x0,0x0,0x2ce91800,0x1882,0x10101c,0xc2103c,0x143c3c00,0x3c00,0x18003c3c,0x10001f00,0x181c00,0x20200810,0x8080808,
2881  0x8083e1e,0x7f7f7f7f,0x7c7c7c7c,0x7c611c1c,0x1c1c1c00,0x1e414141,0x41824044,0x810242c,0x14180000,0x8102414,0x8102414,0x382c0810,
2882  0x242c1400,0x81024,0x14104014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102816,0x3e902010,0x10084910,0x4,0x22084343,0xa402102,0x41620000,
2883  0x44,0x33144121,0x42404021,0x41100444,0x40636122,0x43224361,0x10416381,0x22440310,0x20082800,0x4000,0x2001000,0x40000040,
2884  0x10000000,0x0,0x10000000,0x10,0x10100000,0x24000008,0x0,0x606100,0x68000300,0x8106c,0x34000000,0x4f0000,0x44,0x101020,0x441040,
2885  0x420200,0x4200,0x24000404,0x7d00,0x82200,0x20203010,0x14141414,0x14082821,0x40404040,0x10101010,0x42612222,0x22222200,0x23414141,
2886  0x41447e48,0x0,0x0,0x0,0x0,0x4000000,0x18,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10287f,0x49902010,0x10083e10,0x4,0x41080101,
2887  0x1a404002,0x41411818,0x1004004,0x21144140,0x41404040,0x41100448,0x40555141,0x41414140,0x10412281,0x14280610,0x20084400,0x1c7c1c,
2888  0x3e3c7c3a,0x5c703844,0x107f5c3c,0x7c3e3c3c,0x7e424281,0x66427e10,0x10100000,0x40100008,0x1010,0xa04000,0x48100610,0x100c3024,
2889  0x24000000,0x4f3c00,0x2c107e28,0x3820,0x42281060,0x9d1e12,0xbd00,0x24100818,0x427d00,0x82248,0x20200800,0x14141414,0x14142840,
2890  0x40404040,0x10101010,0x41514141,0x41414142,0x43414141,0x41284350,0x1c1c1c1c,0x1c1c6c1c,0x3c3c3c3c,0x70707070,0x3c5c3c3c,
2891  0x3c3c3c18,0x3e424242,0x42427c42,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102824,0x48623010,0x10081c10,0x8,0x41080103,0x127c5e04,
2892  0x41411818,0xe7f3808,0x4f144140,0x41404040,0x41100450,0x40555141,0x41414160,0x1041225a,0x1c280410,0x1008c600,0x226622,0x66661066,
2893  0x62100848,0x10496266,0x66663242,0x10426681,0x24220260,0x100c0000,0xf8280008,0x1010,0x606000,0x48280428,0x28042014,0x48000000,
2894  0x494200,0x52280228,0x105420,0x3cee1058,0xa12236,0xa500,0x18101004,0x427d00,0x8226c,0x76767e10,0x14141414,0x14142840,0x40404040,
2895  0x10101010,0x41514141,0x41414124,0x45414141,0x41284150,0x22222222,0x22221222,0x66666666,0x10101010,0x66626666,0x66666600,
2896  0x66424242,0x42226622,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100024,0x381c4900,0x10086bfe,0x8,0x4908021c,0x22036304,0x3e630000,
2897  0x70000710,0x51227e40,0x417f7f43,0x7f100470,0x40554941,0x43417e3e,0x1041225a,0x8100810,0x10080000,0x24240,0x42421042,0x42100850,
2898  0x10494242,0x42422040,0x1042245a,0x18240410,0x10103900,0x407c003e,0x1818,0x1c3e10,0x4f7c087c,0x7c002010,0x48000000,0x4008,
2899  0x527c0410,0x105078,0x2410104c,0xa13e6c,0x7f00b900,0xfe3c3c,0x421d18,0x1c1c36,0x38383810,0x22222222,0x22144e40,0x7f7f7f7f,
2900  0x10101010,0xf1494141,0x41414118,0x49414141,0x4110435c,0x2020202,0x2021240,0x42424242,0x10101010,0x42424242,0x424242ff,0x4e424242,
2901  0x42244224,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000fe,0xe664d00,0x10080810,0x380010,0x41080c03,0x42014108,0x633d0000,0x70000710,
2902  0x51224140,0x41404041,0x41100448,0x40494541,0x7e414203,0x1041145a,0x14101010,0x10080000,0x3e4240,0x427e1042,0x42100870,0x10494242,
2903  0x4242203c,0x1042245a,0x18241810,0x10104600,0xf8f60008,0x1010,0x600320,0x48f610f6,0xf6000000,0x187eff,0x3c04,0x5ef61810,0x105020,
2904  0x24fe0064,0x9d006c,0x138ad00,0x100000,0x420518,0x36,0xc0c0c020,0x22222222,0x22224840,0x40404040,0x10101010,0x41454141,0x41414118,
2905  0x51414141,0x41107e46,0x3e3e3e3e,0x3e3e7e40,0x7e7e7e7e,0x10101010,0x42424242,0x42424200,0x5a424242,0x42244224,0x0,0x0,0x0,
2906  0x0,0x0,0x0,0x0,0x0,0x28,0x9094500,0x10080010,0x10,0x41081801,0x7f014118,0x41010000,0xe7f3800,0x513e4140,0x41404041,0x41100444,
2907  0x40414541,0x40414101,0x10411466,0x36103010,0x8080000,0x424240,0x42401042,0x42100848,0x10494242,0x42422002,0x10423c5a,0x18142010,
2908  0x10100000,0x407c0010,0x1010,0x260140,0x487c307c,0x7c000000,0x180000,0x202,0x507c2010,0x105020,0x3c10003c,0x423e36,0x1004200,
2909  0x100000,0x420500,0x3e6c,0x41e0440,0x3e3e3e3e,0x3e3e7840,0x40404040,0x10101010,0x41454141,0x41414124,0x61414141,0x41104042,
2910  0x42424242,0x42425040,0x40404040,0x10101010,0x42424242,0x42424218,0x72424242,0x42144214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,
2911  0x49096200,0x8100010,0x18001810,0x22082043,0x2432310,0x61421818,0x1004010,0x4f634121,0x42404021,0x41104444,0x40414322,0x40234143,
2912  0x10411466,0x22106010,0x8080000,0x466622,0x66621066,0x42100844,0x10494266,0x66662042,0x10461824,0x24184010,0x10100000,0x24381010,
2913  0x34001018,0xda4320,0x68386038,0x38000000,0x0,0x4204,0x50384010,0x105420,0x4210100c,0x3c0012,0x3c00,0x0,0x460500,0x48,0xc020c44,
2914  0x63636363,0x63228821,0x40404040,0x10101010,0x42432222,0x22222242,0x62414141,0x41104042,0x46464646,0x46465022,0x62626262,
2915  0x10101010,0x66426666,0x66666618,0x66464646,0x46186618,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,0x3e063d00,0x8100000,0x18001820,
2916  0x1c3e7f3e,0x23c1e20,0x3e3c1818,0x10,0x20417e1e,0x7c7f401e,0x417c3842,0x7f41431c,0x401e40be,0x103e0866,0x41107f10,0x4080000,
2917  0x3a5c1c,0x3a3c103a,0x427c0842,0xe49423c,0x7c3e203c,0xe3a1824,0x66087e10,0x10100000,0x3c103010,0x245a1010,0x5a3e10,0x3f107f10,
2918  0x10000000,0x0,0x3c08,0x2e107e10,0x1038fc,0x101004,0x0,0x0,0xfe0000,0x7f0500,0x0,0x14041438,0x41414141,0x41418e1e,0x7f7f7f7f,
2919  0x7c7c7c7c,0x7c431c1c,0x1c1c1c00,0xbc3e3e3e,0x3e10405c,0x3a3a3a3a,0x3a3a6e1c,0x3c3c3c3c,0x7c7c7c7c,0x3c423c3c,0x3c3c3c00,
2920  0x7c3a3a3a,0x3a087c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x4200000,0x10000020,0x0,0x0,0x10,0x0,0x30000000,0x0,
2921  0x0,0x0,0x60000,0x0,0x1c,0x4380000,0x0,0x2,0x800,0x0,0x40020000,0x0,0x8000c,0x10600000,0x2010,0x48000000,0x240000,0x0,0x0,
2922  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,
2923  0x84008,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x20000040,0x0,0x0,0x20,0x0,0x1e000000,0x0,0x0,0x0,0x20000,0x0,
2924  0x0,0x2000000,0x0,0x26,0x800,0x0,0x40020000,0x0,0x100000,0x10000000,0x2030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x1000,0x0,
2925  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,
2926  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,
2927  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,
2928  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,
2929  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2930  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2931  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2932  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
2933 
2934  // Definition of a 10x19 font.
2935  const unsigned int font10x19[10*19*256/32] = {
2936  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2937  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,
2938  0x0,0x180181c0,0xe81b0300,0x1801,0x81c06c18,0x181c06c,0xe8180,0x181c0e81,0xb0000006,0x60701b,0x1800000,0x0,0x0,0x0,0x0,0x0,
2939  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2940  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,
2941  0x0,0x0,0x0,0x0,0x0,0x0,0xc030360,0xb81b0480,0xc03,0x3606c0c,0x303606c,0xb80c0,0x30360b81,0xb0000003,0xc0d81b,0x3000000,0x0,
2942  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,
2943  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,
2944  0x22000,0x0,0x0,0x0,0x0,0x0,0x0,0x30000,0x0,0xe0,0x38078000,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000c080,0x480,0x3000,
2945  0xc0800030,0xc08000,0x300,0xc080000,0xc,0x302000,0xc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x41c01,0xe020060c,
2946  0x800000,0x4,0x1e0703e0,0xf8060fc1,0xe1fe1e07,0x80000000,0x78,0x307e0,0x3c7c1fe7,0xf83c408f,0x80f10440,0x18660878,0x7e0787e0,
2947  0x78ff9024,0xa0140a0,0x27f83840,0x700e000,0x18000400,0x8000,0x70004002,0x410078,0x0,0x0,0x0,0x0,0x1808,0xc000000,0xf000000,
2948  0xe000000,0x1400,0x1e0001f,0x8007f800,0x0,0x0,0x3a3b,0x61400000,0x14202,0x20000,0x38002020,0x3c1b00,0x3e00000,0xf8,0x1c0001c0,
2949  0x78060001,0xf800000e,0x1e00020,0x8004020,0xc0300c0,0x300c0301,0xf83c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1821e0,0x781e0781,0xe0001f10,
2950  0x24090240,0xa02400f8,0x18018140,0xe81b0480,0x1801,0x81406c18,0x181406c,0x190e8180,0x18140e81,0xb0000006,0x60501b,0x184006c,
2951  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x26042202,0x200c06,0x800000,0x8,0x210d0611,0x40e0803,0x10026188,0x40000000,
2952  0x8c,0xf030418,0xc6431004,0xc64082,0x110840,0x18660884,0x41084410,0x8c081024,0xa012110,0x40082020,0x101b000,0xc000400,0x8000,
2953  0x80004002,0x410008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x18800000,0x10000000,0x2200,0x2300024,0x800,0x0,0x0,0x2e13,0x60800000,
2954  0x8104,0x20040,0x64001040,0x80401b07,0x80100000,0x1e000,0x22000020,0x40c0003,0xc8000002,0x3300020,0x8004020,0xc0300c0,0x300c0301,
2955  0x40c64010,0x4010008,0x2008020,0x43182210,0x84210842,0x10002190,0x24090240,0x9044018c,0xc030220,0xb81b0300,0xc03,0x2206c0c,
2956  0x302206c,0x1e0b80c0,0x30220b81,0xb0000003,0xc0881b,0x304006c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x241f2202,
2957  0x200802,0x4900000,0x8,0x21010408,0x20a0802,0x44090,0x20000000,0x4,0x11878408,0x80411004,0x804082,0x111040,0x1ce50986,0x40986409,
2958  0x81022,0x12012108,0x80102020,0x1031800,0x400,0x8000,0x80004000,0x10008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x10000000,
2959  0x10000000,0x18,0x4000044,0x1000,0x30180,0xd81b0000,0x13,0xe0000000,0x88,0x40,0x400018c0,0x80400018,0x61f00000,0x61800,0x22020020,
2960  0x4000007,0xc8000002,0x2100020,0x8038000,0x1e0781e0,0x781e0301,0x40804010,0x4010008,0x2008020,0x41142619,0x86619866,0x18002190,
2961  0x24090240,0x8887e104,0x0,0x0,0x0,0x0,0x0,0x2000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x2434a202,
2962  0x200802,0x3e00000,0x10,0x40810008,0x21a0804,0x44090,0x20000000,0x80040004,0x20848409,0x409004,0x1004082,0x112040,0x14a50902,
2963  0x40902409,0x81022,0x11321208,0x80202010,0x1060c00,0x7c5e0,0x781e8783,0xf07a5f0e,0x1c10808,0xfc5f078,0x5e07a170,0x7c7e1024,
2964  0xa016190,0x27f82008,0x2000000,0x20000000,0x10000000,0x80200024,0x4000044,0x2000,0x18180,0xc8320000,0x12,0xa1f00037,0x7f888,
2965  0x1e0,0x40410880,0x80600017,0xa2100000,0x5e800,0x22020040,0x38001027,0xc8000002,0x2100020,0x8004020,0x12048120,0x48120482,
2966  0x41004010,0x4010008,0x2008020,0x40942409,0x2409024,0x9044390,0x24090240,0x88841918,0x1f07c1f0,0x7c1f07c3,0x70781e07,0x81e07838,
2967  0xe0380e0,0x1f17c1e0,0x781e0781,0xe0001f90,0x24090240,0x9025e102,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xff241c41,
2968  0x1001,0x1c02000,0x10,0x40810008,0x6120f85,0xe0086190,0x20c03007,0x8007800c,0x27848419,0x409004,0x1004082,0x114040,0x14a48902,
2969  0x40902409,0x81022,0x11321205,0x602010,0x1000000,0x86610,0x84218840,0x80866182,0x411008,0x9261884,0x61086189,0x82101022,0x12012108,
2970  0x40082008,0x2000000,0x20030000,0x20000000,0x80200024,0x4000044,0x3006030,0xc018100,0x4c260000,0x12,0x26080048,0x83000850,
2971  0x20250,0x403e0500,0x8078002c,0x12302200,0x92400,0x1c0200c0,0x4001027,0xc8000002,0x3308820,0x8004020,0x12048120,0x48120482,
2972  0x41004010,0x4010008,0x2008020,0x40922409,0x2409024,0x8884690,0x24090240,0x85040920,0x21886218,0x86218860,0x88842108,0x42108408,
2973  0x2008020,0x21186210,0x84210842,0x10302190,0x24090240,0x88461084,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x4c240182,
2974  0x80001001,0x6b02000,0x20,0x4c810010,0x78220846,0x10081e10,0x20c0301c,0x1fe0e018,0x4d8487e1,0x409fe7,0xf9007f82,0x11a040,
2975  0x13248902,0x41102418,0xe0081022,0x11320c05,0x402008,0x1000000,0x2409,0x409020,0x81024082,0x412008,0x9240902,0x40902101,0x101022,
2976  0x11321208,0x40102008,0x2000000,0x7e0c8000,0xfc000003,0xf0fc0018,0x43802047,0x8c8040c8,0x32008300,0x44240000,0x0,0x4000048,
2977  0x8c801050,0x20440,0x40221dc0,0x808c0028,0x11d0667f,0x8009c400,0x1fc180,0x4001023,0xc8300002,0x1e0ccfb,0x3ec7b020,0x12048120,
2978  0x48120482,0x79007f9f,0xe7f9fe08,0x2008020,0xf0922409,0x2409024,0x8504490,0x24090240,0x85040920,0x802008,0x2008020,0x89004090,
2979  0x24090208,0x2008020,0x40902409,0x2409024,0x8304390,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
2980  0x481c0606,0xc8001001,0x802000,0x20,0x4c810020,0x4220024,0x8102108,0x60000070,0x3820,0x48884419,0x409004,0x10e4082,0x112040,
2981  0x13244902,0x7e1027e0,0x3c081021,0x21320c02,0x802008,0x1000000,0x7e409,0x409020,0x81024082,0x414008,0x9240902,0x40902101,
2982  0x80101022,0x11320c08,0x40202008,0x2038800,0x200bc000,0x20000000,0x80200003,0x80f04044,0xbc080bc,0x2f000200,0x0,0x0,0x6001048,
2983  0x8bc02020,0x20441,0xf8220200,0x80820028,0x1000cc00,0x80094400,0x201e0,0x78001021,0xc830000f,0x8000663c,0xf03c0c0,0x21084210,
2984  0x84210846,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8204890,0x24090240,0x82040930,0x1f87e1f8,0x7e1f87e0,0x89004090,
2985  0x24090208,0x2008020,0x40902409,0x2409024,0x8004690,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
2986  0x480719c4,0x48001001,0x81fc00,0x7800020,0x40810040,0x2420024,0x8104087,0xa0000070,0x3820,0x48884409,0x409004,0x1024082,0x111040,
2987  0x13244902,0x40102410,0x2081021,0x214a1202,0x1802008,0x1000000,0x182409,0x409fe0,0x81024082,0x41a008,0x9240902,0x40902100,
2988  0xf8101021,0x214a0c04,0x80c0c008,0x1847000,0x7c1ee000,0x20000000,0x8020000c,0x8c044,0x1ee181ee,0x7b800000,0x707,0xf3ff0000,
2989  0x3e0084f,0x9ee0c020,0x20440,0x40221fc0,0xc2002c,0x13f11000,0x87892400,0x20000,0x1020,0x48000000,0x3f011c6,0x31cc6180,0x21084210,
2990  0x84210844,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8505090,0x24090240,0x8204191c,0x60982609,0x82609823,0xf9007f9f,
2991  0xe7f9fe08,0x2008020,0x40902409,0x2409024,0x9fe4c90,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xfe048224,
2992  0x28001001,0x2000,0x40,0x40810080,0x27f8024,0x8104080,0x2000001c,0x1fe0e020,0x488fc409,0x409004,0x1024082,0x110840,0x10242902,
2993  0x40102408,0x2081021,0x214a1202,0x1002004,0x1000000,0x102409,0x409000,0x81024082,0x411008,0x9240902,0x40902100,0x6101021,
2994  0x214a0c04,0x81002008,0x2000000,0x201dc000,0x20000000,0x80200000,0x98044,0x1dc101dc,0x77000000,0x700,0x0,0x180448,0x1dc10020,
2995  0x20440,0x403e0200,0x620017,0xa000cc00,0x80052800,0x20000,0x1020,0x48000000,0x6606,0x206100,0x3f0fc3f0,0xfc3f0fc7,0xc1004010,
2996  0x4010008,0x2008020,0x4090a409,0x2409024,0x8886090,0x24090240,0x8207e106,0x40902409,0x2409024,0x81004010,0x4010008,0x2008020,
2997  0x40902409,0x2409024,0x8005890,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98048224,0x30001001,0x2000,
2998  0x40,0x21010100,0x2020024,0x8204080,0x40000007,0x80078000,0x48884408,0x80411004,0x824082,0x110840,0x10242986,0x40086409,0x2081021,
2999  0xe14a2102,0x2002004,0x1000000,0x106409,0x409000,0x81024082,0x410808,0x9240902,0x40902100,0x2101021,0x214a1202,0x82002008,
3000  0x2000000,0x300f8000,0x20000000,0x80fc001d,0xe4088044,0xf8200f8,0x3e000000,0x300,0x0,0x80c48,0xf820020,0x20640,0x40410200,
3001  0x803c0018,0x60006600,0x61800,0x0,0x1020,0x48000000,0xcc0a,0x20a100,0x21084210,0x84210844,0x40804010,0x4010008,0x2008020,
3002  0x4110a619,0x86619866,0x19046110,0x24090240,0x82040102,0x41906419,0x6419064,0x81004010,0x4010008,0x2008020,0x40902409,0x2409024,
3003  0x8307090,0x24090240,0x82840828,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x90248222,0x30000802,0x200c,0xc080,0x21010301,
3004  0x4021042,0x10202108,0xc0c03000,0x80040020,0x4d902418,0xc6431004,0xc24082,0x6210440,0x10241884,0x40084409,0x86080840,0xc0842102,
3005  0x4002002,0x1000000,0x18e610,0x84218820,0x80864082,0x410408,0x9240884,0x61086101,0x6101860,0xc0842103,0x4002008,0x2000000,
3006  0x10850180,0x20330000,0x80200013,0x26184024,0x5040050,0x14000000,0x0,0x0,0x4180848,0x85040020,0x20350,0x40000200,0x800c0007,
3007  0x80002200,0x1e000,0x0,0x1860,0x48000000,0x880a,0x40a188,0x40902409,0x2409028,0x40c64010,0x4010008,0x2008020,0x43106210,0x84210842,
3008  0x10006108,0x42108421,0x2040102,0x6398e639,0x8e6398e4,0x88842088,0x22088208,0x2008020,0x21102210,0x84210842,0x10306118,0x66198661,
3009  0x83061030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0x901f01c1,0xe8000802,0xc,0xc080,0x1e07c7f8,0xf8020f81,0xe0401e07,
3010  0x80c03000,0x20,0x279027e0,0x3c7c1fe4,0x3c408f,0x83c1027f,0x90241878,0x4007c404,0xf8080780,0xc0844082,0x7f82002,0x1000000,
3011  0xfa5e0,0x781e87c0,0x807a409f,0xc0410207,0x9240878,0x5e07a100,0xf80e0fa0,0xc0846183,0x7f82008,0x2000000,0xf020100,0x40321360,
3012  0x80200014,0xa3e0201f,0x8207f820,0x8000000,0x0,0x0,0x3e01037,0x207f820,0x201e1,0xfc000200,0x80040000,0x0,0x0,0x1fc000,0x17b0,
3013  0x48000000,0x12,0xc120f0,0x40902409,0x2409028,0x783c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1061e0,0x781e0781,0xe000be07,0x81e0781e,
3014  0x204017c,0x3e8fa3e8,0xfa3e8fa3,0x70781f07,0xc1f07c7f,0x1fc7f1fc,0x1e1021e0,0x781e0781,0xe0007e0f,0xa3e8fa3e,0x8305e030,0x0,
3015  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,
3016  0x0,0x0,0x2001,0x1000000,0x0,0x0,0x20000,0x400000,0x0,0x40002000,0x0,0x1,0x2008,0x2000000,0x100,0x40240000,0x80200008,0x40000000,
3017  0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80040000,0x0,0x0,0x0,0x1000,0x48000000,0x1f,0x181f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3018  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,
3019  0x0,0x0,0x0,0x6000,0x0,0x10000000,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x3800,0x7000000,0x0,0x0,0x840000,0x400000,0x0,0x40002000,
3020  0x0,0x2,0x2008,0x2000000,0x200,0x40440000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80780000,0x0,0x0,0x0,0x1000,0x48000400,
3021  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,
3022  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,
3023  0x780000,0x3800000,0x0,0x40002000,0x0,0xe,0x1808,0xc000000,0x3,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,
3024  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,
3025  0x0,0x0,0x0,0x0,0x0,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,
3026  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,
3027  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3028 
3029  // Definition of a 12x24 font.
3030  const unsigned int font12x24[12*24*256/32] = {
3031  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3032  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,
3033  0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc001806,0xc81980,0x60000000,0xc001806,0x1980c00,0x18060198,0xc80c,
3034  0x180600,0xc8198000,0xc001,0x80601980,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3035  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3036  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,
3037  0x0,0x0,0x0,0x0,0x0,0x0,0x600300f,0x1301980,0x90000000,0x600300f,0x1980600,0x300f0198,0x13006,0x300f01,0x30198000,0x6003,
3038  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,
3039  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3040  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,
3041  0x80000000,0x90000000,0x3006019,0x80000300,0x60198000,0x3,0x601980,0x0,0x3006,0x1980000,0x60000000,0x0,0x0,0xe0000000,0x0,
3042  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3043  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,
3044  0x0,0x0,0x0,0x0,0x0,0xc800019,0x80000000,0x198000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x1001,0x420000,0x0,0x0,0x90000000,
3045  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000c06,0xc80001,0x10000000,0x18000c06,0x1800,0xc060000,0xc818,0xc0600,0xc8000000,
3046  0x18000,0xc0600000,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80660207,0x800f8060,0x300c004,0x0,0x6,
3047  0xe00703f,0x3f00383,0xf80f07fc,0x1f01f000,0x0,0xf8,0x607f,0x7c7e07,0xfe7fe0f8,0x6063fc1f,0x86066007,0xe7060f0,0x7f80f07f,
3048  0x81f8fff6,0x6606c03,0x70ee077f,0xe0786000,0xf0070000,0xc000060,0xc0,0x3e000,0x60006003,0x600fc00,0x0,0x0,0x0,0x0,0x0,0x3c0603,
3049  0xc0000000,0x7800000,0xf0000,0x0,0xf00001f,0x80001fe0,0x7fe000,0x0,0x0,0x0,0x168fe609,0x0,0x90e07,0x6000,0x3c000e,0x70000f8,
3050  0x1980001f,0x0,0x1f8,0xf00000f,0xf00180,0xfe000,0xe00e,0x1001,0x20060,0x6006006,0x600600,0x600fe07c,0x7fe7fe7f,0xe7fe3fc3,
3051  0xfc3fc3fc,0x7e07060f,0xf00f00,0xf00f0000,0xf360660,0x6606606e,0x76001e0,0xc00180f,0x1681981,0x10000000,0xc00180f,0x1980c00,
3052  0x180f0198,0x3801680c,0x180f01,0x68198000,0xc001,0x80f01980,0x18600198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,
3053  0x8044020c,0xc01f8060,0x2004004,0x0,0xc,0x3f81f07f,0x87f80383,0xf81f87fc,0x3f83f800,0x0,0x1fc,0x780607f,0x81fe7f87,0xfe7fe1fc,
3054  0x6063fc1f,0x860c6007,0xe7061f8,0x7fc1f87f,0xc3fcfff6,0x6606c03,0x30c6067f,0xe0783000,0xf00d8000,0x6000060,0xc0,0x7e000,0x60006003,
3055  0x600fc00,0x0,0x0,0xc00,0x0,0x0,0x7c0603,0xe0000000,0xfc00000,0x1f0000,0x0,0x900003f,0xc0003fe0,0x7fe000,0x0,0x0,0x0,0x1302660f,
3056  0x0,0xf0606,0x6004,0x7e0006,0x60601f8,0x19800001,0x80000000,0x1f8,0x19800010,0x81080300,0x3f2000,0x2011,0x1001,0x1c0060,0x6006006,
3057  0x600600,0x601fe1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f87061f,0x81f81f81,0xf81f8000,0x3fa60660,0x66066066,0x66003f0,0x6003009,
3058  0x1301981,0x10000000,0x6003009,0x1980600,0x30090198,0x1f013006,0x300901,0x30198000,0x6003,0x901980,0x30600198,0x0,0x0,0x0,
3059  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc0f8c,0xc0180060,0x6006044,0x40000000,0xc,0x3181b041,0xc41c0783,0x388018,
3060  0x71c71800,0x0,0x106,0x18c0f061,0xc38261c6,0x600384,0x60606001,0x86186007,0xe78630c,0x60e30c60,0xe7040606,0x630cc03,0x39c30c00,
3061  0xc0603000,0x3018c000,0x3000060,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,0x60000000,0x18400000,0x180000,
3062  0x0,0x19800070,0x40003600,0xc000,0x0,0x0,0x0,0x25a06,0x0,0x6030c,0x4,0xe20007,0xe060180,0xf000,0x80000000,0xf0000,0x10800000,
3063  0x80080600,0x7f2000,0x2020,0x80001001,0x20000,0xf00f00f,0xf00f00,0x601b0382,0x60060060,0x6000600,0x60060060,0x61c78630,0xc30c30c3,
3064  0xc30c000,0x30e60660,0x66066063,0xc600738,0x3006019,0x80000000,0xe0000000,0x3006019,0x80000300,0x60198000,0x3e000003,0x601980,
3065  0x0,0x3006,0x1980000,0x60600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc1fcc,0xc0180060,0x6006035,0x80000000,
3066  0x18,0x71c03000,0xc00c0583,0x300018,0x60c60c00,0x0,0x6,0x3060f060,0xc30060c6,0x600300,0x60606001,0x86306007,0x9e78670e,0x60670e60,
3067  0x66000606,0x630c606,0x19830c01,0xc0601800,0x30306000,0x60,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,
3068  0x60000000,0x18000000,0x300000,0x0,0x78060,0x6600,0x1c000,0x300c,0x39819c0,0x0,0x25a00,0x0,0x30c,0x4,0xc00003,0xc060180,0x30c1f,
3069  0x80000000,0x30c000,0x10800001,0x80700000,0x7f2000,0x2020,0x80001001,0x20060,0xf00f00f,0xf00f00,0xf01b0300,0x60060060,0x6000600,
3070  0x60060060,0x60c78670,0xe70e70e7,0xe70e000,0x70c60660,0x66066063,0xc7f8618,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0,
3071  0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x87ff3a4c,0xc0180060,0x400600e,0x600000,0x18,0x60c03000,
3072  0xc00c0d83,0x700018,0x60c60c00,0x20,0x400006,0x3060f060,0xc6006066,0x600600,0x60606001,0x86606006,0x966c6606,0x60660660,0x66000606,
3073  0x630c666,0xf019801,0x80601800,0x30603000,0x1f06f,0xf01ec0,0xf03fe1ec,0x6703e01f,0x61c0c06,0xdc6701f0,0x6f01ec0c,0xe1f87fc6,
3074  0xc60cc03,0x71c60c7f,0xc0600600,0x60000000,0x30000000,0x300000,0x40040,0x88060,0x6600,0x18000,0x300c,0x1981980,0x0,0x2421f,
3075  0x80003ce0,0x7fc198,0x601f,0xc02021,0x980600c0,0x40230,0x80000000,0x402000,0x19806003,0x80006,0xc7f2000,0x2020,0x80001001,
3076  0x420060,0xf00f00f,0xf00f00,0xf01b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x6606208,0x60e60660,0x66066061,
3077  0x987fc670,0x1f01f01f,0x1f01f01,0xf039c0f0,0xf00f00f,0xf03e03,0xe03e03e0,0x1f06701f,0x1f01f01,0xf01f0060,0x1e660c60,0xc60c60c6,
3078  0xc6f060c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x7ff3207,0x8c0c0000,0xc00300e,0x600000,0x30,0x60c03000,
3079  0xc01c0983,0xf0600030,0x31860c06,0x6001e0,0x78000e,0x23e1f861,0xc6006066,0x600600,0x60606001,0x86c06006,0x966c6606,0x60660660,
3080  0xe7000606,0x630c666,0xf01f803,0x600c00,0x30000000,0x3f87f,0x83f83fc3,0xf83fe3fc,0x7f83e01f,0x6380c07,0xfe7f83f8,0x7f83fc0d,
3081  0xf3fc7fc6,0xc71cc03,0x3183187f,0xc0600600,0x60000000,0xff806000,0x300000,0x40040,0x88070,0x6600,0x60030060,0x6001818,0x1883180,
3082  0x0,0x2423f,0xc0007ff0,0x607fc1f8,0x603f,0x80c01fc1,0xf80601e0,0x5f220,0x80420000,0x5f2000,0xf006006,0x80006,0xc7f2000,0x2020,
3083  0x82107c07,0xc03c0060,0x1f81f81f,0x81f81f80,0xf03b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x660671c,0x61660660,
3084  0x66066061,0xf860e6c0,0x3f83f83f,0x83f83f83,0xf87fe3f8,0x3f83f83f,0x83f83e03,0xe03e03e0,0x3f87f83f,0x83f83f83,0xf83f8060,
3085  0x3fc60c60,0xc60c60c3,0x187f8318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x883200,0x300c0000,0xc003035,0x80600000,
3086  0x30,0x66c03001,0xc0f81983,0xf86f0030,0x1f071c06,0x600787,0xfe1e001c,0x6261987f,0x86006067,0xfe7fc600,0x7fe06001,0x87c06006,
3087  0xf6646606,0x60e6067f,0xc3e00606,0x61986f6,0x600f007,0x600c00,0x30000000,0x21c71,0x830831c3,0x1c06031c,0x71c06003,0x6700c06,
3088  0x6671c318,0x71831c0f,0x16040c06,0xc318606,0x1b031803,0x80600600,0x60000000,0x30009000,0x300000,0x40040,0x7003e,0x67e0,0x90070090,
3089  0x9001818,0x8c3100,0x0,0x60,0x4000e730,0x900380f0,0x6034,0x80c018c7,0xfe060338,0xb0121,0x80c60000,0x909000,0x6008,0x1080006,
3090  0xc3f2000,0x2011,0x3180060,0x60060e0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0x60664660,0x66066066,
3091  0x66063b8,0x62660660,0x66066060,0xf06066c0,0x21c21c21,0xc21c21c2,0x1c466308,0x31c31c31,0xc31c0600,0x60060060,0x31871c31,0x83183183,
3092  0x18318000,0x71860c60,0xc60c60c3,0x18718318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1981a00,0xe03e0000,0xc003044,
3093  0x40600000,0x60,0x66c03001,0x80f03182,0x1c7f8030,0x3f83fc06,0x601e07,0xfe078038,0x6661987f,0x86006067,0xfe7fc61e,0x7fe06001,
3094  0x87e06006,0x66666606,0x7fc6067f,0x81f80606,0x61986f6,0x6006006,0x600600,0x30000000,0xc60,0xc60060c6,0xc06060c,0x60c06003,
3095  0x6e00c06,0x6660c60c,0x60c60c0e,0x6000c06,0xc318666,0x1f031803,0x600600,0x603c2000,0x30016800,0x1fe0000,0x1f81f8,0x1c1f,0x804067e1,
3096  0x68060168,0x16800810,0xc42300,0x0,0x60,0x20c331,0x68030060,0x6064,0x3fc1040,0xf006031c,0xa011e,0x818c7fe0,0x909000,0x7fe1f,
3097  0x80f00006,0xc0f2060,0xf80e,0x18c0780,0x780781c0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0xfc666660,
3098  0x66066066,0x66061f0,0x66660660,0x66066060,0x606066e0,0xc00c00,0xc00c00c0,0xc066600,0x60c60c60,0xc60c0600,0x60060060,0x60c60c60,
3099  0xc60c60c6,0xc60c000,0x61c60c60,0xc60c60c3,0x1860c318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1980f81,0x80373000,
3100  0xc003004,0x7fe0001,0xf0000060,0x60c03003,0x183180,0xc71c060,0x3181ec00,0x7000,0xe070,0x66619860,0xc6006066,0x60061e,0x60606001,
3101  0x87606006,0x66626606,0x7f860661,0xc01c0606,0x6198696,0xf00600e,0x600600,0x30000000,0x1fc60,0xc60060c7,0xfc06060c,0x60c06003,
3102  0x7c00c06,0x6660c60c,0x60c60c0c,0x7f00c06,0xc3b8666,0xe01b007,0x3c00600,0x3c7fe000,0xff03ec00,0x1fe0000,0x40040,0xe001,0xc0806603,
3103  0xec0e03ec,0x3ec00010,0x0,0x60000000,0x7f,0x10c3f3,0xec070060,0x6064,0x3fc1040,0x6000030c,0xa0100,0x3187fe1,0xf09f1000,0x7fe00,
3104  0x6,0xc012060,0x0,0xc63c03,0xc03c0380,0x19819819,0x81981981,0x98330600,0x60060060,0x6000600,0x60060060,0xfc662660,0x66066066,
3105  0x66060e0,0x6c660660,0x66066060,0x6060e630,0x1fc1fc1f,0xc1fc1fc1,0xfc3fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
3106  0xc60c7fe,0x62c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe02c6,0x3c633000,0xc003004,
3107  0x7fe0001,0xf00000c0,0x60c03006,0xc6180,0xc60c060,0x60c00c00,0x7000,0xe060,0x66639c60,0x66006066,0x600606,0x60606001,0x86306006,
3108  0x66636606,0x60060660,0xc0060606,0x61f8696,0xf00600c,0x600300,0x30000000,0x3fc60,0xc60060c7,0xfc06060c,0x60c06003,0x7c00c06,
3109  0x6660c60c,0x60c60c0c,0x1f80c06,0xc1b0666,0xe01b00e,0x3c00600,0x3c43c000,0x3007de00,0x600000,0x40040,0x30000,0x61006607,0xde0c07de,
3110  0x7de00000,0x0,0xf07fefff,0x1f,0x8008c3f7,0xde0e0060,0x6064,0xc01047,0xfe00018c,0xb013f,0x86300061,0xf0911000,0x6000,0x6,
3111  0xc012060,0x3f,0x8063c0cc,0x3cc0c700,0x39c39c39,0xc39c39c1,0x98630600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,
3112  0x66061f0,0x78660660,0x66066060,0x607fc618,0x3fc3fc3f,0xc3fc3fc3,0xfc7fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
3113  0xc60c7fe,0x64c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe0260,0x6661b000,0xc003000,
3114  0x600000,0xc0,0x60c0300c,0xc7fe0,0xc60c060,0x60c01c00,0x1e07,0xfe078060,0x6663fc60,0x66006066,0x600606,0x60606001,0x86386006,
3115  0x6636606,0x60060660,0xe0060606,0x60f039c,0x1b806018,0x600300,0x30000000,0x70c60,0xc60060c6,0x6060c,0x60c06003,0x7600c06,
3116  0x6660c60c,0x60c60c0c,0x1c0c06,0xc1b03fc,0xe01f01c,0xe00600,0x70000000,0x3007fc00,0x600000,0x40040,0x0,0x62006607,0xfc1807fc,
3117  0x7fc00000,0x0,0xf0000000,0x1,0xc004c307,0xfc1c0060,0x6064,0xc018c0,0x600000d8,0x5f200,0x3180060,0x50a000,0x6000,0x6,0xc012000,
3118  0x0,0xc601c0,0x4201c600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,0x66063b8,
3119  0x70660660,0x66066060,0x607f860c,0x70c70c70,0xc70c70c7,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,
3120  0x68c60c60,0xc60c60c1,0xf060c1f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3300260,0x6661e000,0xc003000,0x600000,
3121  0x180,0x71c03018,0xc7fe0,0xc60c0c0,0x60c01800,0x787,0xfe1e0060,0x6663fc60,0x630060c6,0x600306,0x60606001,0x86186006,0x661e70e,
3122  0x60070c60,0x60060606,0x60f039c,0x19806038,0x600180,0x30000000,0x60c60,0xc60060c6,0x6060c,0x60c06003,0x6700c06,0x6660c60c,
3123  0x60c60c0c,0xc0c06,0xc1b039c,0x1f00e018,0x600600,0x60000000,0x1803f800,0x600000,0x40040,0x39e00,0x63006603,0xf83803f8,0x3f800000,
3124  0x0,0x60000000,0x0,0xc00cc303,0xf8180060,0x6064,0xc01fc0,0x60060070,0x40200,0x18c0060,0x402000,0x6000,0x6,0xc012000,0x0,0x18c0140,
3125  0x2014600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0300,0x60060060,0x6000600,0x60060060,0x60c61e70,0xe70e70e7,0xe70e71c,0x60e60660,0x66066060,
3126  0x6060060c,0x60c60c60,0xc60c60c6,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,0x70c60c60,0xc60c60c0,
3127  0xe060c0e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33022e0,0x6670c000,0xc003000,0x600600,0x60180,0x31803030,
3128  0x41c0184,0x1831c0c0,0x71c23806,0x6001e0,0x780000,0x62630c60,0xe38261c6,0x600386,0x60606043,0x860c6006,0x661e30c,0x60030c60,
3129  0x740e0607,0xe0f039c,0x31c06030,0x600180,0x30000000,0x61c71,0x830831c3,0x406031c,0x60c06003,0x6300c06,0x6660c318,0x71831c0c,
3130  0x41c0c07,0x1c0e039c,0x1b00e030,0x600600,0x60000000,0x1c41b00e,0x601cc0,0x401f8,0x45240,0xe1803601,0xb03001b0,0x1b000000,
3131  0x0,0x0,0x41,0xc008e711,0xb0300060,0x6034,0x80c02020,0x60060030,0x30c00,0xc60000,0x30c000,0x0,0x7,0x1c012000,0x0,0x3180240,
3132  0x6024608,0x30c30c30,0xc30c30c3,0xc630382,0x60060060,0x6000600,0x60060060,0x61c61e30,0xc30c30c3,0xc30c208,0x70c70e70,0xe70e70e0,
3133  0x6060068c,0x61c61c61,0xc61c61c6,0x1cc62308,0x30430430,0x43040600,0x60060060,0x31860c31,0x83183183,0x18318060,0x31c71c71,
3134  0xc71c71c0,0xe07180e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2203fc0,0x663f6000,0x6006000,0x600600,0x60300,
3135  0x3f81fe7f,0xc7f80187,0xf83f80c0,0x3f83f006,0x600020,0x400060,0x33e6067f,0xc1fe7f87,0xfe6001fe,0x6063fc7f,0x60e7fe6,0x660e3f8,
3136  0x6001f860,0x37fc0603,0xfc06030c,0x30c0607f,0xe06000c0,0x30000000,0x7fc7f,0x83f83fc3,0xfc0603fc,0x60c7fe03,0x61807c6,0x6660c3f8,
3137  0x7f83fc0c,0x7f80fc3,0xfc0e039c,0x3180607f,0xc0600600,0x60000000,0xfc0e00c,0x601986,0x66040040,0x4527f,0xc0803fe0,0xe07fe0e0,
3138  0xe000000,0x0,0x0,0x7f,0x80107ff0,0xe07fc060,0x603f,0x83fe0000,0x60060018,0xf000,0x420000,0xf0000,0x7fe00,0x7,0xfe012000,
3139  0x0,0x2100640,0xc0643f8,0x60660660,0x66066067,0xec3e1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f860e3f,0x83f83f83,0xf83f8000,
3140  0x5fc3fc3f,0xc3fc3fc0,0x606006fc,0x7fc7fc7f,0xc7fc7fc7,0xfcffe3f8,0x3fc3fc3f,0xc3fc7fe7,0xfe7fe7fe,0x3f860c3f,0x83f83f83,
3141  0xf83f8060,0x7f83fc3f,0xc3fc3fc0,0x607f8060,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2201f80,0x3c1e7000,0x6006000,
3142  0x600,0x60300,0xe01fe7f,0xc3f00183,0xe01f0180,0x1f01e006,0x600000,0x60,0x3006067f,0x807c7e07,0xfe6000f8,0x6063fc3e,0x6067fe6,
3143  0x660e0f0,0x6000f060,0x3bf80601,0xf806030c,0x60e0607f,0xe06000c0,0x30000000,0x1ec6f,0xf01ec0,0xf80601ec,0x60c7fe03,0x61c03c6,
3144  0x6660c1f0,0x6f01ec0c,0x3f007c1,0xcc0e030c,0x71c0c07f,0xc0600600,0x60000000,0x7804018,0xe01186,0x66040040,0x39e3f,0x80401fe0,
3145  0x407fe040,0x4000000,0x0,0x0,0x3f,0x203ce0,0x407fc060,0x601f,0x3fe0000,0x60060018,0x0,0x0,0x0,0x7fe00,0x6,0xe6012000,0x0,
3146  0x7e0,0x1807e1f0,0x60660660,0x66066066,0x6c3e07c,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7e060e0f,0xf00f00,0xf00f0000,0x8f01f81f,
3147  0x81f81f80,0x60600670,0x1ec1ec1e,0xc1ec1ec1,0xec79c0f0,0xf80f80f,0x80f87fe7,0xfe7fe7fe,0x1f060c1f,0x1f01f01,0xf01f0000,0x4f01cc1c,
3148  0xc1cc1cc0,0xc06f00c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x6006000,0x600,0x600,0x0,0x0,0x0,0x0,
3149  0x600000,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x600060,0x30000000,0x0,0x0,0xc,0x3,0x0,0x0,0x60000c00,0x0,
3150  0x0,0xc000,0x600600,0x60000000,0x18,0xc03100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f8,0x0,0x0,0x0,0x0,0x6,
3151  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,
3152  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,
3153  0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0xc00,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x21c,0x3,0x0,0x0,0x60000c00,0x0,0x0,0xc000,
3154  0x7c0603,0xe0000000,0x10,0xc02300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f0,0x0,0x0,0x0,0x0,0x6,0x12000,0x1000000,
3155  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,
3156  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,
3157  0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x3f8,0x3e,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x3c0603,0xc0000000,
3158  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,
3159  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,
3160  0x0,0x0,0x0,0x0,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,
3161  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,
3162  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,
3163  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,
3164  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,
3165  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3166  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3167 
3168  // Definition of a 16x32 font.
3169  const unsigned int font16x32[16*32*256/32] = {
3170  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3171  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3172  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,
3173  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70000e0,0x3c00730,0xe7001c0,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0x730,0x70000e0,0x3c00730,
3174  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,
3175  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3176  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3177  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,
3178  0x0,0x0,0x18001c0,0x6600ff0,0xe7003e0,0x0,0x18001c0,0x6600e70,0x18001c0,0x6600e70,0xff0,0x18001c0,0x6600ff0,0xe700000,0x180,
3179  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,
3180  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3181  0x0,0x0,0x0,0x0,0x0,0x0,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,
3182  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,
3183  0xc300ce0,0xe700630,0x0,0x1c00380,0xc300e70,0x1c00380,0xc300e70,0xce0,0x1c00380,0xc300ce0,0xe700000,0x1c0,0x3800c30,0xe700380,
3184  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,
3185  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3186  0x0,0x0,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,
3187  0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x700000,0x0,0x0,0x0,0x7c007c00,0x3e000000,
3188  0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000070,0x1800000,0xc60,0x0,0xe000070,0x1800000,0xe000070,
3189  0x1800000,0x0,0xe000070,0x1800000,0x0,0xe00,0x700180,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3190  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,
3191  0x0,0x0,0x3f0,0xfc0,0x0,0x7000000,0x38000000,0x1c0000,0xfc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,
3192  0x1801f00,0x0,0x0,0x1c,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7300000,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0xe700000,
3193  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,
3194  0xf80,0x70000e0,0x3c00730,0xe700c60,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0xe000730,0x70000e0,0x3c00730,0xe700000,0x700,
3195  0xe003c0,0xe7000e0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300000,0x803c00,0x7c00180,
3196  0xc00300,0x1000000,0x0,0x1c,0x3c007c0,0xfc007e0,0xe01ff8,0x3f03ffc,0x7e007c0,0x0,0x0,0x7c0,0x1c0,0x7f8003f0,0x7f007ff8,0x7ff803f0,
3197  0x70381ffc,0xff0700e,0x7000783c,0x783807c0,0x7fc007c0,0x7fc00fc0,0x7fff7038,0x700ee007,0x780f780f,0x7ffc03f0,0x70000fc0,0x3c00000,
3198  0x3000000,0x38000000,0x1c0000,0x1fc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x1801f80,0x0,0x1f80000,
3199  0x7e,0x0,0x0,0x2400000,0xfc00000,0x7ff0000,0x7ffc0000,0x0,0x0,0x0,0x0,0xf30fb0c,0x2400000,0x0,0x240780f,0x1c0,0xfc,0x780f,
3200  0x18003f0,0xe700000,0x7c00000,0x0,0xff0,0x3c00000,0x78007c0,0xc00000,0xff80000,0xf80,0x7c00000,0xc000c00,0x18001c0,0x1c001c0,
3201  0x1c001c0,0x1c003e0,0x7fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007838,0x7c007c0,0x7c007c0,0x7c00000,0x7c67038,
3202  0x70387038,0x7038780f,0x70001fe0,0x30000c0,0x2400f30,0xe700c60,0x0,0x30000c0,0x2400e70,0x30000c0,0x2400e70,0xf700f30,0x30000c0,
3203  0x2400f30,0xe700000,0x300,0xc00240,0xe7000c0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,
3204  0x630018c,0x807e00,0xfe00180,0xc00300,0x1000000,0x0,0x38,0xff01fc0,0x3ff01ff0,0x1e01ff8,0x7f83ffc,0x1ff80ff0,0x0,0x0,0xff0,
3205  0x1f003e0,0x7fe00ff8,0x7fc07ff8,0x7ff80ff8,0x70381ffc,0xff0701c,0x7000783c,0x78381ff0,0x7fe01ff0,0x7fe01ff0,0x7fff7038,0x781ee007,
3206  0x3c1e380e,0x7ffc0380,0x380001c0,0x3c00000,0x1800000,0x38000000,0x1c0000,0x3c00000,0x380001c0,0xe01c00,0x3800000,0x0,0x0,
3207  0x0,0x7000000,0x0,0x0,0x1e0,0x18003c0,0x0,0x3fc0000,0x70,0x0,0x0,0x6600000,0x1ff00000,0x1fff0000,0x7ffc0000,0x0,0x0,0x0,0x0,
3208  0xcf0239c,0x3c00000,0x0,0x3c0380e,0x1c0,0x2001fe,0x380e,0x18007f8,0xe700000,0x8600000,0x0,0xff0,0x7e00000,0x8c00870,0x1800000,
3209  0x1ff80000,0x180,0xc600000,0xc000c00,0x38001c0,0x3e003e0,0x3e003e0,0x3e001c0,0x7fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,
3210  0x7fc07838,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x1fec7038,0x70387038,0x7038380e,0x70003ce0,0x1800180,0x6600cf0,0xe7007c0,0x0,
3211  0x1800180,0x6600e70,0x1800180,0x6600e70,0x7c00cf0,0x1800180,0x6600cf0,0xe700000,0x180,0x1800660,0xe700180,0x38000e70,0x0,
3212  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630030c,0x3f0e700,0x1e200180,0x1800180,0x21100000,0x0,
3213  0x38,0x1e7819c0,0x38781038,0x1e01c00,0xf080038,0x1c381c38,0x0,0x0,0x1878,0x7fc03e0,0x70e01e18,0x70e07000,0x70001e18,0x703801c0,
3214  0x707038,0x70007c7c,0x7c381c70,0x70701c70,0x70703830,0x1c07038,0x381ce007,0x1c1c3c1e,0x3c0380,0x380001c0,0x7e00000,0xc00000,
3215  0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,0x70c0000,0xe0,
3216  0x0,0x0,0xc300000,0x38300000,0x3c700000,0x3c0000,0x0,0x0,0x0,0x0,0xce022f4,0x1800000,0x0,0x1803c1e,0x1c0,0x2003c2,0x3c1e,
3217  0x1800e08,0x7e0,0x300000,0x0,0x7e00000,0xe700000,0x600030,0x3000000,0x3f980000,0x180,0x18200000,0xc000c00,0x1e0001c0,0x3e003e0,
3218  0x3e003e0,0x3e003e0,0xfe01e18,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70e07c38,0x1c701c70,0x1c701c70,0x1c700000,0x3c787038,
3219  0x70387038,0x70383c1e,0x70003870,0xc00300,0xc300ce0,0x380,0x0,0xc00300,0xc300000,0xc00300,0xc300000,0xfc00ce0,0xc00300,0xc300ce0,
3220  0x0,0xc0,0x3000c30,0x300,0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630031c,0xff8c300,
3221  0x1c000180,0x1800180,0x39380000,0x0,0x70,0x1c3801c0,0x203c001c,0x3e01c00,0x1c000038,0x381c3838,0x0,0x0,0x1038,0xe0e03e0,0x70703c08,
3222  0x70707000,0x70003808,0x703801c0,0x707070,0x70007c7c,0x7c383838,0x70383838,0x70387010,0x1c07038,0x381c700e,0x1e3c1c1c,0x780380,
3223  0x1c0001c0,0xe700000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,
3224  0x0,0xe000000,0xe0,0x0,0x1000100,0x3800,0x70100000,0x38700000,0x780000,0x1c0,0x7801ce0,0xe380000,0x0,0x2264,0x0,0x0,0x1c1c,
3225  0x0,0x200780,0x1c1c,0x1800c00,0x1818,0x7f00000,0x0,0x18180000,0xc300000,0x600070,0x0,0x7f980000,0x180,0x18300000,0xc000c00,
3226  0x3000000,0x3e003e0,0x3e003e0,0x3e003e0,0xee03c08,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,
3227  0x38380000,0x38387038,0x70387038,0x70381c1c,0x7fc03870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbc00000,0x0,0x0,0x0,0x0,0x0,0x0,
3228  0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0xe88c300,0x1c000180,0x38001c0,
3229  0xfe00180,0x0,0x70,0x1c3801c0,0x1c001c,0x6e01c00,0x1c000078,0x381c3818,0x0,0x40000,0x40000038,0x1c0607e0,0x70703800,0x70707000,
3230  0x70003800,0x703801c0,0x7070e0,0x70007c7c,0x7c383838,0x70383838,0x70387000,0x1c07038,0x381c700e,0xf780e38,0x700380,0x1c0001c0,
3231  0x1c380000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,
3232  0xe000000,0xe0,0x0,0x1000100,0x4400,0x70000000,0x38700000,0x700000,0xe0,0x7001c70,0xe380000,0x0,0x2264,0x0,0x0,0xe38,0x0,
3233  0x200700,0xe38,0x1800c00,0x300c,0xc300000,0x0,0x300c0000,0xc300180,0x6003c0,0x0,0x7f980000,0x180,0x18300000,0xc000c00,0x1800000,
3234  0x7e007e0,0x7e007e0,0x7e003e0,0xee03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,0x38380000,
3235  0x38387038,0x70387038,0x70380e38,0x7ff039f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x40000,0x0,0x0,0x38000000,
3236  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0x1c80e700,0x1c000180,0x38001c0,0x3800180,
3237  0x0,0xe0,0x381c01c0,0x1c001c,0x6e01c00,0x38000070,0x381c381c,0x0,0x3c0000,0x78000078,0x38030770,0x70707800,0x70387000,0x70007000,
3238  0x703801c0,0x7071c0,0x7000745c,0x7638701c,0x7038701c,0x70387000,0x1c07038,0x1c38718e,0x7700f78,0xf00380,0xe0001c0,0x381c0000,
3239  0x7e0,0x39e003e0,0x79c03f0,0x3ffc079c,0x39e01fc0,0xfe01c1e,0x3807778,0x39e007e0,0x39e0079c,0x73c07e0,0x7ff83838,0x701ce007,
3240  0x783c701c,0x1ffc01c0,0x18001c0,0x0,0x1c000100,0xe0,0x0,0x1000100,0x4200,0x70000000,0x70700100,0xf00100,0x10000e0,0x7000c70,
3241  0xc700000,0x0,0x2204,0x7e00000,0x1e380100,0x1ffc0f78,0x0,0xf80700,0xf78,0x1800e00,0x63e6,0x18300000,0x0,0x6fe60000,0xe700180,
3242  0xc00060,0x3838,0x7f980000,0x180,0x18300000,0xc000c00,0x18001c0,0x7700770,0x7700770,0x77007f0,0xee07800,0x70007000,0x70007000,
3243  0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1008,0x707c7038,0x70387038,0x70380f78,0x707039c0,0x7e007e0,0x7e007e0,
3244  0x7e007e0,0x1f3c03e0,0x3f003f0,0x3f003f0,0x1fc01fc0,0x1fc01fc0,0x7f039e0,0x7e007e0,0x7e007e0,0x7e00380,0x7ce3838,0x38383838,
3245  0x3838701c,0x39e0701c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6307fff,0x1c807e0c,0xe000180,
3246  0x30000c0,0x3800180,0x0,0xe0,0x381c01c0,0x1c001c,0xce01fe0,0x38000070,0x381c381c,0x3800380,0xfc0000,0x7e0000f0,0x30030770,
3247  0x70707000,0x70387000,0x70007000,0x703801c0,0x707380,0x700076dc,0x7638701c,0x7038701c,0x70387800,0x1c07038,0x1c3873ce,0x7f00770,
3248  0xe00380,0xe0001c0,0x700e0000,0x1ff8,0x3ff00ff0,0xffc0ff8,0x3ffc0ffc,0x3bf01fc0,0xfe01c3c,0x3807f78,0x3bf00ff0,0x3ff00ffc,
3249  0x77e0ff0,0x7ff83838,0x3838e007,0x3c783838,0x1ffc01c0,0x18001c0,0x0,0x7ff00380,0x1e0,0x0,0x1000100,0x4200,0x78000000,0x70700380,
3250  0xe00380,0x3800060,0xe000e30,0x1c600000,0x0,0x2204,0xff00000,0x7f7c0380,0x1ffc0770,0x1c0,0x3fc0700,0x18040770,0x1800780,0x4e12,
3251  0x18300104,0x0,0x4c320000,0x7e00180,0x1c00030,0x3838,0x7f980000,0x180,0x18302080,0xc000c00,0x18001c0,0x7700770,0x7700770,
3252  0x7700770,0x1ee07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c381c,0x705c7038,0x70387038,
3253  0x70380770,0x70383b80,0x1ff81ff8,0x1ff81ff8,0x1ff81ff8,0x3fbe0ff0,0xff80ff8,0xff80ff8,0x1fc01fc0,0x1fc01fc0,0xff83bf0,0xff00ff0,
3254  0xff00ff0,0xff00380,0xffc3838,0x38383838,0x38383838,0x3ff03838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3255  0x0,0x1c0,0x7fff,0x1c803c38,0xf000000,0x70000e0,0xfe00180,0x0,0x1c0,0x381c01c0,0x3c0078,0xce01ff0,0x39e000f0,0x1c38381c,0x3800380,
3256  0x3e07ffc,0xf8001f0,0x307b0770,0x70e07000,0x70387000,0x70007000,0x703801c0,0x707700,0x700076dc,0x7638701c,0x7038701c,0x70387e00,
3257  0x1c07038,0x1c3873ce,0x3e007f0,0x1e00380,0x70001c0,0x0,0x1038,0x3c381e18,0x1c7c1e3c,0x3801e3c,0x3c7801c0,0xe01c78,0x380739c,
3258  0x3c781c38,0x3c381c3c,0x7c21e10,0x7003838,0x3838700e,0x1ef03838,0x3c01c0,0x18001c0,0x0,0x7fe007c0,0x1c0,0x0,0x1000100,0x6400,
3259  0x7e000000,0x707007c0,0x1e007c0,0x7c00070,0xe000638,0x18600000,0x0,0x0,0x1e100000,0x73ce07c0,0x3c07f0,0x1c0,0x7240700,0x1ddc3ffe,
3260  0x1800de0,0x8c01,0x1870030c,0x0,0x8c310000,0x3c00180,0x3800030,0x3838,0x7f980000,0x180,0x183030c0,0xc000c00,0x430001c0,0x7700770,
3261  0x7700770,0x7700770,0x1ce07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1c38,0x70dc7038,
3262  0x70387038,0x703807f0,0x70383b80,0x10381038,0x10381038,0x10381038,0x21e71e18,0x1e3c1e3c,0x1e3c1e3c,0x1c001c0,0x1c001c0,0x1e383c78,
3263  0x1c381c38,0x1c381c38,0x1c380380,0x1c383838,0x38383838,0x38383838,0x3c383838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3264  0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0x1e8000e0,0x1f000000,0x70000e0,0x39380180,0x0,0x1c0,0x3b9c01c0,0x3c07f0,0x18e01078,0x3bf800e0,
3265  0x7e0383c,0x3800380,0x1f807ffc,0x3f001c0,0x61ff0e38,0x7fc07000,0x70387ff0,0x7ff07000,0x7ff801c0,0x707f00,0x7000729c,0x7338701c,
3266  0x7070701c,0x70703fc0,0x1c07038,0x1e7873ce,0x1c003e0,0x3c00380,0x70001c0,0x0,0x1c,0x3c381c00,0x1c3c1c1c,0x3801c3c,0x383801c0,
3267  0xe01cf0,0x380739c,0x38381c38,0x3c381c3c,0x7801c00,0x7003838,0x3838700e,0xfe03c78,0x7801c0,0x18001c0,0x0,0x1c000c20,0xff8,
3268  0x0,0x1ff01ff0,0x3818,0x3fc00100,0x707e0c20,0x3c00c20,0xc200030,0xc000618,0x18c00000,0x0,0x0,0x1c000080,0xe1ce0c20,0x7803e0,
3269  0x1c0,0xe200700,0xff83ffe,0x1801878,0x9801,0x1cf0071c,0x7ffc0000,0x8c310000,0x7ffe,0x7000030,0x3838,0x3f980380,0x180,0xc6038e0,
3270  0x7f9c7f9c,0x3e1c01c0,0xe380e38,0xe380e38,0xe380f78,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,0x1c001c0,0xfe387338,0x701c701c,
3271  0x701c701c,0x701c0e70,0x719c7038,0x70387038,0x703803e0,0x70383b80,0x1c001c,0x1c001c,0x1c001c,0xe71c00,0x1c1c1c1c,0x1c1c1c1c,
3272  0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380000,0x3c383838,0x38383838,0x38383c78,0x3c383c78,0x0,0x0,0x0,0x0,
3273  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0xf800380,0x3f830000,0x70000e0,0x31080180,0x0,0x380,0x3b9c01c0,
3274  0x7807e0,0x38e00038,0x3c3800e0,0xff01c3c,0x3800380,0x7c000000,0x7c03c0,0x61870e38,0x7fc07000,0x70387ff0,0x7ff070fc,0x7ff801c0,
3275  0x707f80,0x7000739c,0x7338701c,0x7ff0701c,0x7fe00ff0,0x1c07038,0xe7073ce,0x1c003e0,0x3800380,0x38001c0,0x0,0x1c,0x381c3800,
3276  0x381c380e,0x380381c,0x383801c0,0xe01de0,0x380739c,0x3838381c,0x381c381c,0x7001e00,0x7003838,0x1c70718e,0x7e01c70,0xf00380,
3277  0x18001e0,0x1e000000,0x1c001bb0,0xff8,0x0,0x1000100,0xe0,0xff00300,0x707e1bb0,0x3801bb0,0x1bb00010,0x8000308,0x30c00000,0x0,
3278  0x0,0x1e0000c0,0xe1ce1bb0,0xf003e0,0x1c0,0x1c203ff8,0x63003e0,0x180181c,0x9801,0xfb00e38,0x7ffc0000,0x8fc10000,0x7ffe,0xe000860,
3279  0x3838,0x1f980380,0x180,0x7c01c70,0x1f001f0,0x1f003c0,0xe380e38,0xe380e38,0xe380e38,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,
3280  0x1c001c0,0xfe387338,0x701c701c,0x701c701c,0x701c07e0,0x731c7038,0x70387038,0x703803e0,0x70383980,0x1c001c,0x1c001c,0x1c001c,
3281  0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x387c3838,0x38383838,0x38381c70,
3282  0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc30,0x7f00e00,0x33c30000,0x70000e0,0x1007ffe,
3283  0x0,0x380,0x3b9c01c0,0xf00078,0x30e0001c,0x3c1c01c0,0x1c381fdc,0x0,0x70000000,0x1c0380,0x63030e38,0x70707000,0x70387000,0x700070fc,
3284  0x703801c0,0x707b80,0x7000739c,0x7338701c,0x7fc0701c,0x7fc001f0,0x1c07038,0xe703e5c,0x3e001c0,0x7800380,0x38001c0,0x0,0x7fc,
3285  0x381c3800,0x381c380e,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7001fc0,0x7003838,0x1c70718e,0x7c01c70,
3286  0xe01f00,0x180007c,0x7f8c0000,0x7fc03fb8,0x1c0,0x0,0x1000100,0x700,0x1f00600,0x70703fb8,0x7803fb8,0x3fb80000,0x8000000,0x180,
3287  0x0,0x0,0x1fc00060,0xe1ce3fb8,0xe001c0,0x1c0,0x1c203ff8,0xc1801c0,0x180c,0x9801,0x1c70,0xc0000,0x8cc10000,0x180,0xfe007c0,
3288  0x3838,0x7980380,0xff0,0xe38,0x3e003e00,0x3e000380,0xe380e38,0xe380e38,0xe380e38,0x38e07000,0x70007000,0x70007000,0x1c001c0,
3289  0x1c001c0,0x70387338,0x701c701c,0x701c701c,0x701c03c0,0x731c7038,0x70387038,0x703801c0,0x703838e0,0x7fc07fc,0x7fc07fc,0x7fc07fc,
3290  0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x38dc3838,0x38383838,0x38381c70,
3291  0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc60,0xf83878,0x71e30000,0x70000e0,0x1007ffe,
3292  0x7f0,0x380,0x381c01c0,0x1e0003c,0x60e0001c,0x381c01c0,0x381c079c,0x0,0x7c000000,0x7c0380,0x63031c1c,0x70307000,0x70387000,
3293  0x7000701c,0x703801c0,0x7071c0,0x7000739c,0x71b8701c,0x7000701c,0x71e00078,0x1c07038,0xe703e7c,0x7e001c0,0xf000380,0x38001c0,
3294  0x0,0x1ffc,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fc0,0x380739c,0x3838381c,0x381c381c,0x7000ff0,0x7003838,0x1ef03bdc,
3295  0x3800ee0,0x1e01f00,0x180007c,0x61fc0000,0x7fc07f3c,0x1c0,0x0,0x1000100,0x1800,0x780c00,0x70707f3c,0xf007f3c,0x7f3c0000,0x0,
3296  0x3c0,0x3ffcffff,0x0,0xff00030,0xe1fe7f3c,0x1e001c0,0x1c0,0x1c200700,0xc183ffe,0xe0c,0x9801,0x1ff038e0,0xc07f0,0x8c610000,
3297  0x180,0x0,0x3838,0x1980380,0x0,0x1ff0071c,0xe000e000,0xe0000f80,0x1c1c1c1c,0x1c1c1c1c,0x1c1c1e38,0x38e07000,0x70007000,0x70007000,
3298  0x1c001c0,0x1c001c0,0x703871b8,0x701c701c,0x701c701c,0x701c03c0,0x761c7038,0x70387038,0x703801c0,0x70703870,0x1ffc1ffc,0x1ffc1ffc,
3299  0x1ffc1ffc,0xfff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x389c3838,0x38383838,
3300  0x38380ee0,0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xfffc,0xbc60fc,0x70e30000,0x70000e0,
3301  0x180,0x7f0,0x700,0x381c01c0,0x3e0001c,0x7ffc001c,0x381c03c0,0x381c001c,0x0,0x1f807ffc,0x3f00380,0x63031ffc,0x70387000,0x70387000,
3302  0x7000701c,0x703801c0,0x7071e0,0x7000701c,0x71b8701c,0x7000701c,0x70f00038,0x1c07038,0x7e03e7c,0x77001c0,0xe000380,0x1c001c0,
3303  0x0,0x3c1c,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x70003f8,0x7003838,0xee03bdc,
3304  0x3c00ee0,0x3c00380,0x18000e0,0xf00000,0x1c007e7c,0x3c0,0x0,0x1000100,0x0,0x381800,0x70707e7c,0xe007e7c,0x7e7c0000,0x0,0x7c0,
3305  0x0,0x0,0x3f80018,0xe1fe7e7c,0x3c001c0,0x1c0,0x1c200700,0xc183ffe,0xf0c,0x8c01,0x38e0,0xc07f0,0x8c710000,0x180,0x0,0x3838,
3306  0x1980000,0x0,0x71c,0x7000f0,0x700f00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x3fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
3307  0x703871b8,0x701c701c,0x701c701c,0x701c07e0,0x7c1c7038,0x70387038,0x703801c0,0x7ff03838,0x3c1c3c1c,0x3c1c3c1c,0x3c1c3c1c,
3308  0x3fff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x391c3838,0x38383838,0x38380ee0,
3309  0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffc,0x9c01ce,0x70f60000,0x70000e0,0x180,
3310  0x0,0x700,0x381c01c0,0x780001c,0x7ffc001c,0x381c0380,0x381c003c,0x0,0x3e07ffc,0xf800380,0x63031ffc,0x70387000,0x70387000,
3311  0x7000701c,0x703801c0,0x7070f0,0x7000701c,0x71b8701c,0x7000701c,0x70700038,0x1c07038,0x7e03e7c,0xf7801c0,0x1e000380,0x1c001c0,
3312  0x0,0x381c,0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7000078,0x7003838,0xee03a5c,
3313  0x7c00fe0,0x78001c0,0x18001c0,0x0,0x1c003ef8,0x380,0x0,0x1000100,0x810,0x383000,0x70703ef8,0x1e003ef8,0x3ef80000,0x0,0x7c0,
3314  0x0,0x0,0x78000c,0xe1c03ef8,0x78001c0,0x1c0,0x1c200700,0x63001c0,0x18003f8,0x4e12,0x1c70,0xc0000,0x4c320000,0x180,0x0,0x3838,
3315  0x1980000,0x0,0xe38,0x700118,0x701e00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x7fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
3316  0x703871b8,0x701c701c,0x701c701c,0x701c0e70,0x7c1c7038,0x70387038,0x703801c0,0x7fc0381c,0x381c381c,0x381c381c,0x381c381c,
3317  0x78e03800,0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x3b1c3838,0x38383838,0x38380fe0,
3318  0x381c0fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1860,0x9c0186,0x707e0000,0x30000c0,0x180,
3319  0x0,0xe00,0x183801c0,0xf00001c,0xe0001c,0x181c0380,0x381c0038,0x0,0xfc0000,0x7e000000,0x61873c1e,0x70383800,0x70707000,0x7000381c,
3320  0x703801c0,0x707070,0x7000701c,0x70f83838,0x70003838,0x70780038,0x1c07038,0x7e03c3c,0xe3801c0,0x1c000380,0xe001c0,0x0,0x381c,
3321  0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01ef0,0x380739c,0x3838381c,0x381c381c,0x7000038,0x7003838,0xfe03e7c,0xfe007c0,
3322  0x70001c0,0x18001c0,0x0,0xe001ff0,0x380,0x0,0x1000100,0x162c,0x381800,0x30701ff0,0x1c001ff0,0x1ff00000,0x0,0x3c0,0x0,0x0,
3323  0x380018,0xe1c01ff0,0x70001c0,0x1c0,0x1c200700,0xff801c0,0x18000f0,0x63e6,0xe38,0x0,0x6c3e0000,0x0,0x0,0x3838,0x1980000,0x0,
3324  0x1c70,0xf0000c,0xf01c00,0x3c1e3c1e,0x3c1e3c1e,0x3c1e3c1c,0x70e03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x707070f8,
3325  0x38383838,0x38383838,0x38381c38,0x38387038,0x70387038,0x703801c0,0x7000381c,0x381c381c,0x381c381c,0x381c381c,0x70e03800,
3326  0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0380,0x3e1c3838,0x38383838,0x383807c0,0x381c07c0,
3327  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18c0,0x9c0186,0x783c0000,0x38001c0,0x180,0x3800000,
3328  0x3800e00,0x1c3801c0,0x1e00003c,0xe00038,0x1c1c0780,0x381c0038,0x3800380,0x3c0000,0x78000000,0x61ff380e,0x70383808,0x70707000,
3329  0x7000381c,0x703801c0,0x40707078,0x7000701c,0x70f83838,0x70003838,0x70384038,0x1c07038,0x7e03c3c,0x1e3c01c0,0x3c000380,0xe001c0,
3330  0x0,0x383c,0x3c381c00,0x1c3c1c00,0x3801c3c,0x383801c0,0xe01c78,0x380739c,0x38381c38,0x3c381c3c,0x7000038,0x7003878,0x7c01e78,
3331  0x1ef007c0,0xf0001c0,0x18001c0,0x0,0xe000ee0,0x7800380,0xe380000,0x1001ff0,0x2242,0x40380c00,0x38700ee0,0x3c000ee0,0xee00000,
3332  0x0,0x0,0x0,0x0,0x380030,0xe1c00ee0,0xf0001c0,0x1c0,0xe200700,0xdd801c0,0x1800038,0x300c,0x71c,0x0,0x300c0000,0x0,0x0,0x3838,
3333  0x1980000,0x0,0x38e0,0xb0000c,0xb01c08,0x380e380e,0x380e380e,0x380e380e,0x70e03808,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
3334  0x707070f8,0x38383838,0x38383838,0x3838381c,0x38387038,0x70387038,0x703801c0,0x7000381c,0x383c383c,0x383c383c,0x383c383c,
3335  0x70e01c00,0x1c001c00,0x1c001c00,0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383878,0x38783878,0x387807c0,
3336  0x3c3807c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x18c0,0x10b801ce,0x3c3e0000,0x38001c0,0x180,
3337  0x3800000,0x3801c00,0x1e7801c0,0x3c002078,0xe02078,0x1c380700,0x1c3810f0,0x3800380,0x40000,0x40000380,0x307b380e,0x70701e18,
3338  0x70e07000,0x70001c1c,0x703801c0,0x60e0703c,0x7000701c,0x70f83c78,0x70003c70,0x703c70f0,0x1c03870,0x3c01c3c,0x3c1c01c0,0x78000380,
3339  0x7001c0,0x0,0x3c7c,0x3c381e18,0x1c7c1e0c,0x3801c3c,0x383801c0,0xe01c38,0x3c0739c,0x38381c38,0x3c381c3c,0x7001078,0x7803c78,
3340  0x7c01c38,0x1c780380,0x1e0001c0,0x18001c0,0x0,0x70c06c0,0x7000380,0xe300000,0x1000100,0x2142,0x70f00600,0x3c7006c0,0x780006c0,
3341  0x6c00000,0x0,0x0,0x0,0x0,0x10780060,0x73e206c0,0x1e0001c0,0x1c0,0x7240700,0x180c01c0,0x1800018,0x1818,0x30c,0x0,0x18180000,
3342  0x0,0x0,0x3c78,0x1980000,0x0,0x30c0,0x130000c,0x1301c18,0x380e380e,0x380e380e,0x380e380e,0x70e01e18,0x70007000,0x70007000,
3343  0x1c001c0,0x1c001c0,0x70e070f8,0x3c783c78,0x3c783c78,0x3c781008,0x7c783870,0x38703870,0x387001c0,0x70003a3c,0x3c7c3c7c,0x3c7c3c7c,
3344  0x3c7c3c7c,0x79f11e18,0x1e0c1e0c,0x1e0c1e0c,0x1c001c0,0x1c001c0,0x1c783838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383c78,0x3c783c78,
3345  0x3c780380,0x3c380380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x38c0,0x1ff800fc,0x1fee0000,
3346  0x1800180,0x180,0x3800000,0x3801c00,0xff01ffc,0x3ffc3ff0,0xe03ff0,0xff00700,0x1ff81fe0,0x3800380,0x0,0x380,0x3000780f,0x7ff00ff8,
3347  0x7fc07ff8,0x70000ffc,0x70381ffc,0x7fe0701c,0x7ff8701c,0x70781ff0,0x70001ff0,0x701c7ff0,0x1c01fe0,0x3c01c38,0x380e01c0,0x7ffc0380,
3348  0x7001c0,0x0,0x1fdc,0x3ff00ff0,0xffc0ffc,0x3800fdc,0x38383ffe,0xe01c3c,0x1fc739c,0x38380ff0,0x3ff00ffc,0x7001ff0,0x3f81fb8,
3349  0x7c01c38,0x3c3c0380,0x1ffc01c0,0x18001c0,0x0,0x3fc0380,0x7000380,0xc70718c,0x1000100,0x2244,0x7ff00200,0x1fff0380,0x7ffc0380,
3350  0x3800000,0x0,0x0,0x0,0x0,0x1ff000c0,0x7f7e0380,0x1ffc01c0,0x1c0,0x3fc3ffe,0x1c0,0x1800018,0x7e0,0x104,0x0,0x7e00000,0x7ffe,
3351  0x0,0x3fde,0x1980000,0x0,0x2080,0x3300018,0x3300ff0,0x780f780f,0x780f780f,0x780f780e,0xf0fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,
3352  0x1ffc1ffc,0x7fc07078,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x7ff01fe0,0x1fe01fe0,0x1fe001c0,0x70003bf8,0x1fdc1fdc,0x1fdc1fdc,
3353  0x1fdc1fdc,0x3fbf0ff0,0xffc0ffc,0xffc0ffc,0x3ffe3ffe,0x3ffe3ffe,0xff03838,0xff00ff0,0xff00ff0,0xff00000,0x3ff01fb8,0x1fb81fb8,
3354  0x1fb80380,0x3ff00380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x31c0,0x7e00078,0x7cf0000,0x1800180,
3355  0x0,0x3800000,0x3803800,0x3c01ffc,0x3ffc0fe0,0xe01fc0,0x3e00e00,0x7e00f80,0x3800380,0x0,0x380,0x18007007,0x7fc003f0,0x7f007ff8,
3356  0x700003f0,0x70381ffc,0x3f80701e,0x7ff8701c,0x707807c0,0x700007c0,0x701e1fc0,0x1c00fc0,0x3c01818,0x780f01c0,0x7ffc0380,0x3801c0,
3357  0x0,0xf9c,0x39e003e0,0x79c03f0,0x380079c,0x38383ffe,0xe01c1e,0x7c739c,0x383807e0,0x39e0079c,0x7000fc0,0x1f80f38,0x3801c38,
3358  0x781e0380,0x1ffc01c0,0x18001c0,0x0,0x1f80100,0xe000700,0x1c60718c,0x1000100,0x1e3c,0x1fc00100,0x7ff0100,0x7ffc0100,0x1000000,
3359  0x0,0x0,0x0,0x0,0xfc00080,0x3e3c0100,0x1ffc01c0,0x1c0,0xf83ffe,0x1c0,0x1800838,0x0,0x0,0x0,0x0,0x7ffe,0x0,0x3b9e,0x1980000,
3360  0x0,0x0,0x2300038,0x23003e0,0x70077007,0x70077007,0x70077007,0xe0fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007078,
3361  0x7c007c0,0x7c007c0,0x7c00000,0xc7c00fc0,0xfc00fc0,0xfc001c0,0x700039f0,0xf9c0f9c,0xf9c0f9c,0xf9c0f9c,0x1f1e03e0,0x3f003f0,
3362  0x3f003f0,0x3ffe3ffe,0x3ffe3ffe,0x7e03838,0x7e007e0,0x7e007e0,0x7e00000,0x63e00f38,0xf380f38,0xf380380,0x39e00380,0x0,0x0,
3363  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,
3364  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,
3365  0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1c0,0x18001c0,0x0,0x0,0xe000700,0x18600000,0x1000100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3366  0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800ff0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0x1800000,0x0,0x6300070,0x6300000,0x0,
3367  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,
3368  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,
3369  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,
3370  0x0,0x0,0x1c,0x0,0xe00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1e0,0x18003c0,0x0,0x0,0xc000700,0x18c00000,0x1000000,0x0,
3371  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x18007e0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000,
3372  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,
3373  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,
3374  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,
3375  0x3f0,0xfc0,0x0,0x0,0x0,0x0,0x838,0x0,0x1e00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0xf00,0xfc,0x1801f80,0x0,0x0,0x8008e00,0x30c00000,
3376  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,
3377  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,
3378  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,
3379  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,
3380  0x0,0x0,0xff0,0x0,0x1fc00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3e00,0x7c,0x1801f00,0x0,0x0,0x800fe00,0x0,0x0,0x0,0x0,0x0,0x0,
3381  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7c00000,0x0,0x3001fc,0x300000,
3382  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,
3383  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,
3384  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,
3385  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,
3386  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,
3387  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,
3388  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3389  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,
3390  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3391  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3392  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3393  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3394  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3395  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3396  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3397  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3398  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3399  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3400  0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3401 
3402  // Definition of a 19x38 font.
3403  const unsigned int font19x38[19*38*256/32] = {
3404  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3405  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3406  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c380000,0x0,0x1c380,0x0,0x0,0x0,0x0,0x0,
3407  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,
3408  0x1e00000,0x3,0x80000700,0x3c00000,0x380000,0x70003c00,0x0,0xe1800e,0x1c00,0xf000e18,0x0,0x0,0x700000e0,0x780000,0x7000,0x0,
3409  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3410  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3411  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3412  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe700000,0x0,0xe700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3413  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0000e,0x7e003,0xe60071c0,0x7f80000,0x1,0xc0000e00,0x7e0038e,0x1c0000,
3414  0xe0007e00,0x38e00000,0xf98007,0x3800,0x1f800f98,0x1c70000,0x0,0x380001c0,0xfc0071,0xc000e000,0x0,0x0,0x0,0x0,0x3e00000,0x0,
3415  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3416  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3417  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3418  0x0,0x0,0x0,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,
3419  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0001c,0xe7006,0x7c0071c0,0xe180000,0x0,0xe0001c00,0xe70038e,0xe0001,0xc000e700,0x38e00000,
3420  0x19f0003,0x80007000,0x39c019f0,0x1c70000,0x0,0x1c000380,0x1ce0071,0xc001c000,0x0,0x0,0x0,0x0,0x7f00000,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,0x3c00000,
3424  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,
3425  0x0,0x0,0x700038,0x1c3806,0x3c0071c0,0xc0c0000,0x0,0x70003800,0x1c38038e,0x70003,0x8001c380,0x38e00000,0x18f0001,0xc000e000,
3426  0x70e018f0,0x1c70000,0x0,0xe000700,0x3870071,0xc0038000,0x0,0x0,0x0,0x0,0xe380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3427  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3428  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3429  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,
3430  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,
3431  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,
3432  0xe,0x380,0x1800000,0xe00000,0x38001800,0x0,0x38,0xe00,0x6000000,0x0,0x1,0xc0000070,0x300000,0x3800,0x0,0x0,0x0,0x0,0x0,0x0,
3433  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,
3434  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,
3435  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,
3436  0x0,0x0,0xc3000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800000,0x0,0x0,0x0,0xe0,0x1c000f,0xc0000000,0x0,0x0,
3437  0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000007,0x3c003,0xc6000000,0xc180000,0x7,0x700,
3438  0x3c00000,0x700000,0x70003c00,0x0,0xf1801c,0x1c00,0xf000f18,0x0,0x0,0xe00000e0,0x780000,0x7000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3439  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,
3440  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,
3441  0x7,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf800e,0x3e0000,0x0,0x0,0x0,0x1e00000,0x0,0x1,
3442  0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7cc00,0x660,0x0,0x0,0x66000000,0x0,0x0,0x0,0x0,0x7,0x1c000000,0x0,0x0,0x0,0x3fe00000,
3443  0x0,0x0,0x7000000,0x0,0x0,0x0,0x3e0,0x7c001f,0xe0000000,0x0,0x0,0x0,0xe1c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3444  0x0,0x0,0x0,0x1f80,0x380000e,0x7e007,0xe60071c0,0xc180000,0x3,0x80000e00,0x7e0038e,0x380000,0xe0007e00,0x38e00f00,0x1f9800e,
3445  0x3800,0x1f801f98,0x1c70000,0x0,0x700001c0,0xfc0071,0xc000e007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3446  0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61c00600,0x1e00007e,0x70000,0x18003000,0x1800000,0x0,0x0,0x1c01f0,0x7e003f,0xc003f800,
3447  0x1e03ffc,0x7f01ff,0xfc03f000,0x7e000000,0x0,0x0,0xfc0,0x1e,0x7fe000,0x7e03fe00,0x3fff07ff,0xe007e038,0x383ffe0,0xff81c01,
3448  0xe1c000f8,0xf8f00e0,0xfc01ffc,0x3f00ff,0xc000fe07,0xfffc7007,0x1c007700,0x73c01ef,0x78ffff,0xfe0380,0xfe000,0x38000000,0x1800000,
3449  0x700000,0x38,0x1f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0xfc0000,
3450  0x0,0x7f00000,0x0,0x1,0x98000000,0x7f00000,0x3ffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0xcf81f,0xee3807e0,0x0,0x0,0x7e03c01e,0x1c,
3451  0x0,0x1f800000,0xf0078038,0xfc007,0x1c000000,0xfe00000,0x0,0x0,0x3fe000f0,0xf,0xc001f800,0x6000000,0xffc000,0x0,0x1c0007e0,
3452  0x360,0x6c0010,0x70000700,0xf0001e,0x3c000,0x78000f00,0x7f800ff,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,
3453  0x7807007,0xe000fc00,0x1f8003f0,0x7e0000,0x1f867,0x70e00e,0x1c01c380,0x38f00787,0x3fe0,0x180000c,0x66006,0x7c0071c0,0xe380000,
3454  0x1,0x80000c00,0x660038e,0x180000,0xc0006600,0x38e0078e,0x19f0006,0x3000,0x198019f0,0x1c70000,0x0,0x30000180,0xcc0071,0xc000c007,
3455  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,
3456  0x38003800,0x1800000,0x0,0x0,0x3807fc,0x1fe00ff,0xf00ffe00,0x3e03ffc,0xff81ff,0xfc07fc01,0xff800000,0x0,0x0,0x3fe0,0xfe001e,
3457  0x7ff801,0xff83ff80,0x3fff07ff,0xe01ff838,0x383ffe0,0xff81c03,0xc1c000f8,0xf8f80e0,0x3ff01fff,0xffc0ff,0xf003ff87,0xfffc7007,
3458  0x1e00f700,0x71c03c7,0x70ffff,0xfe01c0,0xfe000,0x7c000000,0xc00000,0x700000,0x38,0x3f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,
3459  0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0x3fe0000,0x0,0xff00000,0x0,0x3,0xc000000,0x1ffc0000,0xfffe00,
3460  0xffff0,0x0,0x0,0x0,0x0,0x0,0xc781f,0xee3803c0,0x0,0x0,0x3c01c01c,0x1c,0xc000,0x7fc00000,0x70070038,0x3fe007,0x1c000000,0x1ff80000,
3461  0x0,0x0,0x3fe003fc,0x1f,0xe003fc00,0xc000000,0x3ffc000,0x0,0x7c000ff0,0x60,0xc0000,0x30000700,0xf0001e,0x3c000,0x78000f00,
3462  0x3f000ff,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x7c0701f,0xf803ff00,0x7fe00ffc,0x1ff8000,0x7fe67,
3463  0x70e00e,0x1c01c380,0x38700707,0x7ff0,0xc00018,0xc3006,0x3c0071c0,0x7f00000,0x0,0xc0001800,0xc30038e,0xc0001,0x8000c300,0x38e003fc,
3464  0x18f0003,0x6000,0x30c018f0,0x1c70000,0x0,0x18000300,0x1860071,0xc0018007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3465  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe1801fc0,0x618001ff,0x70000,0x30001800,0x21840000,0x0,0x0,0x380ffe,0x1fe00ff,
3466  0xfc0fff00,0x3e03ffc,0x1ff81ff,0xfc0ffe03,0xffc00000,0x0,0x0,0x7ff0,0x3ff803f,0x7ffc03,0xffc3ffc0,0x3fff07ff,0xe03ffc38,0x383ffe0,
3467  0xff81c07,0x81c000f8,0xf8f80e0,0x7ff81fff,0x81ffe0ff,0xf80fff87,0xfffc7007,0xe00e700,0x70e0387,0x80f0ffff,0xe001c0,0xe000,
3468  0xfe000000,0xe00000,0x700000,0x38,0x3c,0x1c,0x1c00,0x1c00700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x78000e,0x3c000,
3469  0x0,0x7ff0000,0x0,0xf100000,0x0,0x7,0xe000000,0x7ffc0000,0x1fffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0x3,0xf780180,0x0,0x0,0x1801e03c,
3470  0x1c,0xc000,0xffc00000,0x780f0038,0x786000,0x7f00,0x18380000,0x0,0xfe00,0x30c,0x10,0x70020e00,0x1c000000,0x7f8c000,0x0,0x6c001c38,
3471  0x60,0xc0000,0x70000700,0x1f8003f,0x7e000,0xfc001f80,0x3f000ff,0xf03ffc1f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,
3472  0x7c0703f,0xfc07ff80,0xfff01ffe,0x3ffc000,0xffec7,0x70e00e,0x1c01c380,0x38780f07,0xf070,0xe00038,0x1c3800,0x0,0x3e00000,0x0,
3473  0xe0003800,0x1c380000,0xe0003,0x8001c380,0x3e0,0x3,0x8000e000,0x70e00000,0x0,0x0,0x1c000700,0x3870000,0x38007,0x0,0x0,0x0,
3474  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe3807ff0,0xc0c003c1,0x70000,0x70001c00,
3475  0x718e0000,0x0,0x0,0x700f1e,0x1ce00c0,0x3c0c0f80,0x7e03800,0x3e08000,0x381e0f03,0xc1e00000,0x0,0x0,0x7078,0x783c03f,0x701e07,
3476  0xc1c383e0,0x38000700,0x7c1c38,0x3801c00,0x381c0f,0x1c000fc,0x1f8f80e0,0x78781c07,0x81e1e0e0,0x780f0180,0xe007007,0xe00e380,
3477  0xe0f0783,0x80e0000e,0xe000e0,0xe001,0xef000000,0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,
3478  0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xf830000,0x0,0x1e000000,0x0,0x0,0x10000,0x780c0000,0x3e38000,0xe0,0x0,0x0,0x0,0x0,0x0,0x3,
3479  0xd580000,0x0,0x0,0xe038,0x1c,0xc000,0xf0400000,0x380e0038,0x702000,0x1ffc0,0xc0000,0x0,0x3ff80,0x606,0x0,0x30000600,0x0,
3480  0x7f8c000,0x0,0xc001818,0x60,0xc0003,0xe0000700,0x1f8003f,0x7e000,0xfc001f80,0x73801ee,0x7c1c1c,0x38000,0x70000e00,0xe0001,
3481  0xc0003800,0x700383e,0x7c0703c,0x3c078780,0xf0f01e1e,0x3c3c000,0xf0f87,0x70e00e,0x1c01c380,0x38380e07,0xe038,0x0,0x0,0x0,
3482  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,
3483  0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xc380fff0,0xc0c00380,0x70000,0x70001c00,0x3dbc0070,0x0,0x0,0x701e0f,0xe0000,0x1e000380,
3484  0x6e03800,0x7800000,0x781c0707,0x80e00000,0x0,0x0,0x4038,0xe00c03f,0x700e07,0x4380f0,0x38000700,0x700438,0x3801c00,0x381c0e,
3485  0x1c000ec,0x1b8fc0e0,0xf03c1c03,0xc3c0f0e0,0x3c1e0000,0xe007007,0xe00e380,0xe070703,0xc1e0001e,0xe000e0,0xe001,0xc7000000,
3486  0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xe010000,0x0,
3487  0x1c000000,0x10,0x20000,0x6c000,0xf0000000,0x3838000,0x1e0,0x0,0xf000f,0xf1e00,0x78f00000,0x0,0x3,0xdd80000,0x0,0x0,0xf078,
3488  0x0,0xc001,0xe0000000,0x1c1c0038,0x700000,0x3c1e0,0xc0000,0x0,0x783c0,0x606,0x0,0x30000e00,0x0,0xff8c000,0x0,0xc00300c,0x60,
3489  0xc0003,0xe0000000,0x1f8003f,0x7e000,0xfc001f80,0x73801ce,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x7e07078,
3490  0x1e0f03c1,0xe0783c0f,0x781e000,0x1c0787,0x70e00e,0x1c01c380,0x383c1e07,0xff00e038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x878,
3491  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,
3492  0x1c7000,0xc301e630,0xc0c00380,0x70000,0xe0000e00,0xff00070,0x0,0x0,0xe01c07,0xe0000,0xe000380,0xce03800,0x7000000,0x701c0707,
3493  0x600000,0x0,0x4000010,0x38,0x1c00e07f,0x80700e0e,0x38070,0x38000700,0xe00038,0x3801c00,0x381c1c,0x1c000ec,0x1b8ec0e0,0xe01c1c01,
3494  0xc38070e0,0x1c1c0000,0xe007007,0x701c380,0xe078e01,0xc1c0003c,0xe00070,0xe003,0x83800000,0x7f,0x71f000,0x3e003e38,0x3f007ff,
3495  0xe01f1c1c,0x7801fc00,0x3fc00701,0xe01c0077,0x8f071e00,0xf801c7c,0x7c700e,0x3e01fc03,0xfff8380e,0xe007700,0x73c0787,0x387ffc,
3496  0x70000e,0x1c000,0x0,0xe000000,0x0,0x1c000000,0x10,0x20000,0xc2000,0xe0000000,0x3838000,0x3c0,0x0,0xf000f,0x78e00,0x70e00000,
3497  0x0,0x3,0xc980fe0,0x1f0,0xf8000007,0xffc07070,0x0,0x3f801,0xc0000000,0x1e3c0038,0x700000,0x70070,0x7fc0000,0x0,0xe00e0,0x606,
3498  0x1c0000,0x70007c00,0x380e,0xff8c000,0x0,0xc00300c,0x60,0xc0000,0x70000000,0x3fc007f,0x800ff001,0xfe003fc0,0x73801ce,0xe0001c,
3499  0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,0x7607070,0xe0e01c1,0xc0383807,0x700e000,0x1c0387,0x70e00e,0x1c01c380,0x381c1c07,
3500  0xffc0e0f8,0x3f8007f,0xfe001,0xfc003f80,0x7f007e3,0xe003e001,0xf8003f00,0x7e000fc,0xfe001f,0xc003f800,0x7f00003c,0x38f0007,
3501  0xc000f800,0x1f0003e0,0x7c0007,0x8003f0c3,0x80e0701c,0xe0381c0,0x70700387,0x1f01c00e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3502  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0xc0c00380,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03c07,
3503  0x800e0000,0xe000380,0x1ce03800,0x7000000,0x701c0707,0x7003c0,0x780000,0x3c00001e,0x38,0x18006073,0x80700e0e,0x38070,0x38000700,
3504  0xe00038,0x3801c00,0x381c38,0x1c000ee,0x3b8ee0e1,0xe01e1c01,0xc78078e0,0x1c1c0000,0xe007007,0x701c387,0xe03de00,0xe3800038,
3505  0xe00070,0xe007,0x1c00000,0x1ff,0xc077f801,0xff807fb8,0xff807ff,0xe03fdc1d,0xfc01fc00,0x3fc00703,0xc01c007f,0xdf877f00,0x3fe01dfe,
3506  0xff700e,0xff07ff03,0xfff8380e,0x700f700,0x71e0f03,0x80707ffc,0x70000e,0x1c000,0x0,0x1c000008,0x0,0x1c000000,0x10,0x20000,
3507  0x82000,0xe0000000,0x7038000,0x80000380,0x2000040,0x7000e,0x38700,0xf1e00000,0x0,0x3,0xc183ff8,0x3fd,0xfc008007,0xffc038e0,
3508  0x0,0xffc01,0xc0008008,0xe380038,0x380000,0xe3e38,0x1ffc0040,0x80000000,0x1cfc70,0x606,0x1c0000,0xe0007c00,0x380e,0xff8c000,
3509  0x0,0xc00300c,0x8100060,0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0x73801ce,0xe0001c,0x38000,0x70000e00,0xe0001,
3510  0xc0003800,0x7003807,0x77070f0,0xf1e01e3,0xc03c7807,0x8f00f080,0x83c0787,0x70e00e,0x1c01c380,0x380e3807,0xffe0e1c0,0xffe01ff,
3511  0xc03ff807,0xff00ffe0,0x1ffc0ff7,0xf01ff807,0xfc00ff80,0x1ff003fe,0xfe001f,0xc003f800,0x7f0003fc,0x3bf801f,0xf003fe00,0x7fc00ff8,
3512  0x1ff0007,0x8007fd83,0x80e0701c,0xe0381c0,0x70380707,0x7f80e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3513  0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0x618081c0,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03803,0x800e0000,0xe000380,0x18e03800,
3514  0xf000000,0xf01c0707,0x7003c0,0x780000,0xfc00001f,0x80000078,0x301e6073,0x80700e1c,0x38038,0x38000700,0x1c00038,0x3801c00,
3515  0x381c70,0x1c000e6,0x338ee0e1,0xc00e1c01,0xc70038e0,0x1c1c0000,0xe007007,0x701c387,0xe01dc00,0xf7800078,0xe00070,0xe00e,0xe00000,
3516  0x3ff,0xe07ffc03,0xffc0fff8,0x1ffc07ff,0xe07ffc1d,0xfe01fc00,0x3fc00707,0x801c007f,0xdf877f80,0x7ff01fff,0x1fff00e,0xff07ff03,
3517  0xfff8380e,0x700e380,0xe0e0e03,0x80707ffc,0x70000e,0x1c000,0x0,0x7ffc001c,0x0,0x1c000000,0x10,0x20000,0x82000,0xe0000000,
3518  0x7038001,0xc0000780,0x70000e0,0x3800e,0x38700,0xe1c00000,0x0,0x3,0xc183ff8,0x7ff,0xfc01c007,0xffc03de0,0x0,0x1ffc01,0xc001c01c,
3519  0xf780038,0x3c0000,0xcff18,0x380c00c1,0x80000000,0x18fe30,0x30c,0x1c0001,0xc0000e00,0x380e,0xff8c000,0x0,0xc00300c,0xc180060,
3520  0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x877070e0,
3521  0x71c00e3,0x801c7003,0x8e0071c0,0x1c380fc7,0x70e00e,0x1c01c380,0x380f7807,0x1e0e380,0x1fff03ff,0xe07ffc0f,0xff81fff0,0x3ffe0fff,
3522  0xf03ffc0f,0xfe01ffc0,0x3ff807ff,0xfe001f,0xc003f800,0x7f0007fe,0x3bfc03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x800fff83,0x80e0701c,
3523  0xe0381c0,0x70380707,0xffc0e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,
3524  0xfff1c600,0x7f8381e0,0x70000,0xc0000600,0xff00070,0x0,0x0,0x1c03803,0x800e0000,0xe000f00,0x38e03fe0,0xe000000,0xe00e0e07,
3525  0x7003c0,0x780007,0xf0ffff87,0xf00000f0,0x307fe0f3,0xc0703c1c,0x38038,0x38000700,0x1c00038,0x3801c00,0x381ce0,0x1c000e6,0x338e70e1,
3526  0xc00e1c01,0xc70038e0,0x3c1e0000,0xe007007,0x783c38f,0x8e01fc00,0x770000f0,0xe00038,0xe01c,0x700000,0x381,0xe07c1e07,0xc0c1e0f8,
3527  0x3c1e0038,0xf07c1f,0xe001c00,0x1c0070f,0x1c0079,0xf3c7c380,0xf0781f07,0x83c1f00f,0xc10f0300,0x1c00380e,0x700e380,0xe0f1e03,
3528  0xc0f00078,0x70000e,0x1c000,0x0,0xfff8003e,0x0,0x3c000000,0x10,0x20000,0xc6000,0xf0000000,0x7038003,0xe0000f00,0xf8001f0,
3529  0x3801c,0x18300,0xe1800000,0x0,0x3,0xc187818,0x70f,0x9e03e000,0x7801dc0,0x1c,0x3cc401,0xc000efb8,0x7f7f0038,0x3f0000,0x1ce11c,
3530  0x300c01c3,0x80000000,0x38c638,0x3fc,0x1c0003,0x80000600,0x380e,0xff8c000,0x0,0xc00300c,0xe1c0060,0xc0010,0x70000700,0x79e00f3,
3531  0xc01e7803,0xcf0079e0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,
3532  0x8e0070e0,0x38381dc7,0x70e00e,0x1c01c380,0x38077007,0xf0e700,0x1c0f0381,0xe0703c0e,0x781c0f0,0x381e083e,0x787c0c1e,0xf03c1e0,
3533  0x783c0f07,0x800e0001,0xc0003800,0x7000fff,0x3e1c078,0x3c0f0781,0xe0f03c1e,0x783c000,0x1e0f03,0x80e0701c,0xe0381c0,0x70380f07,
3534  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,
3535  0xc0000700,0x3dbc0070,0x0,0x0,0x1c03803,0x800e0000,0x1e01fe00,0x70e03ff8,0xe3e0001,0xe007fc07,0x80f003c0,0x78001f,0xc0ffff81,
3536  0xfc0001e0,0x30e1e0e1,0xc07ff81c,0x38038,0x3ffe07ff,0xc1c0003f,0xff801c00,0x381de0,0x1c000e7,0x738e70e1,0xc00e1c03,0xc70038e0,
3537  0x780f8000,0xe007007,0x383838d,0x8e00f800,0x7f0000e0,0xe00038,0xe000,0x0,0x200,0xf0780e07,0x8041c078,0x380e0038,0xe03c1e,
3538  0xf001c00,0x1c0071e,0x1c0070,0xe1c783c0,0xe0381e03,0x8380f00f,0xe0000,0x1c00380e,0x381c380,0xe07bc01,0xc0e00078,0x70000e,
3539  0x1c000,0x0,0x1c000061,0x0,0x38000000,0x10,0x20000,0x7c000,0x7c000000,0x703fc06,0x10000e00,0x18400308,0x1801c,0x1c381,0xc3800000,
3540  0x0,0x0,0x7000,0xe0f,0xe061000,0x7801fc0,0x1c,0x38c001,0xc0007ff0,0x7fff0038,0x77c000,0x19c00c,0x301c0387,0x0,0x30c618,0xf0,
3541  0x1c0007,0x600,0x380e,0x7f8c007,0x80000000,0xc001818,0x70e03fc,0x387f871f,0xe0e00700,0x70e00e1,0xc01c3803,0x870070e0,0xe1c038f,
3542  0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,0x8e007070,0x703839c7,0x70e00e,
3543  0x1c01c380,0x3807f007,0x70e700,0x10078200,0xf0401e08,0x3c10078,0x200f001c,0x3878041c,0x70380e0,0x701c0e03,0x800e0001,0xc0003800,
3544  0x7001e0f,0x3c1e070,0x1c0e0381,0xc070380e,0x701c000,0x1c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80e07038,0x0,0x0,0x0,0x0,0x0,
3545  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600e600,0x7803f0,0x1,0xc0000700,0x718e0070,0x0,0x0,0x38038c3,
3546  0x800e0000,0x3c01f800,0x60e03ffc,0xeff8001,0xc001f003,0xc1f003c0,0x7800fe,0xffff80,0x3f8003c0,0x60c0e0e1,0xc07fe01c,0x38038,
3547  0x3ffe07ff,0xc1c07e3f,0xff801c00,0x381fe0,0x1c000e3,0x638e30e1,0xc00e1c07,0x870038ff,0xf00ff800,0xe007007,0x38381cd,0x9c007000,
3548  0x3e0001e0,0xe0001c,0xe000,0x0,0x0,0x70780f0f,0x3c078,0x70070038,0x1e03c1c,0x7001c00,0x1c0073c,0x1c0070,0xe1c701c1,0xe03c1e03,
3549  0xc780f00f,0xe0000,0x1c00380e,0x381c387,0xe03f801,0xc0e000f0,0x70000e,0x1c007,0xe0100000,0x1c0000cd,0x80000003,0xffc00000,
3550  0x3ff,0x807ff000,0xe0,0x7fc00060,0x703fc0c,0xd8001e00,0x3360066c,0x1c018,0xc181,0x83000000,0x0,0x0,0x7000,0x300e07,0xe0cd800,
3551  0xf000f80,0x1c,0x78c00f,0xff0038e0,0x3e00038,0xe1e000,0x19800c,0x383c070e,0x7fffc00,0x30fc18,0x0,0xffff80e,0x20e00,0x380e,
3552  0x7f8c007,0x80000000,0xc001c38,0x38703ff,0xf87fff0f,0xcfe00f00,0x70e00e1,0xc01c3803,0x870070e0,0x1e1e078f,0xe1c0001f,0xff03ffe0,
3553  0x7ffc0fff,0x800e0001,0xc0003800,0x700ff83,0x871870e0,0x71c00e3,0x801c7003,0x8e007038,0xe03871c7,0x70e00e,0x1c01c380,0x3803e007,
3554  0x70e700,0x38000,0x70000e00,0x1c00038,0x7001c,0x38f00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7001c07,0x380e0f0,0x1e1e03c3,
3555  0xc078780f,0xf01e000,0x3c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80f07038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3556  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600ff00,0x1e00778,0x38000001,0xc0000700,0x21843fff,0xe0000000,0x0,0x38039e3,0x800e0000,
3557  0x7c01fe00,0xe0e0203e,0xeffc001,0xc00ffe03,0xff700000,0x7f0,0x0,0x7f00380,0x618060e1,0xc07ffc1c,0x38038,0x3ffe07ff,0xc1c07e3f,
3558  0xff801c00,0x381ff0,0x1c000e3,0x638e38e1,0xc00e1fff,0x870038ff,0xc003fe00,0xe007007,0x38381cd,0x9c00f800,0x3e0003c0,0xe0001c,
3559  0xe000,0x0,0x0,0x7070070e,0x38038,0x70070038,0x1c01c1c,0x7001c00,0x1c00778,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0xfc000,
3560  0x1c00380e,0x381c3c7,0x1e01f001,0xe1e001e0,0xf0000e,0x1e01f,0xf8300000,0x1c00019c,0xc0000003,0xffc00000,0x10,0x20000,0x700,
3561  0x1ff000c0,0x703fc19,0xcc003c00,0x67300ce6,0xc038,0xc181,0x83000000,0x0,0x0,0x7e00,0x180e07,0xe19cc00,0x1e000f80,0x1c,0x70c00f,
3562  0xff007070,0x3e00038,0xe0f000,0x19800c,0x1fec0e1c,0x7fffc00,0x30f818,0x0,0xffff81f,0xf003fc00,0x380e,0x3f8c007,0x80000000,
3563  0x7f800ff0,0x1c3803f,0xe007fc00,0xff800e00,0x70e00e1,0xc01c3803,0x870070e0,0x1c0e070f,0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,
3564  0xc0003800,0x700ff83,0x871c70e0,0x71c00e3,0x801c7003,0x8e00701d,0xc038e1c7,0x70e00e,0x1c01c380,0x3803e007,0x70e3c0,0x38000,
3565  0x70000e00,0x1c00038,0x7001c,0x38e00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7003c07,0x8380e0e0,0xe1c01c3,0x80387007,
3566  0xe00e1ff,0xfe381b83,0x80e0701c,0xe0381c0,0x701e1e07,0x707878,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3567  0x0,0x0,0x0,0x0,0x1c,0x3,0xe007fe0,0x7800e3c,0x38000001,0xc0000700,0x1803fff,0xe0000000,0x0,0x70039c3,0x800e0000,0xf8000f80,
3568  0xc0e0000e,0xf83c003,0xc01e0f01,0xff700000,0x7c0,0x0,0x1f00780,0x618061c0,0xe0701e1c,0x38038,0x38000700,0x1c07e38,0x3801c00,
3569  0x381e78,0x1c000e3,0xe38e18e1,0xc00e1fff,0x70038ff,0xe0007f80,0xe007007,0x1c701dd,0x9c00f800,0x1c000780,0xe0000e,0xe000,0x0,
3570  0x7f,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x7fc00,0x1c00380e,
3571  0x1c381c7,0x1c01f000,0xe1c001c0,0xfe0000e,0xfe1f,0xfff00000,0x7ff003fc,0xe0000003,0xffc00000,0x10,0x20000,0x3800,0x3fc0180,
3572  0x703803f,0xce007800,0xff381fe7,0x30,0x0,0xc0,0x0,0x0,0x3fe0,0xc0e07,0xfe3fce00,0x1c000700,0x1c,0x70c00f,0xff006030,0x1c00000,
3573  0xe07800,0x19800c,0xfcc1c38,0x7fffc00,0x30d818,0x0,0xffff81f,0xf001f800,0x380e,0xf8c007,0x80000000,0x7f8007e0,0xe1c3fe,0x7fc00f,
3574  0xf8001e00,0xe0701c0,0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700ff83,0x870c70e0,
3575  0x71c00e3,0x801c7003,0x8e00700f,0x8038c1c7,0x70e00e,0x1c01c380,0x3801c007,0xf0e3e0,0x3ff807f,0xf00ffe01,0xffc03ff8,0x7ff03ff,
3576  0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe383383,0x80e0701c,
3577  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,
3578  0x3c1e1c1c,0x38000001,0xc0000700,0x1803fff,0xe0000007,0xf8000000,0x7003803,0x800e0001,0xf0000381,0xc0e00007,0xf01e003,0x801c0700,
3579  0x7c700000,0x7c0,0x0,0x1f00700,0x618061c0,0xe0700e1c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381e38,0x1c000e1,0xc38e1ce1,
3580  0xc00e1ffc,0x70038e0,0xf0000780,0xe007007,0x1c701dd,0xdc01fc00,0x1c000780,0xe0000e,0xe000,0x0,0x1ff,0xf070070e,0x38038,0x7fff0038,
3581  0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3ff00,0x1c00380e,0x1c381cd,0x9c00e000,0xe1c003c0,
3582  0xf80000e,0x3e18,0x3ff00000,0xffe007fd,0xf0000000,0x38000000,0x10,0x20000,0x1c000,0x3c0300,0x703807f,0xdf007801,0xff7c3fef,
3583  0x80000000,0x0,0x3e0,0x7ffe7ff,0xff000000,0x1ff8,0x60e07,0xfe7fdf00,0x3c000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0xf03800,
3584  0x19800c,0x1c38,0x1c07,0xf830cc18,0x0,0x1c0000,0x0,0x380e,0x18c007,0x80000000,0x0,0xe1cfe0,0x1fc003f,0x80003c00,0xe0701c0,
3585  0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,
3586  0x8e007007,0x3981c7,0x70e00e,0x1c01c380,0x3801c007,0x1e0e0f8,0xfff81ff,0xf03ffe07,0xffc0fff8,0x1fff07ff,0xf8e0003f,0xff87fff0,
3587  0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe386383,0x80e0701c,0xe0381c0,0x700e1c07,
3588  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,
3589  0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0003,0xe00001c3,0x80e00007,0xe00e007,0x80380380,0x700000,0x7f0,0x0,0x7f00700,
3590  0x618061ff,0xe070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381c3c,0x1c000e1,0xc38e1ce1,0xc00e1c00,0x70038e0,0x700003c0,
3591  0xe007007,0x1c701d8,0xdc03dc00,0x1c000f00,0xe00007,0xe000,0x0,0x3ff,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007fc,
3592  0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3f00,0x1c00380e,0x1c381cd,0x9c01f000,0x73800780,0xfe0000e,0xfe10,0x7c00000,0x1c000ffb,
3593  0xf8000000,0x38000000,0x10,0x20000,0x20000,0x1e0700,0x70380ff,0xbf80f003,0xfefe7fdf,0xc0000000,0x0,0x3f0,0x7ffe7ff,0xff000000,
3594  0x1f8,0x30e07,0xfeffbf80,0x78000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0x783800,0x1ce11c,0xe1c,0x1c07,0xf838ce38,0x0,0x1c0000,
3595  0x0,0x380e,0x18c000,0x0,0x0,0x1c38c00,0x1800030,0x7800,0xfff01ff,0xe03ffc07,0xff80fff0,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,
3596  0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,0x8e00700f,0x803b81c7,0x70e00e,0x1c01c380,0x3801c007,0xffe0e03c,
3597  0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0fff,0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,
3598  0x80387007,0xe00e000,0x38c383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3599  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0063c,0x40619c0f,0x30000001,0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0007,0xc00001c3,
3600  0xfffc0007,0xe00e007,0x380380,0xf00000,0xfe,0xffff80,0x3f800700,0x618063ff,0xf070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,
3601  0x381c1e,0x1c000e0,0x38e0ee1,0xc00e1c00,0x70038e0,0x380001c0,0xe007007,0x1ef01d8,0xdc038e00,0x1c001e00,0xe00007,0xe000,0x0,
3602  0x7c0,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0079e,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x780,0x1c00380e,
3603  0xe701cd,0x9c01f000,0x73800f00,0xe0000e,0xe000,0x0,0x1c0007f7,0xf0000000,0x70000000,0x10,0x20000,0x0,0xe0e00,0x703807f,0x7f01e001,
3604  0xfdfc3fbf,0x80000000,0x0,0x7f0,0x0,0x0,0x3c,0x18e07,0x7f7f00,0xf0000700,0x1c,0x70c001,0xc0007070,0x1c00000,0x3e7000,0xcff18,
3605  0x3ffc070e,0x1c07,0xf818c630,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x3870000,0xe000fc00,0x380f000,0x1fff83ff,0xf07ffe0f,
3606  0xffc1fff8,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870770e0,0x71c00e3,0x801c7003,0x8e00701d,
3607  0xc03f01c7,0x70e00e,0x1c01c380,0x3801c007,0xffc0e01c,0x3e0387c0,0x70f80e1f,0x1c3e038,0x7c071e1c,0xe00038,0x70000,0xe0001c00,
3608  0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x398383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,
3609  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,
3610  0x70,0x0,0x0,0x1c003c07,0x800e000f,0x1c3,0xfffc0007,0xe00e007,0x380380,0xe00000,0x1f,0xc0ffff81,0xfc000700,0x618063ff,0xf070070e,
3611  0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0e,0x1c000e0,0x38e0ee1,0xe01e1c00,0x78078e0,0x380001c0,0xe007007,0xee01f8,0xfc078f00,
3612  0x1c001c00,0xe00003,0x8000e000,0x0,0x700,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0070e,0x1c0070,0xe1c701c1,
3613  0xc01c1c01,0xc700700e,0x380,0x1c00380e,0xe700ed,0xb803f800,0x77800f00,0x70000e,0x1c000,0x0,0xe0003f7,0xe0000000,0x70000000,
3614  0x10,0x20000,0x1c0e0,0xe1c00,0x703803f,0x7e01c000,0xfdf81fbf,0x0,0x0,0x3f0,0x0,0x0,0x1c,0x1ce07,0x3f7e00,0xf0000700,0x1c,
3615  0x70c001,0xc00038e0,0x1c00038,0xf7000,0xe3e38,0x3ffc0387,0x1c00,0x1cc770,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x70e0001,
3616  0xe001fe00,0x780e000,0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0ffe,0xe0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,
3617  0x70770f0,0xf1e01e3,0xc03c7807,0x8f00f038,0xe03e03c7,0x70e00e,0x1c01c380,0x3801c007,0xff00e00e,0x38038700,0x70e00e1c,0x1c38038,
3618  0x70071c1c,0xe00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x3b0383,0x80e0701c,
3619  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,
3620  0xc0de03,0xe0000001,0xc0000700,0x70,0x0,0x0,0x1c001c07,0xe001e,0x1c3,0xfffc0007,0x600e00e,0x380380,0xe00000,0x7,0xf0ffff87,
3621  0xf0000000,0x60c0e380,0x7070070e,0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0f,0x1c000e0,0x38e06e0,0xe01c1c00,0x38070e0,
3622  0x1c0001c0,0xe007007,0xee00f8,0xf80f0700,0x1c003c00,0xe00003,0x8000e000,0x0,0x700,0x70780f0f,0x3c078,0x70000038,0x1e03c1c,
3623  0x7001c00,0x1c0070f,0x1c0070,0xe1c701c1,0xe03c1e03,0xc780f00e,0x380,0x1c00380e,0xe700f8,0xf807bc00,0x3f001e00,0x70000e,0x1c000,
3624  0x0,0xe0001ff,0xc0000000,0x70000000,0x10,0x20000,0x33110,0xe0e00,0x383801f,0xfc03c000,0x7ff00ffe,0x0,0x0,0x3e0,0x0,0x0,0x1c,
3625  0x38e07,0x1ffc01,0xe0000700,0x1c,0x78c001,0xc0007ff0,0x1c00038,0x7c000,0x70070,0x1c3,0x80001c00,0xe00e0,0x0,0x1c0000,0x0,
3626  0x380e,0x18c000,0x0,0x0,0xe1c0001,0xe0010700,0x780e000,0x1c038380,0x70700e0e,0x1c1c038,0x78070e0e,0xe0001c,0x38000,0x70000e00,
3627  0xe0001,0xc0003800,0x7003807,0x7037070,0xe0e01c1,0xc0383807,0x700e070,0x701c0387,0x70e00e,0x1c01c380,0x3801c007,0xe00e,0x38038700,
3628  0x70e00e1c,0x1c38038,0x70071c1c,0xf00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003c07,0x8380e0f0,0x1e1e03c3,0xc078780f,
3629  0xf01e007,0x803e0783,0x80e0701c,0xe0381c0,0x7003f007,0x80f00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3630  0x0,0x0,0x0,0x0,0x0,0x6,0x1800061c,0xc0de01,0xc0000000,0xc0000e00,0x70,0xf0000,0x3c00,0x38001c0f,0xe003c,0x3c0,0xe0000e,0x701e00e,
3631  0x3c0780,0x1e003c0,0x780000,0xfc00001f,0x80000000,0x60e1e780,0x78700f07,0x4380f0,0x38000700,0xf00e38,0x3801c00,0xc0781c07,
3632  0x81c000e0,0x38e07e0,0xe03c1c00,0x380f0e0,0x1e0003c0,0xe00780f,0xee00f0,0x780e0780,0x1c007800,0xe00001,0xc000e000,0x0,0x700,
3633  0xf0780e07,0x8041c078,0x38020038,0xe03c1c,0x7001c00,0x1c00707,0x801c0070,0xe1c701c0,0xe0381e03,0x8380f00e,0x80380,0x1c003c1e,
3634  0x7e00f8,0xf80f1e00,0x3f003c00,0x70000e,0x1c000,0x0,0xf0100f7,0x80078000,0x700078f0,0x10,0x7ff000,0x61208,0x1e0700,0x383800f,
3635  0x78078000,0x3de007bc,0x0,0x0,0x0,0x0,0x0,0x401c,0x70e0f,0xf7803,0xc0000700,0x1c,0x38c001,0xc000efb8,0x1c00038,0x1e000,0x3c1e0,
3636  0xc1,0x80000000,0x783c0,0x0,0x0,0x0,0x3c1e,0x18c000,0x0,0x0,0xc180003,0x60000300,0xd80e010,0x3c03c780,0x78f00f1e,0x1e3c03c,
3637  0x70039c0e,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x703f070,0x1e0e03c1,0xc078380f,0x701e0e0,0x381c0787,
3638  0x80f0f01e,0x1e03c3c0,0x7801c007,0xe00e,0x38078700,0xf0e01e1c,0x3c38078,0x700f1c1c,0x78041c,0x1038020,0x70040e00,0x800e0001,
3639  0xc0003800,0x7001c07,0x380e070,0x1c0e0381,0xc070380e,0x701c007,0x801e0703,0xc1e0783c,0xf0781e0,0xf003f007,0x80e00fc0,0x0,
3640  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xe,0x1801867c,0xc0cf83,0xe0000000,0xe0000e00,
3641  0x70,0xf0000,0x3c00,0x38000f1e,0xe0070,0x180780,0xe0603e,0x783c01e,0x1e0f01,0x7c003c0,0x780000,0x3c00001e,0x700,0x307fe700,
3642  0x38701e07,0xc1c383e0,0x38000700,0x7c1e38,0x3801c00,0xe0f01c03,0x81c000e0,0x38e03e0,0x78781c00,0x1e1e0e0,0xe180780,0xe003c1e,
3643  0x7c00f0,0x781e03c0,0x1c007000,0xe00001,0xc000e000,0x0,0x783,0xf07c1e07,0xc0c1e0f8,0x3e0e0038,0xf07c1c,0x7001c00,0x1c00703,
3644  0xc01e0070,0xe1c701c0,0xf0781f07,0x83c1f00e,0xe0f80,0x1e003c3e,0x7e00f8,0xf80e0e00,0x3f003800,0x70000e,0x1c000,0x0,0x7830077,
3645  0xf0000,0x700078f0,0x10,0x20000,0x41208,0xc03c0380,0x3c38007,0x70070000,0x1dc003b8,0x0,0x0,0x0,0x0,0x0,0x707c,0x6070f,0x86077003,
3646  0x80000700,0x1c,0x3ec401,0xc001c01c,0x1c00038,0xf000,0x1ffc0,0x40,0x80000000,0x3ff80,0x0,0x0,0x0,0x3e3e,0x18c000,0x0,0x0,
3647  0x8100006,0x60000300,0x1980f070,0x3801c700,0x38e0071c,0xe3801c,0x70039c0e,0x7c1c1c,0x38000,0x70000e00,0xe0001,0xc0003800,
3648  0x700383e,0x701f03c,0x3c078780,0xf0f01e1e,0x3c3c1c0,0x1c3f0f03,0xc1e0783c,0xf0781e0,0xf001c007,0xe81e,0x3c1f8783,0xf0f07e1e,
3649  0xfc3c1f8,0x783f1e3e,0x187c0c1f,0x703e0e0,0x7c1c0f83,0x800e0001,0xc0003800,0x7001e0f,0x380e078,0x3c0f0781,0xe0f03c1e,0x783c007,
3650  0x801e0f03,0xc3e0787c,0xf0f81e1,0xf003f007,0xc1e00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3651  0x0,0x0,0x1c,0xe,0x3801fff8,0x6187ff,0xe0000000,0xe0000e00,0x70,0xf0000,0x3c00,0x38000ffe,0x1fff0ff,0xfe1fff80,0xe07ffc,0x3ffc01c,
3652  0x1fff01,0xff8003c0,0x780000,0x4000010,0x700,0x301e6700,0x387ffe03,0xffc3ffc0,0x3fff0700,0x3ffe38,0x383ffe0,0xfff01c03,0xc1fff8e0,
3653  0x38e03e0,0x7ff81c00,0x1ffe0e0,0xf1fff80,0xe003ffe,0x7c00f0,0x781c01c0,0x1c00ffff,0xe00001,0xc000e000,0x0,0x3ff,0x707ffc03,
3654  0xffc0fff8,0x1ffe0038,0x7ffc1c,0x707fff0,0x1c00701,0xc00ff070,0xe1c701c0,0x7ff01fff,0x1fff00e,0xfff00,0xff81fee,0x7e00f0,
3655  0x781e0f00,0x1e007ffc,0x70000e,0x1c000,0x0,0x3ff003e,0xf0000,0xe00070e0,0x60830010,0x20000,0x41208,0xfffc01c0,0x1fffe03,0xe00ffff0,
3656  0xf8001f0,0x0,0x0,0x0,0x0,0x0,0x7ff8,0xc07fd,0xfe03e007,0xffc00700,0x1c,0x1ffc1f,0xffc08008,0x1c00038,0x7000,0x7f00,0x0,0x0,
3657  0xfe00,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0x6,0x60000700,0x19807ff0,0x3801c700,0x38e0071c,0xe3801c,0x70039c0f,0xf03ffc1f,
3658  0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,0x701f03f,0xfc07ff80,0xfff01ffe,0x3ffc080,0x83fff03,0xffe07ffc,0xfff81ff,
3659  0xf001c007,0xeffc,0x1ffb83ff,0x707fee0f,0xfdc1ffb8,0x3ff70ff7,0xf83ffc0f,0xff01ffe0,0x3ffc07ff,0x83fff87f,0xff0fffe1,0xfffc0ffe,
3660  0x380e03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x803ffe01,0xfee03fdc,0x7fb80ff,0x7001e007,0xffc00780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3661  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x3801fff0,0x7f83fe,0x70000000,0xe0000e00,0x0,0xf0000,0x3c00,0x700007fc,
3662  0x1fff0ff,0xfe1ffe00,0xe07ff8,0x1ff801c,0xffe01,0xff0003c0,0x780000,0x0,0x700,0x38000f00,0x3c7ffc01,0xff83ff80,0x3fff0700,
3663  0x1ffc38,0x383ffe0,0x7fe01c01,0xe1fff8e0,0x38e03e0,0x3ff01c00,0xffc0e0,0x71fff00,0xe001ffc,0x7c00f0,0x783c01e0,0x1c00ffff,
3664  0xe00000,0xe000e000,0x0,0x1ff,0x7077f801,0xff807fb8,0xffc0038,0x3fdc1c,0x707fff0,0x1c00701,0xe007f070,0xe1c701c0,0x3fe01dfe,
3665  0xff700e,0x7fe00,0xff80fee,0x3c0070,0x703c0780,0x1e007ffc,0x70000e,0x1c000,0x0,0x1fe001c,0xe0000,0xe000e1c0,0x71c78010,0x20000,
3666  0x21318,0xfff800c0,0xfffe01,0xc00ffff0,0x70000e0,0x0,0x0,0x0,0x0,0x0,0x3ff0,0x1803fd,0xfe01c007,0xffc00700,0x1c,0xffc1f,0xffc00000,
3667  0x1c00038,0x7000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0xc,0x60000e00,0x31803fe0,0x7801ef00,0x3de007bc,
3668  0xf7801e,0xf003fc0f,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x701f01f,0xf803ff00,0x7fe00ffc,0x1ff8000,
3669  0x67fe01,0xffc03ff8,0x7ff00ff,0xe001c007,0xeff8,0xffb81ff,0x703fee07,0xfdc0ffb8,0x1ff70ff7,0xf81ff807,0xfe00ffc0,0x1ff803ff,
3670  0x3fff87f,0xff0fffe1,0xfffc07fc,0x380e01f,0xf003fe00,0x7fc00ff8,0x1ff0000,0x37fc00,0xfee01fdc,0x3fb807f,0x7001e007,0x7f800780,
3671  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,
3672  0x0,0xe0000,0x3c00,0x700001f0,0x1fff0ff,0xfe07f800,0xe01fe0,0x7e0038,0x3f800,0xfc0003c0,0x700000,0x0,0x700,0x18000e00,0x1c7ff000,
3673  0x7e03fe00,0x3fff0700,0x7f038,0x383ffe0,0x1f801c00,0xf1fff8e0,0x38e01e0,0xfc01c00,0x3f80e0,0x787fc00,0xe0007f0,0x7c00f0,0x387800f0,
3674  0x1c00ffff,0xe00000,0xe000e000,0x0,0xfc,0x7071f000,0x3f003e38,0x3f00038,0x1f1c1c,0x707fff0,0x1c00700,0xf003f070,0xe1c701c0,
3675  0x1f801c7c,0x7c700e,0x1f800,0x3f8078e,0x3c0070,0x707803c0,0x1c007ffc,0x70000e,0x1c000,0x0,0x7c0008,0x1e0000,0xe000e1c0,0x71c30010,
3676  0x20000,0x1e1f0,0x3fe00020,0x3ffe00,0x800ffff0,0x2000040,0x0,0x0,0x0,0x0,0x0,0xfc0,0x3001f0,0x78008007,0xffc00700,0x1c,0x3f81f,
3677  0xffc00000,0x1c00038,0x407000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x39c7,0x18c000,0x0,0x0,0x18,0x60001c00,0x61801f80,0x7000ee00,
3678  0x1dc003b8,0x77000e,0xe001f80f,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,0x700f007,0xe000fc00,0x1f8003f0,
3679  0x7e0000,0xe1f800,0x7f000fe0,0x1fc003f,0x8001c007,0xe7f0,0x7e380fc,0x701f8e03,0xf1c07e38,0xfc703c1,0xe003f001,0xf8003f00,
3680  0x7e000fc,0x3fff87f,0xff0fffe1,0xfffc03f8,0x380e00f,0xc001f800,0x3f0007e0,0xfc0000,0x61f800,0x78e00f1c,0x1e3803c,0x7001c007,
3681  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,
3682  0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
3683  0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
3684  0x70000e,0x1c000,0x0,0x0,0x1c0000,0xe000c180,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
3685  0x0,0x38,0x70e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x2000,0x0,0x1f,0xf8003800,0x7fe00000,0x0,0x0,0x0,0x0,0x4000,
3686  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,
3687  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,
3688  0x0,0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e000,
3689  0x0,0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
3690  0x70000e,0x1c000,0x0,0x0,0x1c0001,0xe001c380,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
3691  0x0,0x38,0x7fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x3000,0x0,0x1f,0xf8007000,0x7fe00000,0x0,0x0,0x0,0x0,0x6000,
3692  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,
3693  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,
3694  0x0,0x380000,0x1,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x3c18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf000,
3695  0x0,0x0,0x0,0x0,0x0,0xfe0000,0x380fe000,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x38000000,
3696  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,
3697  0x38,0x1f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x1800,0x0,0x0,0x6000e000,0x1800000,0x0,0x0,0x0,0x0,0x3000,0x0,
3698  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,
3699  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,
3700  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,
3701  0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x0,0x0,0x0,0x0,0x607800,0x0,0x3c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x78000000,
3702  0x3f800e,0x3f8000,0x0,0x0,0x300043,0xc0018200,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
3703  0x0,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x11800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x23000,0x0,0x0,
3704  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,
3705  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,
3706  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,
3707  0xfe000,0x0,0x0,0x0,0x0,0x0,0x7ff000,0x0,0x7f800000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf8000000,0x3f800e,0x3f8000,0x0,
3708  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,
3709  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,
3710  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,
3711  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3712  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,
3713  0x7f000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf0000000,0xf800e,0x3e0000,0x0,0x0,0x7f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3714  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,
3715  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,
3716  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,
3717  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3718  0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x1fc000,0x0,0x7e000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xc0000000,0xe,0x0,
3719  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,
3720  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,
3721  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,
3722  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3723  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,
3724  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,
3725  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3726  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3727 
3728  // Definition of a 29x57 font.
3729  const unsigned int font29x57[29*57*256/32] = {
3730  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3731  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3732  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3733  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3734  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,
3735  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,
3736  0xc0000000,0x0,0x7c00,0xf80,0x7e000,0x0,0x7c00000,0xf80000,0x7e000000,0x0,0x0,0x1f00,0x3e0,0x1f800,0x0,0x0,0x0,0x3,0xe0000000,
3737  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,
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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3740  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3741  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3742  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,
3743  0x0,0x0,0x0,0x0,0x0,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,
3744  0x1f0000,0x7e00000,0xf838001f,0xf80001f,0xf0000000,0x0,0x3e00,0x1f00,0x7e000,0x3e1f000,0x3e00000,0x1f00000,0x7e00003e,0x1f000000,
3745  0x3e0,0xe0000f80,0x7c0,0x1f800,0x3e0e00,0x7c3e000,0x0,0x1,0xf0000000,0xf800003f,0x1f0f,0x800001f0,0x0,0x0,0x0,0x0,0x0,0x0,
3746  0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x0,0x0,0x0,0x0,0x0,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,0x0,0x0,0x0,0x0,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e7800,0x0,0x0,
3751  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,
3752  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x1e0000,0xff00001,0xfe38001f,0xf80003f,
3753  0xf8000000,0x0,0x1e00,0x1e00,0xff000,0x3e1f000,0x1e00000,0x1e00000,0xff00003e,0x1f000000,0x7f8,0xe0000780,0x780,0x3fc00,0x7f8e00,
3754  0x7c3e000,0x0,0x0,0xf0000000,0xf000007f,0x80001f0f,0x800001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3755  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3756  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
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,0xef000,0x0,0x0,0x0,0xef000000,0x0,0x0,0x0,0x0,0x0,0x0,
3760  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,
3761  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000,0x3c0000,0x1e780003,0xfff8001f,0xf80003c,0x78000000,0x0,0xf00,0x3c00,0x1e7800,
3762  0x3e1f000,0xf00000,0x3c00001,0xe780003e,0x1f000000,0xfff,0xe00003c0,0xf00,0x79e00,0xfffe00,0x7c3e000,0x0,0x0,0x78000001,0xe00000f3,
3763  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,
3764  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
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,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3769  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,
3770  0x0,0x78000,0x780000,0x3c3c0003,0x8ff0001f,0xf800078,0x3c000000,0x0,0x780,0x7800,0x3c3c00,0x3e1f000,0x780000,0x7800003,0xc3c0003e,
3771  0x1f000000,0xe3f,0xc00001e0,0x1e00,0xf0f00,0xe3fc00,0x7c3e000,0x0,0x0,0x3c000003,0xc00001e1,0xe0001f0f,0x80000780,0x0,0x0,
3772  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,
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,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,
3778  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,
3779  0x83e0001f,0xf800070,0x1c000000,0x0,0x3c0,0xf000,0x781e00,0x3e1f000,0x3c0000,0xf000007,0x81e0003e,0x1f000000,0xe0f,0x800000f0,
3780  0x3c00,0x1e0780,0xe0f800,0x7c3e000,0x0,0x0,0x1e000007,0x800003c0,0xf0001f0f,0x80000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf8000000,
3781  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3787  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,
3788  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,
3789  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3790  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
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,0x1f00000,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,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3794  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,
3795  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,
3796  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x3e000,0x3e00000,0x0,0x78,0x3c000000,0x0,0x1f000,0x3e0,
3797  0x3e000,0x0,0x1f000000,0x3e0000,0x3e000000,0x0,0x0,0x7c00,0xf8,0xf800,0x0,0x0,0x0,0xf,0x80000000,0x1f00001f,0x0,0x3e,0x0,
3798  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3799  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,
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,0xf80000,
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,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x781c0000,0x38,0xe000000,0x0,0x0,0x380e0,0x0,
3803  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,
3804  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,
3805  0x0,0x0,0xf80000,0x7c000,0x3e00000,0xf0380000,0x70,0x1c000000,0x0,0xf800,0x7c0,0x3e000,0x0,0xf800000,0x7c0000,0x3e000000,
3806  0x0,0x3c0,0xe0003e00,0x1f0,0xf800,0x3c0e00,0x0,0x0,0x7,0xc0000000,0x3e00001f,0x0,0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3807  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0xff,0x0,
3808  0xf8,0xf8000,0x1c000,0x0,0x0,0x0,0x0,0x1f,0xc0000000,0x1ff8,0xff00,0x0,0x0,0x3fe000,0x0,0x1fc00001,0xfe000000,0x0,0x0,0x0,
3809  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,
3810  0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x780000,0x1,0xe0000000,0x0,0x780000,0x3,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,
3811  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,
3812  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,
3813  0x0,0x0,0x1ff,0x1f0f8,0x0,0xff000,0x0,0x0,0x0,0x3f,0xff00000f,0x80000000,0xfe0,0x3f80,0xf00,0x0,0x0,0x0,0x1,0xf8000003,0xe0000000,
3814  0x1c00,0xe000,0xe00,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,
3815  0x7f0000,0x0,0x1fc07000,0x0,0x0,0x0,0x0,0x0,0x3f800,0x780000,0x78000,0x7f00001,0xfc38001f,0xf800070,0x1c000000,0x0,0x7800,
3816  0x780,0x7f000,0x3e1f000,0x7800000,0x780000,0x7f00003e,0x1f0003f0,0x7f0,0xe0001e00,0x1e0,0x1fc00,0x7f0e00,0x7c3e000,0x0,0x3,
3817  0xc0000000,0x3c00003f,0x80001f0f,0x80000078,0x1e0000,0x3e1f00,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,0x780000,0x3c1e0000,0x1e078000,0x30000000,0x3ff,0xc00001e0,0xf0,
3819  0x78000,0x1c000,0x0,0x0,0x0,0x0,0x1e0007f,0xf000007e,0x1ffff,0x7ffe0,0x1f80,0x3ffff80,0xfff803,0xfffff800,0xfff80007,0xff800000,
3820  0x0,0x0,0x0,0x0,0x1ffe00,0x0,0xfe0003,0xfff80000,0x3ffe01ff,0xe00003ff,0xffe01fff,0xff0003ff,0xe01e0007,0x803ffff0,0xfff80,
3821  0x3c000fc0,0x7800001f,0x8003f07e,0x1e000f,0xfe0007ff,0xf00003ff,0x8007ffe0,0x1fff8,0x7fffffe,0xf0003c1,0xe000079e,0xf1f,0x1f3e0,
3822  0x1f01ff,0xfff8003f,0xf003c000,0x7fe0,0x3f00,0x0,0x3c0000,0x1,0xe0000000,0x0,0x780000,0xf,0xfe000000,0x78000,0x3c00,0xf000,
3823  0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xfc0000f0,0x3fe00,0x0,0x0,0xfff00,0x0,0x0,0x3fe000,
3824  0x0,0x0,0x0,0x1dc0,0x0,0x3fff00,0x0,0x3ffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff1c07ff,0x3c0f001e,0x3c000000,
3825  0x0,0x0,0x1e3c0,0xf80007c,0x0,0x780000,0x0,0xfff8000,0x3e00,0x1f00000,0x7ff,0xc001f0f8,0x0,0x3ffc00,0x0,0x0,0x0,0x3f,0xff00003f,
3826  0xe0000000,0x3ff8,0xffe0,0x1e00,0x0,0xfffc00,0x0,0x7,0xf800000f,0xf8000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,
3827  0x3f800001,0xfc00003f,0xf80000ff,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,
3828  0xfc00,0x3c001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x0,0x7ff8f0f0,0x3c0780,0x1e03c00,0xf01e000,0x783e0001,0xf01e0000,0xffe00,
3829  0x3c0000,0xf0000,0x7700001,0xfe38001f,0xf800070,0x1c000000,0x0,0x3c00,0xf00,0x77000,0x3e1f000,0x3c00000,0xf00000,0x7700003e,
3830  0x1f0000f8,0xc0007f8,0xe0000f00,0x3c0,0x1dc00,0x7f8e00,0x7c3e000,0x0,0x1,0xe0000000,0x7800003b,0x80001f0f,0x800000f0,0x1e0000,
3831  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,
3832  0x0,0x0,0x780000,0x3c1e0000,0x1e070000,0x300001f0,0x7ff,0xc00001e0,0x1e0,0x7c000,0x1c000,0x0,0x0,0x0,0x0,0x3c000ff,0xf80007fe,
3833  0x3ffff,0x801ffff8,0x1f80,0x3ffff80,0x3fff803,0xfffff801,0xfffc000f,0xffc00000,0x0,0x0,0x0,0x0,0x7fff80,0x0,0xfe0003,0xffff0000,
3834  0xffff01ff,0xfc0003ff,0xffe01fff,0xff000fff,0xf01e0007,0x803ffff0,0xfff80,0x3c001f80,0x7800001f,0xc007f07e,0x1e001f,0xff0007ff,
3835  0xfc0007ff,0xc007fffc,0x3fffc,0x7fffffe,0xf0003c1,0xf0000f9e,0xf0f,0x8003e1e0,0x1e01ff,0xfff8003f,0xf001e000,0x7fe0,0x3f00,
3836  0x0,0x1e0000,0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,
3837  0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x1fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x3de0,0x0,0x7fff80,0x0,0xfffff80,
3838  0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe7bc07ff,0x3e1f000f,0x78000000,0x0,0x0,0xf780,0x7800078,0x0,0x780000,0x180000,
3839  0x1fff8000,0x1e00,0x1e0003c,0xfff,0xc001f0f8,0x0,0x7ffe00,0x0,0x0,0x0,0x3f,0xff00007f,0xf0000000,0x3ffc,0xfff0,0x3c00,0x0,
3840  0x7fffc00,0x0,0x7,0xf800003f,0xfe000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xe00001ff,
3841  0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000fc00,0x3c003ffe,0x1fff0,
3842  0xfff80,0x7ffc00,0x3ffe000,0x0,0xfffce0f0,0x3c0780,0x1e03c00,0xf01e000,0x781e0001,0xe01e0000,0x3fff00,0x1e0000,0x1e0000,0xf780003,
3843  0xcf78001f,0xf800078,0x3c000000,0x0,0x1e00,0x1e00,0xf7800,0x3e1f000,0x1e00000,0x1e00000,0xf780003e,0x1f0000fc,0x7c000f3d,
3844  0xe0000780,0x780,0x3de00,0xf3de00,0x7c3e000,0x0,0x0,0xf0000000,0xf000007b,0xc0001f0f,0x800001e0,0x1e0000,0x3e1f00,0x0,0x0,
3845  0x0,0x0,0x0,0x0,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,
3846  0x3c1e0000,0x1e0f0000,0x300007fc,0xfff,0xc00001e0,0x1e0,0x3c000,0x1c000,0x0,0x0,0x0,0x0,0x3c001ff,0xfc001ffe,0x3ffff,0xc01ffffc,
3847  0x3f80,0x3ffff80,0x7fff803,0xfffff803,0xfffe001f,0xffe00000,0x0,0x0,0x0,0x0,0xffff80,0x7f800,0xfe0003,0xffff8001,0xffff01ff,
3848  0xff0003ff,0xffe01fff,0xff001fff,0xf01e0007,0x803ffff0,0xfff80,0x3c003f00,0x7800001f,0xc007f07f,0x1e003f,0xff8007ff,0xff000fff,
3849  0xe007ffff,0x7fffc,0x7fffffe,0xf0003c0,0xf0000f1e,0xf07,0x8003c1f0,0x3e01ff,0xfff8003f,0xf001e000,0x7fe0,0x7f80,0x0,0xe0000,
3850  0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
3851  0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x3fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x78f0,0x0,0xffff80,0x0,0x3fffff80,0x1f,
3852  0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc7f80070,0x3e1f0007,0x70000000,0x0,0x0,0x7700,0x7c000f8,0x0,0x780000,0x180000,
3853  0x3fff8000,0x1f00,0x3e0003c,0x1f03,0xc001f0f8,0x0,0x703f00,0x0,0x0,0x0,0x3f,0xff0000f0,0xf8000000,0x303e,0xc0f8,0x7800,0x0,
3854  0xffffc00,0x0,0x7,0x3800003e,0x3e000000,0x1c00,0xe000,0x3c00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00000f,0xe00001ff,
3855  0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000fe00,0x3c007fff,0x3fff8,
3856  0x1fffc0,0xfffe00,0x7fff000,0x1,0xffffc0f0,0x3c0780,0x1e03c00,0xf01e000,0x781f0003,0xe01e0000,0x3fff80,0xe0000,0x3c0000,0x1e3c0003,
3857  0x8ff0001f,0xf80003c,0x78000000,0x0,0xe00,0x3c00,0x1e3c00,0x3e1f000,0xe00000,0x3c00001,0xe3c0003e,0x1f00007f,0xf8000e3f,0xc0000380,
3858  0xf00,0x78f00,0xe3fc00,0x7c3e000,0x0,0x0,0x70000001,0xe00000f1,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,
3859  0x0,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,
3860  0x30000ffe,0xf80,0xc00001e0,0x3c0,0x1e000,0x101c040,0x0,0x0,0x0,0x0,0x78003f0,0x7e001ffe,0x3f807,0xe01f00fe,0x3f80,0x3ffff80,
3861  0x7e01803,0xfffff007,0xe03f003f,0x3f00000,0x0,0x0,0x0,0x0,0xfc0fc0,0x3ffe00,0xfe0003,0xffffc003,0xf81f01ff,0xff8003ff,0xffe01fff,
3862  0xff003f01,0xf01e0007,0x803ffff0,0xfff80,0x3c007e00,0x7800001f,0xc007f07f,0x1e007e,0xfc007ff,0xff801f83,0xf007ffff,0x800fc07c,
3863  0x7fffffe,0xf0003c0,0xf0000f0f,0x1e07,0xc007c0f8,0x7c01ff,0xfff8003c,0xf000,0x1e0,0xffc0,0x0,0xf0000,0x1,0xe0000000,0x0,0x780000,
3864  0x3e,0x0,0x78000,0x3c00,0xf000,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0x800000f0,0x1f80,
3865  0x0,0x0,0x7e0780,0x0,0x0,0x1f82000,0x0,0x0,0x0,0x7070,0x0,0x1f80f80,0x0,0x7fffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,
3866  0x0,0x1,0xc3f80070,0x3f3f0007,0xf0000000,0x0,0x0,0x7f00,0x3e001f0,0x0,0x780000,0x180000,0x7f018000,0xf80,0x7c0003c,0x3e00,
3867  0x4001f0f8,0xfe00,0x400f00,0x0,0x0,0x0,0x7f000000,0xe0,0x38000000,0x1e,0x38,0x7800,0x0,0x1ffe1c00,0x0,0x0,0x38000078,0xf000000,
3868  0x1c00,0xe000,0x7f800,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xf00001ff,0xffc03f81,0xf007ffff,0xc03ffffe,
3869  0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf800fe00,0x3c00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,
3870  0x3,0xf07fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x780f8007,0xc01e0000,0x7e0fc0,0xf0000,0x3c0000,0x1c1c0003,0x87f0001f,0xf80003f,
3871  0xf8000000,0x0,0xf00,0x3c00,0x1c1c00,0x3e1f000,0xf00000,0x3c00001,0xc1c0003e,0x1f00003f,0xc0000e1f,0xc00003c0,0xf00,0x70700,
3872  0xe1fc00,0x7c3e000,0x0,0x0,0x78000001,0xe00000e0,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3873  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,
3874  0x1f00,0x1e0,0x3c0,0x1e000,0x3c1c1e0,0x0,0x0,0x0,0x0,0x78007c0,0x1f001f9e,0x3c001,0xf010003e,0x7780,0x3c00000,0xf800000,0xf007,
3875  0xc01f007c,0x1f80000,0x0,0x0,0x0,0x0,0xe003e0,0x7fff00,0x1ef0003,0xc007e007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x301e0007,
3876  0x80007800,0x780,0x3c00fc00,0x7800001f,0xe00ff07f,0x1e00f8,0x3e00780,0x1fc03e00,0xf807801f,0xc01f001c,0xf000,0xf0003c0,0xf0000f0f,
3877  0x1e03,0xc00f8078,0x780000,0xf0003c,0xf000,0x1e0,0x1f3e0,0x0,0x78000,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,
3878  0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0xf0,0xf80,0x0,0x0,0xf80180,0x0,0x0,0x1e00000,
3879  0x0,0x0,0x0,0xe038,0x0,0x3e00380,0x0,0xfe0f0000,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc0f00070,0x3b370003,0xe0000000,
3880  0x0,0x0,0x3e00,0x1e001e0,0x0,0x780000,0x180000,0x7c000000,0x780,0x780003c,0x3c00,0x0,0x7ffc0,0x780,0x0,0x0,0x3,0xffe00000,
3881  0x1c0,0x3c000000,0xe,0x38,0xf000,0x0,0x3ffe1c00,0x0,0x0,0x38000078,0xf000000,0x1c00,0xe000,0x7f000,0xf000,0x3de000,0x1ef0000,
3882  0xf780000,0x7bc00003,0xde00001e,0xf00003e7,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
3883  0xe0001e03,0xfc00fe00,0x3c01f007,0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x7,0xc01f80f0,0x3c0780,0x1e03c00,0xf01e000,0x78078007,
3884  0x801e0000,0x7803c0,0x78000,0x780000,0x380e0003,0x81e00000,0x1f,0xf0000000,0x0,0x780,0x7800,0x380e00,0x0,0x780000,0x7800003,
3885  0x80e00000,0x1ff,0x80000e07,0x800001e0,0x1e00,0xe0380,0xe07800,0x0,0x0,0x0,0x3c000003,0xc00001c0,0x70000000,0x780,0x1e0000,
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,0x0,0x0,0x0,0x0,0x0,0x0,
3887  0x780000,0x3c1e0000,0x3c0e0007,0xfff01c07,0x1e00,0x1e0,0x780,0xf000,0x3e1c3e0,0x0,0x0,0x0,0x0,0xf0007c0,0x1f00181e,0x20000,
3888  0xf000001f,0xf780,0x3c00000,0x1f000000,0x1f00f,0x800f8078,0xf80000,0x0,0x0,0x0,0x0,0x8003e0,0x1fc0f80,0x1ef0003,0xc001e007,
3889  0x800101e0,0x7e003c0,0x1e00,0x7800,0x101e0007,0x80007800,0x780,0x3c00f800,0x7800001e,0xe00ef07f,0x801e00f0,0x1e00780,0x7c03c00,
3890  0x78078007,0xc01e0004,0xf000,0xf0003c0,0x78001e0f,0x1e03,0xe00f807c,0xf80000,0x1f0003c,0x7800,0x1e0,0x3e1f0,0x0,0x3c000,0x1,
3891  0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,
3892  0x1e,0xf0,0x780,0x0,0x0,0x1f00080,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x1e03c,0x0,0x3c00080,0x0,0xf80f0000,0x0,0x1f0000,0x0,0x0,
3893  0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x3bf70003,0xe0000000,0x0,0x0,0x3e00,0x1f003e0,0x0,0x780000,0x180000,0x78000000,0x7c0,0xf80003c,
3894  0x3c00,0x0,0x1f01f0,0x780,0x0,0x0,0xf,0x80f80000,0x1c0,0x1c000000,0xe,0x38,0x1e000,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,0x7800000,
3895  0x1c00,0xe000,0x7fc00,0xf000,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x80007800,0x10078000,0x3c0000,
3896  0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00ff00,0x3c01e003,0xc00f001e,0x7800f0,0x3c00780,0x1e003c00,
3897  0x7,0x800f00f0,0x3c0780,0x1e03c00,0xf01e000,0x7807c00f,0x801e0000,0xf803c0,0x3c000,0xf00000,0x780f0000,0x0,0x7,0xc0000000,
3898  0x0,0x3c0,0xf000,0x780f00,0x0,0x3c0000,0xf000007,0x80f00000,0x7ff,0xc0000000,0xf0,0x3c00,0x1e03c0,0x0,0x0,0x0,0x0,0x1e000007,
3899  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,
3900  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c1e001f,0xfff03803,0x80001e00,0x1e0,0x780,0xf000,0xf9cf80,
3901  0x0,0x0,0x0,0x0,0xf000780,0xf00001e,0x0,0xf800000f,0xe780,0x3c00000,0x1e000000,0x1e00f,0x78078,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,
3902  0x3f003c0,0x1ef0003,0xc000f00f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,0x3c01f000,0x7800001e,0xe00ef07f,
3903  0x801e01f0,0x1e00780,0x3c07c00,0x78078003,0xc03e0000,0xf000,0xf0003c0,0x78001e0f,0x1e01,0xf01f003c,0xf00000,0x3e0003c,0x7800,
3904  0x1e0,0x7c0f8,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,
3905  0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x8,0x40,0x0,0x7e0000,0x7c00000,0x1,0xf00f0000,
3906  0x0,0x3e0000,0x0,0x3f,0xfc0,0xfc3f0,0xfc3f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,0xf003c0,0x0,0x0,0x180000,0xf8000000,
3907  0x3c0,0xf00003c,0x3c00,0x0,0x3c0078,0x7ff80,0x0,0x0,0x1e,0x3c0000,0x1c0,0x1c000000,0xe,0xf0,0x0,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,
3908  0x7800000,0x1c00,0xe000,0x3c00,0x0,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x8000f800,0x78000,0x3c0000,
3909  0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00ff00,0x3c03e003,0xc01f001e,0xf800f0,0x7c00780,0x3e003c00,
3910  0xf,0x800f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803c00f,0x1fffc0,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3911  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,
3912  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x781e003f,0xfff03803,
3913  0x80001e00,0x1e0,0xf80,0xf000,0x3dde00,0x0,0x0,0x0,0x0,0xf000f00,0x780001e,0x0,0x7800000f,0x1e780,0x3c00000,0x3e000000,0x3e00f,
3914  0x780f0,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,0x7c001e0,0x3ef8003,0xc000f00f,0x1e0,0xf003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,
3915  0x3c03e000,0x7800001e,0xf01ef07b,0xc01e01e0,0xf00780,0x3e07800,0x3c078003,0xe03c0000,0xf000,0xf0003c0,0x78001e0f,0x1e00,0xf01e003e,
3916  0x1f00000,0x3c0003c,0x7800,0x1e0,0x78078,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,
3917  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,
3918  0xe70000,0x7800000,0x1,0xe00f0000,0x0,0x3c0000,0x0,0x3f,0xfc0,0xfc1f0,0x1f83f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,
3919  0xf807c0,0x0,0x0,0x180000,0xf0000000,0x3e0,0x1f00003c,0x3e00,0x0,0x70001c,0x3fff80,0x0,0x0,0x38,0xe0000,0x1c0,0x1c000078,
3920  0x1c,0x1fe0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x7df000,0x3ef8000,0x1f7c0000,0xfbe00007,
3921  0xdf00003c,0x780003c7,0x8000f000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f780,
3922  0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0xf80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803e01f,0x1ffff8,0xf001e0,
3923  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,
3924  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3925  0x780000,0x3c1e0000,0x781e003e,0x30703803,0x80001e00,0x1e0,0xf00,0x7800,0xff800,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,
3926  0x0,0x7800000f,0x3c780,0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x2000000,0x800000,0x1e0,0x78000e0,0x3c78003,
3927  0xc000f01e,0x1e0,0xf803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x701cf07b,0xc01e01e0,0xf00780,0x1e07800,
3928  0x3c078001,0xe03c0000,0xf000,0xf0003c0,0x7c003e0f,0x1e00,0xf83e001e,0x1e00000,0x7c0003c,0x3c00,0x1e0,0xf807c,0x0,0x0,0x1fe0001,
3929  0xe1fc0000,0x7f00003,0xf8780007,0xf000003c,0x7f0,0x783f0,0x0,0x0,0x7800000,0x1e00000,0x3e0f8000,0xfc00007,0xf8000007,0xf00001fc,
3930  0xf,0xc0003fc0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,0x1818000,
3931  0x7800000,0x1,0xe00f0000,0x0,0x7c0000,0x0,0x1f,0x80001f80,0x7c1f8,0x1f83e0,0x0,0x0,0x0,0x70,0x38c70007,0xf8000000,0x7f03,
3932  0xf0000000,0x0,0x780780,0x0,0x0,0xfe0000,0xf0000000,0x1e0,0x1e00003c,0x3f00,0x0,0xe07f0e,0x7fff80,0x0,0x0,0x70,0x70000,0x1c0,
3933  0x1c000078,0x3c,0x1fc0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x78f000,0x3c78000,0x1e3c0000,
3934  0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
3935  0xf80f780,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0x1f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801e01e,0x1ffffc,
3936  0xf007e0,0x3fc000,0x1fe0000,0xff00000,0x7f800003,0xfc00001f,0xe0000fc0,0xfc00007f,0xfe0,0x7f00,0x3f800,0x1fc000,0x0,0x0,0x0,
3937  0x1,0xf000001f,0x80000ff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x1f80000,0x1fc1e000,0x0,0x0,0x0,0x0,0x1e1fc0,0x0,0x0,0x0,0x0,
3938  0x0,0x0,0x0,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,
3939  0x781c007c,0x30003803,0x80001f00,0x1e0,0xf00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,0x0,0x7800000f,0x3c780,
3940  0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x1e000000,0xf00000,0x3e0,0xf0000e0,0x3c78003,0xc000f01e,0x1e0,0x7803c0,
3941  0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c0f8000,0x7800001e,0x701cf079,0xe01e01e0,0xf00780,0x1e07800,0x3c078001,0xe03c0000,
3942  0xf000,0xf0003c0,0x3c003c0f,0x3e00,0x787c001f,0x3e00000,0xf80003c,0x3c00,0x1e0,0x1f003e,0x0,0x0,0x1fffc001,0xe7ff0000,0x3ffe000f,
3943  0xfe78003f,0xfc001fff,0xfe001ffc,0xf0078ffc,0x1ffc00,0x7ff000,0x7800f80,0x1e0000f,0x7f1fc01e,0x3ff0001f,0xfe00079f,0xfc0007ff,
3944  0x3c003c7f,0xf001fff8,0x1fffff0,0x3c003c0,0xf0000f1e,0xf1f,0x7c1f0,0x1f00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3c00000,0x100000,
3945  0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7800000,0x1,0xe00f0000,0x1000000,0xf80000,0x40000002,0xf,0x80001f00,0x7e0f8,0x1f07c0,
3946  0x0,0x0,0x0,0x70,0x38c7003f,0xff000000,0xff8f,0xf8000100,0xffffe,0x7c0f80,0x0,0x0,0x3ffc000,0xf0000020,0x1001f0,0x3c00003c,
3947  0x1f80,0x0,0x1c3ffc7,0x7c0780,0x0,0x0,0xe3,0xff038000,0xe0,0x38000078,0x78,0x1ff0,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,
3948  0x7800000,0x1c00,0xe000,0xe00,0xf000,0x78f000,0x3c78000,0x1e3c0000,0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,
3949  0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,
3950  0x4000200f,0x3f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801f03e,0x1ffffe,0xf01fe0,0x3fff800,0x1fffc000,0xfffe0007,0xfff0003f,
3951  0xff8001ff,0xfc003ff3,0xfe0003ff,0xe0007ff8,0x3ffc0,0x1ffe00,0xfff000,0x3ff80001,0xffc0000f,0xfe00007f,0xf000003f,0xf8003c7f,
3952  0xe0003ffc,0x1ffe0,0xfff00,0x7ff800,0x3ffc000,0x1f80000,0xfff1c03c,0x3c01e0,0x1e00f00,0xf007800,0x781f0001,0xf01e7ff0,0x7c0007c,
3953  0x0,0x0,0x0,0x0,0x0,0x0,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,
3954  0x3c1e003f,0xfffff078,0x30003803,0x80000f00,0x1e0,0x1f00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x3c000f00,0x780001e,0x0,0x7800000f,
3955  0x78780,0x3c00000,0x3c000000,0x7c00f,0x780f0,0x3c0007,0xe000003f,0x0,0xfe000000,0xfe0000,0x3c0,0x1f000070,0x7c7c003,0xc000f01e,
3956  0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c1f0000,0x7800001e,0x783cf079,0xe01e03c0,0xf00780,0x1e0f000,0x3c078001,
3957  0xe03c0000,0xf000,0xf0003c0,0x3c003c07,0x81f03c00,0x7c7c000f,0x87c00000,0xf00003c,0x1e00,0x1e0,0x3e001f,0x0,0x0,0x3fffe001,
3958  0xefff8000,0x7fff001f,0xff78007f,0xfe001fff,0xfe003ffe,0xf0079ffe,0x1ffc00,0x7ff000,0x7801f00,0x1e0000f,0xffbfe01e,0x7ff8003f,
3959  0xff0007bf,0xfe000fff,0xbc003cff,0xf803fffc,0x1fffff0,0x3c003c0,0x78001e1e,0xf0f,0x800f80f0,0x1e00ff,0xffe0001e,0xf0,0x780,
3960  0x0,0x0,0x3c00000,0x380000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1008000,0x7800000,0x3,0xe00f0000,0x3800000,0xf00000,0xe0000007,
3961  0xf,0x80001f00,0x3e0f8,0x1e07c0,0x0,0x0,0x0,0x70,0x3807007f,0xff800000,0x1ffdf,0xfc000380,0xffffe,0x3e1f00,0x0,0x0,0xfffe000,
3962  0xf0000030,0x3800f8,0x7c00003c,0xfc0,0x0,0x18780c3,0xf00780,0x80100,0x0,0xc3,0xffc18000,0xf0,0x78000078,0xf0,0xf0,0x0,0x3c003c0,
3963  0xfffe1c00,0x0,0x0,0x380000f0,0x7800801,0x1c00,0xe000,0x1e00,0xf000,0xf8f800,0x7c7c000,0x3e3e0001,0xf1f0000f,0x8f80007c,0x7c000787,
3964  0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078001,0xe03c000f,
3965  0x1e00078,0xf0003c0,0x78001e00,0xe000701f,0x3fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x7800f87c,0x1e007f,0xf07e00,0x7fffc00,0x3fffe001,
3966  0xffff000f,0xfff8007f,0xffc003ff,0xfe007ff7,0xff0007ff,0xf000fffc,0x7ffe0,0x3fff00,0x1fff800,0x3ff80001,0xffc0000f,0xfe00007f,
3967  0xf00000ff,0xf8003cff,0xf0007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x1f80001,0xfffb803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,
3968  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,
3969  0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e003f,0xfffff078,0x30001c07,0xf80,0x1e0,0x1e00,0x3c00,0xff800,0x1e0000,0x0,0x0,0x0,0x3c001e00,
3970  0x3c0001e,0x0,0x7800001e,0x70780,0x3c00000,0x78000000,0x78007,0x800f00f0,0x3e0007,0xe000003f,0x3,0xfe000000,0xff8000,0x7c0,
3971  0x1e000070,0x783c003,0xc001f01e,0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c3e0000,0x7800001e,0x3838f079,
3972  0xe01e03c0,0x780780,0x1e0f000,0x1e078001,0xe03c0000,0xf000,0xf0003c0,0x3c007c07,0x81f03c00,0x3ef80007,0x87800000,0x1f00003c,
3973  0x1e00,0x1e0,0x7c000f,0x80000000,0x0,0x3ffff001,0xffffc000,0xffff003f,0xff7800ff,0xff001fff,0xfe007ffe,0xf007bffe,0x1ffc00,
3974  0x7ff000,0x7803e00,0x1e0000f,0xffffe01e,0xfff8007f,0xff8007ff,0xff001fff,0xbc003dff,0xf807fffc,0x1fffff0,0x3c003c0,0x78001e0f,
3975  0x1e07,0xc01f00f0,0x1e00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7c00000,0x7c0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1018000,0x7800000,
3976  0x3,0xc00f0000,0x7c00000,0x1f00001,0xf000000f,0x80000007,0xc0003e00,0x1e07c,0x3e0780,0x0,0x0,0x0,0x70,0x380700ff,0xff800000,
3977  0x3ffff,0xfe0007c0,0xffffe,0x1e1e00,0x0,0x780000,0x1fffe000,0xf0000078,0x7c0078,0x7800003c,0xff0,0x0,0x38e0003,0x80f00780,
3978  0x180300,0x0,0x1c3,0x81e1c000,0x7f,0xf0000078,0x1e0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800c01,0x80001c00,
3979  0xe000,0x603e00,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x7800078,0x3c000f87,0x8001e000,0x78000,0x3c0000,0x1e00000,
3980  0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f01,0xf000f81e,
3981  0x7bc0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007878,0x1e001f,0xf0f800,0x7fffe00,0x3ffff001,0xffff800f,0xfffc007f,0xffe003ff,
3982  0xff007fff,0xff800fff,0xf001fffe,0xffff0,0x7fff80,0x3fffc00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00001ff,0xfc003dff,0xf000ffff,
3983  0x7fff8,0x3fffc0,0x1fffe00,0xffff000,0x1f80003,0xffff803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,0xe01ffffc,0x3c00078,0x0,
3984  0x0,0x0,0x0,0x0,0x0,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,
3985  0x3c1e003f,0xfffff078,0x30001e0f,0x300780,0x1e0,0x1e00,0x3c00,0x3dde00,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf800003e,
3986  0xf0780,0x3dfc000,0x783f8000,0xf8007,0xc01f00f0,0x3e0007,0xe000003f,0x1f,0xfc000000,0x7ff000,0xf80,0x3e007c70,0x783c003,0xc001e03c,
3987  0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,0x80007800,0x780,0x3c7c0000,0x7800001e,0x3878f078,0xf01e03c0,0x780780,0x1e0f000,0x1e078001,
3988  0xe03e0000,0xf000,0xf0003c0,0x1e007807,0x83f03c00,0x3ef00007,0xcf800000,0x3e00003c,0xf00,0x1e0,0xf80007,0xc0000000,0x0,0x3e01f801,
3989  0xfe07e001,0xf80f007e,0x7f801f8,0x1f801fff,0xfe00fc0f,0xf007f83f,0x1ffc00,0x7ff000,0x7807c00,0x1e0000f,0x87e1e01f,0xe0fc00fc,
3990  0xfc007f8,0x1f803f03,0xfc003df0,0x3807e03c,0x1fffff0,0x3c003c0,0x78003e0f,0x1e03,0xe03e00f8,0x3e00ff,0xffe0001e,0xf0,0x780,
3991  0x0,0x0,0x7800000,0xfe0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7c00000,0x3,0xc00f0000,0xfe00000,0x3e00003,0xf800001f,
3992  0xc0000007,0xc0003e00,0x1e03c,0x3c0f80,0x0,0x0,0x0,0x70,0x380700fc,0x7800000,0x7c1fe,0x3e000fe0,0xffffe,0x1f3e00,0x0,0x780000,
3993  0x3f98e000,0xf000003c,0xfcf8007c,0xf800003c,0x3ffc,0x0,0x31c0001,0x80f00f80,0x380700,0x0,0x183,0x80e0c000,0x3f,0xe0000078,
3994  0x3c0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x38000078,0xf000e01,0xc003ffe0,0x1fff00,0x7ffc00,0xf000,0xf07800,0x783c000,0x3c1e0001,
3995  0xe0f0000f,0x7800078,0x3c000f07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
3996  0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf801f01e,0xf3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007cf8,
3997  0x1e000f,0x80f0f000,0x7c03f00,0x3e01f801,0xf00fc00f,0x807e007c,0x3f003e0,0x1f80707f,0x8f801f80,0xf003f03f,0x1f81f8,0xfc0fc0,
3998  0x7e07e00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00003ff,0xfc003fc1,0xf801f81f,0x800fc0fc,0x7e07e0,0x3f03f00,0x1f81f800,0x1f80007,
3999  0xe07f003c,0x3c01e0,0x1e00f00,0xf007800,0x780f8003,0xe01fe07e,0x3e000f8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4000  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3f,0xfffff078,0x30000ffe,0x1f007c0,0x0,0x1e00,
4001  0x3c00,0xf9cf80,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf00000fc,0x1e0780,0x3fff800,0x78ffe000,0xf0003,0xe03e00f0,
4002  0x3e0007,0xe000003f,0x7f,0xe01fffff,0xf00ffc00,0x1f80,0x3c01ff70,0x783c003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,
4003  0x80007800,0x780,0x3cfc0000,0x7800001e,0x3c78f078,0xf01e03c0,0x780780,0x3e0f000,0x1e078003,0xc01f0000,0xf000,0xf0003c0,0x1e007807,
4004  0x83f83c00,0x1ff00003,0xcf000000,0x3e00003c,0xf00,0x1e0,0x0,0x0,0x0,0x20007801,0xfc03e003,0xe003007c,0x3f803e0,0x7c0003c,
4005  0xf807,0xf007e00f,0x3c00,0xf000,0x780f800,0x1e0000f,0x87e1f01f,0x803c00f8,0x7c007f0,0xf803e01,0xfc003f80,0x80f8004,0x3c000,
4006  0x3c003c0,0x3c003c0f,0x1e03,0xe03e0078,0x3c0000,0x7c0001e,0xf0,0x780,0x0,0x0,0x3ffff800,0x1ff0000,0x0,0x7800000,0x0,0x18,
4007  0xc0,0x0,0x1818000,0x3e00000,0x3,0xc00f0000,0x1ff00000,0x3e00007,0xfc00003f,0xe0000003,0xc0003c00,0xf03c,0x3c0f00,0x0,0x0,
4008  0x0,0x70,0x380701f0,0x800000,0x780fc,0x1e001ff0,0x7c,0xf3c00,0x0,0x780000,0x7e182000,0xf000001f,0xfff00ffc,0xffc0003c,0x3cfe,
4009  0x0,0x31c0001,0x80f01f80,0x780f00,0x0,0x183,0x80e0c000,0xf,0x80000078,0x780,0x38,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x38000078,
4010  0xf000f01,0xe003ffe0,0x1fff00,0x7ff800,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x78000f8,0x3e000f07,0x8003c000,0x78000,
4011  0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
4012  0x78000f00,0x7c03e01e,0x1e3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78003cf0,0x1e0007,0x80f1e000,0x4000f00,0x20007801,0x3c008,
4013  0x1e0040,0xf00200,0x780403f,0x7803e00,0x3007c00f,0x803e007c,0x1f003e0,0xf801f00,0x780000,0x3c00000,0x1e000000,0xf00007f0,
4014  0x3e003f00,0x7801f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e003c,0x3c01e0,0x1e00f00,0xf007800,0x78078003,
4015  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,
4016  0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xf078007c,0x300007fc,0x7e00fe0,0x0,0x1e00,0x3c00,0x3e1c3e0,0x1e0000,0x0,0x0,0x0,0xf0001e00,
4017  0x3c0001e,0x1,0xf000fff8,0x1e0780,0x3fffe00,0x79fff000,0x1f0001,0xfffc00f0,0x7e0007,0xe000003f,0x3ff,0x801fffff,0xf003ff80,
4018  0x3f00,0x3c03fff0,0xf01e003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3df80000,0x7800001e,
4019  0x1c70f078,0x781e03c0,0x780780,0x3c0f000,0x1e078007,0xc01f8000,0xf000,0xf0003c0,0x1e007807,0x83f83c00,0xfe00003,0xff000000,
4020  0x7c00003c,0x780,0x1e0,0x0,0x0,0x0,0x7c01,0xf801f007,0xc00100f8,0x1f803c0,0x3c0003c,0x1f003,0xf007c00f,0x80003c00,0xf000,
4021  0x783f000,0x1e0000f,0x3c0f01f,0x3e01f0,0x3e007e0,0x7c07c00,0xfc003f00,0xf0000,0x3c000,0x3c003c0,0x3c003c0f,0x1e01,0xf07c007c,
4022  0x7c0000,0xfc0001e,0xf0,0x780,0x0,0x0,0x3ffff000,0x3838000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0xff0000,0x3f00000,0x3,0xc00fff00,
4023  0x38380000,0x7c0000e,0xe000070,0x70000001,0xe0003c00,0xf01e,0x780e00,0x0,0x0,0x0,0x0,0x1e0,0x0,0x780f8,0xf003838,0xfc,0xffc00,
4024  0x0,0x780000,0x7c180000,0xf000000f,0xffe00fff,0xffc0003c,0x783f,0x80000000,0x6380000,0xc0f83f80,0xf81f00,0x0,0x303,0x80e06000,
4025  0x0,0x78,0xf00,0x78,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x3800003c,0x3e000f81,0xf003ffe0,0x1fff00,0x1fc000,0xf000,0x1e03c00,
4026  0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e000f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,
4027  0x3c000001,0xe0001e00,0x3c0f0f0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3e07c01e,0x1e3c0f0,0x3c0780,0x1e03c00,
4028  0xf01e000,0x78003ff0,0x1e0007,0x80f1e000,0xf80,0x7c00,0x3e000,0x1f0000,0xf80000,0x7c0001e,0x3c07c00,0x10078007,0x803c003c,
4029  0x1e001e0,0xf000f00,0x780000,0x3c00000,0x1e000000,0xf00007c0,0x1e003e00,0x7c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,
4030  0xf,0x801f003c,0x3c01e0,0x1e00f00,0xf007800,0x7807c007,0xc01f801f,0x1f001f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4031  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xe078003c,0x300001f0,0x3f801ff0,0x0,
4032  0x3c00,0x1e00,0x3c1c1e0,0x1e0000,0x0,0x0,0x0,0xf0001e0f,0x3c0001e,0x3,0xe000fff0,0x3c0780,0x3ffff00,0x7bfff800,0x1e0000,0x7ff00078,
4033  0x7e0007,0xe000003f,0x1ffc,0x1fffff,0xf0007ff0,0x7e00,0x3c07c3f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,
4034  0x1fffff,0x80007800,0x780,0x3ffc0000,0x7800001e,0x1ef0f078,0x781e03c0,0x780780,0x7c0f000,0x1e07801f,0x800ff000,0xf000,0xf0003c0,
4035  0xf00f807,0x83b83c00,0xfc00001,0xfe000000,0xf800003c,0x780,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0xc00000f0,0xf80780,0x3c0003c,
4036  0x1e001,0xf007c007,0x80003c00,0xf000,0x787e000,0x1e0000f,0x3c0f01f,0x1e01e0,0x1e007c0,0x3c07800,0x7c003f00,0xf0000,0x3c000,
4037  0x3c003c0,0x3e007c07,0x80003c00,0xf8f8003c,0x780000,0xf80001e,0xf0,0x780,0x0,0x0,0x7ffff000,0x601c000,0x3,0xffff0000,0x0,
4038  0xfff,0xf8007fff,0xc0000000,0x7e003c,0x1fe0000,0xc0003,0xc00fff00,0x601c0000,0xf800018,0x70000c0,0x38000001,0xe0007800,0x701e,
4039  0x701e00,0x0,0x0,0x0,0x0,0x1e0,0x6,0x700f8,0xf00601c,0xf8,0x7f800,0x0,0x780000,0xf8180000,0xf000000f,0x87c00fff,0xffc0003c,
4040  0xf01f,0xc0000000,0x6380000,0xc07ff780,0x1f03e03,0xfffffe00,0x303,0x81c06000,0x0,0x1ffff,0xfe001e00,0x180f8,0x0,0x3c003c0,
4041  0x3ffe1c00,0x3f00000,0x0,0x3800003f,0xfe0007c0,0xf8000000,0x18000000,0xc0000006,0x1f000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,
4042  0x3c000f0,0x1e001f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f0f0,
4043  0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f0f801e,0x3c3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,
4044  0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07c00,0xf0007,0x8078003c,0x3c001e0,0x1e000f00,0x780000,0x3c00000,
4045  0x1e000000,0xf0000f80,0x1f003e00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0xf,0x3f003c,0x3c01e0,0x1e00f00,0xf007800,
4046  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,
4047  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe078003f,0xb0000000,0xfc003cf0,0x0,0x3c00,0x1e00,0x101c040,0x1e0000,0x0,0x0,0x1,
4048  0xe0001e1f,0x83c0001e,0x7,0xe000fff0,0x3c0780,0x3c03f80,0x7fc0fc00,0x1e0000,0xfff80078,0xfe0007,0xe000003f,0x7fe0,0x1fffff,
4049  0xf0000ffc,0xfc00,0x780f81f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3ffc0000,
4050  0x7800001e,0x1ef0f078,0x3c1e03c0,0x780780,0x1fc0f000,0x1e07ffff,0x7ff00,0xf000,0xf0003c0,0xf00f007,0xc3b87c00,0x7c00001,0xfe000000,
4051  0xf800003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0x800000f0,0xf80780,0x1e0003c,0x1e001,0xf0078007,0x80003c00,0xf000,0x78fc000,
4052  0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,0x3c07800,0x7c003e00,0xf0000,0x3c000,0x3c003c0,0x1e007807,0x80003c00,0x7df0003c,0x780000,
4053  0x1f00001e,0xf0,0x780,0x0,0x0,0x7800000,0xe7ce000,0x3,0xffff0000,0x0,0xfff,0xf8007fff,0xc0000000,0x1f0,0xffe000,0x1c0003,
4054  0xc00fff00,0xe7ce0000,0xf800039,0xf38001cf,0x9c000000,0xe0007800,0x780e,0x701c00,0x0,0x0,0x0,0x0,0x1e0,0x7,0xf0078,0xf00e7ce,
4055  0x1f0,0x7f800,0x0,0x780000,0xf0180000,0xf000000e,0x1c0001f,0xe000003c,0xf007,0xe0000000,0x6380000,0xc03fe780,0x3e07c03,0xfffffe00,
4056  0x303,0xffc06000,0x0,0x1ffff,0xfe003ffe,0x1fff0,0x0,0x3c003c0,0x1ffe1c00,0x3f00000,0x7,0xffc0001f,0xfc0003e0,0x7c000001,0xfc00000f,
4057  0xe000007f,0x1e000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,
4058  0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,
4059  0x783c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07800,
4060  0xf0003,0xc078001e,0x3c000f0,0x1e000780,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,
4061  0x7800780,0x3c003c00,0xf,0x7f003c,0x3c01e0,0x1e00f00,0xf007800,0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4062  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,
4063  0xf0007cf8,0x7800000,0x3c00,0x1e00,0x1c000,0x1e0000,0x0,0x0,0x1,0xe0001e1f,0x83c0001e,0xf,0xc000fff8,0x780780,0x2000f80,0x7f803e00,
4064  0x3e0003,0xfffe007c,0x1fe0000,0x0,0x3ff00,0x0,0x1ff,0x8001f000,0x780f00f0,0x1f00f003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,
4065  0xfe03c00f,0xf81fffff,0x80007800,0x780,0x3ffe0000,0x7800001e,0xee0f078,0x3c1e03c0,0x7807ff,0xff80f000,0x1e07fffe,0x3ffe0,
4066  0xf000,0xf0003c0,0xf00f003,0xc7bc7800,0xfc00000,0xfc000001,0xf000003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xe000f80f,0x800001e0,
4067  0xf80f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x79f8000,0x1e0000f,0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003e00,
4068  0xf0000,0x3c000,0x3c003c0,0x1e007807,0x81e03c00,0x7df0003e,0xf80000,0x3e00003e,0xf0,0x7c0,0xfc000,0x80000000,0x7800000,0x1e7cf000,
4069  0x3,0xffff0000,0x0,0x18,0xc0,0x0,0xf80,0x7ffc00,0x380003,0xc00fff01,0xe7cf0000,0x1f000079,0xf3c003cf,0x9e000000,0xe0007000,
4070  0x380e,0xe01c00,0x0,0x0,0x0,0x0,0x1e0,0x3,0x800f0078,0xf01e7cf,0x3e0,0x3f000,0x0,0x780000,0xf018001f,0xfff8001e,0x1e0000f,
4071  0xc000003c,0xf003,0xe0000000,0x6380000,0xc00fc780,0x7c0f803,0xfffffe00,0x303,0xfe006000,0x0,0x1ffff,0xfe003ffe,0x1ffe0,0x0,
4072  0x3c003c0,0xffe1c00,0x3f00000,0x7,0xffc00007,0xf00001f0,0x3e00001f,0xfc0000ff,0xe00007ff,0x3e000,0x3e01e00,0x1f00f000,0xf8078007,
4073  0xc03c003e,0x1e001e0,0xf001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,
4074  0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000fc0,
4075  0x1e0007,0x80f1f000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c0f800,0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,
4076  0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1e,0xf7803c,0x3c01e0,0x1e00f00,
4077  0xf007800,0x7803e00f,0x801e000f,0x80f803e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4078  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe0f0000f,0xff00001f,0x8000f87c,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,
4079  0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x1f,0x800000fe,0xf00780,0x7c0,0x7f001e00,0x3c0007,0xe03f003f,0x3fe0000,0x0,0x3fc00,0x0,
4080  0x7f,0x8001e000,0x781f00f0,0x1e00f003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3f9f0000,0x7800001e,
4081  0xfe0f078,0x3c1e03c0,0x7807ff,0xff00f000,0x1e07fff8,0xfff8,0xf000,0xf0003c0,0xf81f003,0xc7bc7800,0xfe00000,0x78000003,0xe000003c,
4082  0x1e0,0x1e0,0x0,0x0,0x0,0x1fffc01,0xe000780f,0x1e0,0x780f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7bf0000,0x1e0000f,
4083  0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xf8000,0x3c000,0x3c003c0,0x1f00f807,0x81f03c00,0x3fe0001e,0xf00000,0x7c00007c,
4084  0xf0,0x3e0,0x3ff801,0x80000000,0x7800000,0x3cfcf800,0x3,0xffff0000,0x0,0x18,0xc0,0x0,0x7c00,0x1fff00,0x700003,0xc00f0003,
4085  0xcfcf8000,0x3e0000f3,0xf3e0079f,0x9f000000,0xf000,0x1000,0x0,0x0,0x0,0x0,0x0,0x1f0,0x1,0xc00f0078,0xf03cfcf,0x800007c0,0x1e000,
4086  0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x8000003c,0xf001,0xf0000000,0x6380000,0xc0000000,0xf81f003,0xfffffe00,0x303,
4087  0x87006000,0x0,0x1ffff,0xfe003ffe,0x7f00,0x0,0x3c003c0,0x3fe1c00,0x3f00000,0x7,0xffc00000,0xf8,0x1f0001ff,0xf0000fff,0x80007ffc,
4088  0xfc000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf001e07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,
4089  0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3fc001e,0x1e03c0f0,0x3c0780,
4090  0x1e03c00,0xf01e000,0x78000780,0x1e0007,0x80f0fc00,0x3fff80,0x1fffc00,0xfffe000,0x7fff0003,0xfff8001f,0xffc0001e,0x3c0f000,
4091  0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,0x3c00000,0x1e000000,0xf0001e00,0xf803c00,0x3c078001,0xe03c000f,0x1e00078,
4092  0xf0003c0,0x78001e07,0xfffffe1e,0x1e7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801e00f,0x1e0007,0x807803c0,0x0,0x0,0x0,0x0,0x0,
4093  0x0,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,
4094  0xffc0007e,0xf03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x3f,0x3e,0xf00780,0x3c0,0x7e001e00,
4095  0x7c000f,0x800f001f,0xffde0000,0x0,0x3e000,0x0,0xf,0x8003e000,0x781e0070,0x1e00f003,0xc001f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,
4096  0xf81e0007,0x80007800,0x780,0x3f1f0000,0x7800001e,0x7c0f078,0x1e1e03c0,0x7807ff,0xfc00f000,0x1e07fffe,0xffc,0xf000,0xf0003c0,
4097  0x781e003,0xc71c7800,0x1ff00000,0x78000003,0xe000003c,0x1e0,0x1e0,0x0,0x0,0x0,0xffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,
4098  0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7f000,0x3c000,
4099  0x3c003c0,0xf00f007,0xc1f07c00,0x1fc0001f,0x1f00000,0xfc000ff8,0xf0,0x1ff,0xfffe07,0x80000000,0x7800000,0x7ffcfc00,0x0,0xf000000,
4100  0x0,0x18,0xc0,0x0,0x3e000,0x1ff80,0xe00003,0xc00f0007,0xffcfc000,0x3e0001ff,0xf3f00fff,0x9f800000,0x6000,0x0,0x0,0x7c000,
4101  0x0,0x0,0x0,0xfe,0x0,0xe00f007f,0xff07ffcf,0xc0000fc0,0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x80000000,0xf800,
4102  0xf0000000,0x6380000,0xc0000000,0x1f03c000,0x1e00,0x303,0x83806000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xfe1c00,0x3f00000,0x0,
4103  0x0,0x3c,0xf801fff,0xfff8,0x7ffc0,0x1f8000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf003c07,0x8003c000,0x78000,
4104  0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
4105  0x78000f00,0x1f8001e,0x1e03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e000f,0x80f0ff00,0x1ffff80,0xffffc00,0x7fffe003,
4106  0xffff001f,0xfff800ff,0xffc007ff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,
4107  0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x3c7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801f01f,
4108  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,
4109  0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00000,0xfff003f0,0x1f00f03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x7ff80000,0x3,
4110  0xc0001e0f,0x3c0001e,0x7e,0x1f,0x1e00780,0x3e0,0x7e000f00,0x78000f,0x7800f,0xff9e0000,0x0,0x3fc00,0x0,0x7f,0x8003c000,0x781e0070,
4111  0x3e00f803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3e0f8000,0x7800001e,0x7c0f078,0x1e1e03c0,
4112  0x7807ff,0xf000f000,0x1e07807f,0xfe,0xf000,0xf0003c0,0x781e003,0xc71c7800,0x3ef00000,0x78000007,0xc000003c,0x1e0,0x1e0,0x0,
4113  0x0,0x0,0x1ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,
4114  0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7ff80,0x3c000,0x3c003c0,0xf00f003,0xc1f07800,0x1fc0000f,0x1e00000,0xf8000ff0,0xf0,
4115  0xff,0xffffff,0x80000000,0x3fffc000,0xfff9fe00,0x0,0xf000000,0x0,0x18,0xc0,0x0,0x1f0000,0x1fc0,0x1c00003,0xc00f000f,0xff9fe000,
4116  0x7c0003ff,0xe7f81fff,0x3fc00000,0x0,0x0,0x0,0xfe000,0x1ffffc0f,0xfffffc00,0x0,0xff,0xf0000000,0x700f007f,0xff0fff9f,0xe0000f80,
4117  0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00fff,0xffc00000,0xf800,0xf0000000,0x6380000,0xc0ffff80,0x3e078000,0x1e00,0x7ff80303,
4118  0x83c06000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,0x0,0x7f,0xff00001e,0x7c1fff0,0xfff80,0x7ffc00,0x3f0000,0x7c01f00,
4119  0x3e00f801,0xf007c00f,0x803e007c,0x1f003e0,0xf803c07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
4120  0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f8001e,0x3c03c0f0,0x3c0780,0x1e03c00,0xf01e000,
4121  0x78000780,0x1e001f,0xf07f80,0x3ffff80,0x1ffffc00,0xffffe007,0xffff003f,0xfff801ff,0xffc03fff,0xffc0f000,0x1fffff,0xc0fffffe,
4122  0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,
4123  0xfffffe1e,0x787803c,0x3c01e0,0x1e00f00,0xf007800,0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4124  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,
4125  0x7800000,0x3c00,0x1e00,0x0,0x7fffff80,0x0,0x7ff80000,0x7,0x80001e00,0x3c0001e,0xfc,0xf,0x1e00780,0x1e0,0x7c000f00,0x78000f,
4126  0x78007,0xff1e0000,0x0,0x3ff00,0x0,0x1ff,0x8003c000,0x781e0070,0x3c007803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,
4127  0x80007800,0x780,0x3c07c000,0x7800001e,0x7c0f078,0xf1e03c0,0x780780,0xf000,0x1e07801f,0x3e,0xf000,0xf0003c0,0x781e003,0xcf1c7800,
4128  0x3cf80000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,0x0,0x0,0x3ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,
4129  0x80003c00,0xf000,0x7ff8000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3fff0,0x3c000,0x3c003c0,0xf81f003,
4130  0xc3b87800,0xf80000f,0x1e00001,0xf0000ff0,0xf0,0xff,0xf03fff,0x80000000,0x3fff8001,0xfff1ff00,0x0,0xf000000,0x0,0x18,0xc0,
4131  0x0,0x380000,0x7c0,0x3c00003,0xc00f001f,0xff1ff000,0xf80007ff,0xc7fc3ffe,0x3fe00000,0x0,0x0,0x0,0x1ff000,0x7ffffe1f,0xffffff00,
4132  0x0,0x7f,0xfe000000,0x780f007f,0xff1fff1f,0xf0001f00,0x1e000,0x0,0x780001,0xe0180000,0xf000001c,0xe00fff,0xffc00000,0x7c00,
4133  0xf0000000,0x31c0001,0x80ffff80,0x3e078000,0x1e00,0x7ff80183,0x81c0c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,
4134  0x0,0x7f,0xff00001e,0x7c7ff03,0xc03ff8fe,0x1ffc0f0,0x7e0000,0x7800f00,0x3c007801,0xe003c00f,0x1e0078,0xf003c0,0x7803c07,0x8003c000,
4135  0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,
4136  0xf0001e0,0x78000f00,0x3fc001e,0x7803c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e007f,0xf03fe0,0x7ffff80,0x3ffffc01,
4137  0xffffe00f,0xffff007f,0xfff803ff,0xffc07fff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,
4138  0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x707803c,0x3c01e0,0x1e00f00,0xf007800,
4139  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,
4140  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x30f81f00,0xffe1e00f,0x87800000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,
4141  0x7,0x80001e00,0x3c0001e,0x1f8,0x7,0x83c00780,0x1e0,0x7c000f00,0xf8001e,0x3c001,0xfc1e0000,0x0,0x7fe0,0x0,0xffc,0x3c000,0x781e0070,
4142  0x3ffff803,0xc000783c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x380f078,0xf1e03c0,
4143  0x780780,0xf000,0x1e07800f,0x8000001e,0xf000,0xf0003c0,0x3c3c003,0xcf1e7800,0x7c780000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,
4144  0x0,0x0,0x7f003c01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7f7c000,0x1e0000f,0x3c0f01e,
4145  0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfff8,0x3c000,0x3c003c0,0x781e003,0xc3b87800,0x1fc00007,0x83e00003,0xe0000ff8,0xf0,
4146  0x1ff,0xc007fe,0x0,0x7fff8001,0xffe3ff00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x3c0,0x7800003,0xc00f001f,0xfe3ff000,0xf80007ff,
4147  0x8ffc3ffc,0x7fe00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x1f,0xff000000,0x3c0f007f,0xff1ffe3f,0xf0003e00,0x1e000,0x0,0x780001,
4148  0xe0180000,0xf000001e,0x1e00fff,0xffc00000,0x3f00,0xf0000000,0x31c0001,0x80ffff80,0x1f03c000,0x1e00,0x7ff80183,0x81c0c000,
4149  0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x7f,0xff00003c,0xf87f007,0xc03f83ff,0x81fc01f0,0x7c0000,0x7ffff00,0x3ffff801,
4150  0xffffc00f,0xfffe007f,0xfff003ff,0xff807fff,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
4151  0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf003c0f0,0x3c0780,0x1e03c00,0xf01e000,
4152  0x78000780,0x1ffffe,0xf00ff0,0xfe00780,0x7f003c03,0xf801e01f,0xc00f00fe,0x7807f0,0x3c0ffff,0xffc0f000,0x1fffff,0xc0fffffe,
4153  0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
4154  0x1e,0xf07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783e,0x1e0007,0x801e0f80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4155  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x307c0801,0xe1f1e00f,0x87000000,
4156  0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,0xf,0x1e00,0x3c0001e,0x3f0,0x7,0x83fffffc,0x1e0,0x7c000f00,0xf0001e,0x3c000,0x3e0000,
4157  0x0,0x1ffc,0x1fffff,0xf0007ff0,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x3c000,0x781e0007,0x80007800,
4158  0x780,0x3c03e000,0x7800001e,0xf078,0x79e03c0,0x780780,0xf000,0x1e078007,0x8000000f,0xf000,0xf0003c0,0x3c3c001,0xee0ef000,
4159  0xf87c0000,0x7800001f,0x3c,0x78,0x1e0,0x0,0x0,0x0,0x7c003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
4160  0xf000,0x7e3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x1ffc,0x3c000,0x3c003c0,0x781e003,0xe3b8f800,
4161  0x1fc00007,0x83c00007,0xc00000fc,0xf0,0x3e0,0x8001f8,0x0,0x7800000,0xffc7fe00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,
4162  0xf000003,0xc00f000f,0xfc7fe001,0xf00003ff,0x1ff81ff8,0xffc00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x3,0xff800000,0x1e0f0078,
4163  0xffc7f,0xe0007c00,0x1e000,0x0,0x780001,0xe0180000,0xf000000e,0x1c00007,0x80000000,0x1f81,0xe0000000,0x38e0003,0x80000000,
4164  0xf81f000,0x1e00,0x7ff801c3,0x80e1c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf8,0x1f070007,0xc03803ff,0xc1c001f0,
4165  0xf80000,0xfffff00,0x7ffff803,0xffffc01f,0xfffe00ff,0xfff007ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,
4166  0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f00f,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,0xf003c0f0,
4167  0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1ffffc,0xf003f8,0xf800780,0x7c003c03,0xe001e01f,0xf00f8,0x7807c0,0x3c0fc1e,0xf000,
4168  0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,
4169  0xf0003c0,0x78001e00,0x1e,0x1e07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783c,0x1e0007,0x801e0f00,0x0,0x0,0x0,0x0,0x0,0x0,
4170  0x0,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,
4171  0xc071e007,0xcf000000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0xf,0xf00,0x780001e,0x7e0,0x7,0x83fffffc,0x1e0,0x7c000f00,0x1f0001e,
4172  0x3c000,0x3c0000,0x0,0x3ff,0x801fffff,0xf003ff80,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,
4173  0x80007800,0x780,0x3c01f000,0x7800001e,0xf078,0x79e03c0,0xf00780,0xf000,0x3e078007,0xc000000f,0xf000,0xf0003c0,0x3c3c001,
4174  0xee0ef000,0xf03e0000,0x7800003e,0x3c,0x78,0x1e0,0x0,0x0,0x0,0xf8003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,
4175  0x80003c00,0xf000,0x7c3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfc,0x3c000,0x3c003c0,0x3c3e001,0xe7b8f000,
4176  0x3fe00007,0xc7c0000f,0xc000003e,0xf0,0x7c0,0x0,0x0,0x7c00000,0x7fcffc00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,0x1e000003,
4177  0xc00f0007,0xfcffc003,0xe00001ff,0x3ff00ff9,0xff800000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x1f800000,0xf0f0078,0x7fcff,
4178  0xc000fc00,0x1e000,0x0,0x780001,0xe0180000,0xf000000f,0x87c00007,0x80000000,0xfe3,0xe0000000,0x18780c3,0x0,0x7c0f800,0x1e00,
4179  0xc3,0x80e18000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x1f0,0x3e00000f,0xc0000303,0xe00003f0,0xf00000,0xfffff80,
4180  0x7ffffc03,0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,
4181  0x3c000001,0xe0001e00,0x780f00f,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1f0f801f,0xe00780f0,0x3c0780,0x1e03c00,
4182  0xf01e000,0x78000780,0x1ffff8,0xf000f8,0x1f000780,0xf8003c07,0xc001e03e,0xf01f0,0x780f80,0x3c1f01e,0xf000,0x1e0000,0xf00000,
4183  0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
4184  0x1e,0x3c07803c,0x3c01e0,0x1e00f00,0xf007800,0x78007c7c,0x1e0007,0x801f1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4185  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c00000,0x303c0003,0x8039e003,0xef000000,
4186  0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0xfc0,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,
4187  0x0,0x7f,0xe01fffff,0xf00ffc00,0x3c000,0x781f00f0,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,0x80007800,
4188  0x780,0x3c01f000,0x7800001e,0xf078,0x7de01e0,0xf00780,0x7800,0x3c078003,0xc000000f,0xf000,0xf0003c0,0x3e7c001,0xee0ef001,
4189  0xf01e0000,0x7800003e,0x3c,0x3c,0x1e0,0x0,0x0,0x0,0xf0003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
4190  0xf000,0x781f000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0x7df00003,
4191  0xc780000f,0x8000003e,0xf0,0x780,0x0,0x0,0x3c00000,0x3fcff800,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x1f00fc,0x1e0,0x1e000001,
4192  0xe00f0003,0xfcff8003,0xe00000ff,0x3fe007f9,0xff000000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x7c00000,0xf0f0078,0x3fcff,0x8000f800,
4193  0x1e000,0x0,0x780001,0xe0180000,0xf000001f,0xffe00007,0x8000003c,0x7ff,0xc0000000,0x1c3ffc7,0x0,0x3e07c00,0x1e00,0xe3,0x80738000,
4194  0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x3e0,0x7c00001d,0xc0000001,0xe0000770,0x1f00000,0xfffff80,0x7ffffc03,
4195  0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
4196  0xe0001e00,0x780f00f,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0x3e07c01f,0xc00780f0,0x3c0780,0x1e03c00,0xf01e000,
4197  0x78000780,0x1fffc0,0xf0007c,0x1e000780,0xf0003c07,0x8001e03c,0xf01e0,0x780f00,0x3c1e01e,0xf000,0x1e0000,0xf00000,0x7800000,
4198  0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1e,0x7807803c,
4199  0x3c01e0,0x1e00f00,0xf007800,0x78003c78,0x1e0007,0x800f1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4200  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x83c00000,0x303c0003,0x8039e001,0xee000000,0x1e00,0x3c00,
4201  0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0x1f80,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,0x0,0x1f,0xfc1fffff,
4202  0xf07ff000,0x0,0x780f00f0,0x78003c03,0xc000781e,0x1e0,0xf803c0,0x1e00,0x1e000,0x781e0007,0x80007800,0x780,0x3c00f800,0x7800001e,
4203  0xf078,0x3de01e0,0xf00780,0x7800,0x3c078003,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfe0ff003,0xe01f0000,0x7800007c,0x3c,0x3c,
4204  0x1e0,0x0,0x0,0x0,0xf0007c01,0xe000f80f,0x800001e0,0xf80f00,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x780f800,0x1e0000f,
4205  0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003c00,0x1e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0xf8f80003,0xe780001f,0x1e,
4206  0xf0,0x780,0x0,0x0,0x3c00000,0x1ffff000,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x3bc1de,0x1e0,0xf000001,0xe00f0001,0xffff0007,0xc000007f,
4207  0xffc003ff,0xfe000000,0x0,0x0,0x0,0xfe000,0x0,0x0,0x0,0x0,0x3c00000,0x1e0f0078,0x1ffff,0x1f000,0x1e000,0x0,0x780000,0xf0180000,
4208  0xf000001f,0xfff00007,0x8000003c,0x1ff,0x80000000,0xe0ff0e,0x0,0x1f03e00,0x1e00,0x70,0x70000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,
4209  0xe1c00,0x0,0x0,0x0,0x7c0,0xf8000019,0xc0000000,0xe0000670,0x1e00000,0xf000780,0x78003c03,0xc001e01e,0xf00f0,0x780780,0x3c0f807,
4210  0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf80f007,0xbc03c001,0xe01e000f,
4211  0xf00078,0x78003c0,0x3c001e00,0x7c03e00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,
4212  0xf0007c07,0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0xf800,0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,
4213  0xf0001e00,0x7803c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1f8001f,0xf00f803c,0x3c01e0,0x1e00f00,0xf007800,
4214  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,
4215  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x3c00000,0x303c0003,0x8039f001,0xfe000000,0x1e00,0x3c00,0x0,0x1e0000,0x0,0x0,0x3c,0xf00,
4216  0x780001e,0x3f00,0x7,0x80000780,0x3e0,0x3e000f00,0x3c0001e,0x3c000,0x7c0000,0x0,0x3,0xfe000000,0xff8000,0x0,0x3c0f81f0,0xf0001e03,
4217  0xc000780f,0x1e0,0xf003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x780,0x3c007c00,0x7800001e,0xf078,0x3de01e0,0xf00780,0x7800,
4218  0x3c078001,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfc07f003,0xe00f0000,0x78000078,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
4219  0xf000f007,0x800000f0,0xf80780,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
4220  0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78001,0xe71df000,0xf8f80001,0xef80003e,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,
4221  0xfffe000,0x0,0x3e000000,0x0,0x18,0x7fff,0xc0000000,0x60c306,0x1e0,0x7800001,0xe00f0000,0xfffe0007,0x8000003f,0xff8001ff,
4222  0xfc000000,0x0,0x0,0x0,0x7c000,0x0,0x0,0x0,0x0,0x3c00000,0x3c0f0078,0xfffe,0x3e000,0x1e000,0x0,0x780000,0xf0180000,0xf000003c,
4223  0xfcf80007,0x8000003c,0x7f,0x0,0x70001c,0x0,0xf81f00,0x0,0x38,0xe0000,0x0,0x0,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf81,
4224  0xf0000039,0xc0000000,0xe0000e70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,0x8000f000,0x78000,
4225  0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f007,0xbc03c001,0xe01e000f,0xf00078,0x78003c0,
4226  0x3c001e00,0xf801f00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,0x8003e03c,
4227  0x1f01e0,0xf80f00,0x7c1e01e,0x7800,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,
4228  0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xe00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef8,0x1f000f,
4229  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,
4230  0x0,0x0,0xf,0x3c00000,0x307c0003,0x8038f000,0xfc000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e00003c,0x780,0xf00001e,
4231  0x7e00,0xf,0x80000780,0x3c0,0x3e001e00,0x3c0001f,0x7c000,0x780007,0xe000003f,0x0,0xfe000000,0xfe0000,0x0,0x3c07c3f0,0xf0001e03,
4232  0xc000f80f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x4000f80,0x3c003c00,0x7800001e,0xf078,0x1fe01f0,0x1f00780,
4233  0x7c00,0x7c078001,0xf000001f,0xf000,0xf0003c0,0x1e78001,0xfc07f007,0xc00f8000,0x780000f8,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
4234  0xf000f007,0xc00000f0,0xf80780,0x3c,0x1f003,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
4235  0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78000,0xfe0fe001,0xf07c0001,0xef00007c,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,
4236  0x7cfc000,0xfc00000,0x3c00000f,0xc3f00000,0x18,0x7fff,0xc0000000,0x406303,0x3e0,0x3c00001,0xf00f0000,0x7cfc000f,0x8000001f,
4237  0x3f0000f9,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x780700f8,0x7cfc,0x7c000,0x1e000,0x0,0x780000,0xf8180000,
4238  0xf0000070,0x3c0007,0x8000003c,0x3f,0x80000000,0x3c0078,0x0,0x780f00,0x0,0x1e,0x3c0000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,0xe1c00,
4239  0x0,0x0,0x0,0xf01,0xe0000071,0xc0000000,0xe0001c70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
4240  0x8000f800,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00f003,0xfc03e003,0xe01f001f,
4241  0xf800f8,0x7c007c0,0x3e003e01,0xf000f80f,0xf00f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,
4242  0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0x7c00,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,
4243  0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xc00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef0,
4244  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,
4245  0x0,0x0,0x0,0x0,0x780000,0xf,0x3800040,0x30780003,0x8038f800,0x78000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
4246  0x780,0x1f00001e,0xfc00,0x20001f,0x780,0x80007c0,0x1f001e00,0x7c0000f,0x78000,0xf80007,0xe000003f,0x0,0x1e000000,0xf00000,
4247  0x3c000,0x3c03fff0,0xf0001e03,0xc001f007,0x800101e0,0x7e003c0,0x1e00,0x7800,0x781e0007,0x80007800,0x6000f00,0x3c003e00,0x7800001e,
4248  0xf078,0x1fe00f0,0x1e00780,0x3c00,0x78078000,0xf020001e,0xf000,0x7800780,0xff0001,0xfc07f00f,0x8007c000,0x780001f0,0x3c,0xf,
4249  0x1e0,0x0,0x0,0x0,0xf800fc01,0xf801f007,0xc00100f8,0x1f807c0,0x40003c,0xf807,0xf0078007,0x80003c00,0xf000,0x7803e00,0x1f0000f,
4250  0x3c0f01e,0x1e01f0,0x3e007e0,0x7c07c00,0xfc003c00,0x1e,0x3e000,0x3e007c0,0x1ff8000,0xfe0fe003,0xe03e0001,0xff0000fc,0x1e,
4251  0xf0,0x780,0x0,0x0,0x1f00080,0x3cf8000,0xfc00000,0x3c00001f,0x83f00000,0x18,0xc0,0x0,0xc06203,0x40003c0,0x1c00000,0xf80f0000,
4252  0x3cf8001f,0xf,0x3e000079,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x700780fc,0x3cf8,0xfc000,0x1e000,0x0,0x780000,
4253  0x7c180000,0xf0000020,0x100007,0x8000003c,0xf,0x80000000,0x1f01f0,0x0,0x380700,0x0,0xf,0x80f80000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,
4254  0xe1c00,0x0,0x0,0x0,0xe01,0xc0000071,0xc0000001,0xc0001c70,0x1e00040,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
4255  0x80007800,0x10078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00f003,0xfc01e003,0xc00f001e,
4256  0x7800f0,0x3c00780,0x1e003c00,0xe000700f,0x800f0078,0x7803c0,0x3c01e00,0x1e00f000,0xf0000780,0x1e0000,0xf0003c,0x1f001f80,
4257  0xf800fc07,0xc007e03e,0x3f01f0,0x1f80f80,0xfc1e01f,0x7c00,0x100f8000,0x807c0004,0x3e00020,0x1f000100,0x780000,0x3c00000,0x1e000000,
4258  0xf0000f80,0x1f003c00,0x3c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,0x1f8000f,0x801f003e,0x7c01f0,0x3e00f80,0x1f007c00,
4259  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,
4260  0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0xf,0x7800078,0x31f80001,0xc070fc00,0xfc000000,0x1e00,0x7c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
4261  0x7c0,0x1f00001e,0x1f000,0x38003f,0x780,0xe000f80,0x1f803e00,0x780000f,0x800f8000,0x1f00007,0xe000003f,0x0,0x2000000,0x800000,
4262  0x3c000,0x3e01ff71,0xf0001f03,0xc007f007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x781e0007,0x80007800,0x7801f00,0x3c001f00,0x7800001e,
4263  0xf078,0xfe00f8,0x3e00780,0x3e00,0xf8078000,0xf838003e,0xf000,0x7c00f80,0xff0000,0xfc07e00f,0x8003c000,0x780001e0,0x3c,0xf,
4264  0x1e0,0x0,0x0,0x0,0xf801fc01,0xfc03e003,0xe003007c,0x3f803e0,0x1c0003c,0xfc0f,0xf0078007,0x80003c00,0xf000,0x7801f00,0xf8000f,
4265  0x3c0f01e,0x1e00f8,0x7c007f0,0xf803e01,0xfc003c00,0x8003e,0x1f000,0x1e00fc0,0xff0000,0xfe0fe007,0xc01f0000,0xfe0000f8,0x1e,
4266  0xf0,0x780,0x0,0x0,0xf80180,0x1cf0000,0x1f800000,0x3c00001f,0x83e00000,0x18,0xc0,0x0,0xc06203,0x70007c0,0xe00000,0x7e0f0000,
4267  0x1cf0001e,0x7,0x3c000039,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x7c00000,0xe00780fc,0x2001cf0,0xf8000,0x1e000,0x0,
4268  0x780000,0x7e182000,0xf0000000,0x7,0x8000003c,0x7,0xc0000000,0x7ffc0,0x0,0x180300,0x0,0x3,0xffe00000,0x0,0x0,0x0,0x0,0x0,
4269  0x3f00fc0,0xe1c00,0x0,0x0,0x0,0xc01,0x800000e1,0xc0000003,0xc0003870,0x1f001c0,0x3e0003e1,0xf0001f0f,0x8000f87c,0x7c3e0,0x3e1f00,
4270  0x1f1e007,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e03,0xfc00f001,0xfc01f007,
4271  0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x4000201f,0xc01f007c,0xf803e0,0x7c01f00,0x3e00f801,0xf0000780,0x1e0000,0xf0007c,
4272  0x1f003f80,0xf801fc07,0xc00fe03e,0x7f01f0,0x3f80f80,0x1fc1f03f,0x803e00,0x3007c003,0x803e001c,0x1f000e0,0xf800700,0x780000,
4273  0x3c00000,0x1e000000,0xf00007c0,0x3e003c00,0x3c01f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e001e,0xfc00f0,
4274  0x7e00780,0x3f003c01,0xf8000fe0,0x1fc03e,0x3f800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4275  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,0xfff00001,0xe0f07f03,0xfe000000,0xf00,0x7800,0x0,
4276  0x1e0000,0xfc0000,0x0,0x7e0000f0,0x3f0,0x7e000fff,0xfc03ffff,0xf83f00fe,0x780,0xfc03f80,0xfc0fc00,0xf800007,0xe03f0018,0x7e00007,
4277  0xe000003f,0x0,0x0,0x0,0x3c000,0x1e007c71,0xe0000f03,0xffffe003,0xf01f01ff,0xff8003ff,0xffe01e00,0x3f01,0xf81e0007,0x803ffff0,
4278  0x7e03f00,0x3c000f00,0x7ffffe1e,0xf078,0xfe007e,0xfc00780,0x1f83,0xf0078000,0x783f00fe,0xf000,0x3f03f00,0xff0000,0xfc07e01f,
4279  0x3e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7e07fc01,0xfe07e001,0xf80f007e,0x7f801f8,0xfc0003c,0x7ffe,0xf0078007,
4280  0x807ffffe,0xf000,0x7801f00,0xfff00f,0x3c0f01e,0x1e00fc,0xfc007f8,0x1f803f03,0xfc003c00,0xf80fc,0x1fff0,0x1f83fc0,0xff0000,
4281  0xfc07e007,0xc01f0000,0xfe0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfe0780,0xfe0000,0x1f000000,0x3c00001f,0x7c00e03,0x81c00018,
4282  0xc0,0x0,0x406203,0x7e01fc0,0x700000,0x7fffff80,0xfe0003f,0xffffc003,0xf800001f,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f0,
4283  0x1f800001,0xc007c1fe,0x6000fe0,0x1ffffe,0x1e000,0x0,0x780000,0x3f98e03f,0xffff8000,0x7,0x8000003c,0x7,0xc0000000,0xfe00,
4284  0x0,0x80100,0x0,0x0,0x7f000000,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3f83fe8,0xe1c00,0x0,0x0,0x0,0x801,0xc1,0xc0000007,0x80003070,
4285  0xfc0fc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc03f01,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,
4286  0xffff001f,0xfff800ff,0xffc01fff,0xf800f001,0xfc00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,0x1f,0xf07e003f,0x3f001f8,
4287  0x1f800fc0,0xfc007e07,0xe0000780,0x1e0000,0xf301f8,0xfc0ff80,0x7e07fc03,0xf03fe01f,0x81ff00fc,0xff807e0,0x7fc0f87f,0x81801f80,
4288  0xf003f01f,0x801f80fc,0xfc07e0,0x7e03f00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff807e0,0x7e003c00,0x3c01f81f,0x800fc0fc,0x7e07e0,
4289  0x3f03f00,0x1f81f800,0x1f8000f,0xe07e001f,0x83fc00fc,0x1fe007e0,0xff003f07,0xf8000fe0,0x1fe07e,0x3f800,0x0,0x0,0x0,0x0,0x0,
4290  0x0,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,
4291  0xffe00000,0xffe03fff,0xdf000000,0xf00,0x7800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0x1ff,0xfc000fff,0xfc03ffff,0xf83ffffc,0x780,
4292  0xfffff00,0x7fff800,0xf000007,0xffff001f,0xffe00007,0xe000003f,0x0,0x0,0x0,0x3c000,0x1e000001,0xe0000f03,0xffffc001,0xffff01ff,
4293  0xff0003ff,0xffe01e00,0x1fff,0xf81e0007,0x803ffff0,0x7fffe00,0x3c000f80,0x7ffffe1e,0xf078,0xfe003f,0xff800780,0xfff,0xf0078000,
4294  0x7c3ffffc,0xf000,0x3ffff00,0xff0000,0xf803e01e,0x1e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7fffbc01,0xffffc000,
4295  0xffff003f,0xfff800ff,0xffc0003c,0x3ffe,0xf0078007,0x807ffffe,0xf000,0x7800f80,0x7ff00f,0x3c0f01e,0x1e007f,0xff8007ff,0xff001fff,
4296  0xbc003c00,0xffffc,0x1fff0,0x1fffbc0,0xff0000,0x7c07c00f,0x800f8000,0x7e0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7fff80,0x7c0000,
4297  0x1f000000,0x3c00001e,0x7c00f07,0xc1e00018,0xc0,0x0,0x60e303,0x7ffff80,0x380000,0x3fffff80,0x7c0003f,0xffffc001,0xf000000f,
4298  0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff800003,0x8003ffff,0xfe0007c0,0x1ffffe,0x1e000,0x0,0x780000,0x1fffe03f,0xffff8000,
4299  0x7,0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3fffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x1c1,
4300  0xc000000f,0x7070,0x7fffc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,
4301  0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000f001,0xfc007fff,0x3fff8,0x1fffc0,0xfffe00,0x7fff000,0x3b,0xfffc003f,
4302  0xfff001ff,0xff800fff,0xfc007fff,0xe0000780,0x1e0000,0xf3fff8,0xffff780,0x7fffbc03,0xfffde01f,0xffef00ff,0xff7807ff,0xfbc0ffff,
4303  0xff800fff,0xf001ffff,0x800ffffc,0x7fffe0,0x3ffff00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff803ff,0xfc003c00,0x3c00ffff,0x7fff8,
4304  0x3fffc0,0x1fffe00,0xffff000,0x1f,0xfffc001f,0xffbc00ff,0xfde007ff,0xef003fff,0x780007e0,0x1ffffc,0x1f800,0x0,0x0,0x0,0x0,
4305  0x0,0x0,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,
4306  0xffc00000,0x7fc01fff,0x9f800000,0xf80,0xf800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0xff,0xf8000fff,0xfc03ffff,0xf83ffff8,0x780,
4307  0xffffe00,0x7fff000,0xf000003,0xfffe001f,0xffc00007,0xe000003f,0x0,0x0,0x0,0x3c000,0xf000003,0xe0000f83,0xffff0000,0xffff01ff,
4308  0xfc0003ff,0xffe01e00,0xfff,0xf01e0007,0x803ffff0,0x7fffc00,0x3c0007c0,0x7ffffe1e,0xf078,0x7e003f,0xff000780,0x7ff,0xe0078000,
4309  0x3c3ffff8,0xf000,0x1fffe00,0x7e0000,0xf803e03e,0x1f000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x3fff3c01,0xefff8000,
4310  0x7ffe001f,0xff78007f,0xff80003c,0x1ffc,0xf0078007,0x807ffffe,0xf000,0x78007c0,0x3ff00f,0x3c0f01e,0x1e003f,0xff0007bf,0xfe000fff,
4311  0xbc003c00,0xffff8,0xfff0,0xfff3c0,0x7e0000,0x7c07c01f,0x7c000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3fff80,0x380000,
4312  0x3e000000,0x7c00003e,0x7801f07,0xc1e00018,0xc0,0x0,0x39c1ce,0x7ffff00,0x1c0000,0xfffff80,0x380003f,0xffffc000,0xe0000007,
4313  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff000007,0x1ffcf,0xfe000380,0x1ffffe,0x1e000,0x0,0x780000,0xfffe03f,0xffff8000,0x7,
4314  0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x381,
4315  0xc000001e,0xe070,0x7fff80,0x7c0001f3,0xe0000f9f,0x7cf8,0x3e7c0,0x1f3e00,0xfbe007,0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,
4316  0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000f000,0xfc007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x79,0xfff8001f,
4317  0xffe000ff,0xff0007ff,0xf8003fff,0xc0000780,0x1e0000,0xf3fff0,0x7ffe780,0x3fff3c01,0xfff9e00f,0xffcf007f,0xfe7803ff,0xf3c07ff3,
4318  0xff8007ff,0xe000ffff,0x7fff8,0x3fffc0,0x1fffe00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff801ff,0xf8003c00,0x3c007ffe,0x3fff0,
4319  0x1fff80,0xfffc00,0x7ffe000,0x1d,0xfff8000f,0xff3c007f,0xf9e003ff,0xcf001ffe,0x780007c0,0x1efff8,0x1f000,0x0,0x0,0x0,0x0,
4320  0x0,0x0,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,
4321  0xfe000000,0x1f000fff,0xfc00000,0x780,0xf000,0x0,0x0,0xf80000,0x0,0x7e0001e0,0x7f,0xf0000fff,0xfc03ffff,0xf81ffff0,0x780,
4322  0x7fff800,0x1ffe000,0x1f000000,0xfff8001f,0xff000007,0xe000003e,0x0,0x0,0x0,0x3c000,0xf800003,0xc0000783,0xfff80000,0x3ffe01ff,
4323  0xe00003ff,0xffe01e00,0x7ff,0xc01e0007,0x803ffff0,0x3fff800,0x3c0003c0,0x7ffffe1e,0xf078,0x7e000f,0xfe000780,0x3ff,0xc0078000,
4324  0x3e1fffe0,0xf000,0x7ff800,0x7e0000,0xf803e07c,0xf800,0x780003ff,0xfffc003c,0x3,0xc00001e0,0x0,0x0,0x0,0xffe3c01,0xe7ff0000,
4325  0x3ffc000f,0xfe78003f,0xfe00003c,0x7f0,0xf0078007,0x807ffffe,0xf000,0x78003e0,0xff00f,0x3c0f01e,0x1e001f,0xfe00079f,0xfc0007ff,
4326  0x3c003c00,0x7ffe0,0x1ff0,0x7fe3c0,0x7e0000,0x7c07c03e,0x3e000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfff00,0x100000,
4327  0x3e000000,0x7800003c,0xf800f07,0xc1e00018,0xc0,0x0,0x1f80fc,0x3fffc00,0xc0000,0x3ffff80,0x100003f,0xffffc000,0x40000002,
4328  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xfc000006,0xff87,0xfc000100,0x1ffffe,0x1e000,0x0,0x780000,0x3ffc03f,0xffff8000,0x7,
4329  0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dff9f8,0xe1c00,0x0,0x0,0x0,0x0,0x3ff,
4330  0xf800003c,0xfffe,0x1ffe00,0x780000f3,0xc000079e,0x3cf0,0x1e780,0xf3c00,0x7bc007,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,
4331  0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,0xf000,0xfc001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x70,0xfff00007,
4332  0xff80003f,0xfc0001ff,0xe0000fff,0x780,0x1e0000,0xf3ffe0,0x1ffc780,0xffe3c00,0x7ff1e003,0xff8f001f,0xfc7800ff,0xe3c03fe1,
4333  0xff0003ff,0xc0007ffc,0x3ffe0,0x1fff00,0xfff800,0xfffffc07,0xffffe03f,0xffff01ff,0xfff800ff,0xf0003c00,0x3c003ffc,0x1ffe0,
4334  0xfff00,0x7ff800,0x3ffc000,0x38,0xfff00007,0xfe3c003f,0xf1e001ff,0x8f000ffc,0x780007c0,0x1e7ff0,0x1f000,0x0,0x0,0x0,0x0,0x0,
4335  0x0,0x0,0x0,0x0,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,
4336  0x1fc,0x0,0x780,0xf000,0x0,0x0,0x1f80000,0x0,0x1e0,0x1f,0xc0000000,0x0,0x1ff80,0x0,0xffc000,0x7f8000,0x0,0x3fe00007,0xfc000000,
4337  0x7e,0x0,0x0,0x0,0x0,0x7c00000,0x0,0x0,0xff00000,0x0,0x0,0xfe,0x0,0x0,0x3fc000,0x0,0x0,0x0,0x3,0xf8000000,0xff,0xc0000000,
4338  0x1ff00,0x0,0x1fe000,0x0,0x0,0x0,0x0,0x3c,0x3,0xc00001e0,0x0,0x0,0x0,0x3f80000,0x1fc0000,0x7f00003,0xf8000007,0xf0000000,
4339  0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x7,0xf8000787,0xf00001fc,0x3c000000,0x7f80,0x0,0x1f8000,0x0,0x0,0x0,0x7c000000,0x1e,
4340  0xf0,0x780,0x0,0x0,0x3fc00,0x0,0x3c000000,0x7800003c,0xf000601,0xc00018,0xc0,0x0,0x0,0x3fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4341  0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xf0000000,0x7e03,0xf0000000,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x3c,0x2007,0x80000000,0x0,0x0,
4342  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c7e0f0,0xe1c00,0x0,0x3800000,0x0,0x0,0x3ff,0xf8000078,0xfffe,0x7f800,0x0,0x0,0x0,0x0,
4343  0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,0x7f0000,0x70,0x3fc00001,0xfe00000f,0xf000007f,
4344  0x800003fc,0x0,0x0,0xff00,0x7f0000,0x3f80000,0x1fc00000,0xfe000007,0xf000003f,0x80001f80,0xfc00007f,0xfe0,0x7f00,0x3f800,
4345  0x1fc000,0x0,0x0,0x0,0x3f,0xc0000000,0xff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x78,0x3fc00001,0xf800000f,0xc000007e,0x3f0,0x7c0,
4346  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,
4347  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,
4348  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,
4349  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,
4350  0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,0x1e,0xf0,0x780,0x0,0x0,0x0,0x0,0x3c000000,0x78000078,0xf000000,0x18,0xc0,0x0,0x0,0x0,
4351  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,
4352  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0x1800000,0x0,0x0,0x3ff,0xf80000f0,0xfffe,0x0,0x0,0x0,0x0,
4353  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,
4354  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,
4355  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,
4356  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,
4357  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,
4358  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,
4359  0x1f,0xf0,0xf80,0x0,0x0,0x0,0x0,0x78000000,0xf8000078,0x1e000000,0x8,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4360  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,
4361  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,
4362  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,
4363  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,
4364  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,
4365  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,
4366  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,
4367  0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x1f,0x800000f0,0x1f80,0x0,0x0,0x0,0x0,
4368  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,
4369  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,
4370  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,
4371  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,
4372  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,
4373  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,
4374  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,
4375  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4003,0xe0000000,0x0,0x1f000,0x0,0x0,
4376  0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x1,0xf0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0x70000001,0xf00000e0,
4377  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,
4378  0x0,0x0,0x3c,0xff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,0x0,0x0,0x1,0xc00003ff,
4379  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,
4380  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,
4381  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,
4382  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,
4383  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,
4384  0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780f,0xc0000000,0x0,0x3e000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
4385  0x0,0x0,0x0,0x0,0x3,0xe0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0xf0000103,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4386  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,
4387  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x21e00000,0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,
4388  0x0,0x0,0x0,0x0,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,
4389  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,
4390  0x0,0x0,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,
4391  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,
4392  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,
4393  0x0,0x0,0x7fff,0xc0000000,0x0,0x3ffe000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0xe0000000,0x7,0xfc0000f0,
4394  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,
4395  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,
4396  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,
4397  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,
4398  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,
4399  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4401  0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff,0x80000000,0x0,0x3ffc000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
4402  0x0,0x0,0x0,0x0,0x7f,0xc0000000,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x0,0x0,0x1ff,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4403  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,
4404  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,
4405  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,
4406  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,
4407  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4408  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4409  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,
4410  0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0x80000000,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x80000000,0x0,0x0,0x0,0x0,
4411  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4412  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,
4413  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0,0x0,
4414  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,
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,0x0,0x0,0x0,
4416  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4417  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8,0x0,0x0,0x3fe0000,
4418  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,
4419  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4420  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4421  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x0,0x0,0x0,0x0,0x0,0x7e000,0x1e0000,0x1f80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4423  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4425  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,
4426  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,
4427  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4428  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4429  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4431  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4432  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4433  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4437  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
4438 
4439  // Definition of a 40x38 'danger' color logo.
4440  const unsigned char logo40x38[4576] = {
4441  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,
4442  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,
4443  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,
4444  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,
4445  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,
4446  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,
4447  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,
4448  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,
4449  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,
4450  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,
4451  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,
4452  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,
4453  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,
4454  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,
4455  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,
4456  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,
4457  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,
4458  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,
4459  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,
4460  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,
4461  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,
4462  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,
4463  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,
4464  200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0};
4465 
4467 
4470  inline void warn(const char *format, ...) {
4471  if (cimg::exception_mode()>=1) {
4472  char message[8192] = { 0 };
4473  std::va_list ap;
4474  va_start(ap,format);
4475  std::vsprintf(message,format,ap);
4476  va_end(ap);
4477 #ifdef cimg_strict_warnings
4478  throw CImgWarningException(message);
4479 #else
4480  std::fprintf(cimg_stdout,"\n%s# CImg Warning%s :\n%s\n",cimg::t_red,cimg::t_normal,message);
4481 #endif
4482  }
4483  }
4484 
4485  // Execute an external system command.
4491  inline int system(const char *const command, const char *const module_name=0) {
4492 #if cimg_OS==2
4493  PROCESS_INFORMATION pi;
4494  STARTUPINFO si;
4495  std::memset(&pi,0,sizeof(PROCESS_INFORMATION));
4496  std::memset(&si,0,sizeof(STARTUPINFO));
4497  GetStartupInfo(&si);
4498  si.cb = sizeof(si);
4499  si.wShowWindow = SW_HIDE;
4500  si.dwFlags |= SW_HIDE;
4501  const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);
4502  if (res) {
4503  WaitForSingleObject(pi.hProcess, INFINITE);
4504  CloseHandle(pi.hThread);
4505  CloseHandle(pi.hProcess);
4506  return 0;
4507  } else
4508 #endif
4509  return std::system(command);
4510  return module_name?0:1;
4511  }
4512 
4514  template<typename T>
4515  inline T& temporary(const T&) {
4516  static T temp;
4517  return temp;
4518  }
4519 
4521  template<typename T>
4522  inline void swap(T& a, T& b) { T t = a; a = b; b = t; }
4523 
4525  template<typename T1, typename T2>
4526  inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) {
4527  cimg::swap(a1,b1); cimg::swap(a2,b2);
4528  }
4529 
4531  template<typename T1, typename T2, typename T3>
4532  inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) {
4533  cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3);
4534  }
4535 
4537  template<typename T1, typename T2, typename T3, typename T4>
4538  inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) {
4539  cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);
4540  }
4541 
4543  template<typename T1, typename T2, typename T3, typename T4, typename T5>
4544  inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) {
4545  cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);
4546  }
4547 
4549  template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
4550  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) {
4551  cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
4552  }
4553 
4555  template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
4556  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,
4557  T7& a7, T7& b7) {
4558  cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);
4559  }
4560 
4562  template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
4563  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,
4564  T7& a7, T7& b7, T8& a8, T8& b8) {
4565  cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);
4566  }
4567 
4569 
4572  inline bool endianness() {
4573  const int x = 1;
4574  return ((unsigned char*)&x)[0]?false:true;
4575  }
4576 
4578  template<typename T>
4579  inline void invert_endianness(T* const buffer, const unsigned int size) {
4580  if (size) switch (sizeof(T)) {
4581  case 1 : break;
4582  case 2 : { for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer; ) {
4583  const unsigned short val = *(--ptr);
4584  *ptr = (unsigned short)((val>>8)|((val<<8)));
4585  }} break;
4586  case 4 : { for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer; ) {
4587  const unsigned int val = *(--ptr);
4588  *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24);
4589  }} break;
4590  default : { for (T* ptr = buffer+size; ptr>buffer; ) {
4591  unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);
4592  for (int i = 0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe));
4593  }}
4594  }
4595  }
4596 
4598  template<typename T>
4599  inline T& invert_endianness(T& a) {
4600  invert_endianness(&a,1);
4601  return a;
4602  }
4603 
4605  inline unsigned long time() {
4606 #if cimg_OS==1
4607  struct timeval st_time;
4608  gettimeofday(&st_time,0);
4609  return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
4610 #elif cimg_OS==2
4611  static SYSTEMTIME st_time;
4612  GetSystemTime(&st_time);
4613  return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
4614 #else
4615  return 0;
4616 #endif
4617  }
4618 
4620 
4624  inline void sleep(const unsigned int milliseconds) {
4625 #if cimg_OS==1
4626  struct timespec tv;
4627  tv.tv_sec = milliseconds/1000;
4628  tv.tv_nsec = (milliseconds%1000)*1000000;
4629  nanosleep(&tv,0);
4630 #elif cimg_OS==2
4631  Sleep(milliseconds);
4632 #endif
4633  }
4634 
4635  inline unsigned int _sleep(const unsigned int milliseconds, unsigned long& timer) {
4636  if (!timer) timer = cimg::time();
4637  const unsigned long current_time = cimg::time();
4638  if (current_time>=timer+milliseconds) { timer = current_time; return 0; }
4639  const unsigned long time_diff = timer + milliseconds - current_time;
4640  timer = current_time + time_diff;
4641  cimg::sleep(time_diff);
4642  return (unsigned int)time_diff;
4643  }
4644 
4646 
4650  inline unsigned int wait(const unsigned int milliseconds) {
4651  static unsigned long timer = 0;
4652  if (!timer) timer = cimg::time();
4653  return _sleep(milliseconds,timer);
4654  }
4655 
4656  // Use a specific srand initialization to avoid multi-threads to have to the
4657  // same series of random numbers (executed only once for a single program).
4658  inline void srand() {
4659  static bool first_time = true;
4660  if (first_time) {
4662  unsigned char *const rand_ptr = new unsigned char[1+std::rand()%2048];
4663  std::srand((unsigned int)std::rand() + *(unsigned int*)(void*)rand_ptr);
4664  delete[] rand_ptr;
4665  first_time = false;
4666  }
4667  }
4668 
4670  template<typename T>
4671  inline const T rol(const T a, const unsigned int n=1) {
4672  return n?(T)((a<<n)|(a>>((sizeof(T)<<3)-n))):a;
4673  }
4674 
4676  template<typename T>
4677  inline const T ror(const T a, const unsigned int n=1) {
4678  return n?(T)((a>>n)|(a<<((sizeof(T)<<3)-n))):a;
4679  }
4680 
4682 
4686  template<typename T>
4687  inline T abs(const T a) {
4688  return a>=0?a:-a;
4689  }
4690  inline bool abs(const bool a) {
4691  return a;
4692  }
4693  inline unsigned char abs(const unsigned char a) {
4694  return a;
4695  }
4696  inline unsigned short abs(const unsigned short a) {
4697  return a;
4698  }
4699  inline unsigned int abs(const unsigned int a) {
4700  return a;
4701  }
4702  inline unsigned long abs(const unsigned long a) {
4703  return a;
4704  }
4705  inline double abs(const double a) {
4706  return std::fabs(a);
4707  }
4708  inline float abs(const float a) {
4709  return (float)std::fabs((double)a);
4710  }
4711  inline int abs(const int a) {
4712  return std::abs(a);
4713  }
4714 
4716  template<typename T>
4717  inline T sqr(const T val) {
4718  return val*val;
4719  }
4720 
4722  inline int xln(const int x) {
4723  return x>0?(int)(1+std::log10((double)x)):1;
4724  }
4725 
4727  template<typename t1, typename t2>
4728  inline typename cimg::superset<t1,t2>::type min(const t1& a, const t2& b) {
4729  typedef typename cimg::superset<t1,t2>::type t1t2;
4730  return (t1t2)(a<=b?a:b);
4731  }
4732 
4734  template<typename t1, typename t2, typename t3>
4735  inline typename cimg::superset2<t1,t2,t3>::type min(const t1& a, const t2& b, const t3& c) {
4736  typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
4737  return (t1t2t3)cimg::min(cimg::min(a,b),c);
4738  }
4739 
4741  template<typename t1, typename t2, typename t3, typename t4>
4742  inline typename cimg::superset3<t1,t2,t3,t4>::type min(const t1& a, const t2& b, const t3& c, const t4& d) {
4743  typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
4744  return (t1t2t3t4)cimg::min(cimg::min(a,b,c),d);
4745  }
4746 
4748  template<typename t1, typename t2>
4749  inline typename cimg::superset<t1,t2>::type max(const t1& a, const t2& b) {
4750  typedef typename cimg::superset<t1,t2>::type t1t2;
4751  return (t1t2)(a>=b?a:b);
4752  }
4753 
4755  template<typename t1, typename t2, typename t3>
4756  inline typename cimg::superset2<t1,t2,t3>::type max(const t1& a, const t2& b, const t3& c) {
4757  typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
4758  return (t1t2t3)cimg::max(cimg::max(a,b),c);
4759  }
4760 
4762  template<typename t1, typename t2, typename t3, typename t4>
4763  inline typename cimg::superset3<t1,t2,t3,t4>::type max(const t1& a, const t2& b, const t3& c, const t4& d) {
4764  typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
4765  return (t1t2t3t4)cimg::max(cimg::max(a,b,c),d);
4766  }
4767 
4769  template<typename T>
4770  inline T sign(const T x) {
4771  return (x<0)?(T)(-1):(x==0?(T)0:(T)1);
4772  }
4773 
4775  template<typename T>
4776  inline unsigned int nearest_pow2(const T x) {
4777  unsigned int i = 1;
4778  while (x>i) i<<=1;
4779  return i;
4780  }
4781 
4783 
4787  template<typename T>
4788  inline T mod(const T& x, const T& m) {
4789  const double dx = (double)x, dm = (double)m;
4790  if (x<0) { return (T)(dm+dx+dm*std::floor(-dx/dm)); }
4791  return (T)(dx-dm*std::floor(dx/dm));
4792  }
4793  inline int mod(const bool x, const bool m) {
4794  return m?(x?1:0):0;
4795  }
4796  inline int mod(const char x, const char m) {
4797  return x>=0?x%m:(x%m?m+x%m:0);
4798  }
4799  inline int mod(const short x, const short m) {
4800  return x>=0?x%m:(x%m?m+x%m:0);
4801  }
4802  inline int mod(const int x, const int m) {
4803  return x>=0?x%m:(x%m?m+x%m:0);
4804  }
4805  inline int mod(const long x, const long m) {
4806  return x>=0?x%m:(x%m?m+x%m:0);
4807  }
4808  inline int mod(const unsigned char x, const unsigned char m) {
4809  return x%m;
4810  }
4811  inline int mod(const unsigned short x, const unsigned short m) {
4812  return x%m;
4813  }
4814  inline int mod(const unsigned int x, const unsigned int m) {
4815  return x%m;
4816  }
4817  inline int mod(const unsigned long x, const unsigned long m) {
4818  return x%m;
4819  }
4820 
4822 
4827  template<typename T>
4828  inline T minmod(const T a, const T b) {
4829  return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));
4830  }
4831 
4833  inline double rand() {
4834  static bool first_time = true;
4835  if (first_time) { cimg::srand(); first_time = false; }
4836  return (double)std::rand()/RAND_MAX;
4837  }
4838 
4840  inline double crand() {
4841  return 1-2*cimg::rand();
4842  }
4843 
4845  inline double grand() {
4846  double x1, w;
4847  do {
4848  const double x2 = 2*cimg::rand() - 1.0;
4849  x1 = 2*cimg::rand()-1.0;
4850  w = x1*x1 + x2*x2;
4851  } while (w<=0 || w>=1.0);
4852  return x1*std::sqrt((-2*std::log(w))/w);
4853  }
4854 
4856  inline unsigned int prand(const double z) {
4857  if (z<=1.0e-10) return 0;
4858  if (z>100.0) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z);
4859  unsigned int k = 0;
4860  const double y = std::exp(-z);
4861  for (double s = 1.0; s>=y; ++k) s*=cimg::rand();
4862  return k-1;
4863  }
4864 
4866 
4871  inline double round(const double x, const double y, const int rounding_type=0) {
4872  if (y<=0) return x;
4873  const double delta = cimg::mod(x,y);
4874  if (delta==0.0) return x;
4875  const double
4876  backward = x - delta,
4877  forward = backward + y;
4878  return rounding_type<0?backward:(rounding_type>0?forward:(2*delta<y?backward:forward));
4879  }
4880 
4881  inline double _pythagore(double a, double b) {
4882  const double absa = cimg::abs(a), absb = cimg::abs(b);
4883  if (absa>absb) { const double tmp = absb/absa; return absa*std::sqrt(1.0+tmp*tmp); }
4884  else { const double tmp = absa/absb; return (absb==0?0:absb*std::sqrt(1.0+tmp*tmp)); }
4885  }
4886 
4888  inline char uncase(const char x) {
4889  return (char)((x<'A'||x>'Z')?x:x-'A'+'a');
4890  }
4891 
4893 
4896  inline void uncase(char *const string) {
4897  if (string) for (char *ptr = string; *ptr; ++ptr) *ptr = uncase(*ptr);
4898  }
4899 
4901 
4905  inline float atof(const char *const str) {
4906  float x = 0,y = 1;
4907  if (!str) return 0; else { std::sscanf(str,"%g/%g",&x,&y); return x/y; }
4908  }
4909 
4911 
4915  inline int strncasecmp(const char *const s1, const char *const s2, const int l) {
4916  if (!l) return 0;
4917  if (!s1) return s2?-1:0;
4918  const char *ns1 = s1, *ns2 = s2;
4919  int k, diff = 0; for (k = 0; k<l && !(diff = uncase(*ns1)-uncase(*ns2)); ++k) { ++ns1; ++ns2; }
4920  return k!=l?diff:0;
4921  }
4922 
4924 
4928  inline int strcasecmp(const char *const s1, const char *const s2) {
4929  if (!s1) return s2?-1:0;
4930  const unsigned int l1 = std::strlen(s1), l2 = std::strlen(s2);
4931  return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2));
4932  }
4933 
4935  inline bool strpare(char *const s, const char delimiter=' ', const bool symmetric=false) {
4936  if (!s) return false;
4937  const int l = (int)std::strlen(s);
4938  int p, q;
4939  if (symmetric) for (p = 0, q = l-1; p<q && s[p]==delimiter && s[q]==delimiter; ++p) --q;
4940  else {
4941  for (p = 0; p<l && s[p]==delimiter; ) ++p;
4942  for (q = l-1; q>p && s[q]==delimiter; ) --q;
4943  }
4944  const int n = q - p + 1;
4945  if (n!=l) { std::memmove(s,s+p,n); s[n] = 0; return true; }
4946  return false;
4947  }
4948 
4950  inline void strclean(char *const s) {
4951  if (!s) return;
4952  strpare(s,' ',false);
4953  for (bool need_iter = true; need_iter; ) {
4954  need_iter = false;
4955  need_iter |= strpare(s,'\'',true);
4956  need_iter |= strpare(s,'\"',true);
4957  need_iter |= strpare(s,'`',true);
4958  }
4959  }
4960 
4962  inline void strescape(char *const s) {
4963 #define cimg_strescape(ci,co) case ci: *nd = co; ++ns; break;
4964  static unsigned int val = 0;
4965  for (char *ns = s, *nd = s; *ns || (bool)(*nd=0); ++nd) if (*ns=='\\') switch (*(++ns)) {
4966  cimg_strescape('n','\n');
4967  cimg_strescape('t','\t');
4968  cimg_strescape('v','\v');
4969  cimg_strescape('b','\b');
4970  cimg_strescape('r','\r');
4971  cimg_strescape('f','\f');
4972  cimg_strescape('a','\a');
4973  cimg_strescape('\\','\\');
4974  cimg_strescape('\?','\?');
4975  cimg_strescape('\'','\'');
4976  cimg_strescape('\"','\"');
4977  case 0 : *nd = 0; break;
4978  case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' :
4979  std::sscanf(ns,"%o",&val); while (*ns>='0' && *ns<='7') ++ns;
4980  *nd = val; break;
4981  case 'x':
4982  std::sscanf(++ns,"%x",&val); while ((*ns>='0' && *ns<='7') || (*ns>='a' && *ns<='f') || (*ns>='A' && *ns<='F')) ++ns;
4983  *nd = val; break;
4984  default : *nd='\\';
4985  } else *nd = *(ns++);
4986  }
4987 
4989  inline const char* basename(const char *const s) {
4990  const char *p = 0;
4991  for (const char *np = s; np>=s && (p=np); np = std::strchr(np,cimg_file_separator)+1) {}
4992  return p;
4993  }
4994 
4995  // Generate a random filename.
4996  inline const char* filenamerand() {
4997  static char randomid[9] = { 0,0,0,0,0,0,0,0,0 };
4998  cimg::srand();
4999  for (unsigned int k = 0; k<8; ++k) {
5000  const int v = (int)std::rand()%3;
5001  randomid[k] = (char)(v==0?('0'+(std::rand()%10)):(v==1?('a'+(std::rand()%26)):('A'+(std::rand()%26))));
5002  }
5003  return randomid;
5004  }
5005 
5006  // Convert filename into a Windows-style filename.
5007  inline void winformat_string(char *const s) {
5008  if (s && s[0]) {
5009 #if cimg_OS==2
5010  char *const ns = new char[MAX_PATH];
5011  if (GetShortPathNameA(s,ns,MAX_PATH)) std::strcpy(s,ns);
5012 #endif
5013  }
5014  }
5015 
5017  inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false) {
5018 #define _cimg_test_temporary_path(p) \
5019  if (!path_found) { \
5020  std::sprintf(st_path,"%s",p); \
5021  std::sprintf(tmp,"%s%c%s",st_path,cimg_file_separator,filetmp); \
5022  if ((file=std::fopen(tmp,"wb"))!=0) { std::fclose(file); std::remove(tmp); path_found = true; } \
5023  }
5024  static char *st_path = 0;
5025  if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5026  if (user_path) {
5027  if (!st_path) st_path = new char[1024];
5028  std::memset(st_path,0,1024);
5029  std::strncpy(st_path,user_path,1023);
5030  } else if (!st_path) {
5031  st_path = new char[1024];
5032  std::memset(st_path,0,1024);
5033  bool path_found = false;
5034  char tmp[1024] = { 0 }, filetmp[512] = { 0 };
5035  std::FILE *file = 0;
5036  std::sprintf(filetmp,"%s.tmp",cimg::filenamerand());
5037  char *tmpPath = getenv("TMP");
5038  if (!tmpPath) { tmpPath = getenv("TEMP"); winformat_string(tmpPath); }
5039  if (tmpPath) _cimg_test_temporary_path(tmpPath);
5040 #if cimg_OS==2
5041  _cimg_test_temporary_path("C:\\WINNT\\Temp");
5042  _cimg_test_temporary_path("C:\\WINDOWS\\Temp");
5043  _cimg_test_temporary_path("C:\\Temp");
5045  _cimg_test_temporary_path("D:\\WINNT\\Temp");
5046  _cimg_test_temporary_path("D:\\WINDOWS\\Temp");
5047  _cimg_test_temporary_path("D:\\Temp");
5049 #else
5050  _cimg_test_temporary_path("/tmp");
5051  _cimg_test_temporary_path("/var/tmp");
5052 #endif
5053  if (!path_found) {
5054  st_path[0] = 0;
5055  std::strcpy(tmp,filetmp);
5056  if ((file=std::fopen(tmp,"wb"))!=0) { std::fclose(file); std::remove(tmp); path_found = true; }
5057  }
5058  if (!path_found)
5059  throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n"
5060  "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n"
5061  "#define cimg_temporary_path \"path\" (before including 'CImg.h')");
5062  }
5063  return st_path;
5064  }
5065 
5066  // Return or set path to the "Program files/" directory (windows only).
5067 #if cimg_OS==2
5068  inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false) {
5069  static char *st_path = 0;
5070  if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5071  if (user_path) {
5072  if (!st_path) st_path = new char[1024];
5073  std::memset(st_path,0,1024);
5074  std::strncpy(st_path,user_path,1023);
5075  } else if (!st_path) {
5076  st_path = new char[MAX_PATH];
5077  std::memset(st_path,0,MAX_PATH);
5078  // Note : in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler).
5079 #if !defined(__INTEL_COMPILER)
5080  if (!SHGetSpecialFolderPathA(0,st_path,0x0026,false)) {
5081  const char *pfPath = getenv("PROGRAMFILES");
5082  if (pfPath) std::strncpy(st_path,pfPath,MAX_PATH-1);
5083  else std::strcpy(st_path,"C:\\PROGRA~1");
5084  }
5085 #else
5086  std::strcpy(st_path,"C:\\PROGRA~1");
5087 #endif
5088  }
5089  return st_path;
5090  }
5091 #endif
5092 
5094  inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false) {
5095  static char *st_path = 0;
5096  if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5097  if (user_path) {
5098  if (!st_path) st_path = new char[1024];
5099  std::memset(st_path,0,1024);
5100  std::strncpy(st_path,user_path,1023);
5101  } else if (!st_path) {
5102  st_path = new char[1024];
5103  std::memset(st_path,0,1024);
5104  bool path_found = false;
5105  std::FILE *file = 0;
5106 #if cimg_OS==2
5107  const char *pf_path = programfiles_path();
5108  if (!path_found) {
5109  std::sprintf(st_path,".\\convert.exe");
5110  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5111  }
5112  for (int k = 32; k>=10 && !path_found; --k) {
5113  std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k);
5114  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5115  }
5116  for (int k = 9; k>=0 && !path_found; --k) {
5117  std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k);
5118  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5119  }
5120  for (int k = 32; k>=0 && !path_found; --k) {
5121  std::sprintf(st_path,"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k);
5122  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5123  }
5124  for (int k = 32; k>=10 && !path_found; --k) {
5125  std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k);
5126  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5127  }
5128  for (int k = 9; k>=0 && !path_found; --k) {
5129  std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k);
5130  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5131  }
5132  for (int k = 32; k>=0 && !path_found; --k) {
5133  std::sprintf(st_path,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k);
5134  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5135  }
5136  for (int k = 32; k>=10 && !path_found; --k) {
5137  std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\convert.exe",k);
5138  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5139  }
5140  for (int k = 9; k>=0 && !path_found; --k) {
5141  std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\convert.exe",k);
5142  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5143  }
5144  for (int k = 32; k>=0 && !path_found; --k) {
5145  std::sprintf(st_path,"C:\\IMAGEM~1.%d\\convert.exe",k);
5146  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5147  }
5148  for (int k = 32; k>=10 && !path_found; --k) {
5149  std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
5150  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5151  }
5152  for (int k = 9; k>=0 && !path_found; --k) {
5153  std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
5154  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5155  }
5156  for (int k = 32; k>=0 && !path_found; --k) {
5157  std::sprintf(st_path,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
5158  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5159  }
5160  for (int k = 32; k>=10 && !path_found; --k) {
5161  std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\convert.exe",k);
5162  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5163  }
5164  for (int k = 9; k>=0 && !path_found; --k) {
5165  std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\convert.exe",k);
5166  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5167  }
5168  for (int k = 32; k>=0 && !path_found; --k) {
5169  std::sprintf(st_path,"D:\\IMAGEM~1.%d\\convert.exe",k);
5170  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5171  }
5172  for (int k = 32; k>=10 && !path_found; --k) {
5173  std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
5174  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5175  }
5176  for (int k = 9; k>=0 && !path_found; --k) {
5177  std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
5178  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5179  }
5180  for (int k = 32; k>=0 && !path_found; --k) {
5181  std::sprintf(st_path,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
5182  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5183  }
5184  if (!path_found) std::strcpy(st_path,"convert.exe");
5185 #else
5186  if (!path_found) {
5187  std::sprintf(st_path,"./convert");
5188  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5189  }
5190  if (!path_found) std::strcpy(st_path,"convert");
5191 #endif
5192  winformat_string(st_path);
5193  }
5194  return st_path;
5195  }
5196 
5198  inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false) {
5199  static char *st_path = 0;
5200  if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5201  if (user_path) {
5202  if (!st_path) st_path = new char[1024];
5203  std::memset(st_path,0,1024);
5204  std::strncpy(st_path,user_path,1023);
5205  } else if (!st_path) {
5206  st_path = new char[1024];
5207  std::memset(st_path,0,1024);
5208  bool path_found = false;
5209  std::FILE *file = 0;
5210 #if cimg_OS==2
5211  const char* pf_path = programfiles_path();
5212  if (!path_found) {
5213  std::sprintf(st_path,".\\gm.exe");
5214  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5215  }
5216  for (int k = 32; k>=10 && !path_found; --k) {
5217  std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k);
5218  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5219  }
5220  for (int k = 9; k>=0 && !path_found; --k) {
5221  std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k);
5222  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5223  }
5224  for (int k = 32; k>=0 && !path_found; --k) {
5225  std::sprintf(st_path,"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k);
5226  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5227  }
5228  for (int k = 32; k>=10 && !path_found; --k) {
5229  std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k);
5230  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5231  }
5232  for (int k = 9; k>=0 && !path_found; --k) {
5233  std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k);
5234  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5235  }
5236  for (int k = 32; k>=0 && !path_found; --k) {
5237  std::sprintf(st_path,"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k);
5238  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5239  }
5240  for (int k = 32; k>=10 && !path_found; --k) {
5241  std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\gm.exe",k);
5242  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5243  }
5244  for (int k = 9; k>=0 && !path_found; --k) {
5245  std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\gm.exe",k);
5246  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5247  }
5248  for (int k = 32; k>=0 && !path_found; --k) {
5249  std::sprintf(st_path,"C:\\GRAPHI~1.%d\\gm.exe",k);
5250  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5251  }
5252  for (int k = 32; k>=10 && !path_found; --k) {
5253  std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
5254  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5255  }
5256  for (int k = 9; k>=0 && !path_found; --k) {
5257  std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
5258  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5259  }
5260  for (int k = 32; k>=0 && !path_found; --k) {
5261  std::sprintf(st_path,"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
5262  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5263  }
5264  for (int k = 32; k>=10 && !path_found; --k) {
5265  std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\gm.exe",k);
5266  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5267  }
5268  for (int k = 9; k>=0 && !path_found; --k) {
5269  std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\gm.exe",k);
5270  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5271  }
5272  for (int k = 32; k>=0 && !path_found; --k) {
5273  std::sprintf(st_path,"D:\\GRAPHI~1.%d\\gm.exe",k);
5274  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5275  }
5276  for (int k = 32; k>=10 && !path_found; --k) {
5277  std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
5278  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5279  }
5280  for (int k = 9; k>=0 && !path_found; --k) {
5281  std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
5282  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5283  }
5284  for (int k = 32; k>=0 && !path_found; --k) {
5285  std::sprintf(st_path,"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
5286  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5287  }
5288  if (!path_found) std::strcpy(st_path,"gm.exe");
5289 #else
5290  if (!path_found) {
5291  std::sprintf(st_path,"./gm");
5292  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5293  }
5294  if (!path_found) std::strcpy(st_path,"gm");
5295 #endif
5296  winformat_string(st_path);
5297  }
5298  return st_path;
5299  }
5300 
5302  inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false) {
5303  static char *st_path = 0;
5304  if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5305  if (user_path) {
5306  if (!st_path) st_path = new char[1024];
5307  std::memset(st_path,0,1024);
5308  std::strncpy(st_path,user_path,1023);
5309  } else if (!st_path) {
5310  st_path = new char[1024];
5311  std::memset(st_path,0,1024);
5312  bool path_found = false;
5313  std::FILE *file = 0;
5314 #if cimg_OS==2
5315  const char* pf_path = programfiles_path();
5316  if (!path_found) {
5317  std::sprintf(st_path,".\\medcon.bat");
5318  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5319  }
5320  if (!path_found) {
5321  std::sprintf(st_path,".\\medcon.exe");
5322  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5323  }
5324  if (!path_found) {
5325  std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.bat",pf_path);
5326  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5327  }
5328  if (!path_found) {
5329  std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.exe",pf_path);
5330  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5331  }
5332  if (!path_found) std::strcpy(st_path,"medcon.bat");
5333 #else
5334  if (!path_found) {
5335  std::sprintf(st_path,"./medcon");
5336  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5337  }
5338  if (!path_found) std::strcpy(st_path,"medcon");
5339 #endif
5340  winformat_string(st_path);
5341  }
5342  return st_path;
5343  }
5344 
5346  inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false) {
5347  static char *st_path = 0;
5348  if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5349  if (user_path) {
5350  if (!st_path) st_path = new char[1024];
5351  std::memset(st_path,0,1024);
5352  std::strncpy(st_path,user_path,1023);
5353  } else if (!st_path) {
5354  st_path = new char[1024];
5355  std::memset(st_path,0,1024);
5356  bool path_found = false;
5357  std::FILE *file = 0;
5358 #if cimg_OS==2
5359  if (!path_found) {
5360  std::sprintf(st_path,".\\ffmpeg.exe");
5361  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5362  }
5363  if (!path_found) std::strcpy(st_path,"ffmpeg.exe");
5364 #else
5365  if (!path_found) {
5366  std::sprintf(st_path,"./ffmpeg");
5367  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5368  }
5369  if (!path_found) std::strcpy(st_path,"ffmpeg");
5370 #endif
5371  winformat_string(st_path);
5372  }
5373  return st_path;
5374  }
5375 
5377  inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false) {
5378  static char *st_path = 0;
5379  if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5380  if (user_path) {
5381  if (!st_path) st_path = new char[1024];
5382  std::memset(st_path,0,1024);
5383  std::strncpy(st_path,user_path,1023);
5384  } else if (!st_path) {
5385  st_path = new char[1024];
5386  std::memset(st_path,0,1024);
5387  bool path_found = false;
5388  std::FILE *file = 0;
5389 #if cimg_OS==2
5390  if (!path_found) {
5391  std::sprintf(st_path,".\\gzip.exe");
5392  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5393  }
5394  if (!path_found) std::strcpy(st_path,"gzip.exe");
5395 #else
5396  if (!path_found) {
5397  std::sprintf(st_path,"./gzip");
5398  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5399  }
5400  if (!path_found) std::strcpy(st_path,"gzip");
5401 #endif
5402  winformat_string(st_path);
5403  }
5404  return st_path;
5405  }
5406 
5408  inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false) {
5409  static char *st_path = 0;
5410  if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5411  if (user_path) {
5412  if (!st_path) st_path = new char[1024];
5413  std::memset(st_path,0,1024);
5414  std::strncpy(st_path,user_path,1023);
5415  } else if (!st_path) {
5416  st_path = new char[1024];
5417  std::memset(st_path,0,1024);
5418  bool path_found = false;
5419  std::FILE *file = 0;
5420 #if cimg_OS==2
5421  if (!path_found) {
5422  std::sprintf(st_path,".\\gunzip.exe");
5423  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5424  }
5425  if (!path_found) std::strcpy(st_path,"gunzip.exe");
5426 #else
5427  if (!path_found) {
5428  std::sprintf(st_path,"./gunzip");
5429  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5430  }
5431  if (!path_found) std::strcpy(st_path,"gunzip");
5432 #endif
5433  winformat_string(st_path);
5434  }
5435  return st_path;
5436  }
5437 
5439  inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false) {
5440  static char *st_path = 0;
5441  if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5442  if (user_path) {
5443  if (!st_path) st_path = new char[1024];
5444  std::memset(st_path,0,1024);
5445  std::strncpy(st_path,user_path,1023);
5446  } else if (!st_path) {
5447  st_path = new char[1024];
5448  std::memset(st_path,0,1024);
5449  bool path_found = false;
5450  std::FILE *file = 0;
5451 #if cimg_OS==2
5452  if (!path_found) {
5453  std::sprintf(st_path,".\\dcraw.exe");
5454  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5455  }
5456  if (!path_found) std::strcpy(st_path,"dcraw.exe");
5457 #else
5458  if (!path_found) {
5459  std::sprintf(st_path,"./dcraw");
5460  if ((file=std::fopen(st_path,"r"))!=0) { std::fclose(file); path_found = true; }
5461  }
5462  if (!path_found) std::strcpy(st_path,"dcraw");
5463 #endif
5464  winformat_string(st_path);
5465  }
5466  return st_path;
5467  }
5468 
5470  inline const char *split_filename(const char *const filename, char *const body=0) {
5471  if (!filename) { if (body) body[0] = 0; return 0; }
5472  const char *p = 0; for (const char *np = filename; np>=filename && (p=np); np = std::strchr(np,'.')+1) {}
5473  if (p==filename) {
5474  if (body) std::strcpy(body,filename);
5475  return filename + std::strlen(filename);
5476  }
5477  const unsigned int l = p - filename - 1;
5478  if (body) { std::memcpy(body,filename,l); body[l] = 0; }
5479  return p;
5480  }
5481 
5483  inline char* number_filename(const char *const filename, const int number, const unsigned int n, char *const string) {
5484  if (!filename) { if (string) string[0] = 0; return 0; }
5485  char format[1024] = { 0 }, body[1024] = { 0 };
5486  const char *ext = cimg::split_filename(filename,body);
5487  if (n>0) std::sprintf(format,"%s_%%.%ud.%s",body,n,ext);
5488  else std::sprintf(format,"%s_%%d.%s",body,ext);
5489  std::sprintf(string,format,number);
5490  return string;
5491  }
5492 
5494  inline std::FILE *fopen(const char *const path, const char *const mode) {
5495  if(!path || !mode)
5496  throw CImgArgumentException("cimg::fopen() : File '%s', cannot open with mode '%s'.",
5497  path?path:"(null)",mode?mode:"(null)");
5498  if (path[0]=='-') return (mode[0]=='r')?stdin:stdout;
5499  std::FILE *dest = std::fopen(path,mode);
5500  if (!dest)
5501  throw CImgIOException("cimg::fopen() : File '%s', cannot open file %s",
5502  path,mode[0]=='r'?"for reading.":(mode[0]=='w'?"for writing.":"."),path);
5503  return dest;
5504  }
5505 
5507  inline int fclose(std::FILE *file) {
5508  if (!file) warn("cimg::fclose() : Cannot close (null) file");
5509  if (!file || file==stdin || file==stdout) return 0;
5510  const int errn = std::fclose(file);
5511  if (errn!=0) warn("cimg::fclose() : Error %d during file closing",errn);
5512  return errn;
5513  }
5514 
5516  inline const char *file_type(std::FILE *const file, const char *const filename) {
5517  static const char
5518  *const _pnm = "pnm",
5519  *const _bmp = "bmp",
5520  *const _gif = "gif",
5521  *const _jpeg = "jpeg",
5522  *const _off = "off",
5523  *const _pan = "pan",
5524  *const _png = "png",
5525  *const _tiff = "tiff";
5526  if (!filename && !file) throw CImgArgumentException("cimg::file_type() : Cannot load (null) filename.");
5527  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
5528  const char *ftype = 0, *head;
5529  char header[2048] = { 0 }, item[1024] = { 0 };
5530  const unsigned char *const uheader = (unsigned char*)header;
5531  int err;
5532  const unsigned int siz = (unsigned int)std::fread(header,2048,1,nfile); // Read first 2048 bytes.
5533  if (!file) cimg::fclose(nfile);
5534  if (!ftype) { // Check for BMP format.
5535  if (header[0]=='B' && header[1]=='M') ftype = _bmp;
5536  }
5537  if (!ftype) { // Check for GIF format.
5538  if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' &&
5539  (header[4]=='7' || header[4]=='9')) ftype = _gif;
5540  }
5541  if (!ftype) { // Check for JPEG format.
5542  if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) ftype = _jpeg;
5543  }
5544  if (!ftype) { // Check for OFF format.
5545  if (header[0]=='O' && header[1]=='F' && header[2]=='F' && header[3]=='\n') ftype = _off;
5546  }
5547  if (!ftype) { // Check for PAN format.
5548  if (header[0]=='P' && header[1]=='A' && header[2]=='N' && header[3]=='D' && header[4]=='O' &&
5549  header[5]=='R' && header[6]=='E') ftype = _pan;
5550  }
5551  if (!ftype) { // Check for PNG format.
5552  if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 &&
5553  uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) ftype = _png;
5554  }
5555  if (!ftype) { // Check for PNM format.
5556  head = header;
5557  while (head<header+siz && (err=std::sscanf(head,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err))
5558  head+=1+(err?std::strlen(item):0);
5559  if (std::sscanf(item," P%d",&err)==1) ftype = _pnm;
5560  }
5561  if (!ftype) { // Check for TIFF format.
5562  if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) ftype = _tiff;
5563  }
5564  return ftype;
5565  }
5566 
5568  template<typename T>
5569  inline int fread(T *const ptr, const unsigned int nmemb, std::FILE *stream) {
5570  if (!ptr || nmemb<=0 || !stream)
5571  throw CImgArgumentException("cimg::fread() : Cannot read %u x %u bytes of file pointer '%p' in buffer '%p'",
5572  nmemb,sizeof(T),stream,ptr);
5573  const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
5574  unsigned int toread = nmemb, alread = 0, ltoread = 0, lalread = 0;
5575  do {
5576  ltoread = (toread*sizeof(T))<wlimitT?toread:wlimit;
5577  lalread = (unsigned int)std::fread((void*)(ptr+alread),sizeof(T),ltoread,stream);
5578  alread+=lalread;
5579  toread-=lalread;
5580  } while (ltoread==lalread && toread>0);
5581  if (toread>0) warn("cimg::fread() : File reading problems, only %u/%u elements read",alread,nmemb);
5582  return alread;
5583  }
5584 
5586  template<typename T>
5587  inline int fwrite(const T *ptr, const unsigned int nmemb, std::FILE *stream) {
5588  if (!ptr || !stream)
5589  throw CImgArgumentException("cimg::fwrite() : Cannot write %u x %u bytes of file pointer '%p' from buffer '%p'",
5590  nmemb,sizeof(T),stream,ptr);
5591  if (nmemb<=0) return 0;
5592  const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
5593  unsigned int towrite = nmemb, alwrite = 0, ltowrite = 0, lalwrite = 0;
5594  do {
5595  ltowrite = (towrite*sizeof(T))<wlimitT?towrite:wlimit;
5596  lalwrite = (unsigned int)std::fwrite((void*)(ptr+alwrite),sizeof(T),ltowrite,stream);
5597  alwrite+=lalwrite;
5598  towrite-=lalwrite;
5599  } while (ltowrite==lalwrite && towrite>0);
5600  if (towrite>0) warn("cimg::fwrite() : File writing problems, only %u/%u elements written",alwrite,nmemb);
5601  return alwrite;
5602  }
5603 
5604  inline const char* option(const char *const name, const int argc, const char *const *const argv,
5605  const char *defaut, const char *const usage=0) {
5606  static bool first = true, visu = false;
5607  const char *res = 0;
5608  if (first) {
5609  first=false;
5610  visu = (cimg::option("-h",argc,argv,(char*)0)!=0);
5611  visu |= (cimg::option("-help",argc,argv,(char*)0)!=0);
5612  visu |= (cimg::option("--help",argc,argv,(char*)0)!=0);
5613  }
5614  if (!name && visu) {
5615  if (usage) {
5616  std::fprintf(cimg_stdout,"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);
5617  std::fprintf(cimg_stdout," : %s",usage);
5618  std::fprintf(cimg_stdout," (%s, %s)\n\n",__DATE__,__TIME__);
5619  }
5620  if (defaut) std::fprintf(cimg_stdout,"%s\n",defaut);
5621  }
5622  if (name) {
5623  if (argc>0) {
5624  int k = 0;
5625  while (k<argc && std::strcmp(argv[k],name)) ++k;
5626  res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
5627  } else res = defaut;
5628  if (visu && usage) std::fprintf(cimg_stdout," %s%-16s%s %-24s %s%s%s\n",
5629  cimg::t_bold,name,cimg::t_normal,res?res:"0",cimg::t_green,usage,cimg::t_normal);
5630  }
5631  return res;
5632  }
5633 
5634  inline bool option(const char *const name, const int argc, const char *const *const argv,
5635  const bool defaut, const char *const usage=0) {
5636  const char *s = cimg::option(name,argc,argv,(char*)0);
5637  const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut;
5638  cimg::option(name,0,0,res?"true":"false",usage);
5639  return res;
5640  }
5641 
5642  inline int option(const char *const name, const int argc, const char *const *const argv,
5643  const int defaut, const char *const usage=0) {
5644  const char *s = cimg::option(name,argc,argv,(char*)0);
5645  const int res = s?std::atoi(s):defaut;
5646  char tmp[256] = { 0 };
5647  std::sprintf(tmp,"%d",res);
5648  cimg::option(name,0,0,tmp,usage);
5649  return res;
5650  }
5651 
5652  inline char option(const char *const name, const int argc, const char *const *const argv,
5653  const char defaut, const char *const usage=0) {
5654  const char *s = cimg::option(name,argc,argv,(char*)0);
5655  const char res = s?s[0]:defaut;
5656  char tmp[8] = { 0 };
5657  tmp[0] = res;
5658  cimg::option(name,0,0,tmp,usage);
5659  return res;
5660  }
5661 
5662  inline float option(const char *const name, const int argc, const char *const *const argv,
5663  const float defaut, const char *const usage=0) {
5664  const char *s = cimg::option(name,argc,argv,(char*)0);
5665  const float res = s?cimg::atof(s):defaut;
5666  char tmp[256] = { 0 };
5667  std::sprintf(tmp,"%g",res);
5668  cimg::option(name,0,0,tmp,usage);
5669  return res;
5670  }
5671 
5672  inline double option(const char *const name, const int argc, const char *const *const argv,
5673  const double defaut, const char *const usage=0) {
5674  const char *s = cimg::option(name,argc,argv,(char*)0);
5675  const double res = s?cimg::atof(s):defaut;
5676  char tmp[256] = { 0 };
5677  std::sprintf(tmp,"%g",res);
5678  cimg::option(name,0,0,tmp,usage);
5679  return res;
5680  }
5681 
5682  inline const char* argument(const unsigned int nb, const int argc, const char *const *const argv, const unsigned int nb_singles=0, ...) {
5683  for (int k = 1, pos = 0; k<argc;) {
5684  const char *const item = argv[k];
5685  bool option = (*item=='-'), single_option = false;
5686  if (option) {
5687  va_list ap;
5688  va_start(ap,nb_singles);
5689  for (unsigned int i = 0; i<nb_singles; ++i) if (!cimg::strcasecmp(item,va_arg(ap,char*))) { single_option = true; break; }
5690  va_end(ap);
5691  }
5692  if (option) { ++k; if (!single_option) ++k; }
5693  else { if (pos++==(int)nb) return item; else ++k; }
5694  }
5695  return 0;
5696  }
5697 
5699 
5702  inline void info() {
5703  char tmp[1024] = { 0 };
5704  std::fprintf(cimg_stdout,"\n %sCImg Library %u.%u.%u%s, compiled %s ( %s ) with the following flags :\n\n",
5706  cimg::t_normal,__DATE__,__TIME__);
5707 
5708  std::fprintf(cimg_stdout," > Operating System : %s%-13s%s %s('cimg_OS'=%d)%s\n",
5709  cimg::t_bold,
5710  cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"),
5712  cimg_OS,
5713  cimg::t_normal);
5714 
5715  std::fprintf(cimg_stdout," > CPU endianness : %s%s Endian%s\n",
5716  cimg::t_bold,
5717  cimg::endianness()?"Big":"Little",
5718  cimg::t_normal);
5719 
5720  std::fprintf(cimg_stdout," > Debug messages : %s%-13s%s %s('cimg_debug'=%d)%s\n",
5721  cimg::t_bold,
5722  cimg_debug==0?"Quiet":(cimg_debug==1?"Console":(cimg_debug==2?"Dialog":(cimg_debug==3?"Console+Warnings":"Dialog+Warnings"))),
5724  cimg_debug,
5725  cimg::t_normal);
5726 
5727  std::fprintf(cimg_stdout," > Stricts warnings : %s%-13s%s %s('cimg_strict_warnings' %s)%s\n",
5728  cimg::t_bold,
5729 #ifdef cimg_strict_warnings
5730  "Yes",cimg::t_normal,cimg::t_green,"defined",
5731 #else
5732  "No",cimg::t_normal,cimg::t_green,"undefined",
5733 #endif
5734  cimg::t_normal);
5735 
5736  std::fprintf(cimg_stdout," > Using VT100 messages : %s%-13s%s %s('cimg_use_vt100' %s)%s\n",
5737  cimg::t_bold,
5738 #ifdef cimg_use_vt100
5739  "Yes",cimg::t_normal,cimg::t_green,"defined",
5740 #else
5741  "No",cimg::t_normal,cimg::t_green,"undefined",
5742 #endif
5743  cimg::t_normal);
5744 
5745  std::fprintf(cimg_stdout," > Display type : %s%-13s%s %s('cimg_display'=%d)%s\n",
5746  cimg::t_bold,
5747  cimg_display==0?"No display":
5748  (cimg_display==1?"X11":
5749  (cimg_display==2?"Windows GDI":
5750  (cimg_display==3?"Carbon":"Unknow"))),
5751  cimg::t_normal,cimg::t_green,
5752  cimg_display,
5753  cimg::t_normal);
5754 
5755 #if cimg_display==1
5756  std::fprintf(cimg_stdout," > Using XShm for X11 : %s%-13s%s %s('cimg_use_xshm' %s)%s\n",
5757  cimg::t_bold,
5758 #ifdef cimg_use_xshm
5759  "Yes",cimg::t_normal,cimg::t_green,"defined",
5760 #else
5761  "No",cimg::t_normal,cimg::t_green,"undefined",
5762 #endif
5763  cimg::t_normal);
5764 
5765  std::fprintf(cimg_stdout," > Using XRand for X11 : %s%-13s%s %s('cimg_use_xrandr' %s)%s\n",
5766  cimg::t_bold,
5767 #ifdef cimg_use_xrandr
5768  "Yes",cimg::t_normal,cimg::t_green,"defined",
5769 #else
5770  "No",cimg::t_normal,cimg::t_green,"undefined",
5771 #endif
5772  cimg::t_normal);
5773 #endif
5774  std::fprintf(cimg_stdout," > Using OpenMP : %s%-13s%s %s('cimg_use_openmp' %s)%s\n",
5775  cimg::t_bold,
5776 #ifdef cimg_use_openmp
5777  "Yes",cimg::t_normal,cimg::t_green,"defined",
5778 #else
5779  "No",cimg::t_normal,cimg::t_green,"undefined",
5780 #endif
5781  cimg::t_normal);
5782  std::fprintf(cimg_stdout," > Using PNG library : %s%-13s%s %s('cimg_use_png' %s)%s\n",
5783  cimg::t_bold,
5784 #ifdef cimg_use_png
5785  "Yes",cimg::t_normal,cimg::t_green,"defined",
5786 #else
5787  "No",cimg::t_normal,cimg::t_green,"undefined",
5788 #endif
5789  cimg::t_normal);
5790  std::fprintf(cimg_stdout," > Using JPEG library : %s%-13s%s %s('cimg_use_jpeg' %s)%s\n",
5791  cimg::t_bold,
5792 #ifdef cimg_use_jpeg
5793  "Yes",cimg::t_normal,cimg::t_green,"defined",
5794 #else
5795  "No",cimg::t_normal,cimg::t_green,"undefined",
5796 #endif
5797  cimg::t_normal);
5798 
5799  std::fprintf(cimg_stdout," > Using TIFF library : %s%-13s%s %s('cimg_use_tiff' %s)%s\n",
5800  cimg::t_bold,
5801 #ifdef cimg_use_tiff
5802  "Yes",cimg::t_normal,cimg::t_green,"defined",
5803 #else
5804  "No",cimg::t_normal,cimg::t_green,"undefined",
5805 #endif
5806  cimg::t_normal);
5807 
5808  std::fprintf(cimg_stdout," > Using Magick++ library : %s%-13s%s %s('cimg_use_magick' %s)%s\n",
5809  cimg::t_bold,
5810 #ifdef cimg_use_magick
5811  "Yes",cimg::t_normal,cimg::t_green,"defined",
5812 #else
5813  "No",cimg::t_normal,cimg::t_green,"undefined",
5814 #endif
5815  cimg::t_normal);
5816 
5817  std::fprintf(cimg_stdout," > Using FFTW3 library : %s%-13s%s %s('cimg_use_fftw3' %s)%s\n",
5818  cimg::t_bold,
5819 #ifdef cimg_use_fftw3
5820  "Yes",cimg::t_normal,cimg::t_green,"defined",
5821 #else
5822  "No",cimg::t_normal,cimg::t_green,"undefined",
5823 #endif
5824  cimg::t_normal);
5825 
5826  std::fprintf(cimg_stdout," > Using LAPACK library : %s%-13s%s %s('cimg_use_lapack' %s)%s\n",
5827  cimg::t_bold,
5828 #ifdef cimg_use_lapack
5829  "Yes",cimg::t_normal,cimg::t_green,"defined",
5830 #else
5831  "No",cimg::t_normal,cimg::t_green,"undefined",
5832 #endif
5833  cimg::t_normal);
5834 
5835  std::sprintf(tmp,"\"%.1020s\"",cimg::imagemagick_path());
5836  std::fprintf(cimg_stdout," > Path of ImageMagick : %s%-13s%s\n",
5837  cimg::t_bold,
5838  tmp,
5839  cimg::t_normal);
5840 
5841  std::sprintf(tmp,"\"%.1020s\"",cimg::graphicsmagick_path());
5842  std::fprintf(cimg_stdout," > Path of GraphicsMagick : %s%-13s%s\n",
5843  cimg::t_bold,
5844  tmp,
5845  cimg::t_normal);
5846 
5847  std::sprintf(tmp,"\"%.1020s\"",cimg::medcon_path());
5848  std::fprintf(cimg_stdout," > Path of 'medcon' : %s%-13s%s\n",
5849  cimg::t_bold,
5850  tmp,
5851  cimg::t_normal);
5852 
5853  std::sprintf(tmp,"\"%.1020s\"",cimg::temporary_path());
5854  std::fprintf(cimg_stdout," > Temporary path : %s%-13s%s\n",
5855  cimg::t_bold,
5856  tmp,
5857  cimg::t_normal);
5858 
5859  std::fprintf(cimg_stdout,"\n");
5860  }
5861 
5862  // Declare LAPACK function signatures if necessary.
5863 #ifdef cimg_use_lapack
5864  template<typename T>
5865  inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) {
5866  dgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
5867  }
5868 
5869  inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) {
5870  sgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
5871  }
5872 
5873  template<typename T>
5874  inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {
5875  dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
5876  }
5877 
5878  inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) {
5879  sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
5880  }
5881 
5882  template<typename T>
5883  inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN,
5884  T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) {
5885  dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
5886  }
5887 
5888  inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN,
5889  float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) {
5890  sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
5891  }
5892 
5893  template<typename T>
5894  inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) {
5895  int one = 1;
5896  dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
5897  }
5898 
5899  inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) {
5900  int one = 1;
5901  sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
5902  }
5903 
5904  template<typename T>
5905  inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {
5906  dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
5907  }
5908 
5909  inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) {
5910  ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
5911  }
5912 #endif
5913 
5914  // End of the 'cimg' namespace
5915  }
5916 
5917  /*------------------------------------------------
5918  #
5919  #
5920  # Definition of mathematical operators and
5921  # external functions.
5922  #
5923  #
5924  -------------------------------------------------*/
5925 
5926 #define _cimg_create_ext_operators(typ) \
5927  template<typename T> \
5928  inline CImg<typename cimg::superset<T,typ>::type> operator+(const typ val, const CImg<T>& img) { \
5929  return img + val; \
5930  } \
5931  template<typename T> \
5932  inline CImg<typename cimg::superset<T,typ>::type> operator-(const typ val, const CImg<T>& img) { \
5933  typedef typename cimg::superset<T,typ>::type Tt; \
5934  return CImg<Tt>(img.width,img.height,img.depth,img.dim,val)-=img; \
5935  } \
5936  template<typename T> \
5937  inline CImg<typename cimg::superset<T,typ>::type> operator*(const typ val, const CImg<T>& img) { \
5938  return img*val; \
5939  } \
5940  template<typename T> \
5941  inline CImg<typename cimg::superset<T,typ>::type> operator/(const typ val, const CImg<T>& img) { \
5942  return val*img.get_invert(); \
5943  } \
5944  template<typename T> \
5945  inline CImg<typename cimg::superset<T,typ>::type> operator&(const typ val, const CImg<T>& img) { \
5946  return img & val; \
5947  } \
5948  template<typename T> \
5949  inline CImg<typename cimg::superset<T,typ>::type> operator|(const typ val, const CImg<T>& img) { \
5950  return img | val; \
5951  } \
5952  template<typename T> \
5953  inline CImg<typename cimg::superset<T,typ>::type> operator^(const typ val, const CImg<T>& img) { \
5954  return img ^ val; \
5955  } \
5956 
5958  _cimg_create_ext_operators(unsigned char)
5960  _cimg_create_ext_operators(signed char)
5961  _cimg_create_ext_operators(unsigned short)
5963  _cimg_create_ext_operators(unsigned int)
5965  _cimg_create_ext_operators(unsigned long)
5969 
5970  template<typename T>
5971  inline CImg<_cimg_Tfloat> operator+(const char *const expression, const CImg<T>& img) {
5972  return img + expression;
5973  }
5974 
5975  template<typename T>
5976  inline CImg<_cimg_Tfloat> operator-(const char *const expression, const CImg<T>& img) {
5977  return (CImg<_cimg_Tfloat>(img.width,img.height,img.depth,img.dim)=expression)-=img;
5978  }
5979 
5980  template<typename T>
5981  inline CImg<_cimg_Tfloat> operator*(const char *const expression, const CImg<T>& img) {
5982  return img*expression;
5983  }
5984 
5985  template<typename T>
5986  inline CImg<_cimg_Tfloat> operator/(const char *const expression, const CImg<T>& img) {
5987  return expression*img.get_invert();
5988  }
5989 
5990  template<typename T>
5991  inline CImg<T> operator&(const char *const expression, const CImg<T>& img) {
5992  return img & expression;
5993  }
5994 
5995  template<typename T>
5996  inline CImg<T> operator|(const char *const expression, const CImg<T>& img) {
5997  return img | expression;
5998  }
5999 
6000  template<typename T>
6001  inline CImg<T> operator^(const char *const expression, const CImg<T>& img) {
6002  return img ^ expression;
6003  }
6004 
6005  template<typename T>
6006  inline CImg<_cimg_Tfloat> sqr(const CImg<T>& instance) {
6007  return instance.get_sqr();
6008  }
6009 
6010  template<typename T>
6011  inline CImg<_cimg_Tfloat> sqrt(const CImg<T>& instance) {
6012  return instance.get_sqrt();
6013  }
6014 
6015  template<typename T>
6016  inline CImg<_cimg_Tfloat> exp(const CImg<T>& instance) {
6017  return instance.get_exp();
6018  }
6019 
6020  template<typename T>
6021  inline CImg<_cimg_Tfloat> log(const CImg<T>& instance) {
6022  return instance.get_log();
6023  }
6024 
6025  template<typename T>
6026  inline CImg<_cimg_Tfloat> log10(const CImg<T>& instance) {
6027  return instance.get_log10();
6028  }
6029 
6030  template<typename T>
6031  inline CImg<_cimg_Tfloat> abs(const CImg<T>& instance) {
6032  return instance.get_abs();
6033  }
6034 
6035  template<typename T>
6036  inline CImg<_cimg_Tfloat> cos(const CImg<T>& instance) {
6037  return instance.get_cos();
6038  }
6039 
6040  template<typename T>
6041  inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) {
6042  return instance.get_sin();
6043  }
6044 
6045  template<typename T>
6046  inline CImg<_cimg_Tfloat> tan(const CImg<T>& instance) {
6047  return instance.get_tan();
6048  }
6049 
6050  template<typename T>
6051  inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) {
6052  return instance.get_acos();
6053  }
6054 
6055  template<typename T>
6056  inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) {
6057  return instance.get_asin();
6058  }
6059 
6060  template<typename T>
6061  inline CImg<_cimg_Tfloat> atan(const CImg<T>& instance) {
6062  return instance.get_atan();
6063  }
6064 
6065  template<typename T>
6066  inline CImg<_cimg_Tfloat> cosh(const CImg<T>& instance) {
6067  return instance.get_cosh();
6068  }
6069 
6070  template<typename T>
6071  inline CImg<_cimg_Tfloat> sinh(const CImg<T>& instance) {
6072  return instance.get_sinh();
6073  }
6074 
6075  template<typename T>
6076  inline CImg<_cimg_Tfloat> tanh(const CImg<T>& instance) {
6077  return instance.get_tanh();
6078  }
6079 
6080  template<typename T>
6081  inline CImg<T> transpose(const CImg<T>& instance) {
6082  return instance.get_transpose();
6083  }
6084 
6085  template<typename T>
6086  inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance) {
6087  return instance.get_invert();
6088  }
6089 
6090  template<typename T>
6091  inline CImg<_cimg_Tfloat> pseudoinvert(const CImg<T>& instance) {
6092  return instance.get_pseudoinvert();
6093  }
6094 
6095  /*-------------------------------------------
6096  #
6097  #
6098  #
6099  # Definition of the CImgDisplay structure
6100  #
6101  #
6102  #
6103  --------------------------------------------*/
6104 
6106 
6114  struct CImgDisplay {
6115 
6117  unsigned int width;
6118 
6120  unsigned int height;
6121 
6123  volatile unsigned int window_width;
6124 
6126  volatile unsigned int window_height;
6127 
6129  volatile int window_x;
6130 
6132  volatile int window_y;
6133 
6135  volatile int mouse_x;
6136 
6138  volatile int mouse_y;
6139 
6141  unsigned int normalization;
6142 
6144  char* title;
6145 
6147  volatile unsigned int buttons[512];
6148  volatile unsigned int& button;
6149 
6151  volatile int wheel;
6152 
6154  volatile unsigned int& key;
6155  volatile unsigned int keys[512];
6156 
6158  volatile unsigned int& released_key;
6159  volatile unsigned int released_keys[512];
6160 
6162  volatile bool is_closed;
6163 
6165  volatile bool is_resized;
6166 
6168  volatile bool is_moved;
6169 
6171  volatile bool is_event;
6172 
6174  volatile bool is_keyESC;
6175  volatile bool is_keyF1;
6176  volatile bool is_keyF2;
6177  volatile bool is_keyF3;
6178  volatile bool is_keyF4;
6179  volatile bool is_keyF5;
6180  volatile bool is_keyF6;
6181  volatile bool is_keyF7;
6182  volatile bool is_keyF8;
6183  volatile bool is_keyF9;
6184  volatile bool is_keyF10;
6185  volatile bool is_keyF11;
6186  volatile bool is_keyF12;
6187  volatile bool is_keyPAUSE;
6188  volatile bool is_key1;
6189  volatile bool is_key2;
6190  volatile bool is_key3;
6191  volatile bool is_key4;
6192  volatile bool is_key5;
6193  volatile bool is_key6;
6194  volatile bool is_key7;
6195  volatile bool is_key8;
6196  volatile bool is_key9;
6197  volatile bool is_key0;
6198  volatile bool is_keyBACKSPACE;
6199  volatile bool is_keyINSERT;
6200  volatile bool is_keyHOME;
6201  volatile bool is_keyPAGEUP;
6202  volatile bool is_keyTAB;
6203  volatile bool is_keyQ;
6204  volatile bool is_keyW;
6205  volatile bool is_keyE;
6206  volatile bool is_keyR;
6207  volatile bool is_keyT;
6208  volatile bool is_keyY;
6209  volatile bool is_keyU;
6210  volatile bool is_keyI;
6211  volatile bool is_keyO;
6212  volatile bool is_keyP;
6213  volatile bool is_keyDELETE;
6214  volatile bool is_keyEND;
6215  volatile bool is_keyPAGEDOWN;
6216  volatile bool is_keyCAPSLOCK;
6217  volatile bool is_keyA;
6218  volatile bool is_keyS;
6219  volatile bool is_keyD;
6220  volatile bool is_keyF;
6221  volatile bool is_keyG;
6222  volatile bool is_keyH;
6223  volatile bool is_keyJ;
6224  volatile bool is_keyK;
6225  volatile bool is_keyL;
6226  volatile bool is_keyENTER;
6227  volatile bool is_keySHIFTLEFT;
6228  volatile bool is_keyZ;
6229  volatile bool is_keyX;
6230  volatile bool is_keyC;
6231  volatile bool is_keyV;
6232  volatile bool is_keyB;
6233  volatile bool is_keyN;
6234  volatile bool is_keyM;
6235  volatile bool is_keySHIFTRIGHT;
6236  volatile bool is_keyARROWUP;
6237  volatile bool is_keyCTRLLEFT;
6238  volatile bool is_keyAPPLEFT;
6239  volatile bool is_keyALT;
6240  volatile bool is_keySPACE;
6241  volatile bool is_keyALTGR;
6242  volatile bool is_keyAPPRIGHT;
6243  volatile bool is_keyMENU;
6244  volatile bool is_keyCTRLRIGHT;
6245  volatile bool is_keyARROWLEFT;
6246  volatile bool is_keyARROWDOWN;
6247  volatile bool is_keyARROWRIGHT;
6248  volatile bool is_keyPAD0;
6249  volatile bool is_keyPAD1;
6250  volatile bool is_keyPAD2;
6251  volatile bool is_keyPAD3;
6252  volatile bool is_keyPAD4;
6253  volatile bool is_keyPAD5;
6254  volatile bool is_keyPAD6;
6255  volatile bool is_keyPAD7;
6256  volatile bool is_keyPAD8;
6257  volatile bool is_keyPAD9;
6258  volatile bool is_keyPADADD;
6259  volatile bool is_keyPADSUB;
6260  volatile bool is_keyPADMUL;
6261  volatile bool is_keyPADDIV;
6262 
6265 
6266  // Internal variables
6267  float fps_fps, min, max;
6268  unsigned long timer, fps_frames, fps_timer;
6269 
6271  //---------------------------
6272  //
6274 
6275  //---------------------------
6276 
6277 #ifdef cimgdisplay_plugin
6278 #include cimgdisplay_plugin
6279 #endif
6280 #ifdef cimgdisplay_plugin1
6281 #include cimgdisplay_plugin1
6282 #endif
6283 #ifdef cimgdisplay_plugin2
6284 #include cimgdisplay_plugin2
6285 #endif
6286 #ifdef cimgdisplay_plugin3
6287 #include cimgdisplay_plugin3
6288 #endif
6289 #ifdef cimgdisplay_plugin4
6290 #include cimgdisplay_plugin4
6291 #endif
6292 #ifdef cimgdisplay_plugin5
6293 #include cimgdisplay_plugin5
6294 #endif
6295 #ifdef cimgdisplay_plugin6
6296 #include cimgdisplay_plugin6
6297 #endif
6298 #ifdef cimgdisplay_plugin7
6299 #include cimgdisplay_plugin7
6300 #endif
6301 #ifdef cimgdisplay_plugin8
6302 #include cimgdisplay_plugin8
6303 #endif
6304 
6306  //--------------------------------------------------------
6307  //
6309 
6310  //--------------------------------------------------------
6311 
6314  assign();
6315  }
6316 
6319  width(0),height(0),window_width(0),window_height(0),mouse_x(-1),mouse_y(-1),
6321  is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {}
6322 
6324 
6332  CImgDisplay(const unsigned int dimw, const unsigned int dimh, const char *title=0,
6333  const unsigned int normalization_type=3,
6334  const bool fullscreen_flag=false, const bool closed_flag=false):
6335  width(0),height(0),window_width(0),window_height(0),mouse_x(-1),mouse_y(-1),
6337  is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
6338  assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
6339  }
6340 
6342 
6348  template<typename T>
6349  explicit CImgDisplay(const CImg<T>& img, const char *title=0,
6350  const unsigned int normalization_type=3,
6351  const bool fullscreen_flag=false, const bool closed_flag=false):
6352  width(0),height(0),window_width(0),window_height(0),mouse_x(-1),mouse_y(-1),
6354  is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
6355  assign(img,title,normalization_type,fullscreen_flag,closed_flag);
6356  }
6357 
6359 
6365  template<typename T>
6366  explicit CImgDisplay(const CImgList<T>& list, const char *title=0,
6367  const unsigned int normalization_type=3,
6368  const bool fullscreen_flag=false, const bool closed_flag=false):
6369  width(0),height(0),window_width(0),window_height(0),mouse_x(-1),mouse_y(-1),
6371  is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
6372  assign(list,title,normalization_type,fullscreen_flag,closed_flag);
6373  }
6374 
6376 
6379  CImgDisplay(const CImgDisplay& disp):
6380  width(0),height(0),window_width(0),window_height(0),mouse_x(-1),mouse_y(-1),
6382  is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
6383  assign(disp);
6384  }
6385 
6386 #if cimg_display==0
6387  CImgDisplay& assign() {
6389  return *this;
6390  }
6391 
6393  CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
6394  const unsigned int normalization_type=3,
6395  const bool fullscreen_flag=false, const bool closed_flag=false) {
6396  throw CImgDisplayException("CImgDisplay() : Display has been required but is not available (cimg_display=0)");
6397  const char* avoid_warning = title + dimw + dimh + normalization_type + (int)fullscreen_flag + (int)closed_flag;
6398  avoid_warning = 0;
6399  return *this;
6400  }
6401 
6403  template<typename T>
6404  CImgDisplay& assign(const CImg<T>& img, const char *title=0,
6405  const unsigned int normalization_type=3,
6406  const bool fullscreen_flag=false, const bool closed_flag=false) {
6407  throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
6408  const char* avoid_warning = title + img.width + normalization_type + (int)fullscreen_flag + (int)closed_flag;
6409  avoid_warning = 0;
6410  return assign(0,0);
6411  }
6412 
6414  template<typename T>
6415  CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
6416  const unsigned int normalization_type=3,
6417  const bool fullscreen_flag=false, const bool closed_flag=false) {
6418  throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
6419  const char* avoid_warning = title + list.width + normalization_type + (int)fullscreen_flag + (int)closed_flag;
6420  avoid_warning = 0;
6421  return assign(0,0);
6422  }
6423 
6426  return assign(disp.width,disp.height);
6427  }
6428 #endif
6429 
6431  static CImgDisplay& empty() {
6432  static CImgDisplay _empty;
6433  return _empty.assign();
6434  }
6435 
6436 #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false),CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
6437  static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1,
6438  const int dmin=128, const int dmax=-85,const bool return_last=false) {
6439  unsigned int nw = dx + (dz>1?dz:0), nh = dy + (dz>1?dz:0);
6440  const unsigned int
6442  mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin,
6443  mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin,
6444  Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax,
6445  Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax;
6446  if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0); nw = mw; }
6447  if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0); nh = mh; }
6448  if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0); nw = Mw; }
6449  if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0); nh = Mh; }
6450  if (nw<mw) nw = mw;
6451  if (nh<mh) nh = mh;
6452  if (return_last) return nh;
6453  return nw;
6454  }
6455 
6457  //------------------------------------------
6458  //
6460 
6461  //------------------------------------------
6462 
6463  // Operator=().
6464  template<typename t>
6466  return display(img);
6467  }
6468 
6469  // Operator=().
6470  template<typename t>
6472  return display(list);
6473  }
6474 
6477  return assign(disp);
6478  }
6479 
6481  operator bool() const {
6482  return !is_empty();
6483  }
6484 
6486  //------------------------------------------
6487  //
6489 
6490  //------------------------------------------
6491 
6493  bool is_empty() const {
6494  return (!width || !height);
6495  }
6496 
6498  bool is_key(const bool remove=false) {
6499  for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs) { if (remove) *ptrs = 0; return true; }
6500  return false;
6501  }
6502 
6504  bool is_key(const unsigned int key1, const bool remove) {
6505  for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs==key1) { if (remove) *ptrs = 0; return true; }
6506  return false;
6507  }
6508 
6510  bool is_key(const unsigned int key1, const unsigned int key2, const bool remove) {
6511  const unsigned int seq[] = { key1, key2 };
6512  return is_key(seq,2,remove);
6513  }
6514 
6516  bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const bool remove) {
6517  const unsigned int seq[] = { key1, key2, key3 };
6518  return is_key(seq,3,remove);
6519  }
6520 
6522  bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6523  const unsigned int key4, const bool remove) {
6524  const unsigned int seq[] = { key1, key2, key3, key4 };
6525  return is_key(seq,4,remove);
6526  }
6527 
6529  bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6530  const unsigned int key4, const unsigned int key5, const bool remove) {
6531  const unsigned int seq[] = { key1, key2, key3, key4, key5 };
6532  return is_key(seq,5,remove);
6533  }
6534 
6536  bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6537  const unsigned int key4, const unsigned int key5, const unsigned int key6, const bool remove) {
6538  const unsigned int seq[] = { key1, key2, key3, key4, key5, key6 };
6539  return is_key(seq,6,remove);
6540  }
6541 
6543  bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6544  const unsigned int key4, const unsigned int key5, const unsigned int key6,
6545  const unsigned int key7, const bool remove) {
6546  const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7 };
6547  return is_key(seq,7,remove);
6548  }
6549 
6551  bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6552  const unsigned int key4, const unsigned int key5, const unsigned int key6,
6553  const unsigned int key7, const unsigned int key8, const bool remove) {
6554  const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8 };
6555  return is_key(seq,8,remove);
6556  }
6557 
6559  bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6560  const unsigned int key4, const unsigned int key5, const unsigned int key6,
6561  const unsigned int key7, const unsigned int key8, const unsigned int key9, const bool remove) {
6562  const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8, key9 };
6563  return is_key(seq,9,remove);
6564  }
6565 
6567  bool is_key(const unsigned int *const keyseq, const unsigned int N, const bool remove=true) {
6568  if (keyseq && N) {
6569  const unsigned int *const ps_end = keyseq+N-1, k = *ps_end, *const pk_end = (unsigned int*)keys+1+512-N;
6570  for (unsigned int *pk = (unsigned int*)keys; pk<pk_end; ) {
6571  if (*(pk++)==k) {
6572  bool res = true;
6573  const unsigned int *ps = ps_end, *pk2 = pk;
6574  for (unsigned int i=1; i<N; ++i) res = (*(--ps)==*(pk2++));
6575  if (res) {
6576  if (remove) std::memset((void*)(pk-1),0,sizeof(unsigned int)*N);
6577  return true;
6578  }
6579  }
6580  }
6581  }
6582  return false;
6583  }
6584 
6585  // Update 'is_key' fields.
6586  void _update_iskey(const unsigned int key, const bool pressed=true) {
6587 #define _cimg_iskey_case(k) if (key==cimg::key##k) is_key##k = pressed;
6594  _cimg_iskey_case(BACKSPACE); _cimg_iskey_case(INSERT); _cimg_iskey_case(HOME);
6598  _cimg_iskey_case(DELETE); _cimg_iskey_case(END); _cimg_iskey_case(PAGEDOWN);
6604  _cimg_iskey_case(SHIFTRIGHT); _cimg_iskey_case(ARROWUP); _cimg_iskey_case(CTRLLEFT);
6605  _cimg_iskey_case(APPLEFT); _cimg_iskey_case(ALT); _cimg_iskey_case(SPACE); _cimg_iskey_case(ALTGR);
6606  _cimg_iskey_case(APPRIGHT); _cimg_iskey_case(MENU); _cimg_iskey_case(CTRLRIGHT);
6607  _cimg_iskey_case(ARROWLEFT); _cimg_iskey_case(ARROWDOWN); _cimg_iskey_case(ARROWRIGHT);
6611  _cimg_iskey_case(PAD9); _cimg_iskey_case(PADADD); _cimg_iskey_case(PADSUB);
6612  _cimg_iskey_case(PADMUL); _cimg_iskey_case(PADDIV);
6613  }
6614 
6616  //------------------------------------------
6617  //
6619 
6620  //------------------------------------------
6621 
6623  int dimx() const {
6624  return (int)width;
6625  }
6626 
6628  int dimy() const {
6629  return (int)height;
6630  }
6631 
6633  int window_dimx() const {
6634  return (int)window_width;
6635  }
6636 
6638  int window_dimy() const {
6639  return (int)window_height;
6640  }
6641 
6643  int window_posx() const {
6644  return window_x;
6645  }
6646 
6648  int window_posy() const {
6649  return window_y;
6650  }
6651 
6652 #if cimg_display==0
6653 
6655  static int screen_dimx() {
6656  return 0;
6657  }
6658 
6660  static int screen_dimy() {
6661  return 0;
6662  }
6663 
6664 #endif
6665 
6668  if (!fps_timer) fps_timer = cimg::time();
6669  const float delta = (cimg::time()-fps_timer)/1000.0f;
6670  ++fps_frames;
6671  if (delta>=1) {
6672  fps_fps = fps_frames/delta;
6673  fps_frames = 0;
6674  fps_timer = cimg::time();
6675  }
6676  return fps_fps;
6677  }
6678 
6680  //------------------------------------------
6681  //
6683 
6684  //------------------------------------------
6685 
6686 #if cimg_display==0
6687  template<typename T>
6689  CImgDisplay& display(const CImg<T>& img) {
6690  unsigned int avoid_warning = img.width;
6691  avoid_warning = 0;
6692  return *this;
6693  }
6694 #endif
6695 
6697 
6704  template<typename T>
6705  CImgDisplay& display(const CImgList<T>& list, const char axis='x', const char align='p') {
6706  return display(list.get_append(axis,align));
6707  }
6708 
6710 
6714  template<typename T>
6715  CImgDisplay& resize(const CImg<T>& img, const bool redraw=true) {
6716  return resize(img.width,img.height,redraw);
6717  }
6718 
6720  CImgDisplay& resize(const CImgDisplay& disp, const bool redraw=true) {
6721  return resize(disp.width,disp.height,redraw);
6722  }
6723 
6725  CImgDisplay& resize(const bool redraw=true) {
6727  return *this;
6728  }
6729 
6730 #if cimg_display==0
6731 
6733  CImgDisplay& resize(const int width, const int height, const bool redraw=true) {
6734  int avoid_warning = width | height | (int)redraw;
6735  avoid_warning = 0;
6736  return *this;
6737  }
6738 
6739 #endif
6740 
6741  template<typename t, typename T>
6742  static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,
6743  t *ptrd, const unsigned int wd, const unsigned int hd) {
6744  unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd+1], *poffx, *poffy;
6745  float s, curr, old;
6746  s = (float)ws/wd;
6747  poffx = offx; curr = 0; for (unsigned int x = 0; x<wd; ++x) { old=curr; curr+=s; *(poffx++) = (unsigned int)curr-(unsigned int)old; }
6748  s = (float)hs/hd;
6749  poffy = offy; curr = 0; for (unsigned int y = 0; y<hd; ++y) { old=curr; curr+=s; *(poffy++) = ws*((unsigned int)curr-(unsigned int)old); }
6750  *poffy = 0;
6751  poffy = offy;
6752  for (unsigned int y = 0; y<hd; ) {
6753  const T *ptr = ptrs;
6754  poffx = offx;
6755  for (unsigned int x = 0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); }
6756  ++y;
6757  unsigned int dy=*(poffy++);
6758  for (;!dy && y<hd; std::memcpy(ptrd, ptrd-wd, sizeof(t)*wd), ++y, ptrd+=wd, dy=*(poffy++)) {}
6759  ptrs+=dy;
6760  }
6761  delete[] offx; delete[] offy;
6762  }
6763 
6765  CImgDisplay& fullscreen(const bool redraw=true) {
6766  if (is_empty() || is_fullscreen) return *this;
6767  return toggle_fullscreen(redraw);
6768  }
6769 
6771  CImgDisplay& normalscreen(const bool redraw=true) {
6772  if (is_empty() || !is_fullscreen) return *this;
6773  return toggle_fullscreen(redraw);
6774  }
6775 
6776 #if cimg_display==0
6777 
6779  CImgDisplay& toggle_fullscreen(const bool redraw=true) {
6780  bool avoid_warning = redraw;
6781  avoid_warning = false;
6782  return *this;
6783  }
6784 
6787  return *this;
6788  }
6789 
6792  return *this;
6793  }
6794 
6796  CImgDisplay& move(const int posx, const int posy) {
6797  int avoid_warning = posx | posy;
6798  avoid_warning = 0;
6799  return *this;
6800  }
6801 
6804  return *this;
6805  }
6806 
6809  return *this;
6810  }
6811 
6813  CImgDisplay& set_mouse(const int posx, const int posy) {
6814  int avoid_warning = posx | posy;
6815  avoid_warning = 0;
6816  return *this;
6817  }
6818 
6820  CImgDisplay& set_title(const char *format, ...) {
6821  const char *avoid_warning = format;
6822  avoid_warning = 0;
6823  return *this;
6824  }
6825 
6827  template<typename T>
6828  CImgDisplay& render(const CImg<T>& img) {
6829  unsigned int avoid_warning = img.width;
6830  avoid_warning = 0;
6831  return *this;
6832  }
6833 
6836  return *this;
6837  }
6838 
6840  template<typename T>
6841  const CImgDisplay& snapshot(CImg<T>& img) const {
6842  img.assign(width,height,1,3,0);
6843  return *this;
6844  }
6845 #endif
6846 
6849  std::memset((void*)buttons,0,512*sizeof(unsigned int));
6850  std::memset((void*)keys,0,512*sizeof(unsigned int));
6851  std::memset((void*)released_keys,0,512*sizeof(unsigned int));
6861  is_keyPADMUL = is_keyPADDIV = false;
6862  is_resized = is_moved = is_event = false;
6863  fps_timer = fps_frames = timer = wheel = 0;
6864  mouse_x = mouse_y = -1;
6865  fps_fps = 0;
6866  return *this;
6867  }
6868 
6870  CImgDisplay& wait(const unsigned int milliseconds) {
6871  cimg::_sleep(milliseconds,timer);
6872  return *this;
6873  }
6874 
6877  if (!is_empty()) wait(*this);
6878  return *this;
6879  }
6880 
6882  static void wait(CImgDisplay& disp1) {
6883  disp1.is_event = 0;
6884  while (!disp1.is_event) wait_all();
6885  }
6886 
6888  static void wait(CImgDisplay& disp1, CImgDisplay& disp2) {
6889  disp1.is_event = disp2.is_event = 0;
6890  while (!disp1.is_event && !disp2.is_event) wait_all();
6891  }
6892 
6894  static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) {
6895  disp1.is_event = disp2.is_event = disp3.is_event = 0;
6896  while (!disp1.is_event && !disp2.is_event && !disp3.is_event) wait_all();
6897  }
6898 
6900  static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) {
6901  disp1.is_event = disp2.is_event = disp3.is_event = disp4.is_event = 0;
6902  while (!disp1.is_event && !disp2.is_event && !disp3.is_event && !disp4.is_event) wait_all();
6903  }
6904 
6905 #if cimg_display==0
6906 
6908  static void wait_all() {}
6909 
6910 #endif
6911 
6912  // Implementation for X11-based display
6913  //--------------------------------------
6914 #if cimg_display==1
6915  Atom wm_delete_window, wm_delete_protocol;
6916  Window window, background_window;
6917  Colormap colormap;
6918  XImage *image;
6919  void *data;
6920 #ifdef cimg_use_xshm
6921  XShmSegmentInfo *shminfo;
6922 #endif
6923 
6924  static int screen_dimx() {
6925  int res = 0;
6926  if (!cimg::X11attr().display) {
6927  Display *disp = XOpenDisplay((std::getenv("DISPLAY")?std::getenv("DISPLAY"):":0.0"));
6928  if (!disp)
6929  throw CImgDisplayException("CImgDisplay::screen_dimx() : Cannot open X11 display.");
6930  res = DisplayWidth(disp,DefaultScreen(disp));
6931  XCloseDisplay(disp);
6932  } else {
6933 #ifdef cimg_use_xrandr
6934  if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
6935  res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width;
6936  else
6937 #endif
6938  res = DisplayWidth(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
6939  }
6940  return res;
6941  }
6942 
6943  static int screen_dimy() {
6944  int res = 0;
6945  if (!cimg::X11attr().display) {
6946  Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0"));
6947  if (!disp)
6948  throw CImgDisplayException("CImgDisplay::screen_dimy() : Cannot open X11 display.");
6949  res = DisplayHeight(disp,DefaultScreen(disp));
6950  XCloseDisplay(disp);
6951  } else {
6952 #ifdef cimg_use_xrandr
6953  if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
6954  res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height;
6955  else
6956 #endif
6957  res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
6958  }
6959  return res;
6960  }
6961 
6962  static void wait_all() {
6963  if (cimg::X11attr().display) {
6964  XLockDisplay(cimg::X11attr().display);
6965  bool flag = true;
6966  XEvent event;
6967  while (flag) {
6968  XNextEvent(cimg::X11attr().display, &event);
6969  for (unsigned int i = 0; i<cimg::X11attr().nb_wins; ++i)
6970  if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window) {
6971  cimg::X11attr().wins[i]->_handle_events(&event);
6972  if (cimg::X11attr().wins[i]->is_event) flag = false;
6973  }
6974  }
6975  XUnlockDisplay(cimg::X11attr().display);
6976  }
6977  }
6978 
6979  void _handle_events(const XEvent *const pevent) {
6980  XEvent event = *pevent;
6981  switch (event.type) {
6982  case ClientMessage : {
6983  if ((int)event.xclient.message_type==(int)wm_delete_protocol &&
6984  (int)event.xclient.data.l[0]==(int)wm_delete_window) {
6985  XUnmapWindow(cimg::X11attr().display,window);
6986  mouse_x = mouse_y = -1;
6987  if (button) { std::memmove((void*)(buttons+1),(void*)buttons,512-1); button = 0; }
6988  if (key) { std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
6989  if (released_key) { std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
6990  is_closed = is_event = true;
6991  }
6992  } break;
6993  case ConfigureNotify : {
6994  while (XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event)) {}
6995  const unsigned int
6996  nw = event.xconfigure.width,
6997  nh = event.xconfigure.height;
6998  const int
6999  nx = event.xconfigure.x,
7000  ny = event.xconfigure.y;
7001  if (nw && nh && (nw!=window_width || nh!=window_height)) {
7002  window_width = nw;
7003  window_height = nh;
7004  mouse_x = mouse_y = -1;
7005  XResizeWindow(cimg::X11attr().display,window,window_width,window_height);
7006  is_resized = is_event = true;
7007  }
7008  if (nx!=window_x || ny!=window_y) {
7009  window_x = nx;
7010  window_y = ny;
7011  is_moved = is_event = true;
7012  }
7013  } break;
7014  case Expose : {
7015  while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event)) {}
7016  _paint(false);
7017  if (is_fullscreen) {
7018  XWindowAttributes attr;
7019  XGetWindowAttributes(cimg::X11attr().display, window, &attr);
7020  while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
7021  XSetInputFocus(cimg::X11attr().display, window, RevertToParent, CurrentTime);
7022  }
7023  } break;
7024  case ButtonPress : {
7025  do {
7026  mouse_x = event.xmotion.x;
7027  mouse_y = event.xmotion.y;
7028  if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7029  switch (event.xbutton.button) {
7030  case 1 : std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=1; is_event = true; break;
7031  case 2 : std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=4; is_event = true; break;
7032  case 3 : std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=2; is_event = true; break;
7033  }
7034  } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event));
7035  } break;
7036  case ButtonRelease : {
7037  do {
7038  mouse_x = event.xmotion.x;
7039  mouse_y = event.xmotion.y;
7040  if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7041  switch (event.xbutton.button) {
7042  case 1 : std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~1U; is_event = true; break;
7043  case 2 : std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~4U; is_event = true; break;
7044  case 3 : std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~2U; is_event = true; break;
7045  case 4 : ++wheel; is_event = true; break;
7046  case 5 : --wheel; is_event = true; break;
7047  }
7048  } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event));
7049  } break;
7050  case KeyPress : {
7051  char tmp;
7052  KeySym ksym;
7053  XLookupString(&event.xkey,&tmp,1,&ksym,0);
7054  _update_iskey((unsigned int)ksym,true);
7055  if (key) std::memmove((void*)(keys+1),(void*)keys,512-1);
7056  key = (unsigned int)ksym;
7057  if (released_key) { std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
7058  is_event = true;
7059  } break;
7060  case KeyRelease : {
7061  char tmp;
7062  KeySym ksym;
7063  XLookupString(&event.xkey,&tmp,1,&ksym,0);
7064  _update_iskey((unsigned int)ksym,false);
7065  if (key) { std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
7066  if (released_key) std::memmove((void*)(released_keys+1),(void*)released_keys,512-1);
7067  released_key = (unsigned int)ksym;
7068  is_event = true;
7069  } break;
7070  case EnterNotify: {
7071  while (XCheckWindowEvent(cimg::X11attr().display,window,EnterWindowMask,&event)) {}
7072  mouse_x = event.xmotion.x;
7073  mouse_y = event.xmotion.y;
7074  if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7075  } break;
7076  case LeaveNotify : {
7077  while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event)) {}
7078  mouse_x = mouse_y =-1;
7079  is_event = true;
7080  } break;
7081  case MotionNotify : {
7082  while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event)) {}
7083  mouse_x = event.xmotion.x;
7084  mouse_y = event.xmotion.y;
7085  if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7086  is_event = true;
7087  } break;
7088  }
7089  }
7090 
7091  static void* _events_thread(void *arg) {
7092  arg = 0;
7093  XEvent event;
7094  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
7095  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
7096  for (;;) {
7097  XLockDisplay(cimg::X11attr().display);
7098  bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event);
7099  if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display,
7100  ExposureMask|StructureNotifyMask|ButtonPressMask|
7101  KeyPressMask|PointerMotionMask|EnterWindowMask|LeaveWindowMask|
7102  ButtonReleaseMask|KeyReleaseMask,&event);
7103  if (event_flag) {
7104  for (unsigned int i = 0; i<cimg::X11attr().nb_wins; ++i)
7105  if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window)
7106  cimg::X11attr().wins[i]->_handle_events(&event);
7107  }
7108  XUnlockDisplay(cimg::X11attr().display);
7109  pthread_testcancel();
7110  cimg::sleep(7);
7111  }
7112  return 0;
7113  }
7114 
7115  void _set_colormap(Colormap& colormap, const unsigned int dim) {
7116  XColor palette[256];
7117  switch (dim) {
7118  case 1 : { // palette for greyscale images
7119  for (unsigned int index = 0; index<256; ++index) {
7120  palette[index].pixel = index;
7121  palette[index].red = palette[index].green = palette[index].blue = (unsigned short)(index<<8);
7122  palette[index].flags = DoRed | DoGreen | DoBlue;
7123  }
7124  } break;
7125  case 2 : { // palette for RG images
7126  for (unsigned int index = 0, r = 8; r<256; r+=16)
7127  for (unsigned int g = 8; g<256; g+=16) {
7128  palette[index].pixel = index;
7129  palette[index].red = palette[index].blue = (unsigned short)(r<<8);
7130  palette[index].green = (unsigned short)(g<<8);
7131  palette[index++].flags = DoRed | DoGreen | DoBlue;
7132  }
7133  } break;
7134  default : { // palette for RGB images
7135  for (unsigned int index = 0, r = 16; r<256; r+=32)
7136  for (unsigned int g = 16; g<256; g+=32)
7137  for (unsigned int b = 32; b<256; b+=64) {
7138  palette[index].pixel = index;
7139  palette[index].red = (unsigned short)(r<<8);
7140  palette[index].green = (unsigned short)(g<<8);
7141  palette[index].blue = (unsigned short)(b<<8);
7142  palette[index++].flags = DoRed | DoGreen | DoBlue;
7143  }
7144  }
7145  }
7146  XStoreColors(cimg::X11attr().display,colormap,palette,256);
7147  }
7148 
7149  void _map_window() {
7150  XWindowAttributes attr;
7151  XEvent event;
7152  bool exposed = false, mapped = false;
7153  XMapRaised(cimg::X11attr().display,window);
7154  XSync(cimg::X11attr().display,False);
7155  do {
7156  XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask | ExposureMask,&event);
7157  switch (event.type) {
7158  case MapNotify : mapped = true; break;
7159  case Expose : exposed = true; break;
7160  default : XSync(cimg::X11attr().display, False); cimg::sleep(10);
7161  }
7162  } while (!(exposed && mapped));
7163  do {
7164  XGetWindowAttributes(cimg::X11attr().display, window, &attr);
7165  if (attr.map_state!=IsViewable) { XSync(cimg::X11attr().display,False); cimg::sleep(10); }
7166  } while (attr.map_state != IsViewable);
7167  window_x = attr.x;
7168  window_y = attr.y;
7169  }
7170 
7171  void _paint(const bool wait_expose=true) {
7172  if (!is_closed) {
7173  if (wait_expose) {
7174  static XEvent event;
7175  event.xexpose.type = Expose;
7176  event.xexpose.serial = 0;
7177  event.xexpose.send_event = True;
7178  event.xexpose.display = cimg::X11attr().display;
7179  event.xexpose.window = window;
7180  event.xexpose.x = 0;
7181  event.xexpose.y = 0;
7182  event.xexpose.width = dimx();
7183  event.xexpose.height = dimy();
7184  event.xexpose.count = 0;
7185  XSendEvent(cimg::X11attr().display, window, False, 0, &event);
7186  } else {
7187 #ifdef cimg_use_xshm
7188  if (shminfo) XShmPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height,False);
7189  else
7190 #endif
7191  XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
7192  XSync(cimg::X11attr().display, False);
7193  }
7194  }
7195  }
7196 
7197  template<typename T>
7198  void _resize(T foo, const unsigned int ndimx, const unsigned int ndimy, const bool redraw) {
7199  foo = 0;
7200 #ifdef cimg_use_xshm
7201  if (shminfo) {
7202  XShmSegmentInfo *nshminfo = new XShmSegmentInfo;
7203  XImage *nimage = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7204  cimg::X11attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy);
7205  if (!nimage) {
7206  delete nshminfo;
7207  return;
7208  } else {
7209  nshminfo->shmid = shmget(IPC_PRIVATE, ndimx*ndimy*sizeof(T), IPC_CREAT | 0777);
7210  if (nshminfo->shmid==-1) {
7211  XDestroyImage(nimage);
7212  delete nshminfo;
7213  return;
7214  } else {
7215  nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0);
7216  if (nshminfo->shmaddr==(char*)-1) {
7217  shmctl(nshminfo->shmid,IPC_RMID,0);
7218  XDestroyImage(nimage);
7219  delete nshminfo;
7220  return;
7221  } else {
7222  nshminfo->readOnly = False;
7223  cimg::X11attr().shm_enabled = true;
7224  XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
7225  XShmAttach(cimg::X11attr().display, nshminfo);
7226  XSync(cimg::X11attr().display, False);
7227  XSetErrorHandler(oldXErrorHandler);
7228  if (!cimg::X11attr().shm_enabled) {
7229  shmdt(nshminfo->shmaddr);
7230  shmctl(nshminfo->shmid,IPC_RMID,0);
7231  XDestroyImage(nimage);
7232  delete nshminfo;
7233  return;
7234  } else {
7235  T *const ndata = (T*)nimage->data;
7236  if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
7237  else std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
7238  XShmDetach(cimg::X11attr().display, shminfo);
7239  XDestroyImage(image);
7240  shmdt(shminfo->shmaddr);
7241  shmctl(shminfo->shmid,IPC_RMID,0);
7242  delete shminfo;
7243  shminfo = nshminfo;
7244  image = nimage;
7245  data = (void*)ndata;
7246  }
7247  }
7248  }
7249  }
7250  } else
7251 #endif
7252  {
7253  T *ndata = (T*)std::malloc(ndimx*ndimy*sizeof(T));
7254  if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
7255  else std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
7256  data = (void*)ndata;
7257  XDestroyImage(image);
7258  image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7259  cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,ndimx,ndimy,8,0);
7260  }
7261  }
7262 
7263  void _init_fullscreen() {
7264  background_window = 0;
7265  if (is_fullscreen && !is_closed) {
7266 #ifdef cimg_use_xrandr
7267  int foo;
7268  if (XRRQueryExtension(cimg::X11attr().display,&foo,&foo)) {
7269  XRRRotations(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display), &cimg::X11attr().curr_rotation);
7270  if (!cimg::X11attr().resolutions) {
7271  cimg::X11attr().resolutions = XRRSizes(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display),&foo);
7272  cimg::X11attr().nb_resolutions = (unsigned int)foo;
7273  }
7274  if (cimg::X11attr().resolutions) {
7275  cimg::X11attr().curr_resolution = 0;
7276  for (unsigned int i = 0; i<cimg::X11attr().nb_resolutions; ++i) {
7277  const unsigned int
7278  nw = (unsigned int)(cimg::X11attr().resolutions[i].width),
7279  nh = (unsigned int)(cimg::X11attr().resolutions[i].height);
7280  if (nw>=width && nh>=height &&
7281  nw<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width) &&
7282  nh<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height))
7283  cimg::X11attr().curr_resolution = i;
7284  }
7285  if (cimg::X11attr().curr_resolution>0) {
7286  XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
7287  XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
7288  cimg::X11attr().curr_resolution, cimg::X11attr().curr_rotation, CurrentTime);
7289  XRRFreeScreenConfigInfo(config);
7290  XSync(cimg::X11attr().display, False);
7291  }
7292  }
7293  }
7294  if (!cimg::X11attr().resolutions)
7295  cimg::warn("CImgDisplay::_create_window() : Xrandr extension is not supported by the X server.");
7296 #endif
7297  const unsigned int sx = screen_dimx(), sy = screen_dimy();
7298  XSetWindowAttributes winattr;
7299  winattr.override_redirect = True;
7300  if (sx!=width || sy!=height) {
7301  background_window = XCreateWindow(cimg::X11attr().display,
7302  RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),0,0,
7303  sx,sy,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
7304  const unsigned int bufsize = sx*sy*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
7305  void *background_data = std::malloc(bufsize);
7306  std::memset(background_data,0,bufsize);
7307  XImage *background_image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7308  cimg::X11attr().nb_bits,ZPixmap,0,(char*)background_data,sx,sy,8,0);
7309  XEvent event;
7310  XSelectInput(cimg::X11attr().display,background_window,StructureNotifyMask);
7311  XMapRaised(cimg::X11attr().display,background_window);
7312  do XWindowEvent(cimg::X11attr().display,background_window,StructureNotifyMask,&event);
7313  while (event.type!=MapNotify);
7314 #ifdef cimg_use_xshm
7315  if (shminfo) XShmPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy,False);
7316  else
7317 #endif
7318  XPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy);
7319  XWindowAttributes attr;
7320  XGetWindowAttributes(cimg::X11attr().display, background_window, &attr);
7321  while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
7322  XDestroyImage(background_image);
7323  }
7324  }
7325  }
7326 
7327  void _desinit_fullscreen() {
7328  if (is_fullscreen) {
7329  XUngrabKeyboard(cimg::X11attr().display,CurrentTime);
7330 #ifdef cimg_use_xrandr
7331  if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution) {
7332  XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
7333  XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
7334  0, cimg::X11attr().curr_rotation, CurrentTime);
7335  XRRFreeScreenConfigInfo(config);
7336  XSync(cimg::X11attr().display, False);
7337  cimg::X11attr().curr_resolution = 0;
7338  }
7339 #endif
7340  if (background_window) XDestroyWindow(cimg::X11attr().display,background_window);
7341  background_window = 0;
7342  is_fullscreen = false;
7343  }
7344  }
7345 
7346  static int _assign_xshm(Display *dpy, XErrorEvent *error) {
7347  dpy = 0; error = 0;
7348  cimg::X11attr().shm_enabled = false;
7349  return 0;
7350  }
7351 
7352  void _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0,
7353  const unsigned int normalization_type=3,
7354  const bool fullscreen_flag=false, const bool closed_flag=false) {
7355 
7356  // Allocate space for window title
7357  const char *const nptitle = ptitle?ptitle:"";
7358  const unsigned int s = std::strlen(nptitle) + 1;
7359  char *tmp_title = s?new char[s]:0;
7360  if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char));
7361 
7362  // Destroy previous display window if existing
7363  if (!is_empty()) assign();
7364 
7365  // Open X11 display if necessary.
7366  if (!cimg::X11attr().display) {
7367  static bool xinit_threads = false;
7368  if (!xinit_threads) { XInitThreads(); xinit_threads = true; }
7369  cimg::X11attr().nb_wins = 0;
7370  cimg::X11attr().display = XOpenDisplay((std::getenv("DISPLAY")?std::getenv("DISPLAY"):":0.0"));
7371  if (!cimg::X11attr().display)
7372  throw CImgDisplayException("CImgDisplay::_create_window() : Cannot open X11 display");
7373  cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display));
7374  if (cimg::X11attr().nb_bits!=8 && cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24 && cimg::X11attr().nb_bits!=32)
7375  throw CImgDisplayException("CImgDisplay::_create_window() : %u bits mode is not supported "
7376  "(only 8, 16, 24 and 32 bits modes are supported)",cimg::X11attr().nb_bits);
7377  cimg::X11attr().gc = new GC;
7378  *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
7379  Visual *visual = DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
7380  XVisualInfo vtemplate;
7381  vtemplate.visualid = XVisualIDFromVisual(visual);
7382  int nb_visuals;
7383  XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals);
7384  if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11attr().blue_first = true;
7385  cimg::X11attr().byte_order = ImageByteOrder(cimg::X11attr().display);
7386  XFree(vinfo);
7387  XLockDisplay(cimg::X11attr().display);
7388  cimg::X11attr().event_thread = new pthread_t;
7389  pthread_create(cimg::X11attr().event_thread,0,_events_thread,0);
7390  } else XLockDisplay(cimg::X11attr().display);
7391 
7392  // Set display variables
7393  width = cimg::min(dimw,(unsigned int)screen_dimx());
7394  height = cimg::min(dimh,(unsigned int)screen_dimy());
7395  normalization = normalization_type<4?normalization_type:3;
7396  is_fullscreen = fullscreen_flag;
7397  window_x = window_y = 0;
7398  is_closed = closed_flag;
7399  title = tmp_title;
7400  flush();
7401 
7402  // Create X11 window and palette (if 8bits display)
7403  if (is_fullscreen) {
7404  if (!is_closed) _init_fullscreen();
7405  const unsigned int sx = screen_dimx(), sy = screen_dimy();
7406  XSetWindowAttributes winattr;
7407  winattr.override_redirect = True;
7408  window = XCreateWindow(cimg::X11attr().display,
7409  RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7410  (sx-width)/2,(sy-height)/2,
7411  width,height,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
7412  } else
7413  window = XCreateSimpleWindow(cimg::X11attr().display,
7414  RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7415  0,0,width,height,2,0,0x0L);
7416  XStoreName(cimg::X11attr().display,window,title?title:" ");
7417  if (cimg::X11attr().nb_bits==8) {
7418  colormap = XCreateColormap(cimg::X11attr().display,window,DefaultVisual(cimg::X11attr().display,
7419  DefaultScreen(cimg::X11attr().display)),AllocAll);
7420  _set_colormap(colormap,3);
7421  XSetWindowColormap(cimg::X11attr().display,window,colormap);
7422  }
7423  window_width = width;
7425 
7426  // Create XImage
7427  const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
7428 #ifdef cimg_use_xshm
7429  shminfo = 0;
7430  if (XShmQueryExtension(cimg::X11attr().display)) {
7431  shminfo = new XShmSegmentInfo;
7432  image = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7433  cimg::X11attr().nb_bits,ZPixmap,0,shminfo,width,height);
7434  if (!image) {
7435  delete shminfo;
7436  shminfo = 0;
7437  } else {
7438  shminfo->shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777);
7439  if (shminfo->shmid==-1) {
7440  XDestroyImage(image);
7441  delete shminfo;
7442  shminfo = 0;
7443  } else {
7444  shminfo->shmaddr = image->data = (char*)(data = shmat(shminfo->shmid,0,0));
7445  if (shminfo->shmaddr==(char*)-1) {
7446  shmctl(shminfo->shmid,IPC_RMID,0);
7447  XDestroyImage(image);
7448  delete shminfo;
7449  shminfo = 0;
7450  } else {
7451  shminfo->readOnly = False;
7452  cimg::X11attr().shm_enabled = true;
7453  XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
7454  XShmAttach(cimg::X11attr().display, shminfo);
7455  XSync(cimg::X11attr().display, False);
7456  XSetErrorHandler(oldXErrorHandler);
7457  if (!cimg::X11attr().shm_enabled) {
7458  shmdt(shminfo->shmaddr);
7459  shmctl(shminfo->shmid,IPC_RMID,0);
7460  XDestroyImage(image);
7461  delete shminfo;
7462  shminfo = 0;
7463  }
7464  }
7465  }
7466  }
7467  }
7468  if (!shminfo)
7469 #endif
7470  {
7471  data = std::malloc(bufsize);
7472  image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7473  cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0);
7474  }
7475 
7476  wm_delete_window = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False);
7477  wm_delete_protocol = XInternAtom(cimg::X11attr().display, "WM_PROTOCOLS", False);
7478  XSetWMProtocols(cimg::X11attr().display, window, &wm_delete_window, 1);
7479  XSelectInput(cimg::X11attr().display,window,
7480  ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask |
7481  EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask);
7482  if (is_fullscreen) XGrabKeyboard(cimg::X11attr().display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
7483  cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this;
7484  if (!is_closed) _map_window(); else { window_x = window_y = cimg::type<int>::min(); }
7485  XUnlockDisplay(cimg::X11attr().display);
7486  }
7487 
7488  CImgDisplay& assign() {
7489  if (is_empty()) return *this;
7490  XLockDisplay(cimg::X11attr().display);
7491 
7492  // Remove display window from event thread list.
7493  unsigned int i;
7494  for (i = 0; i<cimg::X11attr().nb_wins && cimg::X11attr().wins[i]!=this; ++i) {}
7495  for (; i<cimg::X11attr().nb_wins-1; ++i) cimg::X11attr().wins[i] = cimg::X11attr().wins[i+1];
7496  --cimg::X11attr().nb_wins;
7497 
7498  // Destroy window, image, colormap and title.
7499  if (is_fullscreen && !is_closed) _desinit_fullscreen();
7500  XDestroyWindow(cimg::X11attr().display,window);
7501  window = 0;
7502 #ifdef cimg_use_xshm
7503  if (shminfo) {
7504  XShmDetach(cimg::X11attr().display, shminfo);
7505  XDestroyImage(image);
7506  shmdt(shminfo->shmaddr);
7507  shmctl(shminfo->shmid,IPC_RMID,0);
7508  delete shminfo;
7509  shminfo = 0;
7510  } else
7511 #endif
7512  XDestroyImage(image);
7513  data = 0; image = 0;
7514  if (cimg::X11attr().nb_bits==8) XFreeColormap(cimg::X11attr().display,colormap);
7515  colormap = 0;
7516  XSync(cimg::X11attr().display, False);
7517 
7518  // Reset display variables
7519  if (title) delete[] title;
7521  window_x = window_y = 0;
7522  is_fullscreen = false;
7523  is_closed = true;
7524  min = max = 0;
7525  title = 0;
7526  flush();
7527 
7528  // End event thread and close display if necessary
7529  XUnlockDisplay(cimg::X11attr().display);
7530 
7531  /* The code below was used to close the X11 display when not used anymore,
7532  unfortunately, since the latest Xorg versions, it randomely hangs, so
7533  I prefer to remove it. A fix would be needed anyway.
7534 
7535  if (!cimg::X11attr().nb_wins) {
7536  // Kill event thread
7537  pthread_cancel(*cimg::X11attr().event_thread);
7538  XUnlockDisplay(cimg::X11attr().display);
7539  pthread_join(*cimg::X11attr().event_thread,0);
7540  delete cimg::X11attr().event_thread;
7541  cimg::X11attr().event_thread = 0;
7542  XCloseDisplay(cimg::X11attr().display);
7543  cimg::X11attr().display = 0;
7544  delete cimg::X11attr().gc;
7545  cimg::X11attr().gc = 0;
7546  } else XUnlockDisplay(cimg::X11attr().display);
7547  */
7548  return *this;
7549  }
7550 
7551  CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
7552  const unsigned int normalization_type=3,
7553  const bool fullscreen_flag=false, const bool closed_flag=false) {
7554  if (!dimw || !dimh) return assign();
7555  _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
7556  min = max = 0;
7557  std::memset(data,0,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
7558  (cimg::X11attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*width*height);
7559  return paint();
7560  }
7561 
7562  template<typename T>
7563  CImgDisplay& assign(const CImg<T>& img, const char *title=0,
7564  const unsigned int normalization_type=3,
7565  const bool fullscreen_flag=false, const bool closed_flag=false) {
7566  if (!img) return assign();
7567  CImg<T> tmp;
7568  const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
7569  _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
7570  if (normalization==2) min = (float)nimg.minmax(max);
7571  return render(nimg).paint();
7572  }
7573 
7574  template<typename T>
7575  CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
7576  const unsigned int normalization_type=3,
7577  const bool fullscreen_flag=false, const bool closed_flag=false) {
7578  if (!list) return assign();
7579  CImg<T> tmp;
7580  const CImg<T> img = list>'x', &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
7581  _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
7582  if (normalization==2) min = (float)nimg.minmax(max);
7583  return render(nimg).paint();
7584  }
7585 
7586  CImgDisplay& assign(const CImgDisplay& disp) {
7587  if (!disp) return assign();
7588  _assign(disp.width,disp.height,disp.title,disp.normalization,disp.is_fullscreen,disp.is_closed);
7589  std::memcpy(data,disp.data,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
7590  cimg::X11attr().nb_bits==16?sizeof(unsigned short):
7591  sizeof(unsigned int))*width*height);
7592  return paint();
7593  }
7594 
7595  CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
7596  if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
7597  if (is_empty()) return assign(nwidth,nheight);
7598  const unsigned int
7599  tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
7600  tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
7601  dimx = tmpdimx?tmpdimx:1,
7602  dimy = tmpdimy?tmpdimy:1;
7603  XLockDisplay(cimg::X11attr().display);
7604  if (window_width!=dimx || window_height!=dimy) XResizeWindow(cimg::X11attr().display,window,dimx,dimy);
7605  if (width!=dimx || height!=dimy) switch (cimg::X11attr().nb_bits) {
7606  case 8 : { unsigned char foo = 0; _resize(foo,dimx,dimy,redraw); } break;
7607  case 16 : { unsigned short foo = 0; _resize(foo,dimx,dimy,redraw); } break;
7608  default : { unsigned int foo = 0; _resize(foo,dimx,dimy,redraw); }
7609  }
7611  is_resized = false;
7612  XUnlockDisplay(cimg::X11attr().display);
7614  if (redraw) return paint();
7615  return *this;
7616  }
7617 
7618  CImgDisplay& toggle_fullscreen(const bool redraw=true) {
7619  if (is_empty()) return *this;
7620  if (redraw) {
7621  const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
7622  void *odata = std::malloc(bufsize);
7623  std::memcpy(odata,data,bufsize);
7625  std::memcpy(data,odata,bufsize);
7626  std::free(odata);
7627  return paint(false);
7628  }
7630  }
7631 
7632  CImgDisplay& show() {
7633  if (!is_empty() && is_closed) {
7634  XLockDisplay(cimg::X11attr().display);
7635  if (is_fullscreen) _init_fullscreen();
7636  _map_window();
7637  is_closed = false;
7638  XUnlockDisplay(cimg::X11attr().display);
7639  return paint();
7640  }
7641  return *this;
7642  }
7643 
7644  CImgDisplay& close() {
7645  if (!is_empty() && !is_closed) {
7646  XLockDisplay(cimg::X11attr().display);
7647  if (is_fullscreen) _desinit_fullscreen();
7648  XUnmapWindow(cimg::X11attr().display,window);
7649  window_x = window_y = -1;
7650  is_closed = true;
7651  XUnlockDisplay(cimg::X11attr().display);
7652  }
7653  return *this;
7654  }
7655 
7656  CImgDisplay& move(const int posx, const int posy) {
7657  if (is_empty()) return *this;
7658  show();
7659  XLockDisplay(cimg::X11attr().display);
7660  XMoveWindow(cimg::X11attr().display,window,posx,posy);
7661  window_x = posx; window_y = posy;
7662  is_moved = false;
7663  XUnlockDisplay(cimg::X11attr().display);
7664  return paint();
7665  }
7666 
7667  CImgDisplay& show_mouse() {
7668  if (is_empty()) return *this;
7669  XLockDisplay(cimg::X11attr().display);
7670  XUndefineCursor(cimg::X11attr().display,window);
7671  XUnlockDisplay(cimg::X11attr().display);
7672  return *this;
7673  }
7674 
7675  CImgDisplay& hide_mouse() {
7676  if (is_empty()) return *this;
7677  XLockDisplay(cimg::X11attr().display);
7678  const char pix_data[8] = { 0 };
7679  XColor col;
7680  col.red = col.green = col.blue = 0;
7681  Pixmap pix = XCreateBitmapFromData(cimg::X11attr().display,window,pix_data,8,8);
7682  Cursor cur = XCreatePixmapCursor(cimg::X11attr().display,pix,pix,&col,&col,0,0);
7683  XFreePixmap(cimg::X11attr().display,pix);
7684  XDefineCursor(cimg::X11attr().display,window,cur);
7685  XUnlockDisplay(cimg::X11attr().display);
7686  return *this;
7687  }
7688 
7689  CImgDisplay& set_mouse(const int posx, const int posy) {
7690  if (is_empty() || is_closed) return *this;
7691  XLockDisplay(cimg::X11attr().display);
7692  // XWarpPointer(cimg::X11attr().display,None,window,0,0,0,0,posx,posy);
7693  XWarpPointer(cimg::X11attr().display,0L,window,0,0,0,0,posx,posy);
7694  mouse_x = posx; mouse_y = posy;
7695  is_moved = false;
7696  XSync(cimg::X11attr().display, False);
7697  XUnlockDisplay(cimg::X11attr().display);
7698  return *this;
7699  }
7700 
7701  CImgDisplay& set_title(const char *format, ...) {
7702  if (is_empty()) return *this;
7703  char tmp[1024] = { 0 };
7704  va_list ap;
7705  va_start(ap, format);
7706  std::vsprintf(tmp,format,ap);
7707  va_end(ap);
7708  if (title) delete[] title;
7709  const unsigned int s = std::strlen(tmp) + 1;
7710  title = new char[s];
7711  std::memcpy(title,tmp,s*sizeof(char));
7712  XLockDisplay(cimg::X11attr().display);
7713  XStoreName(cimg::X11attr().display,window,tmp);
7714  XUnlockDisplay(cimg::X11attr().display);
7715  return *this;
7716  }
7717 
7718  template<typename T>
7719  CImgDisplay& display(const CImg<T>& img) {
7720  if (img.is_empty())
7721  throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
7722  if (is_empty()) assign(img.width,img.height);
7723  return render(img).paint(false);
7724  }
7725 
7726  CImgDisplay& paint(const bool wait_expose=true) {
7727  if (is_empty()) return *this;
7728  XLockDisplay(cimg::X11attr().display);
7729  _paint(wait_expose);
7730  XUnlockDisplay(cimg::X11attr().display);
7731  return *this;
7732  }
7733 
7734  template<typename T>
7735  CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
7736  if (is_empty()) return *this;
7737  if (!img)
7738  throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
7739  img.width,img.height,img.depth,img.dim,img.data);
7740  if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
7741  if (cimg::X11attr().nb_bits==8 && (img.width!=width || img.height!=height)) return render(img.get_resize(width,height,1,-100,1));
7742  if (cimg::X11attr().nb_bits==8 && !flag8 && img.dim==3) {
7743  typedef typename cimg::last<T,unsigned char>::type uchar;
7744  static const CImg<uchar> default_palette = CImg<uchar>::default_LUT256();
7745  return render(img.get_index(default_palette,true,false));
7746  }
7747 
7748  const T
7749  *data1 = img.data,
7750  *data2 = (img.dim>1)?img.ptr(0,0,0,1):data1,
7751  *data3 = (img.dim>2)?img.ptr(0,0,0,2):data1;
7752 
7753  if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
7754  XLockDisplay(cimg::X11attr().display);
7755 
7756  if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
7757  min = max = 0;
7758  switch (cimg::X11attr().nb_bits) {
7759  case 8 : { // 256 color palette, no normalization
7760  _set_colormap(colormap,img.dim);
7761  unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
7762  unsigned char *ptrd = (unsigned char*)ndata;
7763  switch (img.dim) {
7764  case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) (*ptrd++) = (unsigned char)*(data1++);
7765  break;
7766  case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7767  const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++);
7768  (*ptrd++) = (R&0xf0) | (G>>4);
7769  } break;
7770  default : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7771  const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
7772  (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
7773  }
7774  }
7775  if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
7776  } break;
7777  case 16 : { // 16 bits colors, no normalization
7778  unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
7779  unsigned char *ptrd = (unsigned char*)ndata;
7780  const unsigned int M = 248;
7781  switch (img.dim) {
7782  case 1 :
7783  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7784  const unsigned char val = (unsigned char)*(data1++), G = val>>2;
7785  *(ptrd++) = (val&M) | (G>>3);
7786  *(ptrd++) = (G<<5) | (G>>1);
7787  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7788  const unsigned char val = (unsigned char)*(data1++), G = val>>2;
7789  *(ptrd++) = (G<<5) | (G>>1);
7790  *(ptrd++) = (val&M) | (G>>3);
7791  }
7792  break;
7793  case 2 :
7794  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7795  const unsigned char G = (unsigned char)*(data2++)>>2;
7796  *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
7797  *(ptrd++) = (G<<5);
7798  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7799  const unsigned char G = (unsigned char)*(data2++)>>2;
7800  *(ptrd++) = (G<<5);
7801  *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
7802  }
7803  break;
7804  default :
7805  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7806  const unsigned char G = (unsigned char)*(data2++)>>2;
7807  *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
7808  *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
7809  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7810  const unsigned char G = (unsigned char)*(data2++)>>2;
7811  *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
7812  *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
7813  }
7814  }
7815  if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
7816  } break;
7817  default : { // 24 bits colors, no normalization
7818  unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
7819  if (sizeof(int)==4) { // 32 bits int uses optimized version
7820  unsigned int *ptrd = ndata;
7821  switch (img.dim) {
7822  case 1 :
7823  if (cimg::X11attr().byte_order==cimg::endianness())
7824  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7825  const unsigned char val = (unsigned char)*(data1++);
7826  *(ptrd++) = (val<<16) | (val<<8) | val;
7827  }
7828  else
7829  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7830  const unsigned char val = (unsigned char)*(data1++)<<8;
7831  *(ptrd++) = (val<<16) | (val<<8) | val;
7832  }
7833  break;
7834  case 2 :
7835  if (cimg::X11attr().byte_order==cimg::endianness())
7836  for (unsigned int xy = img.width*img.height; xy>0; --xy)
7837  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
7838  else
7839  for (unsigned int xy = img.width*img.height; xy>0; --xy)
7840  *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
7841  break;
7842  default :
7843  if (cimg::X11attr().byte_order==cimg::endianness())
7844  for (unsigned int xy = img.width*img.height; xy>0; --xy)
7845  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
7846  else
7847  for (unsigned int xy = img.width*img.height; xy>0; --xy)
7848  *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
7849  }
7850  } else {
7851  unsigned char *ptrd = (unsigned char*)ndata;
7852  switch (img.dim) {
7853  case 1 :
7854  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7855  *(ptrd++) = 0;
7856  *(ptrd++) = (unsigned char)*(data1++);
7857  *(ptrd++) = 0;
7858  *(ptrd++) = 0;
7859  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7860  *(ptrd++) = 0;
7861  *(ptrd++) = 0;
7862  *(ptrd++) = (unsigned char)*(data1++);
7863  *(ptrd++) = 0;
7864  }
7865  break;
7866  case 2 :
7867  if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
7868  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7869  *(ptrd++) = 0;
7870  *(ptrd++) = (unsigned char)*(data2++);
7871  *(ptrd++) = (unsigned char)*(data1++);
7872  *(ptrd++) = 0;
7873  }
7874  break;
7875  default :
7876  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7877  *(ptrd++) = 0;
7878  *(ptrd++) = (unsigned char)*(data1++);
7879  *(ptrd++) = (unsigned char)*(data2++);
7880  *(ptrd++) = (unsigned char)*(data3++);
7881  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7882  *(ptrd++) = (unsigned char)*(data3++);
7883  *(ptrd++) = (unsigned char)*(data2++);
7884  *(ptrd++) = (unsigned char)*(data1++);
7885  *(ptrd++) = 0;
7886  }
7887  }
7888  }
7889  if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
7890  }
7891  }
7892  } else {
7893  if (normalization==3) {
7894  if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
7895  else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
7896  } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
7897  const float delta = max-min, mm = delta?delta:1.0f;
7898  switch (cimg::X11attr().nb_bits) {
7899  case 8 : { // 256 color palette, with normalization
7900  _set_colormap(colormap,img.dim);
7901  unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
7902  unsigned char *ptrd = (unsigned char*)ndata;
7903  switch (img.dim) {
7904  case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7905  const unsigned char R = (unsigned char)(255*(*(data1++)-min)/mm);
7906  *(ptrd++) = R;
7907  } break;
7908  case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7909  const unsigned char
7910  R = (unsigned char)(255*(*(data1++)-min)/mm),
7911  G = (unsigned char)(255*(*(data2++)-min)/mm);
7912  (*ptrd++) = (R&0xf0) | (G>>4);
7913  } break;
7914  default :
7915  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7916  const unsigned char
7917  R = (unsigned char)(255*(*(data1++)-min)/mm),
7918  G = (unsigned char)(255*(*(data2++)-min)/mm),
7919  B = (unsigned char)(255*(*(data3++)-min)/mm);
7920  *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
7921  }
7922  }
7923  if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
7924  } break;
7925  case 16 : { // 16 bits colors, with normalization
7926  unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
7927  unsigned char *ptrd = (unsigned char*)ndata;
7928  const unsigned int M = 248;
7929  switch (img.dim) {
7930  case 1 :
7931  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7932  const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
7933  *(ptrd++) = (val&M) | (G>>3);
7934  *(ptrd++) = (G<<5) | (val>>3);
7935  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7936  const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
7937  *(ptrd++) = (G<<5) | (val>>3);
7938  *(ptrd++) = (val&M) | (G>>3);
7939  }
7940  break;
7941  case 2 :
7942  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7943  const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
7944  *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
7945  *(ptrd++) = (G<<5);
7946  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7947  const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
7948  *(ptrd++) = (G<<5);
7949  *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
7950  }
7951  break;
7952  default :
7953  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7954  const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
7955  *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
7956  *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
7957  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7958  const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
7959  *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
7960  *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
7961  }
7962  }
7963  if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
7964  } break;
7965  default : { // 24 bits colors, with normalization
7966  unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
7967  if (sizeof(int)==4) { // 32 bits int uses optimized version
7968  unsigned int *ptrd = ndata;
7969  switch (img.dim) {
7970  case 1 :
7971  if (cimg::X11attr().byte_order==cimg::endianness())
7972  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7973  const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
7974  *(ptrd++) = (val<<16) | (val<<8) | val;
7975  }
7976  else
7977  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
7978  const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
7979  *(ptrd++) = (val<<24) | (val<<16) | (val<<8);
7980  }
7981  break;
7982  case 2 :
7983  if (cimg::X11attr().byte_order==cimg::endianness())
7984  for (unsigned int xy = img.width*img.height; xy>0; --xy)
7985  *(ptrd++) =
7986  ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
7987  ((unsigned char)(255*(*(data2++)-min)/mm)<<8);
7988  else
7989  for (unsigned int xy = img.width*img.height; xy>0; --xy)
7990  *(ptrd++) =
7991  ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
7992  ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
7993  break;
7994  default :
7995  if (cimg::X11attr().byte_order==cimg::endianness())
7996  for (unsigned int xy = img.width*img.height; xy>0; --xy)
7997  *(ptrd++) =
7998  ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
7999  ((unsigned char)(255*(*(data2++)-min)/mm)<<8) |
8000  (unsigned char)(255*(*(data3++)-min)/mm);
8001  else
8002  for (unsigned int xy = img.width*img.height; xy>0; --xy)
8003  *(ptrd++) =
8004  ((unsigned char)(255*(*(data3++)-min)/mm)<<24) |
8005  ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
8006  ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
8007  }
8008  } else {
8009  unsigned char *ptrd = (unsigned char*)ndata;
8010  switch (img.dim) {
8011  case 1 :
8012  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8013  const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8014  (*ptrd++) = 0;
8015  (*ptrd++) = val;
8016  (*ptrd++) = val;
8017  (*ptrd++) = val;
8018  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8019  const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8020  (*ptrd++) = val;
8021  (*ptrd++) = val;
8022  (*ptrd++) = val;
8023  (*ptrd++) = 0;
8024  }
8025  break;
8026  case 2 :
8027  if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
8028  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8029  (*ptrd++) = 0;
8030  (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
8031  (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
8032  (*ptrd++) = 0;
8033  }
8034  break;
8035  default :
8036  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8037  (*ptrd++) = 0;
8038  (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
8039  (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
8040  (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
8041  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8042  (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
8043  (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
8044  (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
8045  (*ptrd++) = 0;
8046  }
8047  }
8048  }
8049  if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
8050  }
8051  }
8052  }
8053  XUnlockDisplay(cimg::X11attr().display);
8054  return *this;
8055  }
8056 
8057  template<typename T>
8058  const CImgDisplay& snapshot(CImg<T>& img) const {
8059  if (is_empty()) img.assign();
8060  else {
8061  img.assign(width,height,1,3);
8062  T
8063  *data1 = img.ptr(0,0,0,0),
8064  *data2 = img.ptr(0,0,0,1),
8065  *data3 = img.ptr(0,0,0,2);
8066  if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
8067  switch (cimg::X11attr().nb_bits) {
8068  case 8 : {
8069  unsigned char *ptrs = (unsigned char*)data;
8070  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8071  const unsigned char val = *(ptrs++);
8072  *(data1++) = val&0xe0;
8073  *(data2++) = (val&0x1c)<<3;
8074  *(data3++) = val<<6;
8075  }
8076  } break;
8077  case 16 : {
8078  unsigned char *ptrs = (unsigned char*)data;
8079  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8080  const unsigned char val0 = *(ptrs++), val1 = *(ptrs++);
8081  *(data1++) = val0&0xf8;
8082  *(data2++) = (val0<<5) | ((val1&0xe0)>>5);
8083  *(data3++) = val1<<3;
8084  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8085  const unsigned short val0 = *(ptrs++), val1 = *(ptrs++);
8086  *(data1++) = val1&0xf8;
8087  *(data2++) = (val1<<5) | ((val0&0xe0)>>5);
8088  *(data3++) = val0<<3;
8089  }
8090  } break;
8091  default : {
8092  unsigned char *ptrs = (unsigned char*)data;
8093  if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8094  ++ptrs;
8095  *(data1++) = *(ptrs++);
8096  *(data2++) = *(ptrs++);
8097  *(data3++) = *(ptrs++);
8098  } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8099  *(data3++) = *(ptrs++);
8100  *(data2++) = *(ptrs++);
8101  *(data1++) = *(ptrs++);
8102  ++ptrs;
8103  }
8104  }
8105  }
8106  }
8107  return *this;
8108  }
8109 
8110  // Implementation for Windows-based display
8111  //-------------------------------------------
8112 #elif cimg_display==2
8113  CLIENTCREATESTRUCT ccs;
8114  BITMAPINFO bmi;
8115  unsigned int *data;
8116  DEVMODE curr_mode;
8117  HWND window;
8118  HWND background_window;
8119  HDC hdc;
8120  HANDLE thread;
8121  HANDLE created;
8122  HANDLE mutex;
8123  bool mouse_tracking;
8124  bool visible_cursor;
8125 
8126  static int screen_dimx() {
8127  DEVMODE mode;
8128  mode.dmSize = sizeof(DEVMODE);
8129  mode.dmDriverExtra = 0;
8130  EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
8131  return mode.dmPelsWidth;
8132  }
8133 
8134  static int screen_dimy() {
8135  DEVMODE mode;
8136  mode.dmSize = sizeof(DEVMODE);
8137  mode.dmDriverExtra = 0;
8138  EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
8139  return mode.dmPelsHeight;
8140  }
8141 
8142  static void wait_all() {
8143  WaitForSingleObject(cimg::Win32attr().wait_event,INFINITE);
8144  }
8145 
8146  static LRESULT APIENTRY _handle_events(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
8147 #ifdef _WIN64
8148  CImgDisplay* disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA);
8149 #else
8150  CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
8151 #endif
8152  MSG st_msg;
8153 
8154  switch (msg) {
8155  case WM_CLOSE :
8156  disp->mouse_x = disp->mouse_y = -1;
8157  disp->window_x = disp->window_y = 0;
8158  if (disp->button) {
8159  std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8160  disp->button = 0;
8161  }
8162  if (disp->key) {
8163  std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
8164  disp->key = 0;
8165  }
8166  if (disp->released_key) { std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
8167  disp->is_closed = true;
8168  ReleaseMutex(disp->mutex);
8169  ShowWindow(disp->window,SW_HIDE);
8170  disp->is_event = true;
8171  SetEvent(cimg::Win32attr().wait_event);
8172  return 0;
8173  case WM_SIZE : {
8174  while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
8175  WaitForSingleObject(disp->mutex,INFINITE);
8176  const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);
8177  if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
8178  disp->window_width = nw;
8179  disp->window_height = nh;
8180  disp->mouse_x = disp->mouse_y = -1;
8181  disp->is_resized = disp->is_event = true;
8182  SetEvent(cimg::Win32attr().wait_event);
8183  }
8184  ReleaseMutex(disp->mutex);
8185  } break;
8186  case WM_MOVE : {
8187  while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
8188  WaitForSingleObject(disp->mutex,INFINITE);
8189  const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));
8190  if (nx!=disp->window_x || ny!=disp->window_y) {
8191  disp->window_x = nx;
8192  disp->window_y = ny;
8193  disp->is_moved = disp->is_event = true;
8194  SetEvent(cimg::Win32attr().wait_event);
8195  }
8196  ReleaseMutex(disp->mutex);
8197  } break;
8198  case WM_PAINT :
8199  disp->paint();
8200  break;
8201  case WM_KEYDOWN :
8202  disp->_update_iskey((unsigned int)wParam,true);
8203  if (disp->key) std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
8204  disp->key = (unsigned int)wParam;
8205  if (disp->released_key) { std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
8206  disp->is_event = true;
8207  SetEvent(cimg::Win32attr().wait_event);
8208  break;
8209  case WM_MOUSEMOVE : {
8210  while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {}
8211  disp->mouse_x = LOWORD(lParam);
8212  disp->mouse_y = HIWORD(lParam);
8213 #if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT)
8214  if (!disp->mouse_tracking) {
8215  TRACKMOUSEEVENT tme;
8216  tme.cbSize = sizeof(TRACKMOUSEEVENT);
8217  tme.dwFlags = TME_LEAVE;
8218  tme.hwndTrack = disp->window;
8219  if (TrackMouseEvent(&tme)) disp->mouse_tracking = true;
8220  }
8221 #endif
8222  if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
8223  disp->mouse_x = disp->mouse_y = -1;
8224  disp->is_event = true;
8225  SetEvent(cimg::Win32attr().wait_event);
8226  } break;
8227  case WM_MOUSELEAVE : {
8228  disp->mouse_x = disp->mouse_y = -1;
8229  disp->mouse_tracking = false;
8230  } break;
8231  case WM_LBUTTONDOWN :
8232  std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8233  disp->button|=1U;
8234  disp->is_event = true;
8235  SetEvent(cimg::Win32attr().wait_event);
8236  break;
8237  case WM_RBUTTONDOWN :
8238  std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8239  disp->button|=2U;
8240  disp->is_event = true;
8241  SetEvent(cimg::Win32attr().wait_event);
8242  break;
8243  case WM_MBUTTONDOWN :
8244  std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8245  disp->button|=4U;
8246  disp->is_event = true;
8247  SetEvent(cimg::Win32attr().wait_event);
8248  break;
8249  case 0x020A : // WM_MOUSEWHEEL:
8250  disp->wheel+=(int)((short)HIWORD(wParam))/120;
8251  disp->is_event = true;
8252  SetEvent(cimg::Win32attr().wait_event);
8253  case WM_KEYUP :
8254  disp->_update_iskey((unsigned int)wParam,false);
8255  if (disp->key) { std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
8256  if (disp->released_key) std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
8257  disp->released_key = (unsigned int)wParam;
8258  disp->is_event = true;
8259  SetEvent(cimg::Win32attr().wait_event);
8260  break;
8261  case WM_LBUTTONUP :
8262  std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8263  disp->button&=~1U;
8264  disp->is_event = true;
8265  SetEvent(cimg::Win32attr().wait_event);
8266  break;
8267  case WM_RBUTTONUP :
8268  std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8269  disp->button&=~2U;
8270  disp->is_event = true;
8271  SetEvent(cimg::Win32attr().wait_event);
8272  break;
8273  case WM_MBUTTONUP :
8274  std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8275  disp->button&=~4U;
8276  disp->is_event = true;
8277  SetEvent(cimg::Win32attr().wait_event);
8278  break;
8279  case WM_SETCURSOR :
8280  if (disp->visible_cursor) ShowCursor(TRUE);
8281  else ShowCursor(FALSE);
8282  break;
8283  }
8284  return DefWindowProc(window,msg,wParam,lParam);
8285  }
8286 
8287  static DWORD WINAPI _events_thread(void* arg) {
8288  CImgDisplay *disp = (CImgDisplay*)(((void**)arg)[0]);
8289  const char *title = (const char*)(((void**)arg)[1]);
8290  MSG msg;
8291  delete[] (void**)arg;
8292  disp->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
8293  disp->bmi.bmiHeader.biWidth = disp->width;
8294  disp->bmi.bmiHeader.biHeight = -(int)disp->height;
8295  disp->bmi.bmiHeader.biPlanes = 1;
8296  disp->bmi.bmiHeader.biBitCount = 32;
8297  disp->bmi.bmiHeader.biCompression = BI_RGB;
8298  disp->bmi.bmiHeader.biSizeImage = 0;
8299  disp->bmi.bmiHeader.biXPelsPerMeter = 1;
8300  disp->bmi.bmiHeader.biYPelsPerMeter = 1;
8301  disp->bmi.bmiHeader.biClrUsed = 0;
8302  disp->bmi.bmiHeader.biClrImportant = 0;
8303  disp->data = new unsigned int[disp->width*disp->height];
8304  if (!disp->is_fullscreen) { // Normal window
8305  RECT rect;
8306  rect.left = rect.top = 0; rect.right = disp->width-1; rect.bottom = disp->height-1;
8307  AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8308  const int border1 = (rect.right-rect.left+1-disp->width)/2, border2 = rect.bottom-rect.top+1-disp->height-border1;
8309  disp->window = CreateWindowA("MDICLIENT",title?title:" ",
8310  WS_OVERLAPPEDWINDOW | (disp->is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
8311  disp->width + 2*border1, disp->height + border1 + border2,
8312  0,0,0,&(disp->ccs));
8313  if (!disp->is_closed) {
8314  GetWindowRect(disp->window,&rect);
8315  disp->window_x = rect.left + border1;
8316  disp->window_y = rect.top + border2;
8317  } else disp->window_x = disp->window_y = 0;
8318  } else { // Fullscreen window
8319  const unsigned int sx = screen_dimx(), sy = screen_dimy();
8320  disp->window = CreateWindowA("MDICLIENT",title?title:" ",
8321  WS_POPUP | (disp->is_closed?0:WS_VISIBLE), (sx-disp->width)/2, (sy-disp->height)/2,
8322  disp->width,disp->height,0,0,0,&(disp->ccs));
8323  disp->window_x = disp->window_y = 0;
8324  }
8325  SetForegroundWindow(disp->window);
8326  disp->hdc = GetDC(disp->window);
8327  disp->window_width = disp->width;
8328  disp->window_height = disp->height;
8329  disp->flush();
8330 #ifdef _WIN64
8331  SetWindowLongPtr(disp->window,GWLP_USERDATA,(LONG_PTR)disp);
8332  SetWindowLongPtr(disp->window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
8333 #else
8334  SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
8335  SetWindowLong(disp->window,GWL_WNDPROC,(LONG)_handle_events);
8336 #endif
8337  SetEvent(disp->created);
8338  while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
8339  return 0;
8340  }
8341 
8342  CImgDisplay& _update_window_pos() {
8343  if (!is_closed) {
8344  RECT rect;
8345  rect.left = rect.top = 0; rect.right = width-1; rect.bottom = height-1;
8346  AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8347  const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
8348  GetWindowRect(window,&rect);
8349  window_x = rect.left + border1;
8350  window_y = rect.top + border2;
8351  } else window_x = window_y = -1;
8352  return *this;
8353  }
8354 
8355  void _init_fullscreen() {
8356  background_window = 0;
8357  if (is_fullscreen && !is_closed) {
8358  DEVMODE mode;
8359  unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U;
8360  for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) {
8361  const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight;
8362  if (nw>=width && nh>=height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) {
8363  bestbpp = mode.dmBitsPerPel;
8364  ibest = imode;
8365  bw = nw; bh = nh;
8366  }
8367  }
8368  if (bestbpp) {
8369  curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0;
8370  EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&curr_mode);
8371  EnumDisplaySettings(0,ibest,&mode);
8372  ChangeDisplaySettings(&mode,0);
8373  } else curr_mode.dmSize = 0;
8374 
8375  const unsigned int sx = screen_dimx(), sy = screen_dimy();
8376  if (sx!=width || sy!=height) {
8377  CLIENTCREATESTRUCT background_ccs;
8378  background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);
8379  SetForegroundWindow(background_window);
8380  }
8381  } else curr_mode.dmSize = 0;
8382  }
8383 
8384  void _desinit_fullscreen() {
8385  if (is_fullscreen) {
8386  if (background_window) DestroyWindow(background_window);
8387  background_window = 0;
8388  if (curr_mode.dmSize) ChangeDisplaySettings(&curr_mode,0);
8389  is_fullscreen = false;
8390  }
8391  }
8392 
8393  CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0,
8394  const unsigned int normalization_type=3,
8395  const bool fullscreen_flag=false, const bool closed_flag=false) {
8396 
8397  // Allocate space for window title
8398  const char *const nptitle = ptitle?ptitle:"";
8399  const unsigned int s = std::strlen(nptitle) + 1;
8400  char *tmp_title = s?new char[s]:0;
8401  if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char));
8402 
8403  // Destroy previous window if existing
8404  if (!is_empty()) assign();
8405 
8406  // Set display variables
8407  width = cimg::min(dimw,(unsigned int)screen_dimx());
8408  height = cimg::min(dimh,(unsigned int)screen_dimy());
8409  normalization = normalization_type<4?normalization_type:3;
8410  is_fullscreen = fullscreen_flag;
8411  window_x = window_y = 0;
8412  is_closed = closed_flag;
8413  visible_cursor = true;
8414  mouse_tracking = false;
8415  title = tmp_title;
8416  flush();
8417  if (is_fullscreen) _init_fullscreen();
8418 
8419  // Create event thread
8420  void *arg = (void*)(new void*[2]);
8421  ((void**)arg)[0]=(void*)this;
8422  ((void**)arg)[1]=(void*)title;
8423  unsigned long ThreadID = 0;
8424  mutex = CreateMutex(0,FALSE,0);
8425  created = CreateEvent(0,FALSE,FALSE,0);
8426  thread = CreateThread(0,0,_events_thread,arg,0,&ThreadID);
8427  WaitForSingleObject(created,INFINITE);
8428  return *this;
8429  }
8430 
8431  CImgDisplay& assign() {
8432  if (is_empty()) return *this;
8433  DestroyWindow(window);
8434  TerminateThread(thread,0);
8435  if (data) delete[] data;
8436  if (title) delete[] title;
8437  if (is_fullscreen) _desinit_fullscreen();
8439  window_x = window_y = 0;
8440  is_fullscreen = false;
8441  is_closed = true;
8442  min = max = 0;
8443  title = 0;
8444  flush();
8445  return *this;
8446  }
8447 
8448  CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
8449  const unsigned int normalization_type=3,
8450  const bool fullscreen_flag=false, const bool closed_flag=false) {
8451  if (!dimw || !dimh) return assign();
8452  _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
8453  min = max = 0;
8454  std::memset(data,0,sizeof(unsigned int)*width*height);
8455  return paint();
8456  }
8457 
8458  template<typename T>
8459  CImgDisplay& assign(const CImg<T>& img, const char *title=0,
8460  const unsigned int normalization_type=3,
8461  const bool fullscreen_flag=false, const bool closed_flag=false) {
8462  if (!img) return assign();
8463  CImg<T> tmp;
8464  const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
8465  _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
8466  if (normalization==2) min = (float)nimg.minmax(max);
8467  return display(nimg);
8468  }
8469 
8470  template<typename T>
8471  CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
8472  const unsigned int normalization_type=3,
8473  const bool fullscreen_flag=false, const bool closed_flag=false) {
8474  if (!list) return assign();
8475  CImg<T> tmp;
8476  const CImg<T> img = list>'x', &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
8477  _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
8478  if (normalization==2) min = (float)nimg.minmax(max);
8479  return display(nimg);
8480  }
8481 
8482  CImgDisplay& assign(const CImgDisplay& disp) {
8483  if (!disp) return assign();
8484  _assign(disp.width,disp.height,disp.title,disp.normalization,disp.is_fullscreen,disp.is_closed);
8485  std::memcpy(data,disp.data,sizeof(unsigned int)*width*height);
8486  return paint();
8487  }
8488 
8489  CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
8490  if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
8491  if (is_empty()) return assign(nwidth,nheight);
8492  const unsigned int
8493  tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100),
8494  tmpdimy=(nheight>0)?nheight:(-nheight*height/100),
8495  dimx = tmpdimx?tmpdimx:1,
8496  dimy = tmpdimy?tmpdimy:1;
8497  if (window_width!=dimx || window_height!=dimy) {
8498  RECT rect; rect.left = rect.top = 0; rect.right = dimx-1; rect.bottom = dimy-1;
8499  AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8500  const int cwidth = rect.right-rect.left+1, cheight = rect.bottom-rect.top+1;
8501  SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
8502  }
8503  if (width!=dimx || height!=dimy) {
8504  unsigned int *ndata = new unsigned int[dimx*dimy];
8505  if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
8506  else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
8507  delete[] data;
8508  data = ndata;
8509  bmi.bmiHeader.biWidth = dimx;
8510  bmi.bmiHeader.biHeight = -(int)dimy;
8511  width = dimx;
8512  height = dimy;
8513  }
8515  is_resized = false;
8517  if (redraw) return paint();
8518  return *this;
8519  }
8520 
8521  CImgDisplay& toggle_fullscreen(const bool redraw=true) {
8522  if (is_empty()) return *this;
8523  if (redraw) {
8524  const unsigned int bufsize = width*height*4;
8525  void *odata = std::malloc(bufsize);
8526  std::memcpy(odata,data,bufsize);
8527  assign(width,height,title,normalization,!is_fullscreen,false);
8528  std::memcpy(data,odata,bufsize);
8529  std::free(odata);
8530  return paint();
8531  }
8532  return assign(width,height,title,normalization,!is_fullscreen,false);
8533  }
8534 
8535  CImgDisplay& show() {
8536  if (is_empty()) return *this;
8537  if (is_closed) {
8538  is_closed = false;
8539  if (is_fullscreen) _init_fullscreen();
8540  ShowWindow(window,SW_SHOW);
8541  _update_window_pos();
8542  }
8543  return paint();
8544  }
8545 
8546  CImgDisplay& close() {
8547  if (is_empty()) return *this;
8548  if (!is_closed && !is_fullscreen) {
8549  if (is_fullscreen) _desinit_fullscreen();
8550  ShowWindow(window,SW_HIDE);
8551  is_closed = true;
8552  window_x = window_y = 0;
8553  }
8554  return *this;
8555  }
8556 
8557  CImgDisplay& move(const int posx, const int posy) {
8558  if (is_empty()) return *this;
8559  if (!is_fullscreen) {
8560  RECT rect; rect.left = rect.top = 0; rect.right=window_width-1; rect.bottom=window_height-1;
8561  AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8562  const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
8563  SetWindowPos(window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
8564  } else SetWindowPos(window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
8565  window_x = posx;
8566  window_y = posy;
8567  is_moved = false;
8568  return show();
8569  }
8570 
8571  CImgDisplay& show_mouse() {
8572  if (is_empty()) return *this;
8573  visible_cursor = true;
8574  ShowCursor(TRUE);
8575  SendMessage(window,WM_SETCURSOR,0,0);
8576  return *this;
8577  }
8578 
8579  CImgDisplay& hide_mouse() {
8580  if (is_empty()) return *this;
8581  visible_cursor = false;
8582  ShowCursor(FALSE);
8583  SendMessage(window,WM_SETCURSOR,0,0);
8584  return *this;
8585  }
8586 
8587  CImgDisplay& set_mouse(const int posx, const int posy) {
8588  if (!is_closed && posx>=0 && posy>=0) {
8589  _update_window_pos();
8590  const int res = (int)SetCursorPos(window_x+posx,window_y+posy);
8591  if (res) { mouse_x = posx; mouse_y = posy; }
8592  }
8593  return *this;
8594  }
8595 
8596  CImgDisplay& set_title(const char *format, ...) {
8597  if (is_empty()) return *this;
8598  char tmp[1024] = { 0 };
8599  va_list ap;
8600  va_start(ap, format);
8601  std::vsprintf(tmp,format,ap);
8602  va_end(ap);
8603  if (title) delete[] title;
8604  const unsigned int s = std::strlen(tmp) + 1;
8605  title = new char[s];
8606  std::memcpy(title,tmp,s*sizeof(char));
8607  SetWindowTextA(window, tmp);
8608  return *this;
8609  }
8610 
8611  template<typename T>
8612  CImgDisplay& display(const CImg<T>& img) {
8613  if (img.is_empty())
8614  throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
8615  if (is_empty()) assign(img.width,img.height);
8616  return render(img).paint();
8617  }
8618 
8619  CImgDisplay& paint() {
8620  if (!is_closed) {
8621  WaitForSingleObject(mutex,INFINITE);
8622  SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
8623  ReleaseMutex(mutex);
8624  }
8625  return *this;
8626  }
8627 
8628  template<typename T>
8629  CImgDisplay& render(const CImg<T>& img) {
8630  if (is_empty()) return *this;
8631  if (!img)
8632  throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
8633  img.width,img.height,img.depth,img.dim,img.data);
8634  if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
8635 
8636  const T
8637  *data1 = img.data,
8638  *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
8639  *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
8640 
8641  WaitForSingleObject(mutex,INFINITE);
8642  unsigned int
8643  *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
8644  *ptrd = ndata;
8645 
8646  if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
8647  min = max = 0;
8648  switch (img.dim) {
8649  case 1 : {
8650  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8651  const unsigned char val = (unsigned char)*(data1++);
8652  *(ptrd++) = (val<<16) | (val<<8) | val;
8653  }} break;
8654  case 2 : {
8655  for (unsigned int xy = img.width*img.height; xy>0; --xy)
8656  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
8657  } break;
8658  default : {
8659  for (unsigned int xy = img.width*img.height; xy>0; --xy)
8660  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
8661  }
8662  }
8663  } else {
8664  if (normalization==3) {
8665  if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
8666  else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
8667  } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
8668  const float delta = max-min, mm = delta?delta:1.0f;
8669  switch (img.dim) {
8670  case 1 : {
8671  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8672  const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8673  *(ptrd++) = (val<<16) | (val<<8) | val;
8674  }} break;
8675  case 2 : {
8676  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8677  const unsigned char
8678  R = (unsigned char)(255*(*(data1++)-min)/mm),
8679  G = (unsigned char)(255*(*(data2++)-min)/mm);
8680  *(ptrd++) = (R<<16) | (G<<8);
8681  }} break;
8682  default : {
8683  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8684  const unsigned char
8685  R = (unsigned char)(255*(*(data1++)-min)/mm),
8686  G = (unsigned char)(255*(*(data2++)-min)/mm),
8687  B = (unsigned char)(255*(*(data3++)-min)/mm);
8688  *(ptrd++) = (R<<16) | (G<<8) | B;
8689  }}
8690  }
8691  }
8692  if (ndata!=data) { _render_resize(ndata,img.width,img.height,data,width,height); delete[] ndata; }
8693  ReleaseMutex(mutex);
8694  return *this;
8695  }
8696 
8697  template<typename T>
8698  const CImgDisplay& snapshot(CImg<T>& img) const {
8699  if (is_empty()) img.assign();
8700  else {
8701  img.assign(width,height,1,3);
8702  T
8703  *data1 = img.ptr(0,0,0,0),
8704  *data2 = img.ptr(0,0,0,1),
8705  *data3 = img.ptr(0,0,0,2);
8706  unsigned int *ptrs = data;
8707  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8708  const unsigned int val = *(ptrs++);
8709  *(data1++) = (unsigned char)(val>>16);
8710  *(data2++) = (unsigned char)((val>>8)&0xFF);
8711  *(data3++) = (unsigned char)(val&0xFF);
8712  }
8713  }
8714  return *this;
8715  }
8716 
8717  // Implementation for MacOSX/Carbon-based display
8718  //------------------------------------------------
8719 #elif cimg_display==3
8720  unsigned int *data; // The bits of the picture
8721  WindowRef carbonWindow; // The opaque carbon window struct associated with the display
8722  MPCriticalRegionID paintCriticalRegion; // Critical section used when drawing
8723  CGColorSpaceRef csr; // Needed for painting
8724  CGDataProviderRef dataProvider; // Needed for painting
8725  CGImageRef imageRef; // The image
8726  UInt32 lastKeyModifiers; // Buffer storing modifiers state
8727 
8728  // Define the kind of the queries which can be serialized using the event thread.
8729  typedef enum {
8730  COM_CREATEWINDOW = 0, // Create window query
8731  COM_RELEASEWINDOW, // Release window query
8732  COM_SHOWWINDOW, // Show window query
8733  COM_HIDEWINDOW, // Hide window query
8734  COM_SHOWMOUSE, // Show mouse query
8735  COM_HIDEMOUSE, // Hide mouse query
8736  COM_RESIZEWINDOW, // Resize window query
8737  COM_MOVEWINDOW, // Move window query
8738  COM_SETTITLE, // Set window title query
8739  COM_SETMOUSEPOS // Set cursor position query
8740  } CImgCarbonQueryKind;
8741 
8742  // The query destructor send to the event thread.
8743  struct CbSerializedQuery {
8744  CImgDisplay* sender; // Query's sender
8745  CImgCarbonQueryKind kind; // The kind of the query sent to the background thread
8746  short x, y; // X:Y values for move/resize operations
8747  char *c; // Char values for window title
8748  bool createFullScreenWindow; // Boolean value used for full-screen window creation
8749  bool createClosedWindow; // Boolean value used for closed-window creation
8750  bool update; // Boolean value used for resize
8751  bool success; // Succes or failure of the message, used as return value
8752  CbSerializedQuery(CImgDisplay *s, CImgCarbonQueryKind k):sender(s),kind(k),success(false) {}
8753 
8754  inline static CbSerializedQuery BuildReleaseWindowQuery(CImgDisplay* sender) {
8755  return CbSerializedQuery(sender, COM_RELEASEWINDOW);
8756  }
8757  inline static CbSerializedQuery BuildCreateWindowQuery(CImgDisplay* sender, const bool fullscreen, const bool closed) {
8758  CbSerializedQuery q(sender, COM_CREATEWINDOW);
8759  q.createFullScreenWindow = fullscreen;
8760  q.createClosedWindow = closed;
8761  return q;
8762  }
8763  inline static CbSerializedQuery BuildShowWindowQuery(CImgDisplay* sender) {
8764  return CbSerializedQuery(sender, COM_SHOWWINDOW);
8765  }
8766  inline static CbSerializedQuery BuildHideWindowQuery(CImgDisplay* sender) {
8767  return CbSerializedQuery(sender, COM_HIDEWINDOW);
8768  }
8769  inline static CbSerializedQuery BuildShowMouseQuery(CImgDisplay* sender) {
8770  return CbSerializedQuery(sender, COM_SHOWMOUSE);
8771  }
8772  inline static CbSerializedQuery BuildHideMouseQuery(CImgDisplay* sender) {
8773  return CbSerializedQuery(sender, COM_HIDEMOUSE);
8774  }
8775  inline static CbSerializedQuery BuildResizeWindowQuery(CImgDisplay* sender, const int x, const int y, bool update) {
8776  CbSerializedQuery q(sender, COM_RESIZEWINDOW);
8777  q.x = x, q.y = y;
8778  q.update = update;
8779  return q;
8780  }
8781  inline static CbSerializedQuery BuildMoveWindowQuery(CImgDisplay* sender, const int x, const int y) {
8782  CbSerializedQuery q(sender, COM_MOVEWINDOW);
8783  q.x = x, q.y = y;
8784  return q;
8785  }
8786  inline static CbSerializedQuery BuildSetWindowTitleQuery(CImgDisplay* sender, char* c) {
8787  CbSerializedQuery q(sender, COM_SETTITLE);
8788  q.c = c;
8789  return q;
8790  }
8791  inline static CbSerializedQuery BuildSetWindowPosQuery(CImgDisplay* sender, const int x, const int y) {
8792  CbSerializedQuery q(sender, COM_SETMOUSEPOS);
8793  q.x = x, q.y = y;
8794  return q;
8795  }
8796  };
8797 
8798  // Send a serialized query in a synchroneous way.
8799  // @param c Application Carbon global settings.
8800  // @param m The query to send.
8801  // @result Success/failure of the operation returned by the event thread.
8802  bool _CbSendMsg(cimg::CarbonInfo& c, CbSerializedQuery m) {
8803  MPNotifyQueue(c.com_queue,&m,0,0); // Send the given message
8804  MPWaitOnSemaphore(c.sync_event,kDurationForever); // Wait end of processing notification
8805  return m.success;
8806  }
8807 
8808  // Free the window attached to the current display.
8809  // @param c Application Carbon global settings.
8810  // @result Success/failure of the operation.
8811  bool _CbFreeAttachedWindow(cimg::CarbonInfo& c) {
8812  if (!_CbSendMsg(c, CbSerializedQuery::BuildReleaseWindowQuery(this))) // Ask the main thread to free the given window
8813  throw CImgDisplayException("Cannot release window associated with the current display.");
8814  // If a window existed, ask to release it
8815  MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
8816  --c.windowCount; //Decrement the window count
8817  MPExitCriticalRegion(c.windowListCR); // Unlock the list
8818  return c.windowCount == 0;
8819  }
8820 
8821  // Create the window attached to the current display.
8822  // @param c Application Carbon global settings.
8823  // @param title The window title, if any.
8824  // @param fullscreen Shoud we start in fullscreen mode ?
8825  // @param create_closed If true, the window is created but not displayed.
8826  // @result Success/failure of the operation.
8827  void _CbCreateAttachedWindow(cimg::CarbonInfo& c, const char* title, const bool fullscreen, const bool create_closed) {
8828  if (!_CbSendMsg(c,CbSerializedQuery::BuildCreateWindowQuery(this,fullscreen,create_closed))) // Ask the main thread to create the window
8829  throw CImgDisplayException("Cannot create the window associated with the current display.");
8830  if (title) set_title(title); // Set the title, if any
8831  // Now we can register the window
8832  MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
8833  ++c.windowCount; //Increment the window count
8834  MPExitCriticalRegion(c.windowListCR); // Unlock the list
8835  }
8836 
8837  // Destroy graphic objects previously allocated. We free the image, the data provider, then the colorspace.
8838  void _CbFinalizeGraphics() {
8839  CGImageRelease (imageRef); // Release the picture
8840  CGDataProviderRelease(dataProvider); // Release the DP
8841  CGColorSpaceRelease(csr); // Free the cs
8842  }
8843 
8844  // Create graphic objects associated to a display. We have to create a colormap, a data provider, and the image.
8845  void _CbInitializeGraphics() {
8846  csr = CGColorSpaceCreateDeviceRGB(); // Create the color space first
8847  if (!csr)
8848  throw CImgDisplayException("CGColorSpaceCreateDeviceRGB() failed.");
8849  // Create the DP
8850  dataProvider = CGDataProviderCreateWithData(0,data,height*width*sizeof(unsigned int),0);
8851  if (!dataProvider)
8852  throw CImgDisplayException("CGDataProviderCreateWithData() failed.");
8853  // ... and finally the image.
8854  if (cimg::endianness())
8855  imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
8856  kCGImageAlphaNoneSkipFirst,dataProvider,0,false,kCGRenderingIntentDefault);
8857  else
8858  imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
8859  kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,dataProvider,0,false,kCGRenderingIntentDefault);
8860  if (!imageRef)
8861  throw CImgDisplayException("CGImageCreate() failed.");
8862  }
8863 
8864  // Reinit graphic objects. Free them, then reallocate all.
8865  // This is used when image bounds are changed or when data source get invalid.
8866  void _CbReinitGraphics() {
8867  MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
8868  _CbFinalizeGraphics();
8869  _CbInitializeGraphics();
8870  MPExitCriticalRegion(paintCriticalRegion);
8871  }
8872 
8873  // Convert a point having global coordonates into the window coordonates.
8874  // We use this function to replace the deprecated GlobalToLocal QuickDraw API.
8875  // @param mouseEvent The mouse event which triggered the event handler.
8876  // @param window The window where the event occured.
8877  // @param point The modified point struct.
8878  // @result True if the point struct has been converted successfully.
8879  static bool _CbToLocalPointFromMouseEvent(EventRef mouseEvent, WindowRef window, HIPoint* point) {
8880  Rect bounds;
8881  if (GetWindowBounds(window,kWindowStructureRgn,&bounds)==noErr) {
8882  point->x -= bounds.left;
8883  point->y -= bounds.top;
8884  HIViewRef view = NULL;
8885  if (HIViewGetViewForMouseEvent(HIViewGetRoot(window),mouseEvent,&view)==noErr)
8886  return HIViewConvertPoint(point, NULL, view) == noErr;
8887  }
8888  return false;
8889  }
8890 
8891  static int screen_dimx() {
8892  return CGDisplayPixelsWide(kCGDirectMainDisplay);
8893  }
8894 
8895  static int screen_dimy() {
8896  return CGDisplayPixelsHigh(kCGDirectMainDisplay);
8897  }
8898 
8899  CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
8900  const unsigned int normalization_type=3,
8901  const bool fullscreen_flag=false, const bool closed_flag=false) {
8902  if (!dimw || !dimh) return assign();
8903  _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
8904  min = max = 0;
8905  std::memset(data,0,sizeof(unsigned int)*width*height);
8906  return paint();
8907  }
8908 
8909  template<typename T>
8910  CImgDisplay& assign(const CImg<T>& img, const char *title=0,
8911  const unsigned int normalization_type=3,
8912  const bool fullscreen_flag=false, const bool closed_flag=false) {
8913  if (!img) return assign();
8914  CImg<T> tmp;
8915  const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
8916  _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
8917  if (normalization==2) min = (float)nimg.minmax(max);
8918  return display(nimg);
8919  }
8920 
8921  template<typename T>
8922  CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
8923  const unsigned int normalization_type=3,
8924  const bool fullscreen_flag=false, const bool closed_flag=false) {
8925  if (!list) return assign();
8926  CImg<T> tmp;
8927  const CImg<T> img = list>'x', &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
8928  _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
8929  if (normalization==2) min = (float)nimg.minmax(max);
8930  return display(nimg);
8931  }
8932 
8933  CImgDisplay& assign(const CImgDisplay &win) {
8934  if (!win) return assign();
8935  _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
8936  std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
8937  return paint();
8938  }
8939 
8940  template<typename T>
8941  CImgDisplay& display(const CImg<T>& img) {
8942  if (is_empty()) assign(img.width,img.height);
8943  return render(img).paint();
8944  }
8945 
8946  CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
8947  if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
8948  if (is_empty()) return assign(nwidth,nheight);
8949  const unsigned int
8950  tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
8951  tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
8952  dimx = tmpdimx?tmpdimx:1,
8953  dimy = tmpdimy?tmpdimy:1;
8954  cimg::CarbonInfo& c = cimg::CarbonAttr();
8955 
8956  if ((window_width!=dimx || window_height!=dimy) &&
8957  !_CbSendMsg(c,CbSerializedQuery::BuildResizeWindowQuery(this,dimx,dimy,redraw)))
8958  throw CImgDisplayException("CImgDisplay::resize() : Cannot resize the window associated to the current display.");
8959 
8960  if (width!=dimx || height!=dimy) {
8961  unsigned int *ndata = new unsigned int[dimx*dimy];
8962  if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
8963  else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
8964  unsigned int const* old_data = data;
8965  data = ndata;
8966  delete[] old_data;
8967  _CbReinitGraphics();
8968  }
8970  is_resized = false;
8972  if (redraw) return paint();
8973  return *this;
8974  }
8975 
8976  CImgDisplay& move(const int posx, const int posy) {
8977  if (is_empty()) return *this;
8978  if (!is_fullscreen) {
8979  // If the operation succeeds, window_x and window_y are updated by the event thread
8980  cimg::CarbonInfo& c = cimg::CarbonAttr();
8981  // Send the query
8982  if (!_CbSendMsg(c,CbSerializedQuery::BuildMoveWindowQuery(this,posx,posy)))
8983  throw CImgDisplayException("CImgDisplay::move() : Cannot move the window associated to the current display.");
8984  }
8985  return show();
8986  }
8987 
8988  CImgDisplay& set_mouse(const int posx, const int posy) {
8989  if (!is_closed && posx>=0 && posy>=0) {
8990  // If the operation succeeds, mouse_x and mouse_y are updated by the event thread
8991  cimg::CarbonInfo& c = cimg::CarbonAttr();
8992  // Send the query
8993  if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowPosQuery(this,posx,posy)))
8994  throw CImgDisplayException("CImgDisplay::set_mouse() : Cannot set the mouse position to the current display.");
8995  }
8996  return *this;
8997  }
8998 
8999  CImgDisplay& hide_mouse() {
9000  if (is_empty()) return *this;
9001  cimg::CarbonInfo& c = cimg::CarbonAttr();
9002  // Send the query
9003  if (!_CbSendMsg(c,CbSerializedQuery::BuildHideMouseQuery(this)))
9004  throw CImgDisplayException("CImgDisplay::hide_mouse() : Cannot hide the mouse associated to the current display.");
9005  return *this;
9006  }
9007 
9008  CImgDisplay& show_mouse() {
9009  if (is_empty()) return *this;
9010  cimg::CarbonInfo& c = cimg::CarbonAttr();
9011  // Send the query
9012  if (!_CbSendMsg(c,CbSerializedQuery::BuildShowMouseQuery(this)))
9013  throw CImgDisplayException("CImgDisplay::show_mouse() : Cannot show the mouse associated to the current display.");
9014  return *this;
9015  }
9016 
9017  static void wait_all() {
9018  cimg::CarbonInfo& c = cimg::CarbonAttr();
9019  MPWaitOnSemaphore(c.wait_event,kDurationForever);
9020  }
9021 
9022  CImgDisplay& show() {
9023  if (is_empty()) return *this;
9024  if (is_closed) {
9025  cimg::CarbonInfo& c = cimg::CarbonAttr();
9026  if (!_CbSendMsg(c,CbSerializedQuery::BuildShowWindowQuery(this)))
9027  throw CImgDisplayException("CImgDisplay::show() : Cannot show the window associated to the current display.");
9028  }
9029  return paint();
9030  }
9031 
9032  CImgDisplay& close() {
9033  if (is_empty()) return *this;
9034  if (!is_closed && !is_fullscreen) {
9035  cimg::CarbonInfo& c = cimg::CarbonAttr();
9036  // If the operation succeeds, window_x and window_y are updated on the event thread
9037  if (!_CbSendMsg(c,CbSerializedQuery::BuildHideWindowQuery(this)))
9038  throw CImgDisplayException("CImgDisplay::close() : Cannot hide the window associated to the current display.");
9039  }
9040  return *this;
9041  }
9042 
9043  CImgDisplay& set_title(const char *format, ...) {
9044  if (is_empty()) return *this;
9045  char tmp[1024] = { 0 };
9046  va_list ap;
9047  va_start(ap, format);
9048  std::vsprintf(tmp,format,ap);
9049  va_end(ap);
9050  if (title) delete[] title;
9051  const unsigned int s = std::strlen(tmp) + 1;
9052  title = new char[s];
9053  std::memcpy(title,tmp,s*sizeof(char));
9054  cimg::CarbonInfo& c = cimg::CarbonAttr();
9055  if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowTitleQuery(this,tmp)))
9056  throw CImgDisplayException("CImgDisplay::set_title() : Cannot set the window title associated to the current display.");
9057  return *this;
9058  }
9059 
9060  CImgDisplay& paint() {
9061  if (!is_closed) {
9062  MPEnterCriticalRegion(paintCriticalRegion,kDurationForever);
9063  CGrafPtr portPtr = GetWindowPort(carbonWindow);
9064  CGContextRef currentContext = 0;
9065  QDBeginCGContext(portPtr,&currentContext);
9066  CGContextSetRGBFillColor(currentContext,255,255,255,255);
9067  CGContextFillRect(currentContext,CGRectMake(0,0,window_width,window_height));
9068  CGContextDrawImage(currentContext,CGRectMake(0,int(window_height-height)<0?0:window_height-height,width,height),imageRef);
9069  CGContextFlush(currentContext);
9070  QDEndCGContext(portPtr, &currentContext);
9071  MPExitCriticalRegion(paintCriticalRegion);
9072  }
9073  return *this;
9074  }
9075 
9076  template<typename T>
9077  CImgDisplay& render(const CImg<T>& img) {
9078  if (is_empty()) return *this;
9079  if (!img)
9080  throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
9081  img.width,img.height,img.depth,img.dim,img.data);
9082  if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
9083  const T
9084  *data1 = img.data,
9085  *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
9086  *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
9087  MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
9088  unsigned int
9089  *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
9090  *ptrd = ndata;
9091  if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
9092  min = max = 0;
9093  for (unsigned int xy = img.width*img.height; xy>0; --xy)
9094  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
9095  } else {
9096  if (normalization==3) {
9097  if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
9098  else {
9099  min = (float)cimg::type<T>::min();
9100  max = (float)cimg::type<T>::max();
9101  }
9102  } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
9103  const float delta = max-min, mm = delta?delta:1.0f;
9104  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
9105  const unsigned char
9106  R = (unsigned char)(255*(*(data1++)-min)/mm),
9107  G = (unsigned char)(255*(*(data2++)-min)/mm),
9108  B = (unsigned char)(255*(*(data3++)-min)/mm);
9109  *(ptrd++) = (R<<16) | (G<<8) | (B);
9110  }
9111  }
9112  if (ndata!=data) {
9113  _render_resize(ndata,img.width,img.height,data,width,height);
9114  delete[] ndata;
9115  }
9116  MPExitCriticalRegion(paintCriticalRegion);
9117  return *this;
9118  }
9119 
9120  template<typename T>
9121  const CImgDisplay& snapshot(CImg<T>& img) const {
9122  if (is_empty()) img.assign();
9123  else {
9124  img.assign(width,height,1,3);
9125  T
9126  *data1 = img.ptr(0,0,0,0),
9127  *data2 = img.ptr(0,0,0,1),
9128  *data3 = img.ptr(0,0,0,2);
9129  unsigned int *ptrs = data;
9130  for (unsigned int xy = img.width*img.height; xy>0; --xy) {
9131  const unsigned int val = *(ptrs++);
9132  *(data1++) = (unsigned char)(val>>16);
9133  *(data2++) = (unsigned char)((val>>8)&0xFF);
9134  *(data3++) = (unsigned char)(val&0xFF);
9135  }
9136  }
9137  return *this;
9138  }
9139 
9140  CImgDisplay& toggle_fullscreen(const bool redraw=true) {
9141  if (is_empty()) return *this;
9142  if (redraw) {
9143  const unsigned int bufsize = width*height*4;
9144  void *odata = std::malloc(bufsize);
9145  std::memcpy(odata,data,bufsize);
9146  assign(width,height,title,normalization,!is_fullscreen,false);
9147  std::memcpy(data,odata,bufsize);
9148  std::free(odata);
9149  return paint();
9150  }
9151  return assign(width,height,title,normalization,!is_fullscreen,false);
9152  }
9153 
9154  static OSStatus CarbonEventHandler(EventHandlerCallRef myHandler, EventRef theEvent, void* userData) {
9155  OSStatus result = eventNotHandledErr;
9156  CImgDisplay* disp = (CImgDisplay*) userData;
9157  (void)myHandler; // Avoid "unused parameter"
9158  cimg::CarbonInfo& c = cimg::CarbonAttr();
9159  // Gets the associated display
9160  if (disp) {
9161  // Window events are always handled
9162  if (GetEventClass(theEvent)==kEventClassWindow) switch (GetEventKind (theEvent)) {
9163  case kEventWindowClose :
9164  disp->mouse_x = disp->mouse_y = -1;
9165  disp->window_x = disp->window_y = 0;
9166  if (disp->button) {
9167  std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
9168  disp->button = 0;
9169  }
9170  if (disp->key) {
9171  std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
9172  disp->key = 0;
9173  }
9174  if (disp->released_key) { std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
9175  disp->is_closed = true;
9176  HideWindow(disp->carbonWindow);
9177  disp->is_event = true;
9178  MPSignalSemaphore(c.wait_event);
9179  result = noErr;
9180  break;
9181  // There is a lot of case where we have to redraw our window
9182  case kEventWindowBoundsChanging :
9183  case kEventWindowResizeStarted :
9184  case kEventWindowCollapsed : //Not sure it's really needed :-)
9185  break;
9186  case kEventWindowZoomed :
9187  case kEventWindowExpanded :
9188  case kEventWindowResizeCompleted : {
9189  MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
9190  // Now we retrieve the new size of the window
9191  Rect newContentRect;
9192  GetWindowBounds(disp->carbonWindow,kWindowContentRgn,&newContentRect);
9193  const unsigned int
9194  nw = (unsigned int)(newContentRect.right - newContentRect.left),
9195  nh = (unsigned int)(newContentRect.bottom - newContentRect.top);
9196 
9197  // Then we update CImg internal settings
9198  if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
9199  disp->window_width = nw;
9200  disp->window_height = nh;
9201  disp->mouse_x = disp->mouse_y = -1;
9202  disp->is_resized = true;
9203  }
9204  disp->is_event = true;
9205  MPExitCriticalRegion(disp->paintCriticalRegion);
9206  disp->paint(); // Coords changed, must update the screen
9207  MPSignalSemaphore(c.wait_event);
9208  result = noErr;
9209  } break;
9210  case kEventWindowDragStarted :
9211  case kEventWindowDragCompleted : {
9212  MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
9213  // Now we retrieve the new size of the window
9214  Rect newContentRect ;
9215  GetWindowBounds(disp->carbonWindow,kWindowStructureRgn,&newContentRect);
9216  const int nx = (int)(newContentRect.left), ny = (int)(newContentRect.top);
9217  // Then we update CImg internal settings
9218  if (nx!=disp->window_x || ny!=disp->window_y) {
9219  disp->window_x = nx;
9220  disp->window_y = ny;
9221  disp->is_moved = true;
9222  }
9223  disp->is_event = true;
9224  MPExitCriticalRegion(disp->paintCriticalRegion);
9225  disp->paint(); // Coords changed, must update the screen
9226  MPSignalSemaphore(c.wait_event);
9227  result = noErr;
9228  } break;
9229  case kEventWindowPaint :
9230  disp->paint();
9231  break;
9232  }
9233 
9234  switch (GetEventClass(theEvent)) {
9235  case kEventClassKeyboard : {
9236  if (GetEventKind(theEvent)==kEventRawKeyModifiersChanged) {
9237  // Apple has special keys named "notifiers", we have to convert this (exotic ?) key handling into the regular CImg processing.
9238  UInt32 newModifiers;
9239  if (GetEventParameter(theEvent,kEventParamKeyModifiers,typeUInt32,0,sizeof(UInt32),0,&newModifiers)==noErr) {
9240  int newKeyCode = -1;
9241  UInt32 changed = disp->lastKeyModifiers^newModifiers;
9242  // Find what changed here
9243  if ((changed & rightShiftKey)!=0) newKeyCode = cimg::keySHIFTRIGHT;
9244  if ((changed & shiftKey)!=0) newKeyCode = cimg::keySHIFTLEFT;
9245 
9246  // On the Mac, the "option" key = the ALT key
9247  if ((changed & (optionKey | rightOptionKey))!=0) newKeyCode = cimg::keyALTGR;
9248  if ((changed & controlKey)!=0) newKeyCode = cimg::keyCTRLLEFT;
9249  if ((changed & rightControlKey)!=0) newKeyCode = cimg::keyCTRLRIGHT;
9250  if ((changed & cmdKey)!=0) newKeyCode = cimg::keyAPPLEFT;
9251  if ((changed & alphaLock)!=0) newKeyCode = cimg::keyCAPSLOCK;
9252  if (newKeyCode != -1) { // Simulate keystroke
9253  if (disp->key) std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
9254  disp->key = (int)newKeyCode;
9255  }
9256  disp->lastKeyModifiers = newModifiers; // Save current state
9257  }
9258  disp->is_event = true;
9259  MPSignalSemaphore(c.wait_event);
9260  }
9261  if (GetEventKind(theEvent)==kEventRawKeyDown || GetEventKind(theEvent)==kEventRawKeyRepeat) {
9262  char keyCode;
9263  if (GetEventParameter(theEvent,kEventParamKeyMacCharCodes,typeChar,0,sizeof(keyCode),0,&keyCode)==noErr) {
9264  disp->_update_iskey((unsigned int)keyCode,true);
9265  if (disp->key) std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
9266  disp->key = (unsigned int)keyCode;
9267  if (disp->released_key) { std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
9268  }
9269  disp->is_event = true;
9270  MPSignalSemaphore(c.wait_event);
9271  }
9272  } break;
9273 
9274  case kEventClassMouse :
9275  switch (GetEventKind(theEvent)) {
9276  case kEventMouseDragged :
9277  // When you push the main button on the Apple mouse while moving it, you got NO kEventMouseMoved msg,
9278  // but a kEventMouseDragged one. So we merge them here.
9279  case kEventMouseMoved :
9280  HIPoint point;
9281  if (GetEventParameter(theEvent,kEventParamMouseLocation,typeHIPoint,0,sizeof(point),0,&point)==noErr) {
9282  if (_CbToLocalPointFromMouseEvent(theEvent,disp->carbonWindow,&point)) {
9283  disp->mouse_x = (int)point.x;
9284  disp->mouse_y = (int)point.y;
9285  if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
9286  disp->mouse_x = disp->mouse_y = -1;
9287  } else disp->mouse_x = disp->mouse_y = -1;
9288  }
9289  disp->is_event = true;
9290  MPSignalSemaphore(c.wait_event);
9291  break;
9292  case kEventMouseDown :
9293  UInt16 btn;
9294  if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
9295  std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
9296  if (btn==kEventMouseButtonPrimary) disp->button|=1U;
9297  // For those who don't have a multi-mouse button (as me), I think it's better to allow the user
9298  // to emulate a right click by using the Control key
9299  if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
9300  cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Down]");
9301  if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button|=2U;
9302  if (btn==kEventMouseButtonTertiary) disp->button|=4U;
9303  }
9304  disp->is_event = true;
9305  MPSignalSemaphore(c.wait_event);
9306  break;
9307  case kEventMouseWheelMoved :
9308  EventMouseWheelAxis wheelax;
9309  SInt32 delta;
9310  if (GetEventParameter(theEvent,kEventParamMouseWheelAxis,typeMouseWheelAxis,0,sizeof(wheelax),0,&wheelax)==noErr)
9311  if (wheelax==kEventMouseWheelAxisY) {
9312  if (GetEventParameter(theEvent,kEventParamMouseWheelDelta,typeLongInteger,0,sizeof(delta),0,&delta)==noErr)
9313  if (delta>0) disp->wheel+=delta/120; //FIXME: why 120 ?
9314  disp->is_event = true;
9315  MPSignalSemaphore(c.wait_event);
9316  }
9317  break;
9318  }
9319  }
9320 
9321  switch (GetEventClass(theEvent)) {
9322  case kEventClassKeyboard :
9323  if (GetEventKind(theEvent)==kEventRawKeyUp) {
9324  UInt32 keyCode;
9325  if (GetEventParameter(theEvent,kEventParamKeyCode,typeUInt32,0,sizeof(keyCode),0,&keyCode)==noErr) {
9326  disp->_update_iskey((unsigned int)keyCode,false);
9327  if (disp->key) { std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
9328  if (disp->released_key) std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
9329  disp->released_key = (int)keyCode;
9330  }
9331  disp->is_event = true;
9332  MPSignalSemaphore(c.wait_event);
9333  }
9334  break;
9335 
9336  case kEventClassMouse :
9337  switch (GetEventKind(theEvent)) {
9338  case kEventMouseUp :
9339  UInt16 btn;
9340  if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
9341  std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
9342  if (btn==kEventMouseButtonPrimary) disp->button&=~1U;
9343  // See note in kEventMouseDown handler.
9344  if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
9345  cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Up]");
9346  if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button&=~2U;
9347  if (btn==kEventMouseButtonTertiary) disp->button&=~2U;
9348  }
9349  disp->is_event = true;
9350  MPSignalSemaphore(c.wait_event);
9351  break;
9352  }
9353  }
9354  }
9355  return (result);
9356  }
9357 
9358  static void* _events_thread(void* args) {
9359  (void)args; // Make the compiler happy
9360  cimg::CarbonInfo& c = cimg::CarbonAttr();
9361  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
9362  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
9363  MPSignalSemaphore(c.sync_event); // Notify the caller that all goes fine
9364  EventRef theEvent;
9365  EventTargetRef theTarget;
9366  OSStatus err;
9367  CbSerializedQuery* query;
9368  theTarget = GetEventDispatcherTarget();
9369 
9370  // Enter in the main loop
9371  while (true) {
9372  pthread_testcancel(); /* Check if cancelation happens */
9373  err = ReceiveNextEvent(0,0,kDurationImmediate,true,&theEvent); // Fetch new events
9374  if (err==noErr) { // Received a carbon event, so process it !
9375  SendEventToEventTarget (theEvent, theTarget);
9376  ReleaseEvent(theEvent);
9377  } else if (err == eventLoopTimedOutErr) { // There is no event to process, so check if there is new messages to process
9378  OSStatus r =MPWaitOnQueue(c.com_queue,(void**)&query,0,0,10*kDurationMillisecond);
9379  if (r!=noErr) continue; //nothing in the queue or an error.., bye
9380  // If we're here, we've something to do now.
9381  if (query) {
9382  switch (query->kind) {
9383  case COM_SETMOUSEPOS : { // change the cursor position
9384  query->success = CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,CGPointMake(query->sender->window_x+query->x,query->sender->window_y+query->y))
9385  == kCGErrorSuccess;
9386  if (query->success) {
9387  query->sender->mouse_x = query->x;
9388  query->sender->mouse_y = query->y;
9389  } else cimg::warn("CImgDisplay::_events_thread() : CGDisplayMoveCursorToPoint failed.");
9390  } break;
9391  case COM_SETTITLE : { // change the title bar caption
9392  CFStringRef windowTitle = CFStringCreateWithCString(0,query->c,kCFStringEncodingMacRoman);
9393  query->success = SetWindowTitleWithCFString(query->sender->carbonWindow,windowTitle)==noErr;
9394  if (!query->success)
9395  cimg::warn("CImgDisplay::_events_thread() : SetWindowTitleWithCFString failed.");
9396  CFRelease(windowTitle);
9397  } break;
9398  case COM_RESIZEWINDOW : { // Resize a window
9399  SizeWindow(query->sender->carbonWindow,query->x,query->y,query->update);
9400  // If the window has been resized successfully, update display informations
9401  query->sender->window_width = query->x;
9402  query->sender->window_height = query->y;
9403  query->success = true;
9404  } break;
9405  case COM_MOVEWINDOW : { // Move a window
9406  MoveWindow(query->sender->carbonWindow,query->x,query->y,false);
9407  query->sender->window_x = query->x;
9408  query->sender->window_y = query->y;
9409  query->sender->is_moved = false;
9410  query->success = true;
9411  } break;
9412  case COM_SHOWMOUSE : { // Show the mouse
9413  query->success = CGDisplayShowCursor(kCGDirectMainDisplay)==noErr;
9414  if (!query->success)
9415  cimg::warn("CImgDisplay::_events_thread() : CGDisplayShowCursor failed.");
9416  } break;
9417  case COM_HIDEMOUSE : { // Hide the mouse
9418  query->success = CGDisplayHideCursor(kCGDirectMainDisplay)==noErr;
9419  if (!query->success)
9420  cimg::warn("CImgDisplay::_events_thread() : CGDisplayHideCursor failed.");
9421  } break;
9422  case COM_SHOWWINDOW : { // We've to show a window
9423  ShowWindow(query->sender->carbonWindow);
9424  query->success = true;
9425  query->sender->is_closed = false;
9426  } break;
9427  case COM_HIDEWINDOW : { // We've to show a window
9428  HideWindow(query->sender->carbonWindow);
9429  query->sender->is_closed = true;
9430  query->sender->window_x = query->sender->window_y = 0;
9431  query->success = true;
9432  } break;
9433  case COM_RELEASEWINDOW : { // We have to release a given window handle
9434  query->success = true;
9435  CFRelease(query->sender->carbonWindow);
9436  } break;
9437  case COM_CREATEWINDOW : { // We have to create a window
9438  query->success = true;
9439  WindowAttributes windowAttrs;
9440  Rect contentRect;
9441  if (query->createFullScreenWindow) {
9442  // To simulate a "true" full screen, we remove menus and close boxes
9443  windowAttrs = (1L << 9); //Why ? kWindowNoTitleBarAttribute seems to be not defined on 10.3
9444  // Define a full screen bound rect
9445  SetRect(&contentRect,0,0,CGDisplayPixelsWide(kCGDirectMainDisplay),CGDisplayPixelsHigh(kCGDirectMainDisplay));
9446  } else { // Set the window size
9447  SetRect(&contentRect,0,0,query->sender->width,query->sender->height); // Window will be centered with RepositionWindow.
9448  // Use default attributes
9449  windowAttrs = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute | kWindowLiveResizeAttribute;
9450  }
9451  // Update window position
9452  if (query->createClosedWindow) query->sender->window_x = query->sender->window_y = 0;
9453  else {
9454  query->sender->window_x = contentRect.left;
9455  query->sender->window_y = contentRect.top;
9456  }
9457  // Update window flags
9458  query->sender->window_width = query->sender->width;
9459  query->sender->window_height = query->sender->height;
9460  query->sender->flush();
9461  // Create the window
9462  if (CreateNewWindow(kDocumentWindowClass,windowAttrs,&contentRect,&query->sender->carbonWindow)!=noErr) {
9463  query->success = false;
9464  cimg::warn("CImgDisplay::_events_thread() : CreateNewWindow() failed.");
9465  }
9466  // Send it to the foreground
9467  if (RepositionWindow(query->sender->carbonWindow,0,kWindowCenterOnMainScreen)!=noErr) query->success = false;
9468  // Show it, if needed
9469  if (!query->createClosedWindow) ShowWindow(query->sender->carbonWindow);
9470 
9471  // Associate a valid event handler
9472  EventTypeSpec eventList[] = {
9473  { kEventClassWindow, kEventWindowClose },
9474  { kEventClassWindow, kEventWindowResizeStarted },
9475  { kEventClassWindow, kEventWindowResizeCompleted },
9476  { kEventClassWindow, kEventWindowDragStarted},
9477  { kEventClassWindow, kEventWindowDragCompleted },
9478  { kEventClassWindow, kEventWindowPaint },
9479  { kEventClassWindow, kEventWindowBoundsChanging },
9480  { kEventClassWindow, kEventWindowCollapsed },
9481  { kEventClassWindow, kEventWindowExpanded },
9482  { kEventClassWindow, kEventWindowZoomed },
9483  { kEventClassKeyboard, kEventRawKeyDown },
9484  { kEventClassKeyboard, kEventRawKeyUp },
9485  { kEventClassKeyboard, kEventRawKeyRepeat },
9486  { kEventClassKeyboard, kEventRawKeyModifiersChanged },
9487  { kEventClassMouse, kEventMouseMoved },
9488  { kEventClassMouse, kEventMouseDown },
9489  { kEventClassMouse, kEventMouseUp },
9490  { kEventClassMouse, kEventMouseDragged }
9491  };
9492 
9493  // Set up the handler
9494  if (InstallWindowEventHandler(query->sender->carbonWindow,NewEventHandlerUPP(CarbonEventHandler),GetEventTypeCount(eventList),
9495  eventList,(void*)query->sender,0)!=noErr) {
9496  query->success = false;
9497  cimg::warn("CImgDisplay::_events_thread() : InstallWindowEventHandler failed.");
9498  }
9499 
9500  // Paint
9501  query->sender->paint();
9502  } break;
9503  default :
9504  cimg::warn("CImgDisplay::_events_thread() : Received unknow code %d.",query->kind);
9505  }
9506  // Signal that the message has been processed
9507  MPSignalSemaphore(c.sync_event);
9508  }
9509  }
9510  }
9511  // If we are here, the application is now finished
9512  pthread_exit(0);
9513  }
9514 
9515  CImgDisplay& assign() {
9516  if (is_empty()) return *this;
9517  cimg::CarbonInfo& c = cimg::CarbonAttr();
9518  // Destroy the window associated to the display
9519  _CbFreeAttachedWindow(c);
9520  // Don't destroy the background thread here.
9521  // If you check whether _CbFreeAttachedWindow() returned true,
9522  // - saying that there were no window left on screen - and
9523  // you destroy the background thread here, ReceiveNextEvent won't
9524  // work anymore if you create a new window after. So the
9525  // background thread must be killed (pthread_cancel() + pthread_join())
9526  // only on the application shutdown.
9527 
9528  // Finalize graphics
9529  _CbFinalizeGraphics();
9530 
9531  // Do some cleanup
9532  if (data) delete[] data;
9533  if (title) delete[] title;
9535  window_x = window_y = 0;
9536  is_fullscreen = false;
9537  is_closed = true;
9538  min = max = 0;
9539  title = 0;
9540  flush();
9541  if (MPDeleteCriticalRegion(paintCriticalRegion)!=noErr)
9542  throw CImgDisplayException("CImgDisplay()::assign() : MPDeleteCriticalRegion failed.");
9543  return *this;
9544  }
9545 
9546  CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0,
9547  const unsigned int normalization_type=3,
9548  const bool fullscreen_flag=false, const bool closed_flag=false) {
9549  cimg::CarbonInfo& c = cimg::CarbonAttr();
9550 
9551  // Allocate space for window title
9552  const char *const nptitle = ptitle?ptitle:"";
9553  const unsigned int s = std::strlen(nptitle) + 1;
9554  char *tmp_title = s?new char[s]:0;
9555  if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char));
9556 
9557  // Destroy previous window if existing
9558  if (!is_empty()) assign();
9559 
9560  // Set display variables
9561  width = cimg::min(dimw,(unsigned int)screen_dimx());
9562  height = cimg::min(dimh,(unsigned int)screen_dimy());
9563  normalization = normalization_type<4?normalization_type:3;
9564  is_fullscreen = fullscreen_flag;
9565  is_closed = closed_flag;
9566  lastKeyModifiers = 0;
9567  title = tmp_title;
9568  flush();
9569 
9570  // Create the paint CR
9571  if (MPCreateCriticalRegion(&paintCriticalRegion) != noErr)
9572  throw CImgDisplayException("CImgDisplay::_assign() : MPCreateCriticalRegion() failed.");
9573 
9574  // Create the thread if it's not already created
9575  if (c.event_thread==0) {
9576  // Background thread does not exists, so create it !
9577  if (pthread_create(&c.event_thread,0,_events_thread,0)!=0)
9578  throw CImgDisplayException("CImgDisplay::_assign() : pthread_create() failed.");
9579  // Wait for thread initialization
9580  MPWaitOnSemaphore(c.sync_event, kDurationForever);
9581  }
9582 
9583  // Init disp. graphics
9584  data = new unsigned int[width*height];
9585  _CbInitializeGraphics();
9586 
9587  // Now ask the thread to create the window
9588  _CbCreateAttachedWindow(c,nptitle,fullscreen_flag,closed_flag);
9589  return *this;
9590  }
9591 
9592 #endif
9593 
9595  };
9596 
9597  /*
9598  #--------------------------------------
9599  #
9600  #
9601  #
9602  # Definition of the CImg<T> structure
9603  #
9604  #
9605  #
9606  #--------------------------------------
9607  */
9608 
9610 
9700  template<typename T>
9701  struct CImg {
9702 
9704 
9711  unsigned int width;
9712 
9714 
9722  unsigned int height;
9723 
9725 
9733  unsigned int depth;
9734 
9736 
9744  unsigned int dim;
9745 
9748 
9750  T *data;
9751 
9753 
9758  typedef T* iterator;
9759 
9761 
9766  typedef const T* const_iterator;
9767 
9769  typedef T value_type;
9770 
9771  // Define common T-dependant types.
9789  typedef typename cimg::last<T,int>::type intT;
9794 
9796  //---------------------------
9797  //
9799 
9800  //---------------------------
9801 #ifdef cimg_plugin
9802 #include cimg_plugin
9803 #endif
9804 #ifdef cimg_plugin1
9805 #include cimg_plugin1
9806 #endif
9807 #ifdef cimg_plugin2
9808 #include cimg_plugin2
9809 #endif
9810 #ifdef cimg_plugin3
9811 #include cimg_plugin3
9812 #endif
9813 #ifdef cimg_plugin4
9814 #include cimg_plugin4
9815 #endif
9816 #ifdef cimg_plugin5
9817 #include cimg_plugin5
9818 #endif
9819 #ifdef cimg_plugin6
9820 #include cimg_plugin6
9821 #endif
9822 #ifdef cimg_plugin7
9823 #include cimg_plugin7
9824 #endif
9825 #ifdef cimg_plugin8
9826 #include cimg_plugin8
9827 #endif
9828 
9830  //---------------------------------------------------------
9831  //
9833 
9834  //---------------------------------------------------------
9835 
9837 
9845  ~CImg() {
9846  if (data && !is_shared) delete[] data;
9847  }
9848 
9850 
9857  CImg():width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {}
9858 
9860 
9874  explicit CImg(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1):
9875  is_shared(false) {
9876  const unsigned int siz = dx*dy*dz*dv;
9877  if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; }
9878  else { width = height = depth = dim = 0; data = 0; }
9879  }
9880 
9882 
9893  CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val):
9894  is_shared(false) {
9895  const unsigned int siz = dx*dy*dz*dv;
9896  if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(val); }
9897  else { width = height = depth = dim = 0; data = 0; }
9898  }
9899 
9901  CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
9902  const int val0, const int val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
9903 #define _CImg_stdarg(img,a0,a1,N,t) { \
9904  unsigned int _siz = (unsigned int)N; \
9905  if (_siz--) { \
9906  va_list ap; \
9907  va_start(ap,a1); \
9908  T *ptrd = (img).data; \
9909  *(ptrd++) = (T)a0; \
9910  if (_siz--) { \
9911  *(ptrd++) = (T)a1; \
9912  for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \
9913  } \
9914  va_end(ap); \
9915  }}
9916  assign(dx,dy,dz,dv);
9917  _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
9918  }
9919 
9921  CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
9922  const double val0, const double val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
9923  assign(dx,dy,dz,dv);
9924  _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
9925  }
9926 
9928  CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
9929  const char *const values, const bool repeat_values):is_shared(false) {
9930  const unsigned int siz = dx*dy*dz*dv;
9931  if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(values,repeat_values); }
9932  else { width = height = depth = dim = 0; data = 0; }
9933  }
9934 
9936 
9940  template<typename t>
9941  CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
9942  const unsigned int dz=1, const unsigned int dv=1, const bool shared=false):is_shared(false) {
9943  if (shared)
9944  throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a (%s*) buffer "
9945  "(different pixel types).",
9947  const unsigned int siz = dx*dy*dz*dv;
9948  if (data_buffer && siz) {
9949  width = dx; height = dy; depth = dz; dim = dv; data = new T[siz];
9950  const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
9951  } else { width = height = depth = dim = 0; data = 0; }
9952  }
9953 
9954  CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
9955  const unsigned int dz=1, const unsigned int dv=1, const bool shared=false) {
9956  const unsigned int siz = dx*dy*dz*dv;
9957  if (data_buffer && siz) {
9958  width = dx; height = dy; depth = dz; dim = dv; is_shared = shared;
9959  if (is_shared) data = const_cast<T*>(data_buffer);
9960  else { data = new T[siz]; std::memcpy(data,data_buffer,siz*sizeof(T)); }
9961  } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
9962  }
9963 
9965 
9975  explicit CImg(const char *const filename):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
9976  assign(filename);
9977  }
9978 
9980 
9997  template<typename t>
9998  CImg(const CImg<t>& img):is_shared(false) {
9999  const unsigned int siz = img.size();
10000  if (img.data && siz) {
10001  width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
10002  const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
10003  } else { width = height = depth = dim = 0; data = 0; }
10004  }
10005 
10006  CImg(const CImg<T>& img) {
10007  const unsigned int siz = img.size();
10008  if (img.data && siz) {
10009  width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = img.is_shared;
10010  if (is_shared) data = const_cast<T*>(img.data);
10011  else { data = new T[siz]; std::memcpy(data,img.data,siz*sizeof(T)); }
10012  } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
10013  }
10014 
10016 
10029  template<typename t>
10030  CImg(const CImg<t>& img, const bool shared):is_shared(false) {
10031  if (shared)
10032  throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a CImg<%s> instance "
10033  "(different pixel types).",
10035  const unsigned int siz = img.size();
10036  if (img.data && siz) {
10037  width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
10038  const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
10039  } else { width = height = depth = dim = 0; data = 0; }
10040  }
10041 
10042  CImg(const CImg<T>& img, const bool shared) {
10043  const unsigned int siz = img.size();
10044  if (img.data && siz) {
10045  width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = shared;
10046  if (is_shared) data = const_cast<T*>(img.data);
10047  else { data = new T[siz]; std::memcpy(data,img.data,siz*sizeof(T)); }
10048  } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
10049  }
10050 
10052  template<typename t>
10053  CImg(const CImg<t>& img, const char *const dimensions):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10054  assign(img,dimensions);
10055  }
10056 
10058  template<typename t>
10059  CImg(const CImg<t>& img, const char *const dimensions, const T val):
10060  width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10061  assign(img,dimensions).fill(val);
10062  }
10063 
10065  template<typename t>
10066  CImg(const CImg<t>& img, const char *const dimensions, const char *const values, const bool repeat_values):
10067  width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10068  assign(img,dimensions).fill(values,repeat_values);
10069  }
10070 
10072  explicit CImg(const CImgDisplay &disp):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10073  disp.snapshot(*this);
10074  }
10075 
10078  return CImg<T>(data,width,height,depth,dim,true);
10079  }
10080 
10081  const CImg<T> get_shared() const {
10082  return CImg<T>(data,width,height,depth,dim,true);
10083  }
10084 
10086 
10091  return assign();
10092  }
10093 
10095 
10104  if (data && !is_shared) delete[] data;
10105  width = height = depth = dim = 0; is_shared = false; data = 0;
10106  return *this;
10107  }
10108 
10110 
10125  CImg<T>& assign(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1) {
10126  const unsigned int siz = dx*dy*dz*dv;
10127  if (!siz) return assign();
10128  const unsigned int curr_siz = size();
10129  if (siz!=curr_siz) {
10130  if (is_shared)
10131  throw CImgArgumentException("CImg<%s>::assign() : Cannot assign image (%u,%u,%u,%u) to shared instance image (%u,%u,%u,%u,%p).",
10132  pixel_type(),dx,dy,dz,dv,width,height,depth,dim,data);
10133  else { if (data) delete[] data; data = new T[siz]; }
10134  }
10135  width = dx; height = dy; depth = dz; dim = dv;
10136  return *this;
10137  }
10138 
10140 
10151  CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val) {
10152  return assign(dx,dy,dz,dv).fill(val);
10153  }
10154 
10156  CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10157  const int val0, const int val1, ...) {
10158  assign(dx,dy,dz,dv);
10159  _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
10160  return *this;
10161  }
10162 
10164  CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10165  const double val0, const double val1, ...) {
10166  assign(dx,dy,dz,dv);
10167  _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
10168  return *this;
10169  }
10170 
10172  CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10173  const char *const values, const bool repeat_values) {
10174  return assign(dx,dy,dz,dv).fill(values,repeat_values);
10175  }
10176 
10178  template<typename t>
10179  CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
10180  const unsigned int dz=1, const unsigned int dv=1) {
10181  const unsigned int siz = dx*dy*dz*dv;
10182  if (!data_buffer || !siz) return assign();
10183  assign(dx,dy,dz,dv);
10184  const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
10185  return *this;
10186  }
10187 
10188  CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
10189  const unsigned int dz=1, const unsigned int dv=1) {
10190  const unsigned int siz = dx*dy*dz*dv;
10191  if (!data_buffer || !siz) return assign();
10192  const unsigned int curr_siz = size();
10193  if (data_buffer==data && siz==curr_siz) return assign(dx,dy,dz,dv);
10194  if (is_shared || data_buffer+siz<data || data_buffer>=data+size()) {
10195  assign(dx,dy,dz,dv);
10196  if (is_shared) std::memmove(data,data_buffer,siz*sizeof(T));
10197  else std::memcpy(data,data_buffer,siz*sizeof(T));
10198  } else {
10199  T *new_data = new T[siz];
10200  std::memcpy(new_data,data_buffer,siz*sizeof(T));
10201  delete[] data; data = new_data; width = dx; height = dy; depth = dz; dim = dv;
10202  }
10203  return *this;
10204  }
10205 
10207  template<typename t>
10208  CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy,
10209  const unsigned int dz, const unsigned int dv, const bool shared) {
10210  if (shared)
10211  throw CImgArgumentException("CImg<%s>::assign() : Cannot assign buffer (%s*) to shared instance image (%u,%u,%u,%u,%p)"
10212  "(different pixel types).",
10214  return assign(data_buffer,dx,dy,dz,dv);
10215  }
10216 
10217  CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
10218  const unsigned int dz, const unsigned int dv, const bool shared) {
10219  const unsigned int siz = dx*dy*dz*dv;
10220  if (!data_buffer || !siz) return assign();
10221  if (!shared) { if (is_shared) assign(); assign(data_buffer,dx,dy,dz,dv); }
10222  else {
10223  if (!is_shared) {
10224  if (data_buffer+siz<data || data_buffer>=data+size()) assign();
10225  else cimg::warn("CImg<%s>::assign() : Shared instance image has overlapping memory !",
10226  pixel_type());
10227  }
10228  width = dx; height = dy; depth = dz; dim = dv; is_shared = true;
10229  data = const_cast<T*>(data_buffer);
10230  }
10231  return *this;
10232  }
10233 
10235 
10244  CImg<T>& assign(const char *const filename) {
10245  return load(filename);
10246  }
10247 
10249 
10258  template<typename t>
10259  CImg<T>& assign(const CImg<t>& img) {
10260  return assign(img.data,img.width,img.height,img.depth,img.dim);
10261  }
10262 
10264 
10276  template<typename t>
10277  CImg<T>& assign(const CImg<t>& img, const bool shared) {
10278  return assign(img.data,img.width,img.height,img.depth,img.dim,shared);
10279  }
10280 
10282  template<typename t>
10283  CImg<T>& assign(const CImg<t>& img, const char *const dimensions) {
10284  if (!dimensions || !*dimensions) return assign(img.width,img.height,img.depth,img.dim);
10285  unsigned int siz[4] = { 0,1,1,1 }, k = 0;
10286  for (const char *s = dimensions; *s && k<4; ++k) {
10287  char item[256] = { 0 };
10288  if (std::sscanf(s,"%255[^0-9%xyzvwhdcXYZVWHDC]",item)>0) s+=std::strlen(item);
10289  if (*s) {
10290  unsigned int val = 0; char sep = 0;
10291  if (std::sscanf(s,"%u%c",&val,&sep)>0) {
10292  if (sep=='%') siz[k] = val*(k==0?width:k==1?height:k==2?depth:dim)/100;
10293  else siz[k] = val;
10294  while (*s>='0' && *s<='9') ++s; if (sep=='%') ++s;
10295  } else switch (cimg::uncase(*s)) {
10296  case 'x' : case 'w' : siz[k] = img.width; ++s; break;
10297  case 'y' : case 'h' : siz[k] = img.height; ++s; break;
10298  case 'z' : case 'd' : siz[k] = img.depth; ++s; break;
10299  case 'v' : case 'c' : siz[k] = img.dim; ++s; break;
10300  default :
10301  throw CImgArgumentException("CImg<%s>::assign() : Misplaced character '%c' in input dimension string '%s'.",
10302  pixel_type(),*s,dimensions);
10303  }
10304  }
10305  }
10306  return assign(siz[0],siz[1],siz[2],siz[3]);
10307  }
10308 
10310  template<typename t>
10311  CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T val) {
10312  return assign(img,dimensions).fill(val);
10313  }
10314 
10316  template<typename t>
10317  CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const char *const values, const bool repeat_values) {
10318  return assign(img,dimensions).fill(values,repeat_values);
10319  }
10320 
10322  CImg<T>& assign(const CImgDisplay &disp) {
10323  disp.snapshot(*this);
10324  return *this;
10325  }
10326 
10328 
10331  template<typename t>
10333  img.assign(*this);
10334  assign();
10335  return img;
10336  }
10337 
10339  if (is_shared || img.is_shared) { img.assign(*this); assign(); } else { img.assign(); swap(img); }
10340  return img;
10341  }
10342 
10343  template<typename t>
10344  CImgList<t>& transfer_to(CImgList<t>& list, const unsigned int pos=~0U) {
10345  const unsigned int npos = pos>list.width?list.width:pos;
10346  transfer_to(list.insert(1,npos)[npos]);
10347  return list;
10348  }
10349 
10351  static CImg<T>& empty() {
10352  static CImg<T> _empty;
10353  return _empty.assign();
10354  }
10355 
10358  cimg::swap(width,img.width);
10359  cimg::swap(height,img.height);
10360  cimg::swap(depth,img.depth);
10361  cimg::swap(dim,img.dim);
10362  cimg::swap(data,img.data);
10363  cimg::swap(is_shared,img.is_shared);
10364  return img;
10365  }
10366 
10368  //------------------------------------------
10369  //
10371 
10372  //------------------------------------------
10373 
10375 
10390 #if cimg_debug>=3
10391  T& operator[](const unsigned int off) {
10392  if (!data || off>=size()) {
10393  cimg::warn("CImg<%s>::operator[] : Pixel access requested at offset=%u "
10394  "outside the image range (%u,%u,%u,%u) (size=%u)",
10395  pixel_type(),off,width,height,depth,dim,size());
10396  return *data;
10397  }
10398  else return data[off];
10399  }
10400 
10401  const T& operator[](const unsigned int off) const {
10402  return const_cast<CImg<T>*>(this)->operator[](off);
10403  }
10404 #else
10405  T& operator[](const unsigned int off) {
10406  return data[off];
10407  }
10408 
10409  const T& operator[](const unsigned int off) const {
10410  return data[off];
10411  }
10412 #endif
10413 
10415 
10435 #if cimg_debug>=3
10436  T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
10437  const unsigned int off = (unsigned int)offset(x,y,z,v);
10438  if (!data || off>=size()) {
10439  cimg::warn("CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%u) "
10440  "outside the image range (%u,%u,%u,%u) (size=%u)",
10441  pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
10442  return *data;
10443  }
10444  else return data[off];
10445  }
10446 
10447  const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
10448  return const_cast<CImg<T>*>(this)->operator()(x,y,z,v);
10449  }
10450 #else
10451  T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
10452  return data[x + y*width + z*width*height + v*width*height*depth];
10453  }
10454 
10455  const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
10456  return data[x + y*width + z*width*height + v*width*height*depth];
10457  }
10458 #endif
10459 
10461  operator bool() const {
10462  return data && width && height && depth && dim;
10463  }
10464 
10466 
10470  CImg<T>& operator=(const T val) {
10471  return fill(val);
10472  }
10473 
10475 
10482  CImg<T>& operator=(const char *const expression) {
10483  const unsigned int omode = cimg::exception_mode();
10484  cimg::exception_mode() = 0;
10485  try {
10486  fill(expression,true);
10487  } catch (CImgException&) {
10488  cimg::exception_mode() = omode;
10489  load(expression);
10490  }
10491  cimg::exception_mode() = omode;
10492  return *this;
10493  }
10494 
10496 
10501  template<typename t>
10502  CImg<T>& operator=(const CImg<t>& img) {
10503  return assign(img);
10504  }
10505 
10506  CImg<T>& operator=(const CImg<T>& img) {
10507  return assign(img);
10508  }
10509 
10512  disp.snapshot(*this);
10513  return *this;
10514  }
10515 
10517  template<typename t>
10518  CImg<T>& operator+=(const t val) {
10519  cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr) + val);
10520  return *this;
10521  }
10522 
10524  CImg<T>& operator+=(const char *const expression) {
10525  const unsigned int omode = cimg::exception_mode();
10526  cimg::exception_mode() = 0;
10527  try {
10528  _cimg_math_parser mp(expression,"operator+=");
10529  T *ptrd = data;
10530  cimg_forXYZV(*this,x,y,z,v) { *ptrd = (T)(*ptrd + mp.eval(*this,x,y,z,v)); ++ptrd; }
10531  } catch (CImgException&) {
10532  cimg::exception_mode() = omode;
10533  CImg<T> values(width,height,depth,dim);
10534  values = expression;
10535  *this+=values;
10536  }
10537  cimg::exception_mode() = omode;
10538  return *this;
10539  }
10540 
10542  template<typename t>
10543  CImg<T>& operator+=(const CImg<t>& img) {
10544  const unsigned int siz = size(), isiz = img.size();
10545  if (siz && isiz) {
10546  if (is_overlapped(img)) return *this+=+img;
10547  T *ptrd = data, *const ptrd_end = data + siz;
10548  if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
10549  for (const t *ptrs = img.data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd + *(ptrs++));
10550  for (const t *ptrs = img.data; ptrd<ptrd_end; ++ptrd) *ptrd = (T)(*ptrd + *(ptrs++));
10551  }
10552  return *this;
10553  }
10554 
10557  cimg_for(*this,ptr,T) ++(*ptr);
10558  return *this;
10559  }
10560 
10563  const CImg<T> copy(*this,false);
10564  ++*this;
10565  return copy;
10566  }
10567 
10569 
10573  CImg<T> operator+() const {
10574  return CImg<T>(*this,false);
10575  }
10576 
10578  template<typename t>
10579  CImg<_cimg_Tt> operator+(const t val) const {
10580  return CImg<_cimg_Tt>(*this,false)+=val;
10581  }
10582 
10584  CImg<Tfloat> operator+(const char *const expression) const {
10585  return CImg<Tfloat>(*this,false)+=expression;
10586  }
10587 
10589  template<typename t>
10590  CImg<_cimg_Tt> operator+(const CImg<t>& img) const {
10591  return CImg<_cimg_Tt>(*this,false)+=img;
10592  }
10593 
10595  template<typename t>
10596  CImg<T>& operator-=(const t val) {
10597  cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)-val);
10598  return *this;
10599  }
10600 
10602  CImg<T>& operator-=(const char *const expression) {
10603  const unsigned int omode = cimg::exception_mode();
10604  cimg::exception_mode() = 0;
10605  try {
10606  _cimg_math_parser mp(expression,"operator-=");
10607  T *ptrd = data;
10608  cimg_forXYZV(*this,x,y,z,v) { *ptrd = (T)(*ptrd - mp.eval(*this,x,y,z,v)); ++ptrd; }
10609  } catch (CImgException&) {
10610  cimg::exception_mode() = omode;
10611  CImg<T> values(width,height,depth,dim);
10612  values = expression;
10613  *this-=values;
10614  }
10615  cimg::exception_mode() = omode;
10616  return *this;
10617  }
10618 
10620  template<typename t>
10621  CImg<T>& operator-=(const CImg<t>& img) {
10622  const unsigned int siz = size(), isiz = img.size();
10623  if (siz && isiz) {
10624  if (is_overlapped(img)) return *this-=+img;
10625  T *ptrd = data, *const ptrd_end = data + siz;
10626  if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
10627  for (const t *ptrs = img.data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd - *(ptrs++));
10628  for (const t *ptrs = img.data; ptrd<ptrd_end; ++ptrd) *ptrd = (T)(*ptrd - *(ptrs++));
10629  }
10630  return *this;
10631  }
10632 
10635  cimg_for(*this,ptr,T) *ptr = *ptr-(T)1;
10636  return *this;
10637  }
10638 
10641  const CImg<T> copy(*this,false);
10642  --*this;
10643  return copy;
10644  }
10645 
10647  CImg<T> operator-() const {
10648  return CImg<T>(width,height,depth,dim,(T)0)-=*this;
10649  }
10650 
10652  template<typename t>
10653  CImg<_cimg_Tt> operator-(const t val) const {
10654  return CImg<_cimg_Tt>(*this,false)-=val;
10655  }
10656 
10658  CImg<Tfloat> operator-(const char *const expression) const {
10659  return CImg<Tfloat>(*this,false)-=expression;
10660  }
10661 
10663  template<typename t>
10664  CImg<_cimg_Tt> operator-(const CImg<t>& img) const {
10665  return CImg<_cimg_Tt>(*this,false)-=img;
10666  }
10667 
10669  template<typename t>
10670  CImg<T>& operator*=(const t val) {
10671  cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)*val);
10672  return *this;
10673  }
10674 
10676  CImg<T>& operator*=(const char *const expression) {
10677  const unsigned int omode = cimg::exception_mode();
10678  cimg::exception_mode() = 0;
10679  try {
10680  _cimg_math_parser mp(expression,"operator*=");
10681  T *ptrd = data;
10682  cimg_forXYZV(*this,x,y,z,v) { *ptrd = (T)(*ptrd * mp.eval(*this,x,y,z,v)); ++ptrd; }
10683  } catch (CImgException&) {
10684  cimg::exception_mode() = omode;
10685  CImg<Tfloat> values(width,height,depth,dim);
10686  values = expression;
10687  *this*=values;
10688  }
10689  cimg::exception_mode() = omode;
10690  return *this;
10691  }
10692 
10694  template<typename t>
10695  CImg<T>& operator*=(const CImg<t>& img) {
10696  return ((*this)*img).transfer_to(*this);
10697  }
10698 
10700  template<typename t>
10701  CImg<_cimg_Tt> operator*(const t val) const {
10702  return CImg<_cimg_Tt>(*this,false)*=val;
10703  }
10704 
10706  CImg<Tfloat> operator*(const char *const expression) const {
10707  return CImg<Tfloat>(*this,false)*=expression;
10708  }
10709 
10711  template<typename t>
10712  CImg<_cimg_Tt> operator*(const CImg<t>& img) const {
10713  if (width!=img.height || depth!=1 || dim!=1)
10714  throw CImgArgumentException("operator*() : can't multiply a matrix image (%u,%u,%u,%u) by a matrix image (%u,%u,%u,%u)",
10715  width,height,depth,dim,img.width,img.height,img.depth,img.dim);
10716  CImg<_cimg_Tt> res(img.width,height);
10717  _cimg_Tt val;
10718 #ifdef cimg_use_openmp
10719 #pragma omp parallel for if (size()>=1000 && img.size()>=1000) private(val)
10720 #endif
10721  cimg_forXY(res,i,j) { val = 0; cimg_forX(*this,k) val+=(*this)(k,j)*img(i,k); res(i,j) = val; }
10722  return res;
10723  }
10724 
10726  template<typename t>
10727  CImg<T>& operator/=(const t val) {
10728  cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)/val);
10729  return *this;
10730  }
10731 
10733  CImg<T>& operator/=(const char *const expression) {
10734  const unsigned int omode = cimg::exception_mode();
10735  cimg::exception_mode() = 0;
10736  try {
10737  _cimg_math_parser mp(expression,"operator/=");
10738  T *ptrd = data;
10739  cimg_forXYZV(*this,x,y,z,v) { *ptrd = (T)(*ptrd / mp.eval(*this,x,y,z,v)); ++ptrd; }
10740  } catch (CImgException&) {
10741  cimg::exception_mode() = omode;
10742  CImg<Tfloat> values(width,height,depth,dim);
10743  values = expression;
10744  *this/=values;
10745  }
10746  cimg::exception_mode() = omode;
10747  return *this;
10748  }
10749 
10751  template<typename t>
10752  CImg<T>& operator/=(const CImg<t>& img) {
10753  return (*this*img.get_invert()).transfer_to(*this);
10754  }
10755 
10757  template<typename t>
10758  CImg<_cimg_Tt> operator/(const t val) const {
10759  return CImg<_cimg_Tt>(*this,false)/=val;
10760  }
10761 
10763  CImg<Tfloat> operator/(const char *const expression) const {
10764  return CImg<Tfloat>(*this,false)/=expression;
10765  }
10766 
10768  template<typename t>
10769  CImg<_cimg_Tt> operator/(const CImg<t>& img) const {
10770  return (*this)*img.get_invert();
10771  }
10772 
10774  template<typename t>
10775  CImg<T>& operator%=(const t val) {
10776  cimg_for(*this,ptr,T) (*ptr) = (T)cimg::mod(*ptr,(T)val);
10777  return *this;
10778  }
10779 
10781  CImg<T>& operator%=(const char *const expression) {
10782  const unsigned int omode = cimg::exception_mode();
10783  cimg::exception_mode() = 0;
10784  try {
10785  _cimg_math_parser mp(expression,"operator%=");
10786  T *ptrd = data;
10787  cimg_forXYZV(*this,x,y,z,v) { *ptrd = (T)cimg::mod(*ptrd,(T)mp.eval(*this,x,y,z,v)); ++ptrd; }
10788  } catch (CImgException&) {
10789  cimg::exception_mode() = omode;
10790  CImg<T> values(width,height,depth,dim);
10791  values = expression;
10792  *this%=values;
10793  }
10794  cimg::exception_mode() = omode;
10795  return *this;
10796  }
10797 
10799  template<typename t>
10800  CImg<T>& operator%=(const CImg<t>& img) {
10801  const unsigned int siz = size(), isiz = img.size();
10802  if (siz && isiz) {
10803  if (is_overlapped(img)) return *this%=+img;
10804  T *ptrd = data, *const ptrd_end = data + siz;
10805  if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
10806  for (const t *ptrs = img.data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = cimg::mod(*ptrd,(T)*(ptrs++));
10807  for (const t *ptrs = img.data; ptrd<ptrd_end; ++ptrd) *ptrd = cimg::mod(*ptrd,(T)*(ptrs++));
10808  }
10809  return *this;
10810  }
10811 
10813  template<typename t>
10814  CImg<_cimg_Tt> operator%(const t val) const {
10815  return CImg<_cimg_Tt>(*this,false)%=val;
10816  }
10817 
10819  CImg<Tfloat> operator%(const char *const expression) const {
10820  return CImg<Tfloat>(*this,false)%=expression;
10821  }
10822 
10824  template<typename t>
10825  CImg<_cimg_Tt> operator%(const CImg<t>& img) const {
10826  return CImg<_cimg_Tt>(*this,false)%=img;
10827  }
10828 
10830  template<typename t>
10831  CImg<T>& operator&=(const t val) {
10832  cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr & (unsigned long)val);
10833  return *this;
10834  }
10835 
10837  CImg<T>& operator&=(const char *const expression) {
10838  const unsigned int omode = cimg::exception_mode();
10839  cimg::exception_mode() = 0;
10840  try {
10841  _cimg_math_parser mp(expression,"operator&=");
10842  T *ptrd = data;
10843  cimg_forXYZV(*this,x,y,z,v) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)mp.eval(*this,x,y,z,v)); ++ptrd; }
10844  } catch (CImgException&) {
10845  cimg::exception_mode() = omode;
10846  CImg<T> values(width,height,depth,dim);
10847  values = expression;
10848  *this&=values;
10849  }
10850  cimg::exception_mode() = omode;
10851  return *this;
10852  }
10853 
10855  template<typename t>
10856  CImg<T>& operator&=(const CImg<t>& img) {
10857  const unsigned int siz = size(), isiz = img.size();
10858  if (siz && isiz) {
10859  if (is_overlapped(img)) return *this&=+img;
10860  T *ptrd = data, *const ptrd_end = data + siz;
10861  if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
10862  for (const t *ptrs = img.data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)*(ptrs++));
10863  for (const t *ptrs = img.data; ptrd<ptrd_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)*(ptrs++));
10864  }
10865  return *this;
10866  }
10867 
10869  template<typename t>
10870  CImg<T> operator&(const t val) const {
10871  return (+*this)&=val;
10872  }
10873 
10875  template<typename t>
10876  CImg<T>& operator|=(const t val) {
10877  cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr | (unsigned long)val);
10878  return *this;
10879  }
10880 
10882  CImg<T>& operator|=(const char *const expression) {
10883  const unsigned int omode = cimg::exception_mode();
10884  cimg::exception_mode() = 0;
10885  try {
10886  _cimg_math_parser mp(expression,"operator|=");
10887  T *ptrd = data;
10888  cimg_forXYZV(*this,x,y,z,v) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)mp.eval(*this,x,y,z,v)); ++ptrd; }
10889  } catch (CImgException&) {
10890  cimg::exception_mode() = omode;
10891  CImg<T> values(width,height,depth,dim);
10892  values = expression;
10893  *this|=values;
10894  }
10895  cimg::exception_mode() = omode;
10896  return *this;
10897  }
10898 
10900  template<typename t>
10901  CImg<T>& operator|=(const CImg<t>& img) {
10902  const unsigned int siz = size(), isiz = img.size();
10903  if (siz && isiz) {
10904  if (is_overlapped(img)) return *this|=+img;
10905  T *ptrd = data, *const ptrd_end = data + siz;
10906  if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
10907  for (const t *ptrs = img.data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)*(ptrs++));
10908  for (const t *ptrs = img.data; ptrd<ptrd_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)*(ptrs++));
10909  }
10910  return *this;
10911  }
10912 
10914  template<typename t>
10915  CImg<T> operator|(const t val) const {
10916  return (+*this)|=val;
10917  }
10918 
10920  template<typename t>
10921  CImg<T>& operator^=(const t val) {
10922  cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr ^ (unsigned long)val);
10923  return *this;
10924  }
10925 
10927  CImg<T>& operator^=(const char *const expression) {
10928  const unsigned int omode = cimg::exception_mode();
10929  cimg::exception_mode() = 0;
10930  try {
10931  _cimg_math_parser mp(expression,"operator^=");
10932  T *ptrd = data;
10933  cimg_forXYZV(*this,x,y,z,v) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)mp.eval(*this,x,y,z,v)); ++ptrd; }
10934  } catch (CImgException&) {
10935  cimg::exception_mode() = omode;
10936  CImg<T> values(width,height,depth,dim);
10937  values = expression;
10938  *this^=values;
10939  }
10940  cimg::exception_mode() = omode;
10941  return *this;
10942  }
10943 
10945  template<typename t>
10946  CImg<T>& operator^=(const CImg<t>& img) {
10947  const unsigned int siz = size(), isiz = img.size();
10948  if (siz && isiz) {
10949  if (is_overlapped(img)) return *this^=+img;
10950  T *ptrd = data, *const ptrd_end = data + siz;
10951  if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
10952  for (const t *ptrs = img.data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)*(ptrs++));
10953  for (const t *ptrs = img.data; ptrd<ptrd_end; ++ptrd) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)*(ptrs++));
10954  }
10955  return *this;
10956  }
10957 
10959  template<typename t>
10960  CImg<T> operator^(const t val) const {
10961  return (+*this)^=val;
10962  }
10963 
10965  CImg<T> operator~() const {
10966  CImg<T> res(width,height,depth,dim);
10967  const T *ptrs = end();
10968  cimg_for(res,ptrd,T) { const unsigned long val = (unsigned long)*(--ptrs); *ptrd = (T)~val; }
10969  return res;
10970  }
10971 
10973  CImg<T>& operator<<=(const int n) {
10974  cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)<<n);
10975  return *this;
10976  }
10977 
10979  CImg<T> operator<<(const int n) const {
10980  return (+*this)<<=n;
10981  }
10982 
10984  CImg<T>& operator>>=(const int n) {
10985  cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)>>n);
10986  return *this;
10987  }
10988 
10990  CImg<T> operator>>(const int n) const {
10991  return (+*this)>>=n;
10992  }
10993 
10995  template<typename t>
10996  bool operator==(const CImg<t>& img) const {
10997  const unsigned int siz = size();
10998  bool vequal = true;
10999  if (siz!=img.size()) return false;
11000  t *ptrs = img.data + siz;
11001  for (T *ptrd = data + siz; vequal && ptrd>data; vequal = vequal && ((*(--ptrd))==(*(--ptrs)))) {}
11002  return vequal;
11003  }
11004 
11006  template<typename t>
11007  bool operator!=(const CImg<t>& img) const {
11008  return !((*this)==img);
11009  }
11010 
11012  template<typename t>
11014  return CImgList<_cimg_Tt>(*this,img);
11015  }
11016 
11018  template<typename t>
11020  return CImgList<_cimg_Tt>(list).insert(*this,0);
11021  }
11022 
11024  CImgList<T> operator<(const char axis) const {
11025  return get_split(axis);
11026  }
11027 
11029  //-------------------------------------
11030  //
11032 
11033  //-------------------------------------
11034 
11036 
11041  static const char* pixel_type() {
11042  return cimg::type<T>::string();
11043  }
11044 
11046  int dimx() const {
11047  return (int)width;
11048  }
11049 
11051  int dimy() const {
11052  return (int)height;
11053  }
11054 
11056  int dimz() const {
11057  return (int)depth;
11058  }
11059 
11061  int dimv() const {
11062  return (int)dim;
11063  }
11064 
11066 
11075  unsigned int size() const {
11076  return width*height*depth*dim;
11077  }
11078 
11080  T* ptr() {
11081  return data;
11082  }
11083 
11084  const T* ptr() const {
11085  return data;
11086  }
11087 
11089 
11106 #if cimg_debug>=3
11107  T *ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
11108  const unsigned int off = (unsigned int)offset(x,y,z,v);
11109  if (off>=size()) {
11110  cimg::warn("CImg<%s>::ptr() : Asked for a pointer at coordinates (%u,%u,%u,%u) (offset=%u), "
11111  "outside image range (%u,%u,%u,%u) (size=%u)",
11112  pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
11113  return data;
11114  }
11115  return data + off;
11116  }
11117 
11118  const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
11119  return const_cast<CImg<T>*>(this)->ptr(x,y,z,v);
11120  }
11121 #else
11122  T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
11123  return data + x + y*width + z*width*height + v*width*height*depth;
11124  }
11125 
11126  const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
11127  return data + x + y*width + z*width*height + v*width*height*depth;
11128  }
11129 #endif
11130 
11132 
11147  int offset(const int x, const int y=0, const int z=0, const int v=0) const {
11148  return x + y*width + z*width*height + v*width*height*depth;
11149  }
11150 
11153  return data;
11154  }
11155 
11157  return data;
11158  }
11159 
11162  return data + size();
11163  }
11164 
11166  return data + size();
11167  }
11168 
11170  const T& front() const {
11171  return *data;
11172  }
11173 
11174  T& front() {
11175  return *data;
11176  }
11177 
11179  const T& back() const {
11180  return *(data + size() - 1);
11181  }
11182 
11183  T& back() {
11184  return *(data + size() - 1);
11185  }
11186 
11188  T& at(const int off, const T out_val) {
11189  return (off<0 || off>=(int)size())?(cimg::temporary(out_val)=out_val):(*this)[off];
11190  }
11191 
11192  T at(const int off, const T out_val) const {
11193  return (off<0 || off>=(int)size())?out_val:(*this)[off];
11194  }
11195 
11197  T& at(const int off) {
11198  if (!size())
11199  throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
11200  pixel_type());
11201  return _at(off);
11202  }
11203 
11204  T at(const int off) const {
11205  if (!size())
11206  throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
11207  pixel_type());
11208  return _at(off);
11209  }
11210 
11211  T& _at(const int off) {
11212  const unsigned int siz = (unsigned int)size();
11213  return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
11214  }
11215 
11216  T _at(const int off) const {
11217  const unsigned int siz = (unsigned int)size();
11218  return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
11219  }
11220 
11222  T& atXYZV(const int x, const int y, const int z, const int v, const T out_val) {
11223  return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?
11224  (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11225  }
11226 
11227  T atXYZV(const int x, const int y, const int z, const int v, const T out_val) const {
11228  return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v);
11229  }
11230 
11232  T& atXYZV(const int x, const int y, const int z, const int v) {
11233  if (is_empty())
11234  throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
11235  pixel_type());
11236  return _atXYZV(x,y,z,v);
11237  }
11238 
11239  T atXYZV(const int x, const int y, const int z, const int v) const {
11240  if (is_empty())
11241  throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
11242  pixel_type());
11243  return _atXYZV(x,y,z,v);
11244  }
11245 
11246  T& _atXYZV(const int x, const int y, const int z, const int v) {
11247  return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
11248  z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
11249  }
11250 
11251  T _atXYZV(const int x, const int y, const int z, const int v) const {
11252  return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
11253  z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
11254  }
11255 
11257  T& atXYZ(const int x, const int y, const int z, const int v, const T out_val) {
11258  return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?
11259  (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11260  }
11261 
11262  T atXYZ(const int x, const int y, const int z, const int v, const T out_val) const {
11263  return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v);
11264  }
11265 
11267  T& atXYZ(const int x, const int y, const int z, const int v=0) {
11268  if (is_empty())
11269  throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
11270  pixel_type());
11271  return _atXYZ(x,y,z,v);
11272  }
11273 
11274  T atXYZ(const int x, const int y, const int z, const int v=0) const {
11275  if (is_empty())
11276  throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
11277  pixel_type());
11278  return _atXYZ(x,y,z,v);
11279  }
11280 
11281  T& _atXYZ(const int x, const int y, const int z, const int v=0) {
11282  return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
11283  z<0?0:(z>=dimz()?dimz()-1:z),v);
11284  }
11285 
11286  T _atXYZ(const int x, const int y, const int z, const int v=0) const {
11287  return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
11288  z<0?0:(z>=dimz()?dimz()-1:z),v);
11289  }
11290 
11292  T& atXY(const int x, const int y, const int z, const int v, const T out_val) {
11293  return (x<0 || y<0 || x>=dimx() || y>=dimy())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11294  }
11295 
11296  T atXY(const int x, const int y, const int z, const int v, const T out_val) const {
11297  return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v);
11298  }
11299 
11301  T& atXY(const int x, const int y, const int z=0, const int v=0) {
11302  if (is_empty())
11303  throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
11304  pixel_type());
11305  return _atXY(x,y,z,v);
11306  }
11307 
11308  T atXY(const int x, const int y, const int z=0, const int v=0) const {
11309  if (is_empty())
11310  throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
11311  pixel_type());
11312  return _atXY(x,y,z,v);
11313  }
11314 
11315  T& _atXY(const int x, const int y, const int z=0, const int v=0) {
11316  return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
11317  }
11318 
11319  T _atXY(const int x, const int y, const int z=0, const int v=0) const {
11320  return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
11321  }
11322 
11324  T& atX(const int x, const int y, const int z, const int v, const T out_val) {
11325  return (x<0 || x>=dimx())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11326  }
11327 
11328  T atX(const int x, const int y, const int z, const int v, const T out_val) const {
11329  return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v);
11330  }
11331 
11333  T& atX(const int x, const int y=0, const int z=0, const int v=0) {
11334  if (is_empty())
11335  throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
11336  pixel_type());
11337  return _atX(x,y,z,v);
11338  }
11339 
11340  T atX(const int x, const int y=0, const int z=0, const int v=0) const {
11341  if (is_empty())
11342  throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
11343  pixel_type());
11344  return _atX(x,y,z,v);
11345  }
11346 
11347  T& _atX(const int x, const int y=0, const int z=0, const int v=0) {
11348  return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
11349  }
11350 
11351  T _atX(const int x, const int y=0, const int z=0, const int v=0) const {
11352  return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
11353  }
11354 
11356  Tfloat linear_atXYZV(const float fx, const float fy, const float fz, const float fv, const T out_val) const {
11357  const int
11358  x = (int)fx-(fx>=0?0:1), nx = x+1,
11359  y = (int)fy-(fy>=0?0:1), ny = y+1,
11360  z = (int)fz-(fz>=0?0:1), nz = z+1,
11361  v = (int)fv-(fv>=0?0:1), nv = v+1;
11362  const float
11363  dx = fx-x,
11364  dy = fy-y,
11365  dz = fz-z,
11366  dv = fv-v;
11367  const Tfloat
11368  Icccc = (Tfloat)atXYZV(x,y,z,v,out_val), Inccc = (Tfloat)atXYZV(nx,y,z,v,out_val),
11369  Icncc = (Tfloat)atXYZV(x,ny,z,v,out_val), Inncc = (Tfloat)atXYZV(nx,ny,z,v,out_val),
11370  Iccnc = (Tfloat)atXYZV(x,y,nz,v,out_val), Incnc = (Tfloat)atXYZV(nx,y,nz,v,out_val),
11371  Icnnc = (Tfloat)atXYZV(x,ny,nz,v,out_val), Innnc = (Tfloat)atXYZV(nx,ny,nz,v,out_val),
11372  Icccn = (Tfloat)atXYZV(x,y,z,nv,out_val), Inccn = (Tfloat)atXYZV(nx,y,z,nv,out_val),
11373  Icncn = (Tfloat)atXYZV(x,ny,z,nv,out_val), Inncn = (Tfloat)atXYZV(nx,ny,z,nv,out_val),
11374  Iccnn = (Tfloat)atXYZV(x,y,nz,nv,out_val), Incnn = (Tfloat)atXYZV(nx,y,nz,nv,out_val),
11375  Icnnn = (Tfloat)atXYZV(x,ny,nz,nv,out_val), Innnn = (Tfloat)atXYZV(nx,ny,nz,nv,out_val);
11376  return Icccc +
11377  dx*(Inccc-Icccc +
11378  dy*(Icccc+Inncc-Icncc-Inccc +
11379  dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
11380  dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
11381  dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
11382  dz*(Icccc+Incnc-Iccnc-Inccc +
11383  dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
11384  dv*(Icccc+Inccn-Inccc-Icccn)) +
11385  dy*(Icncc-Icccc +
11386  dz*(Icccc+Icnnc-Iccnc-Icncc +
11387  dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
11388  dv*(Icccc+Icncn-Icncc-Icccn)) +
11389  dz*(Iccnc-Icccc +
11390  dv*(Icccc+Iccnn-Iccnc-Icccn)) +
11391  dv*(Icccn-Icccc);
11392  }
11393 
11395  Tfloat linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
11396  if (is_empty())
11397  throw CImgInstanceException("CImg<%s>::linear_atXYZV() : Instance image is empty.",
11398  pixel_type());
11399  return _linear_atXYZV(fx,fy,fz,fv);
11400  }
11401 
11402  Tfloat _linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
11403  const float
11404  nfx = fx<0?0:(fx>width-1?width-1:fx),
11405  nfy = fy<0?0:(fy>height-1?height-1:fy),
11406  nfz = fz<0?0:(fz>depth-1?depth-1:fz),
11407  nfv = fv<0?0:(fv>dim-1?dim-1:fv);
11408  const unsigned int
11409  x = (unsigned int)nfx,
11410  y = (unsigned int)nfy,
11411  z = (unsigned int)nfz,
11412  v = (unsigned int)nfv;
11413  const float
11414  dx = nfx-x,
11415  dy = nfy-y,
11416  dz = nfz-z,
11417  dv = nfv-v;
11418  const unsigned int
11419  nx = dx>0?x+1:x,
11420  ny = dy>0?y+1:y,
11421  nz = dz>0?z+1:z,
11422  nv = dv>0?v+1:v;
11423  const Tfloat
11424  Icccc = (Tfloat)(*this)(x,y,z,v), Inccc = (Tfloat)(*this)(nx,y,z,v),
11425  Icncc = (Tfloat)(*this)(x,ny,z,v), Inncc = (Tfloat)(*this)(nx,ny,z,v),
11426  Iccnc = (Tfloat)(*this)(x,y,nz,v), Incnc = (Tfloat)(*this)(nx,y,nz,v),
11427  Icnnc = (Tfloat)(*this)(x,ny,nz,v), Innnc = (Tfloat)(*this)(nx,ny,nz,v),
11428  Icccn = (Tfloat)(*this)(x,y,z,nv), Inccn = (Tfloat)(*this)(nx,y,z,nv),
11429  Icncn = (Tfloat)(*this)(x,ny,z,nv), Inncn = (Tfloat)(*this)(nx,ny,z,nv),
11430  Iccnn = (Tfloat)(*this)(x,y,nz,nv), Incnn = (Tfloat)(*this)(nx,y,nz,nv),
11431  Icnnn = (Tfloat)(*this)(x,ny,nz,nv), Innnn = (Tfloat)(*this)(nx,ny,nz,nv);
11432  return Icccc +
11433  dx*(Inccc-Icccc +
11434  dy*(Icccc+Inncc-Icncc-Inccc +
11435  dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
11436  dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
11437  dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
11438  dz*(Icccc+Incnc-Iccnc-Inccc +
11439  dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
11440  dv*(Icccc+Inccn-Inccc-Icccn)) +
11441  dy*(Icncc-Icccc +
11442  dz*(Icccc+Icnnc-Iccnc-Icncc +
11443  dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
11444  dv*(Icccc+Icncn-Icncc-Icccn)) +
11445  dz*(Iccnc-Icccc +
11446  dv*(Icccc+Iccnn-Iccnc-Icccn)) +
11447  dv*(Icccn-Icccc);
11448  }
11449 
11451  Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int v, const T out_val) const {
11452  const int
11453  x = (int)fx-(fx>=0?0:1), nx = x+1,
11454  y = (int)fy-(fy>=0?0:1), ny = y+1,
11455  z = (int)fz-(fz>=0?0:1), nz = z+1;
11456  const float
11457  dx = fx-x,
11458  dy = fy-y,
11459  dz = fz-z;
11460  const Tfloat
11461  Iccc = (Tfloat)atXYZ(x,y,z,v,out_val), Incc = (Tfloat)atXYZ(nx,y,z,v,out_val),
11462  Icnc = (Tfloat)atXYZ(x,ny,z,v,out_val), Innc = (Tfloat)atXYZ(nx,ny,z,v,out_val),
11463  Iccn = (Tfloat)atXYZ(x,y,nz,v,out_val), Incn = (Tfloat)atXYZ(nx,y,nz,v,out_val),
11464  Icnn = (Tfloat)atXYZ(x,ny,nz,v,out_val), Innn = (Tfloat)atXYZ(nx,ny,nz,v,out_val);
11465  return Iccc +
11466  dx*(Incc-Iccc +
11467  dy*(Iccc+Innc-Icnc-Incc +
11468  dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
11469  dz*(Iccc+Incn-Iccn-Incc)) +
11470  dy*(Icnc-Iccc +
11471  dz*(Iccc+Icnn-Iccn-Icnc)) +
11472  dz*(Iccn-Iccc);
11473  }
11474 
11476  Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
11477  if (is_empty())
11478  throw CImgInstanceException("CImg<%s>::linear_atXYZ() : Instance image is empty.",
11479  pixel_type());
11480  return _linear_atXYZ(fx,fy,fz,v);
11481  }
11482 
11483  Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
11484  const float
11485  nfx = fx<0?0:(fx>width-1?width-1:fx),
11486  nfy = fy<0?0:(fy>height-1?height-1:fy),
11487  nfz = fz<0?0:(fz>depth-1?depth-1:fz);
11488  const unsigned int
11489  x = (unsigned int)nfx,
11490  y = (unsigned int)nfy,
11491  z = (unsigned int)nfz;
11492  const float
11493  dx = nfx-x,
11494  dy = nfy-y,
11495  dz = nfz-z;
11496  const unsigned int
11497  nx = dx>0?x+1:x,
11498  ny = dy>0?y+1:y,
11499  nz = dz>0?z+1:z;
11500  const Tfloat
11501  Iccc = (Tfloat)(*this)(x,y,z,v), Incc = (Tfloat)(*this)(nx,y,z,v),
11502  Icnc = (Tfloat)(*this)(x,ny,z,v), Innc = (Tfloat)(*this)(nx,ny,z,v),
11503  Iccn = (Tfloat)(*this)(x,y,nz,v), Incn = (Tfloat)(*this)(nx,y,nz,v),
11504  Icnn = (Tfloat)(*this)(x,ny,nz,v), Innn = (Tfloat)(*this)(nx,ny,nz,v);
11505  return Iccc +
11506  dx*(Incc-Iccc +
11507  dy*(Iccc+Innc-Icnc-Incc +
11508  dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
11509  dz*(Iccc+Incn-Iccn-Incc)) +
11510  dy*(Icnc-Iccc +
11511  dz*(Iccc+Icnn-Iccn-Icnc)) +
11512  dz*(Iccn-Iccc);
11513  }
11514 
11516  Tfloat linear_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
11517  const int
11518  x = (int)fx-(fx>=0?0:1), nx = x+1,
11519  y = (int)fy-(fy>=0?0:1), ny = y+1;
11520  const float
11521  dx = fx-x,
11522  dy = fy-y;
11523  const Tfloat
11524  Icc = (Tfloat)atXY(x,y,z,v,out_val), Inc = (Tfloat)atXY(nx,y,z,v,out_val),
11525  Icn = (Tfloat)atXY(x,ny,z,v,out_val), Inn = (Tfloat)atXY(nx,ny,z,v,out_val);
11526  return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
11527  }
11528 
11530  Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11531  if (is_empty())
11532  throw CImgInstanceException("CImg<%s>::linear_atXY() : Instance image is empty.",
11533  pixel_type());
11534  return _linear_atXY(fx,fy,z,v);
11535  }
11536 
11537  Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11538  const float
11539  nfx = fx<0?0:(fx>width-1?width-1:fx),
11540  nfy = fy<0?0:(fy>height-1?height-1:fy);
11541  const unsigned int
11542  x = (unsigned int)nfx,
11543  y = (unsigned int)nfy;
11544  const float
11545  dx = nfx-x,
11546  dy = nfy-y;
11547  const unsigned int
11548  nx = dx>0?x+1:x,
11549  ny = dy>0?y+1:y;
11550  const Tfloat
11551  Icc = (Tfloat)(*this)(x,y,z,v), Inc = (Tfloat)(*this)(nx,y,z,v),
11552  Icn = (Tfloat)(*this)(x,ny,z,v), Inn = (Tfloat)(*this)(nx,ny,z,v);
11553  return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
11554  }
11555 
11557  Tfloat linear_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
11558  const int
11559  x = (int)fx-(fx>=0?0:1), nx = x+1;
11560  const float
11561  dx = fx-x;
11562  const Tfloat
11563  Ic = (Tfloat)atX(x,y,z,v,out_val), In = (Tfloat)atXY(nx,y,z,v,out_val);
11564  return Ic + dx*(In-Ic);
11565  }
11566 
11568  Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11569  if (is_empty())
11570  throw CImgInstanceException("CImg<%s>::linear_atX() : Instance image is empty.",
11571  pixel_type());
11572  return _linear_atX(fx,y,z,v);
11573  }
11574 
11575  Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11576  const float
11577  nfx = fx<0?0:(fx>width-1?width-1:fx);
11578  const unsigned int
11579  x = (unsigned int)nfx;
11580  const float
11581  dx = nfx-x;
11582  const unsigned int
11583  nx = dx>0?x+1:x;
11584  const Tfloat
11585  Ic = (Tfloat)(*this)(x,y,z,v), In = (Tfloat)(*this)(nx,y,z,v);
11586  return Ic + dx*(In-Ic);
11587  }
11588 
11590  Tfloat cubic_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
11591  const int
11592  x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2,
11593  y = (int)fy-(fy>=0?0:1), py = y-1, ny = y+1, ay = y+2;
11594  const float
11595  dx = fx-x, dx2 = dx*dx, dx3 = dx2*dx,
11596  dy = fy-y;
11597  const Tfloat
11598  Ipp = (Tfloat)atXY(px,py,z,v,out_val), Icp = (Tfloat)atXY(x,py,z,v,out_val),
11599  Inp = (Tfloat)atXY(nx,py,z,v,out_val), Iap = (Tfloat)atXY(ax,py,z,v,out_val),
11600  Ipc = (Tfloat)atXY(px,y,z,v,out_val), Icc = (Tfloat)atXY(x,y,z,v,out_val),
11601  Inc = (Tfloat)atXY(nx,y,z,v,out_val), Iac = (Tfloat)atXY(ax,y,z,v,out_val),
11602  Ipn = (Tfloat)atXY(px,ny,z,v,out_val), Icn = (Tfloat)atXY(x,ny,z,v,out_val),
11603  Inn = (Tfloat)atXY(nx,ny,z,v,out_val), Ian = (Tfloat)atXY(ax,ny,z,v,out_val),
11604  Ipa = (Tfloat)atXY(px,ay,z,v,out_val), Ica = (Tfloat)atXY(x,ay,z,v,out_val),
11605  Ina = (Tfloat)atXY(nx,ay,z,v,out_val), Iaa = (Tfloat)atXY(ax,ay,z,v,out_val),
11606  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)),
11607  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)),
11608  u0p = Icp - Ipp,
11609  u1p = Iap - Inp,
11610  ap = 2*(Icp-Inp) + u0p + u1p,
11611  bp = 3*(Inp-Icp) - 2*u0p - u1p,
11612  u0c = Icc - Ipc,
11613  u1c = Iac - Inc,
11614  ac = 2*(Icc-Inc) + u0c + u1c,
11615  bc = 3*(Inc-Icc) - 2*u0c - u1c,
11616  u0n = Icn - Ipn,
11617  u1n = Ian - Inn,
11618  an = 2*(Icn-Inn) + u0n + u1n,
11619  bn = 3*(Inn-Icn) - 2*u0n - u1n,
11620  u0a = Ica - Ipa,
11621  u1a = Iaa - Ina,
11622  aa = 2*(Ica-Ina) + u0a + u1a,
11623  ba = 3*(Ina-Ica) - 2*u0a - u1a,
11624  valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
11625  valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
11626  valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
11627  vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
11628  u0 = valc - valp,
11629  u1 = vala - valn,
11630  a = 2*(valc-valn) + u0 + u1,
11631  b = 3*(valn-valc) - 2*u0 - u1,
11632  val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
11633  return val<valm?valm:(val>valM?valM:val);
11634  }
11635 
11637  Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11638  if (is_empty())
11639  throw CImgInstanceException("CImg<%s>::cubic_atXY() : Instance image is empty.",
11640  pixel_type());
11641  return _cubic_atXY(fx,fy,z,v);
11642  }
11643 
11644  Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11645  const float
11646  nfx = fx<0?0:(fx>width-1?width-1:fx),
11647  nfy = fy<0?0:(fy>height-1?height-1:fy);
11648  const int
11649  x = (int)nfx,
11650  y = (int)nfy;
11651  const float
11652  dx = nfx-x, dx2 = dx*dx, dx3 = dx2*dx,
11653  dy = nfy-y;
11654  const int
11655  px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2,
11656  py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=dimy()?dimy()-1:y+2;
11657  const Tfloat
11658  Ipp = (Tfloat)(*this)(px,py,z,v), Icp = (Tfloat)(*this)(x,py,z,v),
11659  Inp = (Tfloat)(*this)(nx,py,z,v), Iap = (Tfloat)(*this)(ax,py,z,v),
11660  Ipc = (Tfloat)(*this)(px,y,z,v), Icc = (Tfloat)(*this)(x,y,z,v),
11661  Inc = (Tfloat)(*this)(nx,y,z,v), Iac = (Tfloat)(*this)(ax,y,z,v),
11662  Ipn = (Tfloat)(*this)(px,ny,z,v), Icn = (Tfloat)(*this)(x,ny,z,v),
11663  Inn = (Tfloat)(*this)(nx,ny,z,v), Ian = (Tfloat)(*this)(ax,ny,z,v),
11664  Ipa = (Tfloat)(*this)(px,ay,z,v), Ica = (Tfloat)(*this)(x,ay,z,v),
11665  Ina = (Tfloat)(*this)(nx,ay,z,v), Iaa = (Tfloat)(*this)(ax,ay,z,v),
11666  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)),
11667  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)),
11668  u0p = Icp - Ipp,
11669  u1p = Iap - Inp,
11670  ap = 2*(Icp-Inp) + u0p + u1p,
11671  bp = 3*(Inp-Icp) - 2*u0p - u1p,
11672  u0c = Icc - Ipc,
11673  u1c = Iac - Inc,
11674  ac = 2*(Icc-Inc) + u0c + u1c,
11675  bc = 3*(Inc-Icc) - 2*u0c - u1c,
11676  u0n = Icn - Ipn,
11677  u1n = Ian - Inn,
11678  an = 2*(Icn-Inn) + u0n + u1n,
11679  bn = 3*(Inn-Icn) - 2*u0n - u1n,
11680  u0a = Ica - Ipa,
11681  u1a = Iaa - Ina,
11682  aa = 2*(Ica-Ina) + u0a + u1a,
11683  ba = 3*(Ina-Ica) - 2*u0a - u1a,
11684  valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
11685  valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
11686  valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
11687  vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
11688  u0 = valc - valp,
11689  u1 = vala - valn,
11690  a = 2*(valc-valn) + u0 + u1,
11691  b = 3*(valn-valc) - 2*u0 - u1,
11692  val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
11693  return val<valm?valm:(val>valM?valM:val);
11694  }
11695 
11697  Tfloat cubic_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
11698  const int
11699  x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2;
11700  const float
11701  dx = fx-x;
11702  const Tfloat
11703  Ip = (Tfloat)atX(px,y,z,v,out_val), Ic = (Tfloat)atX(x,y,z,v,out_val),
11704  In = (Tfloat)atX(nx,y,z,v,out_val), Ia = (Tfloat)atX(ax,y,z,v,out_val),
11705  valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
11706  u0 = Ic - Ip,
11707  u1 = Ia - In,
11708  a = 2*(Ic-In) + u0 + u1,
11709  b = 3*(In-Ic) - 2*u0 - u1,
11710  val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
11711  return val<valm?valm:(val>valM?valM:val);
11712  }
11713 
11715  Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11716  if (is_empty())
11717  throw CImgInstanceException("CImg<%s>::cubic_atX() : Instance image is empty.",
11718  pixel_type());
11719  return _cubic_atX(fx,y,z,v);
11720  }
11721 
11722  Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11723  const float
11724  nfx = fx<0?0:(fx>width-1?width-1:fx);
11725  const int
11726  x = (int)nfx;
11727  const float
11728  dx = nfx-x;
11729  const int
11730  px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2;
11731  const Tfloat
11732  Ip = (Tfloat)(*this)(px,y,z,v), Ic = (Tfloat)(*this)(x,y,z,v),
11733  In = (Tfloat)(*this)(nx,y,z,v), Ia = (Tfloat)(*this)(ax,y,z,v),
11734  valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
11735  u0 = Ic - Ip,
11736  u1 = Ia - In,
11737  a = 2*(Ic-In) + u0 + u1,
11738  b = 3*(In-Ic) - 2*u0 - u1,
11739  val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
11740  return val<valm?valm:(val>valM?valM:val);
11741  }
11742 
11744  CImg& set_linear_atXYZ(const T& val, const float fx, const float fy=0, const float fz=0, const int v=0,
11745  const bool add=false) {
11746  const int
11747  x = (int)fx-(fx>=0?0:1), nx = x+1,
11748  y = (int)fy-(fy>=0?0:1), ny = y+1,
11749  z = (int)fz-(fz>=0?0:1), nz = z+1;
11750  const float
11751  dx = fx-x,
11752  dy = fy-y,
11753  dz = fz-z;
11754  if (v>=0 && v<dimv()) {
11755  if (z>=0 && z<dimz()) {
11756  if (y>=0 && y<dimy()) {
11757  if (x>=0 && x<dimx()) {
11758  const float w1 = (1-dx)*(1-dy)*(1-dz), w2 = add?1:(1-w1);
11759  (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
11760  }
11761  if (nx>=0 && nx<dimx()) {
11762  const float w1 = dx*(1-dy)*(1-dz), w2 = add?1:(1-w1);
11763  (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
11764  }
11765  }
11766  if (ny>=0 && ny<dimy()) {
11767  if (x>=0 && x<dimx()) {
11768  const float w1 = (1-dx)*dy*(1-dz), w2 = add?1:(1-w1);
11769  (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
11770  }
11771  if (nx>=0 && nx<dimx()) {
11772  const float w1 = dx*dy*(1-dz), w2 = add?1:(1-w1);
11773  (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
11774  }
11775  }
11776  }
11777  if (nz>=0 && nz<dimz()) {
11778  if (y>=0 && y<dimy()) {
11779  if (x>=0 && x<dimx()) {
11780  const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
11781  (*this)(x,y,nz,v) = (T)(w1*val + w2*(*this)(x,y,nz,v));
11782  }
11783  if (nx>=0 && nx<dimx()) {
11784  const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
11785  (*this)(nx,y,nz,v) = (T)(w1*val + w2*(*this)(nx,y,nz,v));
11786  }
11787  }
11788  if (ny>=0 && ny<dimy()) {
11789  if (x>=0 && x<dimx()) {
11790  const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
11791  (*this)(x,ny,nz,v) = (T)(w1*val + w2*(*this)(x,ny,nz,v));
11792  }
11793  if (nx>=0 && nx<dimx()) {
11794  const float w1 = dx*dy, w2 = add?1:(1-w1);
11795  (*this)(nx,ny,nz,v) = (T)(w1*val + w2*(*this)(nx,ny,nz,v));
11796  }
11797  }
11798  }
11799  }
11800  return *this;
11801  }
11802 
11804  CImg& set_linear_atXY(const T& val, const float fx, const float fy=0, const int z=0, const int v=0,
11805  const bool add=false) {
11806  const int
11807  x = (int)fx-(fx>=0?0:1), nx = x+1,
11808  y = (int)fy-(fy>=0?0:1), ny = y+1;
11809  const float
11810  dx = fx-x,
11811  dy = fy-y;
11812  if (z>=0 && z<dimz() && v>=0 && v<dimv()) {
11813  if (y>=0 && y<dimy()) {
11814  if (x>=0 && x<dimx()) {
11815  const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
11816  (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
11817  }
11818  if (nx>=0 && nx<dimx()) {
11819  const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
11820  (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
11821  }
11822  }
11823  if (ny>=0 && ny<dimy()) {
11824  if (x>=0 && x<dimx()) {
11825  const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
11826  (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
11827  }
11828  if (nx>=0 && nx<dimx()) {
11829  const float w1 = dx*dy, w2 = add?1:(1-w1);
11830  (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
11831  }
11832  }
11833  }
11834  return *this;
11835  }
11836 
11838  CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
11839  if (is_empty()) return CImg<charT>(1,1,1,1,0);
11840  const unsigned int siz = (unsigned int)size();
11841  CImgList<charT> items;
11842  char item[256] = { 0 };
11843  const T *ptrs = ptr();
11844  for (unsigned int off = 0; off<siz-1; ++off) {
11845  std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*(ptrs++)));
11846  const unsigned int l = std::strlen(item);
11847  CImg<charT>(item,l+1).transfer_to(items).back()[l] = separator;
11848  }
11849  std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*ptrs));
11850  CImg<charT>(item,std::strlen(item)+1).transfer_to(items);
11851  CImg<ucharT> res; (items>'x').transfer_to(res);
11852  if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
11853  return res;
11854  }
11855 
11857  //-------------------------------------
11858  //
11860 
11861  //-------------------------------------
11862 
11864  bool is_empty() const {
11865  return !(data && width && height && depth && dim);
11866  }
11867 
11869  bool is_sameX(const unsigned int dx) const {
11870  return (width==dx);
11871  }
11872 
11874  template<typename t>
11875  bool is_sameX(const CImg<t>& img) const {
11876  return is_sameX(img.width);
11877  }
11878 
11880  bool is_sameX(const CImgDisplay& disp) const {
11881  return is_sameX(disp.width);
11882  }
11883 
11885  bool is_sameY(const unsigned int dy) const {
11886  return (height==dy);
11887  }
11888 
11890  template<typename t>
11891  bool is_sameY(const CImg<t>& img) const {
11892  return is_sameY(img.height);
11893  }
11894 
11896  bool is_sameY(const CImgDisplay& disp) const {
11897  return is_sameY(disp.height);
11898  }
11899 
11901  bool is_sameZ(const unsigned int dz) const {
11902  return (depth==dz);
11903  }
11904 
11906  template<typename t>
11907  bool is_sameZ(const CImg<t>& img) const {
11908  return is_sameZ(img.depth);
11909  }
11910 
11912  bool is_sameV(const unsigned int dv) const {
11913  return (dim==dv);
11914  }
11915 
11917  template<typename t>
11918  bool is_sameV(const CImg<t>& img) const {
11919  return is_sameV(img.dim);
11920  }
11921 
11923  bool is_sameXY(const unsigned int dx, const unsigned int dy) const {
11924  return (is_sameX(dx) && is_sameY(dy));
11925  }
11926 
11928  template<typename t>
11929  bool is_sameXY(const CImg<t>& img) const {
11930  return (is_sameX(img) && is_sameY(img));
11931  }
11932 
11934  bool is_sameXY(const CImgDisplay& disp) const {
11935  return (is_sameX(disp) && is_sameY(disp));
11936  }
11937 
11939  bool is_sameXZ(const unsigned int dx, const unsigned int dz) const {
11940  return (is_sameX(dx) && is_sameZ(dz));
11941  }
11942 
11944  template<typename t>
11945  bool is_sameXZ(const CImg<t>& img) const {
11946  return (is_sameX(img) && is_sameZ(img));
11947  }
11948 
11950  bool is_sameXV(const unsigned int dx, const unsigned int dv) const {
11951  return (is_sameX(dx) && is_sameV(dv));
11952  }
11953 
11955  template<typename t>
11956  bool is_sameXV(const CImg<t>& img) const {
11957  return (is_sameX(img) && is_sameV(img));
11958  }
11959 
11961  bool is_sameYZ(const unsigned int dy, const unsigned int dz) const {
11962  return (is_sameY(dy) && is_sameZ(dz));
11963  }
11964 
11966  template<typename t>
11967  bool is_sameYZ(const CImg<t>& img) const {
11968  return (is_sameY(img) && is_sameZ(img));
11969  }
11970 
11972  bool is_sameYV(const unsigned int dy, const unsigned int dv) const {
11973  return (is_sameY(dy) && is_sameV(dv));
11974  }
11975 
11977  template<typename t>
11978  bool is_sameYV(const CImg<t>& img) const {
11979  return (is_sameY(img) && is_sameV(img));
11980  }
11981 
11983  bool is_sameZV(const unsigned int dz, const unsigned int dv) const {
11984  return (is_sameZ(dz) && is_sameV(dv));
11985  }
11986 
11988  template<typename t>
11989  bool is_sameZV(const CImg<t>& img) const {
11990  return (is_sameZ(img) && is_sameV(img));
11991  }
11992 
11994  bool is_sameXYZ(const unsigned int dx, const unsigned int dy, const unsigned int dz) const {
11995  return (is_sameXY(dx,dy) && is_sameZ(dz));
11996  }
11997 
11999  template<typename t>
12000  bool is_sameXYZ(const CImg<t>& img) const {
12001  return (is_sameXY(img) && is_sameZ(img));
12002  }
12003 
12005  bool is_sameXYV(const unsigned int dx, const unsigned int dy, const unsigned int dv) const {
12006  return (is_sameXY(dx,dy) && is_sameV(dv));
12007  }
12008 
12010  template<typename t>
12011  bool is_sameXYV(const CImg<t>& img) const {
12012  return (is_sameXY(img) && is_sameV(img));
12013  }
12014 
12016  bool is_sameXZV(const unsigned int dx, const unsigned int dz, const unsigned int dv) const {
12017  return (is_sameXZ(dx,dz) && is_sameV(dv));
12018  }
12019 
12021  template<typename t>
12022  bool is_sameXZV(const CImg<t>& img) const {
12023  return (is_sameXZ(img) && is_sameV(img));
12024  }
12025 
12027  bool is_sameYZV(const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
12028  return (is_sameYZ(dy,dz) && is_sameV(dv));
12029  }
12030 
12032  template<typename t>
12033  bool is_sameYZV(const CImg<t>& img) const {
12034  return (is_sameYZ(img) && is_sameV(img));
12035  }
12036 
12038  bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
12039  return (is_sameXYZ(dx,dy,dz) && is_sameV(dv));
12040  }
12041 
12043  template<typename t>
12044  bool is_sameXYZV(const CImg<t>& img) const {
12045  return (is_sameXYZ(img) && is_sameV(img));
12046  }
12047 
12049  bool containsXYZV(const int x, const int y=0, const int z=0, const int v=0) const {
12050  return !is_empty() && x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz() && v>=0 && v<dimv();
12051  }
12052 
12054  template<typename t>
12055  bool contains(const T& pixel, t& x, t& y, t& z, t& v) const {
12056  const unsigned int wh = width*height, whz = wh*depth, siz = whz*dim;
12057  const T *const ppixel = &pixel;
12058  if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
12059  unsigned int off = (unsigned int)(ppixel - data);
12060  const unsigned int nv = off/whz;
12061  off%=whz;
12062  const unsigned int nz = off/wh;
12063  off%=wh;
12064  const unsigned int ny = off/width, nx = off%width;
12065  x = (t)nx; y = (t)ny; z = (t)nz; v = (t)nv;
12066  return true;
12067  }
12068 
12070  template<typename t>
12071  bool contains(const T& pixel, t& x, t& y, t& z) const {
12072  const unsigned int wh = width*height, whz = wh*depth, siz = whz*dim;
12073  const T *const ppixel = &pixel;
12074  if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
12075  unsigned int off = ((unsigned int)(ppixel - data))%whz;
12076  const unsigned int nz = off/wh;
12077  off%=wh;
12078  const unsigned int ny = off/width, nx = off%width;
12079  x = (t)nx; y = (t)ny; z = (t)nz;
12080  return true;
12081  }
12082 
12084  template<typename t>
12085  bool contains(const T& pixel, t& x, t& y) const {
12086  const unsigned int wh = width*height, siz = wh*depth*dim;
12087  const T *const ppixel = &pixel;
12088  if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
12089  unsigned int off = ((unsigned int)(ppixel - data))%wh;
12090  const unsigned int ny = off/width, nx = off%width;
12091  x = (t)nx; y = (t)ny;
12092  return true;
12093  }
12094 
12096  template<typename t>
12097  bool contains(const T& pixel, t& x) const {
12098  const T *const ppixel = &pixel;
12099  if (is_empty() || ppixel<data || ppixel>=data+size()) return false;
12100  x = (t)(((unsigned int)(ppixel - data))%width);
12101  return true;
12102  }
12103 
12105  bool contains(const T& pixel) const {
12106  const T *const ppixel = &pixel;
12107  return !is_empty() && ppixel>=data && ppixel<data+size();
12108  }
12109 
12111 
12114  template<typename t>
12115  bool is_overlapped(const CImg<t>& img) const {
12116  const unsigned int csiz = size(), isiz = img.size();
12117  return !((void*)(data+csiz)<=(void*)img.data || (void*)data>=(void*)(img.data+isiz));
12118  }
12119 
12121  template<typename tf>
12122  bool is_object3d(const CImgList<tf>& primitives, const bool check_primitives=true,
12123  const bool throw_exception=false, const char *const calling_function=0) const {
12124  const char *const ncall = calling_function?calling_function:"is_object3d";
12125  if (is_empty()) { // Check for empty object.
12126  if (primitives) {
12127  if (throw_exception)
12128  throw CImgArgumentException("CImg<%s>::%s() : Invalid 3D object, %u primitives defined for 0 vertices.",
12129  pixel_type(),ncall,primitives.width);
12130  return false;
12131  }
12132  return true;
12133  }
12134  if (height!=3 || depth>1 || dim>1) { // Check vertices dimensions.
12135  if (throw_exception)
12136  throw CImgArgumentException("CImg<%s>::%s() : Invalid 3D object, image (%u,%u,%u,%u,%p) is not a set of 3D vertices.",
12137  pixel_type(),ncall,width,height,depth,dim,data);
12138  return false;
12139  }
12140  if (check_primitives) cimglist_for(primitives,l) {
12141  const CImg<tf>& primitive = primitives[l];
12142  const unsigned int psiz = primitive.size();
12143  switch (psiz) {
12144  case 1 : { // Point.
12145  const unsigned int i0 = (unsigned int)primitive[0];
12146  if (i0>=width) {
12147  if (throw_exception)
12148  throw CImgArgumentException("CImg<%s>::%s() : Invalid 3D object, primitive %u = point(%u) references invalid vertice "
12149  "(%u vertices available).",pixel_type(),ncall,l,i0,width);
12150  return false;
12151  }
12152  } break;
12153  case 5 : { // Sphere.
12154  const unsigned int
12155  i0 = (unsigned int)primitive(0),
12156  i1 = (unsigned int)primitive(1),
12157  i2 = (unsigned int)primitive(2);
12158  if (i0>=width || (!i2 && i1>=width)) {
12159  if (throw_exception)
12160  throw CImgArgumentException("CImg<%s>::%s() : Invalid 3D object, primitive %u = sphere(%u,%u,%u) references invalid vertice "
12161  "(%u vertices available).",pixel_type(),ncall,l,i0,i1,i2,width);
12162  return false;
12163  }
12164  } break;
12165  case 2 : // Segment.
12166  case 6 : {
12167  const unsigned int
12168  i0 = (unsigned int)primitive(0),
12169  i1 = (unsigned int)primitive(1);
12170  if (i0>=width || i1>=width) {
12171  if (throw_exception)
12172  throw CImgArgumentException("CImg<%s>::%s() : Invalid 3D object, primitive %u = segment(%u,%u) references invalid vertice "
12173  "(%u vertices available).",pixel_type(),ncall,l,i0,i1,width);
12174  return false;
12175  }
12176  } break;
12177  case 3 : // Triangle.
12178  case 9 : {
12179  const unsigned int
12180  i0 = (unsigned int)primitive(0),
12181  i1 = (unsigned int)primitive(1),
12182  i2 = (unsigned int)primitive(2);
12183  if (i0>=width || i1>=width || i2>=width) {
12184  if (throw_exception)
12185  throw CImgArgumentException("CImg<%s>::%s() : Invalid 3D object, primitive %u = triangle(%u,%u,%u) references invalid vertice "
12186  "(%u vertices available).",pixel_type(),ncall,l,i0,i1,i2,width);
12187  return false;
12188  }
12189  } break;
12190  case 4 : // Rectangle
12191  case 12 : {
12192  const unsigned int
12193  i0 = (unsigned int)primitive(0),
12194  i1 = (unsigned int)primitive(1),
12195  i2 = (unsigned int)primitive(2),
12196  i3 = (unsigned int)primitive(3);
12197  if (i0>=width || i1>=width || i2>=width || i3>=width) {
12198  if (throw_exception)
12199  throw CImgArgumentException("CImg<%s>::%s() : Invalid 3D object, primitive %u = rectangle(%u,%u,%u,%u) references invalid vertice "
12200  "(%u vertices available).",pixel_type(),ncall,l,i0,i1,i2,i3,width);
12201  return false;
12202  }
12203  } break;
12204  default : return false;
12205  }
12206  }
12207  return true;
12208  }
12209 
12211  //-------------------------------------
12212  //
12214 
12215  //-------------------------------------
12216 
12217  // Define the math formula parser/compiler and evaluator.
12221  unsigned int mempos, *level, result;
12222  const char *calling_function;
12223  char *expr;
12224 #define _cimg_freturn(x) { *se = saved_char; return x; }
12225 #define _cimg_fopcode0(op) _cimg_freturn(opcode(op));
12226 #define _cimg_fopcode1(op,i1) _cimg_freturn(opcode(op,i1));
12227 #define _cimg_fopcode2(op,i1,i2) _cimg_freturn(opcode(op,i1,i2));
12228 #define _cimg_fopcode3(op,i1,i2,i3) _cimg_freturn(opcode(op,i1,i2,i3));
12229 #define _cimg_fopcode5(op,i1,i2,i3,i4,i5) _cimg_freturn(opcode(op,i1,i2,i3,i4,i5));
12230 
12231  // Constructor - Destructor.
12232  _cimg_math_parser(const char *const expression, const char *const funcname=0):level(0),calling_function(funcname),expr(0) {
12233  static const char *const funcname0 = "cimg_math_parser";
12234  if (!funcname) calling_function = funcname0;
12235  if (!expression) return;
12236  unsigned int l0 = std::strlen(expression);
12237  expr = new char[l0+1];
12238  std::strcpy(expr,expression);
12240  if (!*expr) return;
12241  char *d = expr; for (const char *s = expr; *s || (bool)(*d=0); ++s) if (*s!=' ') *(d++) = *s;
12242  const unsigned int l = d - expr;
12243  if (!l) return;
12244  cimg::uncase(expr);
12245  int lv = 0; // Count parenthesis level of expression.
12246  unsigned int *pd = level = new unsigned int[l];
12247  for (const char *ps = expr; *ps && lv>=0; ++ps) *(pd++) = (unsigned int)(*ps=='('?lv++:*ps==')'?--lv:lv);
12248  if (lv!=0) throw CImgArgumentException("CImg<%s>::%s() : Unbalanced parenthesis, in formula '%s'.",
12249  pixel_type(),calling_function,expr);
12250  mem.assign(1024); // Compile formula into serie of opcodes.
12251  mem[8] = cimg::valuePI; mem[9] = std::exp(1.0); mem[10] = 0; mempos = 11;
12252  result = compile(expr,expr+l);
12253  }
12254  ~_cimg_math_parser() { if (level) delete[] level; if (expr) delete[] expr; }
12255 
12256  // Insert code instruction.
12257  unsigned int opcode(const char op, const unsigned int arg1=0, const unsigned int arg2=0,
12258  const unsigned int arg3=0, const unsigned int arg4=0, const unsigned int arg5=0) {
12259  if (mempos>=mem.size()) mem.resize(-200,1,1,1,0);
12260  const unsigned int pos = mempos++;
12261  CImg<uintT>::vector(op,pos,arg1,arg2,arg3,arg4,arg5).transfer_to(code);
12262  return pos;
12263  }
12264 
12265  // Compilation procedure.
12266  unsigned int compile(char *const ss, char *const se) {
12267  if (!ss || se<=ss || !*ss) throw CImgArgumentException("CImg<%s>::%s() : Missing item, in formula '%s'.",
12269  char
12270  *const se1 = se-1, *const se2 = se-2, *const se3 = se-3, *const se4 = se-4,
12271  *const ss1 = ss+1, *const ss2 = ss+2, *const ss3 = ss+3, *const ss4 = ss+4, *const ss5 = ss+5, *const ss6 = ss+6;
12272  const char saved_char = *se; *se = 0;
12273  const unsigned int clevel = level[ss-expr], clevel1 = clevel+1;
12274 
12275  // Look for a single value, variable or reccurent expression.
12276  char end = 0; double val = 0;
12277  if (std::sscanf(ss,"%lf%c",&val,&end)==1) {
12278  const unsigned int i = mempos++;
12279  mem[i] = val;
12280  _cimg_freturn(i);
12281  }
12282  if (ss1==se) switch (*ss) {
12283  case 'x' : _cimg_freturn(0); case 'y' : _cimg_freturn(1); case 'z' : _cimg_freturn(2); case 'v' : _cimg_freturn(3);
12284  case 'w' : _cimg_freturn(4); case 'h' : _cimg_freturn(5); case 'd' : _cimg_freturn(6); case 'c' : _cimg_freturn(7);
12285  case 'e' : _cimg_freturn(9);
12286  case 'u' : _cimg_fopcode0('U');
12287  case 'g' : _cimg_fopcode0('G');
12288  case 'i' : _cimg_fopcode0('I');
12289  }
12290  if (ss1==se1 && *ss=='p' && *ss1=='i') _cimg_freturn(8); // pi-value
12291  if (ss3==se) {
12292  if (*ss=='x' && *ss1=='/' && *ss2=='w') _cimg_fopcode0('0');
12293  if (*ss=='y' && *ss1=='/' && *ss2=='h') _cimg_fopcode0('1');
12294  if (*ss=='z' && *ss1=='/' && *ss2=='d') _cimg_fopcode0('2');
12295  if (*ss=='v' && *ss1=='/' && *ss2=='c') _cimg_fopcode0('3');
12296  }
12297 
12298  // Look for a unary of binary operators.
12299  for (char *s = ss1, *ns = 0; s<se3 && (ns=std::strstr(s,"and")) && ns<se3; s=ns+3)
12300  if (level[ns-expr]==clevel) _cimg_fopcode2('A',compile(ss,ns),compile(ns+3,se));
12301  for (char *s = ss1, *ns = 0; s<se2 && (ns=std::strstr(s,"&&")) && ns<se2; s=ns+2)
12302  if (level[ns-expr]==clevel) _cimg_fopcode2('A',compile(ss,ns),compile(ns+2,se));
12303  for (char *s = ss1, *ns = 0; s<se3 && (ns=std::strstr(s,"xor")) && ns<se3; s=ns+3)
12304  if (level[ns-expr]==clevel) _cimg_fopcode2('X',compile(ss,ns),compile(ns+3,se));
12305  for (char *s = ss1, *ns = 0; s<se2 && (ns=std::strstr(s,"or")) && ns<se2; s=ns+2)
12306  if (level[ns-expr]==clevel) _cimg_fopcode2('O',compile(ss,ns),compile(ns+2,se));
12307  for (char *s = ss1, *ns = 0; s<se2 && (ns=std::strstr(s,"||")) && ns<se2; s=ns+2)
12308  if (level[ns-expr]==clevel) _cimg_fopcode2('O',compile(ss,ns),compile(ns+2,se));
12309  for (char *s = ss1, *ns = 0; s<se2 && (ns=std::strstr(s,"<=")) && ns<se2; s=ns+2)
12310  if (level[ns-expr]==clevel) _cimg_fopcode2('l',compile(ss,ns),compile(ns+2,se));
12311  for (char *s = ss1, *ns = 0; s<se2 && (ns=std::strstr(s,">=")) && ns<se2; s=ns+2)
12312  if (level[ns-expr]==clevel) _cimg_fopcode2('g',compile(ss,ns),compile(ns+2,se));
12313  for (char *s = ss1, *ns = 0; s<se2 && (ns=std::strstr(s,"!=")) && ns<se2; s=ns+2)
12314  if (level[ns-expr]==clevel) _cimg_fopcode2('!',compile(ss,ns),compile(ns+2,se));
12315  for (char *s = ss1, *ns = 0; s<se2 && (ns=std::strstr(s,"==")) && ns<se2; s=ns+2)
12316  if (level[ns-expr]==clevel) _cimg_fopcode2('=',compile(ss,ns),compile(ns+2,se));
12317  for (char *s = ss1, *ns = 0; s<se1 && (ns=std::strstr(s,">")) && ns<se1; s=ns+1)
12318  if (level[ns-expr]==clevel) _cimg_fopcode2('>',compile(ss,ns),compile(ns+1,se));
12319  for (char *s = ss1, *ns = 0; s<se1 && (ns=std::strstr(s,"<")) && ns<se1; s=ns+1)
12320  if (level[ns-expr]==clevel) _cimg_fopcode2('<',compile(ss,ns),compile(ns+1,se));
12321  for (char *s = ss1, *ns = 0; s<se1 && (ns=std::strstr(s,"+")) && ns<se1; s=ns+1)
12322  if (level[ns-expr]==clevel) _cimg_fopcode2('+',compile(ss,ns),compile(ns+1,se));
12323  for (char *s = ss1, *ns = 0; s<se1 && (ns=std::strstr(s,"-")) && ns<se1; s=ns+1) {
12324  const char ps = *(ns-1);
12325  if (ps!='*' && ps!='/' && ps!='%' && ps!='^' && ps!='&' && ps!='|' && ps!='^' &&
12326  level[ns-expr]==clevel) _cimg_fopcode2('-',compile(ss,ns),compile(ns+1,se));
12327  }
12328  for (char *s = ss1, *ns = 0; s<se1 && (ns=std::strstr(s,"*")) && ns<se1; s=ns+1)
12329  if (level[ns-expr]==clevel) _cimg_fopcode2('*',compile(ss,ns),compile(ns+1,se));
12330  for (char *s = ss1, *ns = 0; s<se1 && (ns=std::strstr(s,"/")) && ns<se1; s=ns+1)
12331  if (level[ns-expr]==clevel) _cimg_fopcode2('/',compile(ss,ns),compile(ns+1,se));
12332  if (ss<se1) {
12333  if (*ss=='-') _cimg_fopcode1('o',compile(ss1,se));
12334  if (*ss=='+') _cimg_fopcode1('p',compile(ss1,se));
12335  if (*ss=='!') _cimg_fopcode1('n',compile(ss1,se));
12336  if (*ss=='~') _cimg_fopcode1('~',compile(ss1,se));
12337  }
12338  for (char *s = ss1, *ns = 0; s<se1 && (ns=std::strstr(s,"%")) && ns<se1; s=ns+1)
12339  if (level[ns-expr]==clevel) _cimg_fopcode2('%',compile(ss,ns),compile(ns+1,se));
12340  for (char *s = ss1, *ns = 0; s<se3 && (ns=std::strstr(s,"mod")) && ns<se3; s=ns+3)
12341  if (level[ns-expr]==clevel) _cimg_fopcode2('%',compile(ss,ns),compile(ns+3,se));
12342  for (char *s = ss1, *ns = 0; s<se1 && (ns=std::strstr(s,"&")) && ns<se1; s=ns+1)
12343  if (level[ns-expr]==clevel) _cimg_fopcode2('&',compile(ss,ns),compile(ns+1,se));
12344  for (char *s = ss1, *ns = 0; s<se1 && (ns=std::strstr(s,"|")) && ns<se1; s=ns+1)
12345  if (level[ns-expr]==clevel) _cimg_fopcode2('|',compile(ss,ns),compile(ns+1,se));
12346  for (char *s = ss1, *ns = 0; s<se1 && (ns=std::strstr(s,"^")) && ns<se1; s=ns+1)
12347  if (level[ns-expr]==clevel) _cimg_fopcode2('^',compile(ss,ns),compile(ns+1,se));
12348 
12349  // Look for a function call or a parenthesis.
12350  if (*se1==')') {
12351  if (*ss=='(') _cimg_freturn(compile(ss1,se1));
12352  if (!std::strncmp(ss,"sin(",4)) _cimg_fopcode1('s',compile(ss4,se1));
12353  if (!std::strncmp(ss,"cos(",4)) _cimg_fopcode1('c',compile(ss4,se1));
12354  if (!std::strncmp(ss,"tan(",4)) _cimg_fopcode1('t',compile(ss4,se1));
12355  if (!std::strncmp(ss,"asin(",5)) _cimg_fopcode1('S',compile(ss5,se1));
12356  if (!std::strncmp(ss,"acos(",5)) _cimg_fopcode1('C',compile(ss5,se1));
12357  if (!std::strncmp(ss,"atan(",5)) _cimg_fopcode1('T',compile(ss5,se1));
12358  if (!std::strncmp(ss,"sinh(",5)) _cimg_fopcode1('.',compile(ss5,se1));
12359  if (!std::strncmp(ss,"cosh(",5)) _cimg_fopcode1(',',compile(ss5,se1));
12360  if (!std::strncmp(ss,"tanh(",5)) _cimg_fopcode1(';',compile(ss5,se1));
12361  if (!std::strncmp(ss,"log10(",6)) _cimg_fopcode1('Q',compile(ss6,se1));
12362  if (!std::strncmp(ss,"log(",4)) _cimg_fopcode1('q',compile(ss4,se1));
12363  if (!std::strncmp(ss,"ln(",3)) _cimg_fopcode1('q',compile(ss3,se1));
12364  if (!std::strncmp(ss,"exp(",4)) _cimg_fopcode1('e',compile(ss4,se1));
12365  if (!std::strncmp(ss,"sqrt(",5)) _cimg_fopcode1('r',compile(ss5,se1));
12366  if (!std::strncmp(ss,"sign(",5)) _cimg_fopcode1('\\',compile(ss5,se1));
12367  if (!std::strncmp(ss,"rint(",5)) _cimg_fopcode1('i',compile(ss5,se1));
12368  if (!std::strncmp(ss,"abs(",4)) _cimg_fopcode1(':',compile(ss4,se1));
12369  if (!std::strncmp(ss,"atan2(",6)) {
12370  char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1-expr]!=clevel1)) ++s1;
12371  _cimg_fopcode2('#',compile(ss6,s1),compile(s1+1,se1));
12372  }
12373  if (!std::strncmp(ss,"if(",3)) {
12374  char *s1 = ss3; while (s1<se4 && (*s1!=',' || level[s1-expr]!=clevel1)) ++s1;
12375  char *s2 = s1+1; while (s2<se2 && (*s2!=',' || level[s2-expr]!=clevel1)) ++s2;
12376  _cimg_fopcode3('?',compile(ss3,s1),compile(s1+1,s2),compile(s2+1,se1));
12377  }
12378  if (!std::strncmp(ss,"i(",2)) {
12379  unsigned int indx = 0, indy = 1, indz = 2, indv = 3, borders = 10;
12380  if (ss2!=se1) {
12381  char *s1 = ss2; while (s1<se2 && (*s1!=',' || level[s1-expr]!=clevel1)) ++s1;
12382  indx = compile(ss2,s1==se2?++s1:s1);
12383  if (s1<se1) {
12384  char *s2 = s1+1; while (s2<se2 && (*s2!=',' || level[s2-expr]!=clevel1)) ++s2;
12385  indy = compile(s1+1,s2==se2?++s2:s2);
12386  if (s2<se1) {
12387  char *s3 = s2+1; while (s3<se2 && (*s3!=',' || level[s3-expr]!=clevel1)) ++s3;
12388  indz = compile(s2+1,s3==se2?++s3:s3);
12389  if (s3<se1) {
12390  char *s4 = s3+1; while (s4<se2 && (*s4!=',' || level[s4-expr]!=clevel1)) ++s4;
12391  indv = compile(s3+1,s4==se2?++s4:s4);
12392  if (s4<se1) borders = compile(s4+1,se1);
12393  }
12394  }
12395  }
12396  }
12397  _cimg_fopcode5('(',indx,indy,indz,indv,borders);
12398  }
12399  if (!std::strncmp(ss,"min(",4) || !std::strncmp(ss,"max(",4)) {
12401  if (mempos>=mem.size()) mem.resize(-200,1,1,1,0); const unsigned int pos = mempos++;
12402  CImg<uintT>::vector(ss[1]=='i'?'m':'M',pos).transfer_to(opcode);
12403  for (char *s = ss4; s<se; ++s) {
12404  char *ns = s; while (ns<se && (*ns!=',' || level[ns-expr]!=clevel1) && (*ns!=')' || level[ns-expr]!=clevel)) ++ns;
12405  CImg<uintT>::vector(compile(s,ns)).transfer_to(opcode);
12406  s = ns;
12407  }
12408  (opcode>'y').transfer_to(code);
12409  _cimg_freturn(pos);
12410  }
12411  }
12412  // No known item found.
12413  char *item = new char[std::strlen(ss)];
12414  std::strcpy(item,ss);
12415  *se = saved_char;
12416  throw CImgArgumentException("CImg<%s>::%s() : Invalid item '%s', in expression '%s'.",
12418  return 0;
12419  }
12420 
12421  // Evaluation procedure, with image data.
12422  template<typename t>
12423  double eval(const CImg<t>& img, const double x, const double y, const double z, const double v) {
12424  if (!mem) return 0;
12425  mem[0] = x; mem[1] = y; mem[2] = z; mem[3] = v;
12426  mem[4] = img.dimx(); mem[5] = img.dimy(); mem[6] = img.dimz(); mem[7] = img.dimv();
12427  cimglist_for(code,l) {
12428  const CImg<uintT> &opcode = code[l];
12429  double &res = mem[opcode(1)];
12430  switch (opcode(0)) {
12431  case 'U' : res = cimg::rand(); break;
12432  case 'G' : res = cimg::grand(); break;
12433  case 'I' : res = (double)img.atXYZV((int)x,(int)y,(int)z,(int)v,0); break;
12434  case '0' : res = x/img.dimx(); break;
12435  case '1' : res = y/img.dimy(); break;
12436  case '2' : res = z/img.dimz(); break;
12437  case '3' : res = v/img.dimv(); break;
12438  case 'A' : res = (bool)mem[opcode(2)] && (bool)mem[opcode(3)]; break;
12439  case 'X' : res = (bool)mem[opcode(2)] ^ (bool)mem[opcode(3)]; break;
12440  case 'O' : res = (bool)mem[opcode(2)] || (bool)mem[opcode(3)]; break;
12441  case 'l' : res = (mem[opcode(2)] <= mem[opcode(3)]); break;
12442  case 'g' : res = (mem[opcode(2)] >= mem[opcode(3)]); break;
12443  case '!' : res = (mem[opcode(2)] != mem[opcode(3)]); break;
12444  case '=' : res = (mem[opcode(2)] == mem[opcode(3)]); break;
12445  case '>' : res = (mem[opcode(2)] > mem[opcode(3)]); break;
12446  case '<' : res = (mem[opcode(2)] < mem[opcode(3)]); break;
12447  case '+' : res = (mem[opcode(2)] + mem[opcode(3)]); break;
12448  case '-' : res = (mem[opcode(2)] - mem[opcode(3)]); break;
12449  case '*' : res = (mem[opcode(2)] * mem[opcode(3)]); break;
12450  case '/' : res = (mem[opcode(2)] / mem[opcode(3)]); break;
12451  case 'o' : res = -mem[opcode(2)]; break;
12452  case 'p' : res = mem[opcode(2)]; break;
12453  case 'n' : res = !mem[opcode(2)]; break;
12454  case '~' : res = ~(unsigned long)mem[opcode(2)]; break;
12455  case '%' : res = cimg::mod(mem[opcode(2)],mem[opcode(3)]); break;
12456  case '&' : res = ((unsigned long)mem[opcode(2)] & (unsigned long)mem[opcode(3)]); break;
12457  case '|' : res = ((unsigned long)mem[opcode(2)] | (unsigned long)mem[opcode(3)]); break;
12458  case '^' : res = std::pow(mem[opcode(2)],mem[opcode(3)]); break;
12459  case 's' : res = std::sin(mem[opcode(2)]); break;
12460  case 'c' : res = std::cos(mem[opcode(2)]); break;
12461  case 't' : res = std::tan(mem[opcode(2)]); break;
12462  case 'S' : res = std::asin(mem[opcode(2)]); break;
12463  case 'C' : res = std::acos(mem[opcode(2)]); break;
12464  case 'T' : res = std::atan(mem[opcode(2)]); break;
12465  case '.' : res = std::sinh(mem[opcode(2)]); break;
12466  case ',' : res = std::cosh(mem[opcode(2)]); break;
12467  case ';' : res = std::tanh(mem[opcode(2)]); break;
12468  case 'Q' : res = std::log10(mem[opcode(2)]); break;
12469  case 'q' : res = std::log(mem[opcode(2)]); break;
12470  case 'e' : res = std::exp(mem[opcode(2)]); break;
12471  case 'r' : res = std::sqrt(mem[opcode(2)]); break;
12472  case '\\' : res = cimg::sign(mem[opcode(2)]); break;
12473  case 'i' : res = cimg::round(mem[opcode(2)],1); break;
12474  case '(' : {
12475  const int v = (int)mem[opcode(5)];
12476  switch ((int)mem[opcode(6)]) {
12477  case 0 : res = (double)img.linear_atXYZ((float)mem[opcode(2)],
12478  (float)mem[opcode(3)],
12479  (float)mem[opcode(4)],
12480  v<0?0:v>=img.dimv()?img.dimv()-1:v,0); break;
12481  case 1 : res = (double)img.linear_atXYZ((float)mem[opcode(2)],
12482  (float)mem[opcode(3)],
12483  (float)mem[opcode(4)],
12484  v<0?0:v>=img.dimv()?img.dimv()-1:v); break;
12485  default : res = (double)img.linear_atXYZ((float)cimg::mod(mem[opcode(2)],(double)img.dimx()),
12486  (float)cimg::mod(mem[opcode(3)],(double)img.dimy()),
12487  (float)cimg::mod(mem[opcode(4)],(double)img.dimz()),
12488  v<0?0:v>=img.dimv()?img.dimv()-1:v); break;
12489  }
12490  } break;
12491  case ':' : res = cimg::abs(mem[opcode(2)]); break;
12492  case '#' : res = std::atan2(mem[opcode(2)],mem[opcode(3)]); break;
12493  case '?' : res = mem[opcode(2)]?mem[opcode(3)]:mem[opcode(4)]; break;
12494  case 'm' : {
12495  double val = mem[opcode(2)];
12496  for (unsigned int i = 3; i<opcode.height; ++i) val = cimg::min(val,mem[opcode(i)]);
12497  res = val;
12498  } break;
12499  case 'M' : {
12500  double val = mem[opcode(2)];
12501  for (unsigned int i = 3; i<opcode.height; ++i) val = cimg::max(val,mem[opcode(i)]);
12502  res = val;
12503  } break;
12504  default :
12505  throw CImgArgumentException("CImg<%s>::%s() : Invalid opcode %d.",pixel_type(),calling_function,opcode(0));
12506  }
12507  }
12508  return mem[result];
12509  }
12510 
12511  // Evaluation procedure, without image data.
12512  double eval(const double x, const double y, const double z, const double v) {
12513  static const CImg<T> empty;
12514  return eval(empty,x,y,z,v);
12515  }
12516 
12517  };
12518 
12521  cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)(val*val); };
12522  return *this;
12523  }
12524 
12526  return CImg<Tfloat>(*this,false).sqr();
12527  }
12528 
12531  cimg_for(*this,ptr,T) (*ptr) = (T)std::sqrt((double)(*ptr));
12532  return *this;
12533  }
12534 
12536  return CImg<Tfloat>(*this,false).sqrt();
12537  }
12538 
12541  cimg_for(*this,ptr,T) (*ptr) = (T)std::exp((double)(*ptr));
12542  return *this;
12543  }
12544 
12546  return CImg<Tfloat>(*this,false).exp();
12547  }
12548 
12551  cimg_for(*this,ptr,T) (*ptr) = (T)std::log((double)(*ptr));
12552  return *this;
12553  }
12554 
12556  return CImg<Tfloat>(*this,false).log();
12557  }
12558 
12561  cimg_for(*this,ptr,T) (*ptr) = (T)std::log10((double)(*ptr));
12562  return *this;
12563  }
12564 
12566  return CImg<Tfloat>(*this,false).log10();
12567  }
12568 
12571  cimg_for(*this,ptr,T) (*ptr) = cimg::abs(*ptr);
12572  return *this;
12573  }
12574 
12576  return CImg<Tfloat>(*this,false).abs();
12577  }
12578 
12581  cimg_for(*this,ptr,T) (*ptr) = (T)std::cos((double)(*ptr));
12582  return *this;
12583  }
12584 
12586  return CImg<Tfloat>(*this,false).cos();
12587  }
12588 
12591  cimg_for(*this,ptr,T) (*ptr) = (T)std::sin((double)(*ptr));
12592  return *this;
12593  }
12594 
12596  return CImg<Tfloat>(*this,false).sin();
12597  }
12598 
12601  cimg_for(*this,ptr,T) (*ptr) = (T)std::tan((double)(*ptr));
12602  return *this;
12603  }
12604 
12606  return CImg<Tfloat>(*this,false).tan();
12607  }
12608 
12611  cimg_for(*this,ptr,T) (*ptr) = (T)std::cosh((double)(*ptr));
12612  return *this;
12613  }
12614 
12616  return CImg<Tfloat>(*this,false).cosh();
12617  }
12618 
12621  cimg_for(*this,ptr,T) (*ptr) = (T)std::sinh((double)(*ptr));
12622  return *this;
12623  }
12624 
12626  return CImg<Tfloat>(*this,false).sinh();
12627  }
12628 
12631  cimg_for(*this,ptr,T) (*ptr) = (T)std::tanh((double)(*ptr));
12632  return *this;
12633  }
12634 
12636  return CImg<Tfloat>(*this,false).tanh();
12637  }
12638 
12641  cimg_for(*this,ptr,T) (*ptr) = (T)std::acos((double)(*ptr));
12642  return *this;
12643  }
12644 
12646  return CImg<Tfloat>(*this,false).acos();
12647  }
12648 
12651  cimg_for(*this,ptr,T) (*ptr) = (T)std::asin((double)(*ptr));
12652  return *this;
12653  }
12654 
12656  return CImg<Tfloat>(*this,false).asin();
12657  }
12658 
12661  cimg_for(*this,ptr,T) (*ptr) = (T)std::atan((double)(*ptr));
12662  return *this;
12663  }
12664 
12666  return CImg<Tfloat>(*this,false).atan();
12667  }
12668 
12670  template<typename t>
12671  CImg<T>& atan2(const CImg<t>& img) {
12672  const unsigned int smin = cimg::min(size(),img.size());
12673  t *ptrs = img.data + smin;
12674  for (T *ptrd = data + smin; ptrd>data; --ptrd, *ptrd = (T)std::atan2((double)*ptrd,(double)*(--ptrs))) {}
12675  return *this;
12676  }
12677 
12678  template<typename t>
12679  CImg<Tfloat> get_atan2(const CImg<t>& img) const {
12680  return CImg<Tfloat>(*this,false).atan2(img);
12681  }
12682 
12684  template<typename t>
12685  CImg<T>& mul(const CImg<t>& img) {
12686  const unsigned int siz = size(), isiz = img.size();
12687  if (siz && isiz) {
12688  if (is_overlapped(img)) return mul(+img);
12689  T *ptrd = data, *const ptrd_end = data + siz;
12690  if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
12691  for (const t *ptrs = img.data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd * *(ptrs++));
12692  for (const t *ptrs = img.data; ptrd<ptrd_end; ++ptrd) *ptrd = (T)(*ptrd * *(ptrs++));
12693  }
12694  return *this;
12695  }
12696 
12697  template<typename t>
12698  CImg<_cimg_Tt> get_mul(const CImg<t>& img) const {
12699  return CImg<_cimg_Tt>(*this,false).mul(img);
12700  }
12701 
12703  template<typename t>
12704  CImg<T>& div(const CImg<t>& img) {
12705  const unsigned int siz = size(), isiz = img.size();
12706  if (siz && isiz) {
12707  if (is_overlapped(img)) return div(+img);
12708  T *ptrd = data, *const ptrd_end = data + siz;
12709  if (siz>isiz) for (unsigned int n = siz/isiz; n; --n)
12710  for (const t *ptrs = img.data, *ptrs_end = ptrs + isiz; ptrs<ptrs_end; ++ptrd) *ptrd = (T)(*ptrd / *(ptrs++));
12711  for (const t *ptrs = img.data; ptrd<ptrd_end; ++ptrd) *ptrd = (T)(*ptrd / *(ptrs++));
12712  }
12713  return *this;
12714  }
12715 
12716  template<typename t>
12717  CImg<_cimg_Tt> get_div(const CImg<t>& img) const {
12718  return CImg<_cimg_Tt>(*this,false).div(img);
12719  }
12720 
12722  CImg<T>& pow(const double p) {
12723  if (p==0) return fill(1);
12724  if (p==0.5) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)std::sqrt((double)val); } return *this; }
12725  if (p==1) return *this;
12726  if (p==2) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val; } return *this; }
12727  if (p==3) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val; } return *this; }
12728  if (p==4) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val*val; } return *this; }
12729  cimg_for(*this,ptr,T) (*ptr) = (T)std::pow((double)(*ptr),p);
12730  return *this;
12731  }
12732 
12733  CImg<Tfloat> get_pow(const double p) const {
12734  return CImg<Tfloat>(*this,false).pow(p);
12735  }
12736 
12738  template<typename t>
12739  CImg<T>& pow(const CImg<t>& img) {
12740  if (is_overlapped(img)) return pow(+img);
12741  t *ptrs = img.data;
12742  T *ptrf = data + cimg::min(size(),img.size());
12743  for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)std::pow((double)*ptrd,(double)(*(ptrs++)));
12744  return *this;
12745  }
12746 
12747  template<typename t>
12748  CImg<Tfloat> get_pow(const CImg<t>& img) const {
12749  return CImg<Tfloat>(*this,false).pow(img);
12750  }
12751 
12753  CImg<T>& pow(const char *const expression) {
12754  const unsigned int omode = cimg::exception_mode();
12755  cimg::exception_mode() = 0;
12756  try {
12757  _cimg_math_parser mp(expression,"pow");
12758  T *ptrd = data;
12759  cimg_forXYZV(*this,x,y,z,v) { *ptrd = (T)std::pow((double)*ptrd,mp.eval(*this,x,y,z,v)); ++ptrd; }
12760  } catch (CImgException&) {
12761  CImg<Tfloat> values(width,height,depth,dim);
12762  try {
12763  values.fill(expression,true);
12764  } catch (CImgException&) {
12765  cimg::exception_mode() = omode;
12766  values.load(expression);
12767  }
12768  pow(values);
12769  }
12770  cimg::exception_mode() = omode;
12771  return *this;
12772  }
12773 
12774  CImg<Tfloat> get_pow(const char *const expression) const {
12775  return CImg<Tfloat>(*this,false).pow(expression);
12776  }
12777 
12779  CImg<T>& min(const T val) {
12780  cimg_for(*this,ptr,T) (*ptr) = cimg::min(*ptr,val);
12781  return *this;
12782  }
12783 
12784  CImg<T> get_min(const T val) const {
12785  return (+*this).min(val);
12786  }
12787 
12789  template<typename t>
12790  CImg<T>& min(const CImg<t>& img) {
12791  if (is_overlapped(img)) return min(+img);
12792  t *ptrs = img.data;
12793  T *ptrf = data + cimg::min(size(),img.size());
12794  for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::min((T)*(ptrs++),*ptrd);
12795  return *this;
12796  }
12797 
12798  template<typename t>
12799  CImg<_cimg_Tt> get_min(const CImg<t>& img) const {
12800  return CImg<_cimg_Tt>(*this,false).min(img);
12801  }
12802 
12804  CImg<T>& min(const char *const expression) {
12805  const unsigned int omode = cimg::exception_mode();
12806  cimg::exception_mode() = 0;
12807  try {
12808  _cimg_math_parser mp(expression,"min");
12809  T *ptrd = data;
12810  cimg_forXYZV(*this,x,y,z,v) { *ptrd = (T)cimg::min(*ptrd,(T)mp.eval(*this,x,y,z,v)); ++ptrd; }
12811  } catch (CImgException&) {
12812  CImg<T> values(width,height,depth,dim);
12813  try {
12814  values.fill(expression,true);
12815  } catch (CImgException&) {
12816  cimg::exception_mode() = omode;
12817  values.load(expression);
12818  }
12819  min(values);
12820  }
12821  cimg::exception_mode() = omode;
12822  return *this;
12823  }
12824 
12825  CImg<Tfloat> get_min(const char *const expression) const {
12826  return CImg<Tfloat>(*this,false).min(expression);
12827  }
12828 
12830  CImg<T>& max(const T val) {
12831  cimg_for(*this,ptr,T) (*ptr) = cimg::max(*ptr,val);
12832  return *this;
12833  }
12834 
12835  CImg<T> get_max(const T val) const {
12836  return (+*this).max(val);
12837  }
12838 
12840  template<typename t>
12841  CImg<T>& max(const CImg<t>& img) {
12842  if (is_overlapped(img)) return max(+img);
12843  t *ptrs = img.data;
12844  T *ptrf = data + cimg::min(size(),img.size());
12845  for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::max((T)*(ptrs++),*ptrd);
12846  return *this;
12847  }
12848 
12849  template<typename t>
12850  CImg<_cimg_Tt> get_max(const CImg<t>& img) const {
12851  return CImg<_cimg_Tt>(*this,false).max(img);
12852  }
12853 
12855  CImg<T>& max(const char *const expression) {
12856  const unsigned int omode = cimg::exception_mode();
12857  cimg::exception_mode() = 0;
12858  try {
12859  _cimg_math_parser mp(expression,"max");
12860  T *ptrd = data;
12861  cimg_forXYZV(*this,x,y,z,v) { *ptrd = (T)cimg::max(*ptrd,(T)mp.eval(*this,x,y,z,v)); ++ptrd; }
12862  } catch (CImgException&) {
12863  CImg<T> values(width,height,depth,dim);
12864  try {
12865  values.fill(expression,true);
12866  } catch (CImgException&) {
12867  cimg::exception_mode() = omode;
12868  values.load(expression);
12869  }
12870  max(values);
12871  }
12872  cimg::exception_mode() = omode;
12873  return *this;
12874  }
12875 
12876  CImg<Tfloat> get_max(const char *const expression) const {
12877  return CImg<Tfloat>(*this,false).max(expression);
12878  }
12879 
12881  T& min() {
12882  if (is_empty())
12883  throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",pixel_type());
12884  T *ptrmin = data;
12885  T min_value = *ptrmin;
12886  cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
12887  return *ptrmin;
12888  }
12889 
12890  const T& min() const {
12891  if (is_empty())
12892  throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",pixel_type());
12893  const T *ptrmin = data;
12894  T min_value = *ptrmin;
12895  cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
12896  return *ptrmin;
12897  }
12898 
12900  T& max() {
12901  if (is_empty())
12902  throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",pixel_type());
12903  T *ptrmax = data;
12904  T max_value = *ptrmax;
12905  cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
12906  return *ptrmax;
12907  }
12908 
12909  const T& max() const {
12910  if (is_empty())
12911  throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",pixel_type());
12912  const T *ptrmax = data;
12913  T max_value = *ptrmax;
12914  cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
12915  return *ptrmax;
12916  }
12917 
12919  template<typename t>
12920  T& minmax(t& max_val) {
12921  if (is_empty())
12922  throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",pixel_type());
12923  T *ptrmin = data;
12924  T min_value = *ptrmin, max_value = min_value;
12925  cimg_for(*this,ptr,T) {
12926  const T val = *ptr;
12927  if (val<min_value) { min_value = val; ptrmin = ptr; }
12928  if (val>max_value) max_value = val;
12929  }
12930  max_val = (t)max_value;
12931  return *ptrmin;
12932  }
12933 
12934  template<typename t>
12935  const T& minmax(t& max_val) const {
12936  if (is_empty())
12937  throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",pixel_type());
12938  const T *ptrmin = data;
12939  T min_value = *ptrmin, max_value = min_value;
12940  cimg_for(*this,ptr,T) {
12941  const T val = *ptr;
12942  if (val<min_value) { min_value = val; ptrmin = ptr; }
12943  if (val>max_value) max_value = val;
12944  }
12945  max_val = (t)max_value;
12946  return *ptrmin;
12947  }
12948 
12950  template<typename t>
12951  T& maxmin(t& min_val) {
12952  if (is_empty())
12953  throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",pixel_type());
12954  T *ptrmax = data;
12955  T max_value = *ptrmax, min_value = max_value;
12956  cimg_for(*this,ptr,T) {
12957  const T val = *ptr;
12958  if (val>max_value) { max_value = val; ptrmax = ptr; }
12959  if (val<min_value) min_value = val;
12960  }
12961  min_val = (t)min_value;
12962  return *ptrmax;
12963  }
12964 
12965  template<typename t>
12966  const T& maxmin(t& min_val) const {
12967  if (is_empty())
12968  throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",pixel_type());
12969  const T *ptrmax = data;
12970  T max_value = *ptrmax, min_value = max_value;
12971  cimg_for(*this,ptr,T) {
12972  const T val = *ptr;
12973  if (val>max_value) { max_value = val; ptrmax = ptr; }
12974  if (val<min_value) min_value = val;
12975  }
12976  min_val = (t)min_value;
12977  return *ptrmax;
12978  }
12979 
12981  T kth_smallest(const unsigned int k) const {
12982  if (is_empty())
12983  throw CImgInstanceException("CImg<%s>::kth_smallest() : Instance image (%u,%u,%u,%u,%p) is empty.",
12984  pixel_type(),width,height,depth,dim,data);
12985  CImg<T> arr(*this);
12986  unsigned int l = 0, ir = size() - 1;
12987  for (;;) {
12988  if (ir<=l+1) {
12989  if (ir==l+1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
12990  return arr[k];
12991  } else {
12992  const unsigned int mid = (l + ir)>>1;
12993  cimg::swap(arr[mid],arr[l+1]);
12994  if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);
12995  if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]);
12996  if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]);
12997  unsigned int i = l + 1, j = ir;
12998  const T pivot = arr[l+1];
12999  for (;;) {
13000  do ++i; while (arr[i]<pivot);
13001  do --j; while (arr[j]>pivot);
13002  if (j<i) break;
13003  cimg::swap(arr[i],arr[j]);
13004  }
13005  arr[l+1] = arr[j];
13006  arr[j] = pivot;
13007  if (j>=k) ir = j - 1;
13008  if (j<=k) l = i;
13009  }
13010  }
13011  return 0;
13012  }
13013 
13015  T median() const {
13016  const unsigned int s = size();
13017  const T res = kth_smallest(s>>1);
13018  return (s%2)?res:((res+kth_smallest((s>>1)-1))/2);
13019  }
13020 
13022  Tfloat sum() const {
13023  if (is_empty())
13024  throw CImgInstanceException("CImg<%s>::sum() : Instance image (%u,%u,%u,%u,%p) is empty.",
13025  pixel_type(),width,height,depth,dim,data);
13026  Tfloat res = 0;
13027  cimg_for(*this,ptr,T) res+=*ptr;
13028  return res;
13029  }
13030 
13032  Tfloat mean() const {
13033  if (is_empty())
13034  throw CImgInstanceException("CImg<%s>::mean() : Instance image is empty.",pixel_type());
13035  Tfloat val = 0;
13036  cimg_for(*this,ptr,T) val+=*ptr;
13037  return val/size();
13038  }
13039 
13041 
13057  Tfloat variance(const unsigned int variance_method=1) const {
13058  Tfloat foo;
13059  return variancemean(variance_method,foo);
13060  }
13061 
13063  template<typename t>
13064  Tfloat variancemean(const unsigned int variance_method, t& mean) const {
13065  if (is_empty())
13066  throw CImgInstanceException("CImg<%s>::variance() : Instance image is empty.",pixel_type());
13067  Tfloat variance = 0, average = 0;
13068  const unsigned int siz = size();
13069  switch (variance_method) {
13070  case 3 : { // Least trimmed of Squares
13071  CImg<Tfloat> buf(*this);
13072  const unsigned int siz2 = siz>>1;
13073  cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; (*ptrs)*=val; average+=val; }
13074  buf.sort();
13075  Tfloat a = 0;
13076  const Tfloat *ptrs = buf.ptr();
13077  for (unsigned int j = 0; j<siz2; ++j) a+=*(ptrs++);
13078  const Tfloat sig = (Tfloat)(2.6477*std::sqrt(a/siz2));
13079  variance = sig*sig;
13080  } break;
13081  case 2 : { // Least Median of Squares (MAD)
13082  CImg<Tfloat> buf(*this);
13083  buf.sort();
13084  const unsigned int siz2 = siz>>1;
13085  const Tfloat med_i = buf[siz2];
13086  cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; *ptrs = cimg::abs(val - med_i); average+=val; }
13087  buf.sort();
13088  const Tfloat sig = (Tfloat)(1.4828*buf[siz2]);
13089  variance = sig*sig;
13090  } break;
13091  case 1 : { // Least mean square (robust definition)
13092  Tfloat S = 0, S2 = 0;
13093  cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val; S2+=val*val; }
13094  variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;
13095  average = S;
13096  } break;
13097  case 0 :{ // Least mean square (standard definition)
13098  Tfloat S = 0, S2 = 0;
13099  cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val; S2+=val*val; }
13100  variance = (S2 - S*S/siz)/siz;
13101  average = S;
13102  } break;
13103  default :
13104  throw CImgArgumentException("CImg<%s>::variancemean() : Incorrect parameter 'variance_method = %d' (correct values are 0,1,2 or 3).",
13105  pixel_type(),variance_method);
13106  }
13107  mean = (t)(average/siz);
13108  return variance>0?variance:0;
13109  }
13110 
13112  template<typename t>
13113  Tfloat MSE(const CImg<t>& img) const {
13114  if (img.size()!=size())
13115  throw CImgArgumentException("CImg<%s>::MSE() : Instance image (%u,%u,%u,%u) and given image (%u,%u,%u,%u) have different dimensions.",
13116  pixel_type(),width,height,depth,dim,img.width,img.height,img.depth,img.dim);
13117 
13118  Tfloat vMSE = 0;
13119  const t* ptr2 = img.end();
13120  cimg_for(*this,ptr1,T) {
13121  const Tfloat diff = (Tfloat)*ptr1 - (Tfloat)*(--ptr2);
13122  vMSE += diff*diff;
13123  }
13124  vMSE/=img.size();
13125  return vMSE;
13126  }
13127 
13129  template<typename t>
13130  Tfloat PSNR(const CImg<t>& img, const Tfloat valmax=(Tfloat)255) const {
13131  const Tfloat vMSE = (Tfloat)std::sqrt(MSE(img));
13132  return (vMSE!=0)?(Tfloat)(20*std::log10(valmax/vMSE)):(Tfloat)(cimg::type<Tfloat>::max());
13133  }
13134 
13136 
13140  double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double v=0) const {
13141  static _cimg_math_parser *mp = 0;
13142  if (expression) { if (mp) delete mp; mp = new _cimg_math_parser(expression,"eval"); }
13143  if (!mp) throw CImgArgumentException("CImg<%s>::eval() : No expression has been previously defined.",pixel_type());
13144  return mp->eval(*this,x,y,z,v);
13145  }
13146 
13148  CImg<T>& stats(const unsigned int variance_method=1) {
13149  return get_stats(variance_method).transfer_to(*this);
13150  }
13151 
13152  CImg<Tfloat> get_stats(const unsigned int variance_method=1) const {
13153  if (is_empty()) return CImg<Tfloat>();
13154  const unsigned int siz = size();
13155  const T *const odata = data;
13156  const T *pm = odata, *pM = odata;
13157  Tfloat S = 0, S2 = 0;
13158  T m = *pm, M = m;
13159  cimg_for(*this,ptr,T) {
13160  const T val = *ptr;
13161  const Tfloat fval = (Tfloat)val;
13162  if (val<m) { m = val; pm = ptr; }
13163  if (val>M) { M = val; pM = ptr; }
13164  S+=fval;
13165  S2+=fval*fval;
13166  }
13167  const Tfloat
13168  mean_value = S/siz,
13169  _variance_value = variance_method==0?(S2 - S*S/siz)/siz:
13170  (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0):
13171  variance(variance_method)),
13172  variance_value = _variance_value>0?_variance_value:0;
13173  int
13174  xm = 0, ym = 0, zm = 0, vm = 0,
13175  xM = 0, yM = 0, zM = 0, vM = 0;
13176  contains(*pm,xm,ym,zm,vm);
13177  contains(*pM,xM,yM,zM,vM);
13178  return CImg<Tfloat>(1,12).fill((Tfloat)m,(Tfloat)M,mean_value,variance_value,
13179  (Tfloat)xm,(Tfloat)ym,(Tfloat)zm,(Tfloat)vm,
13180  (Tfloat)xM,(Tfloat)yM,(Tfloat)zM,(Tfloat)vM);
13181  }
13182 
13184  //-------------------------------------
13185  //
13187 
13188  //-------------------------------------
13189 
13191  Tfloat magnitude(const int magnitude_type=2) const {
13192  if (is_empty())
13193  throw CImgInstanceException("CImg<%s>::magnitude() : Instance object (%u,%u,%u,%u,%p) is empty.",
13194  pixel_type(),width,height,depth,dim,data);
13195  Tfloat res = 0;
13196  switch (magnitude_type) {
13197  case -1 : {
13198  cimg_foroff(*this,off) {
13199  const Tfloat tmp = cimg::abs((Tfloat)data[off]);
13200  if (tmp>res) res = tmp;
13201  }
13202  return res;
13203  } break;
13204  case 1 : {
13205  cimg_foroff(*this,off) res+=cimg::abs((Tfloat)data[off]);
13206  return res;
13207  } break;
13208  case 2 : return (Tfloat)std::sqrt(dot(*this)); break;
13209  default :
13210  throw CImgArgumentException("CImg<%s>::magnitude() : Incorrect parameter 'magnitude_type=%d' (correct values are -1,1 or 2).",
13211  pixel_type(),magnitude_type);
13212  }
13213  return 0;
13214  }
13215 
13217  Tfloat trace() const {
13218  if (is_empty())
13219  throw CImgInstanceException("CImg<%s>::trace() : Instance matrix (%u,%u,%u,%u,%p) is empty.",
13220  pixel_type(),width,height,depth,dim,data);
13221  Tfloat res = 0;
13222  cimg_forX(*this,k) res+=(*this)(k,k);
13223  return res;
13224  }
13225 
13227  Tfloat det() const {
13228  if (is_empty() || width!=height || depth!=1 || dim!=1)
13229  throw CImgInstanceException("CImg<%s>::det() : Instance matrix (%u,%u,%u,%u,%p) is not square or is empty.",
13230  pixel_type(),width,height,depth,dim,data);
13231  switch (width) {
13232  case 1 : return (Tfloat)((*this)(0,0));
13233  case 2 : return (Tfloat)((*this)(0,0))*(Tfloat)((*this)(1,1)) - (Tfloat)((*this)(0,1))*(Tfloat)((*this)(1,0));
13234  case 3 : {
13235  const Tfloat
13236  a = (Tfloat)data[0], d = (Tfloat)data[1], g = (Tfloat)data[2],
13237  b = (Tfloat)data[3], e = (Tfloat)data[4], h = (Tfloat)data[5],
13238  c = (Tfloat)data[6], f = (Tfloat)data[7], i = (Tfloat)data[8];
13239  return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e;
13240  }
13241  default : {
13242  CImg<Tfloat> lu(*this);
13243  CImg<uintT> indx;
13244  bool d;
13245  lu._LU(indx,d);
13246  Tfloat res = d?(Tfloat)1:(Tfloat)-1;
13247  cimg_forX(lu,i) res*=lu(i,i);
13248  return res;
13249  }
13250  }
13251  return 0;
13252  }
13253 
13255  template<typename t>
13256  Tfloat dot(const CImg<t>& img) const {
13257  if (is_empty())
13258  throw CImgInstanceException("CImg<%s>::dot() : Instance object (%u,%u,%u,%u,%p) is empty.",
13259  pixel_type(),width,height,depth,dim,data);
13260  if (!img)
13261  throw CImgArgumentException("CImg<%s>::trace() : Specified argument (%u,%u,%u,%u,%p) is empty.",
13262  pixel_type(),img.width,img.height,img.depth,img.dim,img.data);
13263  const unsigned int nb = cimg::min(size(),img.size());
13264  Tfloat res = 0;
13265  for (unsigned int off = 0; off<nb; ++off) res+=(Tfloat)data[off]*(Tfloat)img[off];
13266  return res;
13267  }
13268 
13270  CImg<T> get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
13271  static CImg<T> dest;
13272  if (dest.height!=dim) dest.assign(1,dim);
13273  const unsigned int whz = width*height*depth;
13274  const T *ptrs = ptr(x,y,z);
13275  T *ptrd = dest.data;
13276  cimg_forV(*this,k) { *(ptrd++) = *ptrs; ptrs+=whz; }
13277  return dest;
13278  }
13279 
13281  CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
13282  const int n = (int)std::sqrt((double)dim);
13283  CImg<T> dest(n,n);
13284  cimg_forV(*this,k) dest[k]=(*this)(x,y,z,k);
13285  return dest;
13286  }
13287 
13289  CImg<T> get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
13290  if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2),
13291  (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5));
13292  if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2));
13293  return tensor((*this)(x,y,z,0));
13294  }
13295 
13297  template<typename t>
13298  CImg<T>& set_vector_at(const CImg<t>& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) {
13299  if (x<width && y<height && z<depth) {
13300  const unsigned int whz = width*height*depth;
13301  const t *ptrs = vec.data;
13302  T *ptrd = ptr(x,y,z);
13303  for (unsigned int k=cimg::min((unsigned int)vec.size(),dim); k; --k) { *ptrd = (T)*(ptrs++); ptrd+=whz; }
13304  }
13305  return *this;
13306  }
13307 
13309  template<typename t>
13310  CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
13311  return set_vector_at(mat,x,y,z);
13312  }
13313 
13315  template<typename t>
13316  CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
13317  if (ten.height==2) {
13318  (*this)(x,y,z,0) = (T)ten[0];
13319  (*this)(x,y,z,1) = (T)ten[1];
13320  (*this)(x,y,z,2) = (T)ten[3];
13321  }
13322  else {
13323  (*this)(x,y,z,0) = (T)ten[0];
13324  (*this)(x,y,z,1) = (T)ten[1];
13325  (*this)(x,y,z,2) = (T)ten[2];
13326  (*this)(x,y,z,3) = (T)ten[4];
13327  (*this)(x,y,z,4) = (T)ten[5];
13328  (*this)(x,y,z,5) = (T)ten[8];
13329  }
13330  return *this;
13331  }
13332 
13335  return unroll('y');
13336  }
13337 
13339  return get_unroll('y');
13340  }
13341 
13344  const unsigned int siz = size();
13345  switch (siz) {
13346  case 1 : break;
13347  case 4 : width = height = 2; break;
13348  case 9 : width = height = 3; break;
13349  case 16 : width = height = 4; break;
13350  case 25 : width = height = 5; break;
13351  case 36 : width = height = 6; break;
13352  case 49 : width = height = 7; break;
13353  case 64 : width = height = 8; break;
13354  case 81 : width = height = 9; break;
13355  case 100 : width = height = 10; break;
13356  default : {
13357  unsigned int i = 11, i2 = i*i;
13358  while (i2<siz) { i2+=2*i+1; ++i; }
13359  if (i2==siz) width = height = i;
13360  else throw CImgInstanceException("CImg<%s>::matrix() : Image size = %u is not a square number",
13361  pixel_type(),siz);
13362  }
13363  }
13364  return *this;
13365  }
13366 
13368  return (+*this).matrix();
13369  }
13370 
13373  return get_tensor().transfer_to(*this);
13374  }
13375 
13377  CImg<T> res;
13378  const unsigned int siz = size();
13379  switch (siz) {
13380  case 1 : break;
13381  case 3 :
13382  res.assign(2,2);
13383  res(0,0) = (*this)(0);
13384  res(1,0) = res(0,1) = (*this)(1);
13385  res(1,1) = (*this)(2);
13386  break;
13387  case 6 :
13388  res.assign(3,3);
13389  res(0,0) = (*this)(0);
13390  res(1,0) = res(0,1) = (*this)(1);
13391  res(2,0) = res(0,2) = (*this)(2);
13392  res(1,1) = (*this)(3);
13393  res(2,1) = res(1,2) = (*this)(4);
13394  res(2,2) = (*this)(5);
13395  break;
13396  default :
13397  throw CImgInstanceException("CImg<%s>::tensor() : Wrong vector dimension = %u in instance image.",
13398  pixel_type(), dim);
13399  }
13400  return res;
13401  }
13402 
13405  return get_diagonal().transfer_to(*this);
13406  }
13407 
13409  if (is_empty()) return *this;
13410  CImg<T> res(size(),size(),1,1,0);
13411  cimg_foroff(*this,off) res(off,off) = (*this)(off);
13412  return res;
13413  }
13414 
13417  return identity_matrix(cimg::max(width,height)).transfer_to(*this);
13418  }
13419 
13422  }
13423 
13425  CImg<T>& sequence(const T a0, const T a1) {
13426  if (is_empty()) return *this;
13427  const unsigned int siz = size() - 1;
13428  T* ptr = data;
13429  if (siz) {
13430  const Tfloat delta = (Tfloat)a1 - a0;
13431  cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);
13432  } else *ptr = a0;
13433  return *this;
13434  }
13435 
13436  CImg<T> get_sequence(const T a0, const T a1) const {
13437  return (+*this).sequence(a0,a1);
13438  }
13439 
13442  if (width==1) { width=height; height=1; return *this; }
13443  if (height==1) { height=width; width=1; return *this; }
13444  if (width==height) {
13445  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));
13446  return *this;
13447  }
13448  return get_transpose().transfer_to(*this);
13449  }
13450 
13452  return get_permute_axes("yxzv");
13453  }
13454 
13456  template<typename t>
13457  CImg<T>& cross(const CImg<t>& img) {
13458  if (width!=1 || height<3 || img.width!=1 || img.height<3)
13459  throw CImgInstanceException("CImg<%s>::cross() : Arguments (%u,%u,%u,%u,%p) and (%u,%u,%u,%u,%p) must be both 3d vectors.",
13460  pixel_type(),width,height,depth,dim,data,img.width,img.height,img.depth,img.dim,img.data);
13461  const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
13462  (*this)[0] = (T)(y*img[2]-z*img[1]);
13463  (*this)[1] = (T)(z*img[0]-x*img[2]);
13464  (*this)[2] = (T)(x*img[1]-y*img[0]);
13465  return *this;
13466  }
13467 
13468  template<typename t>
13469  CImg<_cimg_Tt> get_cross(const CImg<t>& img) const {
13470  return CImg<_cimg_Tt>(*this).cross(img);
13471  }
13472 
13474  CImg<T>& invert(const bool use_LU=true) {
13475  if (!is_empty()) {
13476  if (width!=height || depth!=1 || dim!=1)
13477  throw CImgInstanceException("CImg<%s>::invert() : Instance matrix (%u,%u,%u,%u,%p) is not square.",
13478  pixel_type(),width,height,depth,dim,data);
13479 #ifdef cimg_use_lapack
13480  int INFO = (int)use_LU, N = width, LWORK = 4*N, *IPIV = new int[N];
13481  Tfloat
13482  *lapA = new Tfloat[N*N],
13483  *WORK = new Tfloat[LWORK];
13484  cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
13485  cimg::getrf(N,lapA,IPIV,INFO);
13486  if (INFO)
13487  cimg::warn("CImg<%s>::invert() : LAPACK library function dgetrf_() returned error code %d.",
13488  pixel_type(),INFO);
13489  else {
13490  cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
13491  if (INFO)
13492  cimg::warn("CImg<%s>::invert() : LAPACK library function dgetri_() returned Error code %d",
13493  pixel_type(),INFO);
13494  }
13495  if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N+l]); else fill(0);
13496  delete[] IPIV; delete[] lapA; delete[] WORK;
13497 #else
13498  const double dete = width>3?-1.0:det();
13499  if (dete!=0.0 && width==2) {
13500  const double
13501  a = data[0], c = data[1],
13502  b = data[2], d = data[3];
13503  data[0] = (T)(d/dete); data[1] = (T)(-c/dete);
13504  data[2] = (T)(-b/dete); data[3] = (T)(a/dete);
13505  } else if (dete!=0.0 && width==3) {
13506  const double
13507  a = data[0], d = data[1], g = data[2],
13508  b = data[3], e = data[4], h = data[5],
13509  c = data[6], f = data[7], i = data[8];
13510  data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete);
13511  data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete);
13512  data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete);
13513  } else {
13514  if (use_LU) { // LU-based inverse computation
13515  CImg<Tfloat> A(*this), indx, col(1,width);
13516  bool d;
13517  A._LU(indx,d);
13518  cimg_forX(*this,j) {
13519  col.fill(0);
13520  col(j) = 1;
13521  col._solve(A,indx);
13522  cimg_forX(*this,i) (*this)(j,i) = (T)col(i);
13523  }
13524  } else { // SVD-based inverse computation
13525  CImg<Tfloat> U(width,width), S(1,width), V(width,width);
13526  SVD(U,S,V,false);
13527  U.transpose();
13528  cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k];
13529  S.diagonal();
13530  *this = V*S*U;
13531  }
13532  }
13533 #endif
13534  }
13535  return *this;
13536  }
13537 
13538  CImg<Tfloat> get_invert(const bool use_LU=true) const {
13539  return CImg<Tfloat>(*this,false).invert(use_LU);
13540  }
13541 
13544  return get_pseudoinvert().transfer_to(*this);
13545  }
13546 
13548  CImg<Tfloat> U, S, V;
13549  SVD(U,S,V);
13550  cimg_forX(V,x) {
13551  const Tfloat s = S(x), invs = s!=0?1/s:(Tfloat)0;
13552  cimg_forY(V,y) V(x,y)*=invs;
13553  }
13554  return V*U.transpose();
13555  }
13556 
13558  template<typename t>
13559  CImg<T>& solve(const CImg<t>& A) {
13560  if (width!=1 || depth!=1 || dim!=1 || height!=A.height || A.depth!=1 || A.dim!=1)
13561  throw CImgArgumentException("CImg<%s>::solve() : Instance matrix size is (%u,%u,%u,%u) while "
13562  "size of given matrix A is (%u,%u,%u,%u).",
13563  pixel_type(),width,height,depth,dim,A.width,A.height,A.depth,A.dim);
13564 
13565  typedef _cimg_Ttfloat Ttfloat;
13566  if (A.width==A.height) {
13567 #ifdef cimg_use_lapack
13568  char TRANS='N';
13569  int INFO, N = height, LWORK = 4*N, one = 1, *IPIV = new int[N];
13570  Ttfloat
13571  *lapA = new Ttfloat[N*N],
13572  *lapB = new Ttfloat[N],
13573  *WORK = new Ttfloat[LWORK];
13574  cimg_forXY(A,k,l) lapA[k*N+l] = (Ttfloat)(A(k,l));
13575  cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));
13576  cimg::getrf(N,lapA,IPIV,INFO);
13577  if (INFO)
13578  cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrf_() returned error code %d.",
13579  pixel_type(),INFO);
13580  if (!INFO) {
13581  cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
13582  if (INFO)
13583  cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrs_() returned Error code %d",
13584  pixel_type(),INFO);
13585  }
13586  if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
13587  delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
13588 #else
13589  CImg<Ttfloat> lu(A);
13590  CImg<Ttfloat> indx;
13591  bool d;
13592  lu._LU(indx,d);
13593  _solve(lu,indx);
13594 #endif
13595  } else assign(A.get_pseudoinvert()*(*this));
13596  return *this;
13597  }
13598 
13599  template<typename t>
13601  return CImg<_cimg_Ttfloat>(*this,false).solve(A);
13602  }
13603 
13604  template<typename t, typename ti>
13605  CImg<T>& _solve(const CImg<t>& A, const CImg<ti>& indx) {
13606  typedef _cimg_Ttfloat Ttfloat;
13607  const int N = size();
13608  int ii = -1;
13609  Ttfloat sum;
13610  for (int i = 0; i<N; ++i) {
13611  const int ip = (int)indx[i];
13612  Ttfloat sum = (*this)(ip);
13613  (*this)(ip) = (*this)(i);
13614  if (ii>=0) for (int j = ii; j<=i-1; ++j) sum-=A(j,i)*(*this)(j);
13615  else if (sum!=0) ii=i;
13616  (*this)(i) = (T)sum;
13617  }
13618  for (int i = N-1; i>=0; --i) {
13619  sum = (*this)(i);
13620  for (int j = i+1; j<N; ++j) sum-=A(j,i)*(*this)(j);
13621  (*this)(i) = (T)(sum/A(i,i));
13622  }
13623  return *this;
13624  }
13625 
13627  // (Use the Thomas Algorithm).
13628  template<typename t>
13629  CImg<T>& solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) {
13630  const int siz = (int)size();
13631  if ((int)a.size()!=siz || (int)b.size()!=siz || (int)c.size()!=siz)
13632  throw CImgArgumentException("CImg<%s>::solve_tridiagonal() : arrays of triagonal coefficients have different size.",pixel_type);
13633  typedef _cimg_Ttfloat Ttfloat;
13634  CImg<Ttfloat> nc(siz);
13635  const T *ptra = a.data, *ptrb = b.data, *ptrc = c.data;
13636  T *ptrnc = nc.data, *ptrd = data;
13637  const Ttfloat valb0 = (Ttfloat)*(ptrb++);
13638  *ptrnc = *(ptrc++)/valb0;
13639  Ttfloat vald = (Ttfloat)(*(ptrd++)/=valb0);
13640  for (int i = 1; i<siz; ++i) {
13641  const Ttfloat
13642  vala = (Tfloat)*(ptra++),
13643  id = 1/(*(ptrb++) - *(ptrnc++)*vala);
13644  *ptrnc = *(ptrc++)*id;
13645  vald = ((*ptrd-=vala*vald)*=id);
13646  ++ptrd;
13647  }
13648  vald = *(--ptrd);
13649  for (int i = siz-2; i>=0; --i) vald = (*(--ptrd)-=*(--ptrnc)*vald);
13650  return *this;
13651  }
13652 
13653  template<typename t>
13654  CImg<_cimg_Ttfloat> get_solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) const {
13655  return CImg<_cimg_Ttfloat>(*this,false).solve_tridiagonal(a,b,c);
13656  }
13657 
13659  template<typename t>
13660  const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
13661  if (is_empty()) { val.assign(); vec.assign(); }
13662  else {
13663  if (width!=height || depth>1 || dim>1)
13664  throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
13665  pixel_type(),width,height,depth,dim,data);
13666  if (val.size()<width) val.assign(1,width);
13667  if (vec.size()<width*width) vec.assign(width,width);
13668  switch (width) {
13669  case 1 : { val[0]=(t)(*this)[0]; vec[0]=(t)1; } break;
13670  case 2 : {
13671  const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a+d;
13672  double f = e*e-4*(a*d-b*c);
13673  if (f<0)
13674  cimg::warn("CImg<%s>::eigen() : Complex eigenvalues",
13675  pixel_type());
13676  f = std::sqrt(f);
13677  const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);
13678  const double theta1 = std::atan2(l2-a,b), theta2 = std::atan2(l1-a,b);
13679  val[0]=(t)l2;
13680  val[1]=(t)l1;
13681  vec(0,0) = (t)std::cos(theta1);
13682  vec(0,1) = (t)std::sin(theta1);
13683  vec(1,0) = (t)std::cos(theta2);
13684  vec(1,1) = (t)std::sin(theta2);
13685  } break;
13686  default :
13687  throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited"
13688  "to 2x2 matrices (given is %ux%u)",
13689  pixel_type(),width,height);
13690  }
13691  }
13692  return *this;
13693  }
13694 
13696  CImgList<Tfloat> res(2);
13697  eigen(res[0],res[1]);
13698  return res;
13699  }
13700 
13702  template<typename t>
13703  const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& vec) const {
13704  if (is_empty()) { val.assign(); vec.assign(); }
13705  else {
13706 #ifdef cimg_use_lapack
13707  char JOB = 'V', UPLO = 'U';
13708  int N = width, LWORK = 4*N, INFO;
13709  Tfloat
13710  *lapA = new Tfloat[N*N],
13711  *lapW = new Tfloat[N],
13712  *WORK = new Tfloat[LWORK];
13713  cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
13714  cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO);
13715  if (INFO)
13716  cimg::warn("CImg<%s>::symmetric_eigen() : LAPACK library function dsyev_() returned error code %d.",
13717  pixel_type(),INFO);
13718  val.assign(1,N);
13719  vec.assign(N,N);
13720  if (!INFO) {
13721  cimg_forY(val,i) val(i) = (T)lapW[N-1-i];
13722  cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N-1-k)*N+l]);
13723  } else { val.fill(0); vec.fill(0); }
13724  delete[] lapA; delete[] lapW; delete[] WORK;
13725 #else
13726  if (width!=height || depth>1 || dim>1)
13727  throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
13728  pixel_type(),width,height,depth,dim,data);
13729  val.assign(1,width);
13730  if (vec.data) vec.assign(width,width);
13731  if (width<3) return eigen(val,vec);
13732  CImg<t> V(width,width);
13733  SVD(vec,val,V,false);
13734  bool ambiguous = false;
13735  float eig = 0;
13736  cimg_forY(val,p) { // check for ambiguous cases.
13737  if (val[p]>eig) eig = (float)val[p];
13738  t scal = 0;
13739  cimg_forY(vec,y) scal+=vec(p,y)*V(p,y);
13740  if (cimg::abs(scal)<0.9f) ambiguous = true;
13741  if (scal<0) val[p] = -val[p];
13742  }
13743  if (ambiguous) {
13744  (eig*=2)++;
13745  SVD(vec,val,V,false,40,eig);
13746  val-=eig;
13747  }
13748  CImg<intT> permutations(width); // sort eigenvalues in decreasing order
13749  CImg<t> tmp(width);
13750  val.sort(permutations,false);
13751  cimg_forY(vec,k) {
13752  cimg_forX(permutations,x) tmp(x) = vec(permutations(x),k);
13753  std::memcpy(vec.ptr(0,k),tmp.data,sizeof(t)*width);
13754  }
13755 #endif
13756  }
13757  return *this;
13758  }
13759 
13761  CImgList<Tfloat> res(2);
13762  symmetric_eigen(res[0],res[1]);
13763  return res;
13764  }
13765 
13767  template<typename t>
13768  CImg<T>& sort(CImg<t>& permutations, const bool increasing=true) {
13769  if (is_empty()) permutations.assign();
13770  else {
13771  if (permutations.size()!=size()) permutations.assign(size());
13772  cimg_foroff(permutations,off) permutations[off] = (t)off;
13773  _quicksort(0,size()-1,permutations,increasing);
13774  }
13775  return *this;
13776  }
13777 
13778  template<typename t>
13779  CImg<T> get_sort(CImg<t>& permutations, const bool increasing=true) const {
13780  return (+*this).sort(permutations,increasing);
13781  }
13782 
13784  CImg<T>& sort(const bool increasing=true) {
13785  CImg<T> foo;
13786  return sort(foo,increasing);
13787  }
13788 
13789  CImg<T> get_sort(const bool increasing=true) const {
13790  return (+*this).sort(increasing);
13791  }
13792 
13793  template<typename t>
13794  CImg<T>& _quicksort(const int min, const int max, CImg<t>& permutations, const bool increasing) {
13795  if (min<max) {
13796  const int mid = (min+max)/2;
13797  if (increasing) {
13798  if ((*this)[min]>(*this)[mid]) {
13799  cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
13800  if ((*this)[mid]>(*this)[max]) {
13801  cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
13802  if ((*this)[min]>(*this)[mid]) {
13803  cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
13804  } else {
13805  if ((*this)[min]<(*this)[mid]) {
13806  cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
13807  if ((*this)[mid]<(*this)[max]) {
13808  cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
13809  if ((*this)[min]<(*this)[mid]) {
13810  cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
13811  }
13812  if (max-min>=3) {
13813  const T pivot = (*this)[mid];
13814  int i = min, j = max;
13815  if (increasing) {
13816  do {
13817  while ((*this)[i]<pivot) ++i;
13818  while ((*this)[j]>pivot) --j;
13819  if (i<=j) {
13820  cimg::swap((*this)[i],(*this)[j]);
13821  cimg::swap(permutations[i++],permutations[j--]);
13822  }
13823  } while (i<=j);
13824  } else {
13825  do {
13826  while ((*this)[i]>pivot) ++i;
13827  while ((*this)[j]<pivot) --j;
13828  if (i<=j) {
13829  cimg::swap((*this)[i],(*this)[j]);
13830  cimg::swap(permutations[i++],permutations[j--]);
13831  }
13832  } while (i<=j);
13833  }
13834  if (min<j) _quicksort(min,j,permutations,increasing);
13835  if (i<max) _quicksort(i,max,permutations,increasing);
13836  }
13837  }
13838  return *this;
13839  }
13840 
13842  template<typename t>
13843  const CImg<T>& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V, const bool sorting=true,
13844  const unsigned int max_iter=40, const float lambda=0) const {
13845  if (is_empty()) { U.assign(); S.assign(); V.assign(); }
13846  else {
13847  U = *this;
13848  if (lambda!=0) {
13849  const unsigned int delta = cimg::min(U.width,U.height);
13850  for (unsigned int i = 0; i<delta; ++i) U(i,i) = (t)(U(i,i) + lambda);
13851  }
13852  if (S.size()<width) S.assign(1,width);
13853  if (V.width<width || V.height<height) V.assign(width,width);
13854  CImg<t> rv1(width);
13855  t anorm = 0, c, f, g = 0, h, s, scale = 0;
13856  int l = 0, nm = 0;
13857 
13858  cimg_forX(U,i) {
13859  l = i+1; rv1[i] = scale*g; g = s = scale = 0;
13860  if (i<dimy()) {
13861  for (int k = i; k<dimy(); ++k) scale+= cimg::abs(U(i,k));
13862  if (scale) {
13863  for (int k = i; k<dimy(); ++k) { U(i,k)/=scale; s+= U(i,k)*U(i,k); }
13864  f = U(i,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i) = f-g;
13865  for (int j = l; j<dimx(); ++j) {
13866  s = 0;
13867  for (int k=i; k<dimy(); ++k) s+= U(i,k)*U(j,k);
13868  f = s/h;
13869  for (int k = i; k<dimy(); ++k) U(j,k)+= f*U(i,k);
13870  }
13871  for (int k = i; k<dimy(); ++k) U(i,k)*= scale;
13872  }
13873  }
13874  S[i]=scale*g;
13875 
13876  g = s = scale = 0;
13877  if (i<dimy() && i!=dimx()-1) {
13878  for (int k = l; k<dimx(); ++k) scale += cimg::abs(U(k,i));
13879  if (scale) {
13880  for (int k = l; k<dimx(); ++k) { U(k,i)/= scale; s+= U(k,i)*U(k,i); }
13881  f = U(l,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g;
13882  for (int k = l; k<dimx(); ++k) rv1[k]=U(k,i)/h;
13883  for (int j = l; j<dimy(); ++j) {
13884  s = 0;
13885  for (int k = l; k<dimx(); ++k) s+= U(k,j)*U(k,i);
13886  for (int k = l; k<dimx(); ++k) U(k,j)+= s*rv1[k];
13887  }
13888  for (int k = l; k<dimx(); ++k) U(k,i)*= scale;
13889  }
13890  }
13891  anorm = (t)cimg::max((float)anorm,(float)(cimg::abs(S[i])+cimg::abs(rv1[i])));
13892  }
13893 
13894  for (int i = dimx()-1; i>=0; --i) {
13895  if (i<dimx()-1) {
13896  if (g) {
13897  for (int j = l; j<dimx(); ++j) V(i,j) =(U(j,i)/U(l,i))/g;
13898  for (int j = l; j<dimx(); ++j) {
13899  s = 0;
13900  for (int k = l; k<dimx(); ++k) s+= U(k,i)*V(j,k);
13901  for (int k = l; k<dimx(); ++k) V(j,k)+= s*V(i,k);
13902  }
13903  }
13904  for (int j = l; j<dimx(); ++j) V(j,i) = V(i,j) = (t)0.0;
13905  }
13906  V(i,i) = (t)1.0; g = rv1[i]; l = i;
13907  }
13908 
13909 
13910  for (int i = cimg::min(dimx(),dimy())-1; i>=0; --i) {
13911  l = i+1; g = S[i];
13912  for (int j = l; j<dimx(); ++j) U(j,i) = 0;
13913  if (g) {
13914  g = 1/g;
13915  for (int j = l; j<dimx(); ++j) {
13916  s = 0; for (int k = l; k<dimy(); ++k) s+= U(i,k)*U(j,k);
13917  f = (s/U(i,i))*g;
13918  for (int k = i; k<dimy(); ++k) U(j,k)+= f*U(i,k);
13919  }
13920  for (int j = i; j<dimy(); ++j) U(i,j)*= g;
13921  } else for (int j = i; j<dimy(); ++j) U(i,j) = 0;
13922  ++U(i,i);
13923  }
13924 
13925  for (int k = dimx()-1; k>=0; --k) {
13926  for (unsigned int its = 0; its<max_iter; ++its) {
13927  bool flag = true;
13928  for (l = k; l>=1; --l) {
13929  nm = l-1;
13930  if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; }
13931  if ((cimg::abs(S[nm])+anorm)==anorm) break;
13932  }
13933  if (flag) {
13934  c = 0; s = 1;
13935  for (int i = l; i<=k; ++i) {
13936  f = s*rv1[i]; rv1[i] = c*rv1[i];
13937  if ((cimg::abs(f)+anorm)==anorm) break;
13938  g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;
13939  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; }
13940  }
13941  }
13942  const t z = S[k];
13943  if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; }
13944  nm = k-1;
13945  t x = S[l], y = S[nm];
13946  g = rv1[nm]; h = rv1[k];
13947  f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y);
13948  g = (t)cimg::_pythagore(f,1.0);
13949  f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x;
13950  c = s = 1;
13951  for (int j = l; j<=nm; ++j) {
13952  const int i = j+1;
13953  g = rv1[i]; h = s*g; g = c*g;
13954  t y = S[i];
13955  t z = (t)cimg::_pythagore(f,h);
13956  rv1[j] = z; c = f/z; s = h/z;
13957  f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c;
13958  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; }
13959  z = (t)cimg::_pythagore(f,h); S[j] = z;
13960  if (z) { z = 1/z; c = f*z; s = h*z; }
13961  f = c*g+s*y; x = c*y-s*g;
13962  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; }
13963  }
13964  rv1[l] = 0; rv1[k]=f; S[k]=x;
13965  }
13966  }
13967 
13968  if (sorting) {
13969  CImg<intT> permutations(width);
13970  CImg<t> tmp(width);
13971  S.sort(permutations,false);
13972  cimg_forY(U,k) {
13973  cimg_forX(permutations,x) tmp(x) = U(permutations(x),k);
13974  std::memcpy(U.ptr(0,k),tmp.data,sizeof(t)*width);
13975  }
13976  cimg_forY(V,k) {
13977  cimg_forX(permutations,x) tmp(x) = V(permutations(x),k);
13978  std::memcpy(V.ptr(0,k),tmp.data,sizeof(t)*width);
13979  }
13980  }
13981  }
13982  return *this;
13983  }
13984 
13985  CImgList<Tfloat> get_SVD(const bool sorting=true,
13986  const unsigned int max_iter=40, const float lambda=0) const {
13987  CImgList<Tfloat> res(3);
13988  SVD(res[0],res[1],res[2],sorting,max_iter,lambda);
13989  return res;
13990  }
13991 
13992  // INNER ROUTINE : Compute the LU decomposition of a permuted matrix (c.f. numerical recipies)
13993  template<typename t>
13994  CImg<T>& _LU(CImg<t>& indx, bool& d) {
13995  const int N = dimx();
13996  int imax = 0;
13997  CImg<Tfloat> vv(N);
13998  indx.assign(N);
13999  d = true;
14000  cimg_forX(*this,i) {
14001  Tfloat vmax = 0;
14002  cimg_forX(*this,j) {
14003  const Tfloat tmp = cimg::abs((*this)(j,i));
14004  if (tmp>vmax) vmax = tmp;
14005  }
14006  if (vmax==0) { indx.fill(0); return fill(0); }
14007  vv[i] = 1/vmax;
14008  }
14009  cimg_forX(*this,j) {
14010  for (int i = 0; i<j; ++i) {
14011  Tfloat sum=(*this)(j,i);
14012  for (int k = 0; k<i; ++k) sum-=(*this)(k,i)*(*this)(j,k);
14013  (*this)(j,i) = (T)sum;
14014  }
14015  Tfloat vmax = 0;
14016  for (int i = j; i<dimx(); ++i) {
14017  Tfloat sum=(*this)(j,i);
14018  for (int k = 0; k<j; ++k) sum-=(*this)(k,i)*(*this)(j,k);
14019  (*this)(j,i) = (T)sum;
14020  const Tfloat tmp = vv[i]*cimg::abs(sum);
14021  if (tmp>=vmax) { vmax=tmp; imax=i; }
14022  }
14023  if (j!=imax) {
14024  cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j));
14025  d =!d;
14026  vv[imax] = vv[j];
14027  }
14028  indx[j] = (t)imax;
14029  if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20;
14030  if (j<N) {
14031  const Tfloat tmp = 1/(Tfloat)(*this)(j,j);
14032  for (int i=j+1; i<N; ++i) (*this)(j,i) = (T)((*this)(j,i)*tmp);
14033  }
14034  }
14035  return *this;
14036  }
14037 
14039 
14047  template<typename tf, typename t>
14048  static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
14049  const unsigned int starting_node, const unsigned int ending_node,
14050  CImg<t>& previous) {
14051 
14052  CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max());
14053  dist(starting_node) = 0;
14054  previous.assign(1,nb_nodes,1,1,(t)-1);
14055  previous(starting_node) = (t)starting_node;
14056  CImg<uintT> Q(nb_nodes);
14057  cimg_forX(Q,u) Q(u) = u;
14058  cimg::swap(Q(starting_node),Q(0));
14059  unsigned int sizeQ = nb_nodes;
14060  while (sizeQ) {
14061  // Update neighbors from minimal vertex
14062  const unsigned int umin = Q(0);
14063  if (umin==ending_node) sizeQ = 0;
14064  else {
14065  const T dmin = dist(umin);
14066  const T infty = cimg::type<T>::max();
14067  for (unsigned int q=1; q<sizeQ; ++q) {
14068  const unsigned int v = Q(q);
14069  const T d = (T)distance(v,umin);
14070  if (d<infty) {
14071  const T alt = dmin + d;
14072  if (alt<dist(v)) {
14073  dist(v) = alt;
14074  previous(v) = (t)umin;
14075  const T distpos = dist(Q(q));
14076  for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos+1)/2-1)); pos=par) cimg::swap(Q(pos),Q(par));
14077  }
14078  }
14079  }
14080  // Remove minimal vertex from queue
14081  Q(0) = Q(--sizeQ);
14082  const T distpos = dist(Q(0));
14083  for (unsigned int pos = 0, left = 0, right = 0;
14084  ((right=2*(pos+1),(left=right-1))<sizeQ && distpos>dist(Q(left))) || (right<sizeQ && distpos>dist(Q(right)));) {
14085  if (right<sizeQ) {
14086  if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; }
14087  else { cimg::swap(Q(pos),Q(right)); pos = right; }
14088  } else { cimg::swap(Q(pos),Q(left)); pos = left; }
14089  }
14090  }
14091  }
14092  return dist;
14093  }
14094 
14096  template<typename tf, typename t>
14097  static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
14098  const unsigned int starting_node, const unsigned int ending_node=~0U) {
14099  CImg<uintT> foo;
14100  return dijkstra(distance,nb_nodes,starting_node,ending_node,foo);
14101  }
14102 
14104 
14110  template<typename t>
14111  CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) {
14112  return get_dijkstra(starting_node,ending_node,previous).transfer_to(*this);
14113  }
14114 
14115  template<typename t>
14116  CImg<T> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) const {
14117  if (width!=height || depth!=1 || dim!=1)
14118  throw CImgInstanceException("CImg<%s>::dijkstra() : Instance image (%u,%u,%u,%u,%p) is not a graph adjacency matrix",
14119  pixel_type(),width,height,depth,dim,data);
14120  return dijkstra(*this,width,starting_node,ending_node,previous);
14121  }
14122 
14124  CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) {
14125  return get_dijkstra(starting_node,ending_node).transfer_to(*this);
14126  }
14127 
14128  CImg<Tfloat> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const {
14129  CImg<uintT> foo;
14130  return get_dijkstra(starting_node,ending_node,foo);
14131  }
14132 
14134  static CImg<T> vector(const T& a0) {
14135  static CImg<T> r(1,1); r[0] = a0;
14136  return r;
14137  }
14138 
14140  static CImg<T> vector(const T& a0, const T& a1) {
14141  static CImg<T> r(1,2); T *ptr = r.data;
14142  *(ptr++) = a0; *(ptr++) = a1;
14143  return r;
14144  }
14145 
14147  static CImg<T> vector(const T& a0, const T& a1, const T& a2) {
14148  static CImg<T> r(1,3); T *ptr = r.data;
14149  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
14150  return r;
14151  }
14152 
14154  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3) {
14155  static CImg<T> r(1,4); T *ptr = r.data;
14156  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14157  return r;
14158  }
14159 
14161  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
14162  static CImg<T> r(1,5); T *ptr = r.data;
14163  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
14164  return r;
14165  }
14166 
14168  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {
14169  static CImg<T> r(1,6); T *ptr = r.data;
14170  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
14171  return r;
14172  }
14173 
14175  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
14176  const T& a4, const T& a5, const T& a6) {
14177  static CImg<T> r(1,7); T *ptr = r.data;
14178  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14179  *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6;
14180  return r;
14181  }
14182 
14184  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
14185  const T& a4, const T& a5, const T& a6, const T& a7) {
14186  static CImg<T> r(1,8); T *ptr = r.data;
14187  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14188  *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
14189  return r;
14190  }
14191 
14193  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
14194  const T& a4, const T& a5, const T& a6, const T& a7,
14195  const T& a8) {
14196  static CImg<T> r(1,9); T *ptr = r.data;
14197  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14198  *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
14199  *(ptr++) = a8;
14200  return r;
14201  }
14202 
14204  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
14205  const T& a4, const T& a5, const T& a6, const T& a7,
14206  const T& a8, const T& a9) {
14207  static CImg<T> r(1,10); T *ptr = r.data;
14208  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14209  *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
14210  *(ptr++) = a8; *(ptr++) = a9;
14211  return r;
14212  }
14213 
14215  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
14216  const T& a4, const T& a5, const T& a6, const T& a7,
14217  const T& a8, const T& a9, const T& a10) {
14218  static CImg<T> r(1,11); T *ptr = r.data;
14219  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14220  *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
14221  *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10;
14222  return r;
14223  }
14224 
14226  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
14227  const T& a4, const T& a5, const T& a6, const T& a7,
14228  const T& a8, const T& a9, const T& a10, const T& a11) {
14229  static CImg<T> r(1,12); T *ptr = r.data;
14230  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14231  *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
14232  *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
14233  return r;
14234  }
14235 
14237  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
14238  const T& a4, const T& a5, const T& a6, const T& a7,
14239  const T& a8, const T& a9, const T& a10, const T& a11,
14240  const T& a12) {
14241  static CImg<T> r(1,13); T *ptr = r.data;
14242  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14243  *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
14244  *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
14245  *(ptr++) = a12;
14246  return r;
14247  }
14248 
14250  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
14251  const T& a4, const T& a5, const T& a6, const T& a7,
14252  const T& a8, const T& a9, const T& a10, const T& a11,
14253  const T& a12, const T& a13) {
14254  static CImg<T> r(1,14); T *ptr = r.data;
14255  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14256  *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
14257  *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
14258  *(ptr++) = a12; *(ptr++) = a13;
14259  return r;
14260  }
14261 
14263  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
14264  const T& a4, const T& a5, const T& a6, const T& a7,
14265  const T& a8, const T& a9, const T& a10, const T& a11,
14266  const T& a12, const T& a13, const T& a14) {
14267  static CImg<T> r(1,15); T *ptr = r.data;
14268  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14269  *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
14270  *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
14271  *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
14272  return r;
14273  }
14274 
14276  static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
14277  const T& a4, const T& a5, const T& a6, const T& a7,
14278  const T& a8, const T& a9, const T& a10, const T& a11,
14279  const T& a12, const T& a13, const T& a14, const T& a15) {
14280  static CImg<T> r(1,16); T *ptr = r.data;
14281  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14282  *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
14283  *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
14284  *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
14285  return r;
14286  }
14287 
14289  static CImg<T> matrix(const T& a0) {
14290  return vector(a0);
14291  }
14292 
14294  static CImg<T> matrix(const T& a0, const T& a1,
14295  const T& a2, const T& a3) {
14296  static CImg<T> r(2,2); T *ptr = r.data;
14297  *(ptr++) = a0; *(ptr++) = a1;
14298  *(ptr++) = a2; *(ptr++) = a3;
14299  return r;
14300  }
14301 
14303  static CImg<T> matrix(const T& a0, const T& a1, const T& a2,
14304  const T& a3, const T& a4, const T& a5,
14305  const T& a6, const T& a7, const T& a8) {
14306  static CImg<T> r(3,3); T *ptr = r.data;
14307  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
14308  *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
14309  *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8;
14310  return r;
14311  }
14312 
14314  static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3,
14315  const T& a4, const T& a5, const T& a6, const T& a7,
14316  const T& a8, const T& a9, const T& a10, const T& a11,
14317  const T& a12, const T& a13, const T& a14, const T& a15) {
14318  static CImg<T> r(4,4); T *ptr = r.data;
14319  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
14320  *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
14321  *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
14322  *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
14323  return r;
14324  }
14325 
14327  static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4,
14328  const T& a5, const T& a6, const T& a7, const T& a8, const T& a9,
14329  const T& a10, const T& a11, const T& a12, const T& a13, const T& a14,
14330  const T& a15, const T& a16, const T& a17, const T& a18, const T& a19,
14331  const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) {
14332  static CImg<T> r(5,5); T *ptr = r.data;
14333  *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
14334  *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9;
14335  *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
14336  *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19;
14337  *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24;
14338  return r;
14339  }
14340 
14342  static CImg<T> tensor(const T& a1) {
14343  return matrix(a1);
14344  }
14345 
14347  static CImg<T> tensor(const T& a1, const T& a2, const T& a3) {
14348  return matrix(a1,a2,a2,a3);
14349  }
14350 
14352  static CImg<T> tensor(const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) {
14353  return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6);
14354  }
14355 
14357  static CImg<T> diagonal(const T& a0) {
14358  return matrix(a0);
14359  }
14360 
14362  static CImg<T> diagonal(const T& a0, const T& a1) {
14363  return matrix(a0,0,0,a1);
14364  }
14365 
14367  static CImg<T> diagonal(const T& a0, const T& a1, const T& a2) {
14368  return matrix(a0,0,0,0,a1,0,0,0,a2);
14369  }
14370 
14372  static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3) {
14373  return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3);
14374  }
14375 
14377  static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
14378  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);
14379  }
14380 
14382  static CImg<T> identity_matrix(const unsigned int N) {
14383  CImg<T> res(N,N,1,1,0);
14384  cimg_forX(res,x) res(x,x) = 1;
14385  return res;
14386  }
14387 
14389  static CImg<T> sequence(const unsigned int N, const T a0, const T a1) {
14390  if (N) return CImg<T>(1,N).sequence(a0,a1);
14391  return CImg<T>();
14392  }
14393 
14395  static CImg<T> rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) {
14396  float X,Y,Z,W;
14397  if (!quaternion_data) {
14398  const float norm = (float)std::sqrt(x*x + y*y + z*z),
14399  nx = norm>0?x/norm:0,
14400  ny = norm>0?y/norm:0,
14401  nz = norm>0?z/norm:1,
14402  nw = norm>0?w:0,
14403  sina = (float)std::sin(nw/2),
14404  cosa = (float)std::cos(nw/2);
14405  X = nx*sina;
14406  Y = ny*sina;
14407  Z = nz*sina;
14408  W = cosa;
14409  } else {
14410  const float norm = (float)std::sqrt(x*x + y*y + z*z + w*w);
14411  if (norm>0) { X = x/norm; Y = y/norm; Z = z/norm; W = w/norm; }
14412  else { X = Y = Z = 0; W = 1; }
14413  }
14414  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;
14415  return CImg<T>::matrix((T)(1-2*(yy+zz)), (T)(2*(xy+zw)), (T)(2*(xz-yw)),
14416  (T)(2*(xy-zw)), (T)(1-2*(xx+zz)), (T)(2*(yz+xw)),
14417  (T)(2*(xz+yw)), (T)(2*(yz-xw)), (T)(1-2*(xx+yy)));
14418  }
14419 
14421  //-----------------------------------
14422  //
14424 
14425  //-----------------------------------
14426 
14428 
14432  CImg<T>& fill(const T val) {
14433  if (is_empty()) return *this;
14434  if (val && sizeof(T)!=1) cimg_for(*this,ptr,T) *ptr = val;
14435  else std::memset(data,(int)val,size()*sizeof(T));
14436  return *this;
14437  }
14438 
14439  CImg<T> get_fill(const T val) const {
14440  return CImg<T>(width,height,depth,dim).fill(val);
14441  }
14442 
14444  CImg<T>& fill(const T val0, const T val1) {
14445  if (is_empty()) return *this;
14446  T *ptr, *ptr_end = end()-1;
14447  for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; }
14448  if (ptr!=ptr_end+1) *(ptr++) = val0;
14449  return *this;
14450  }
14451 
14452  CImg<T> get_fill(const T val0, const T val1) const {
14453  return CImg<T>(width,height,depth,dim).fill(val0,val1);
14454  }
14455 
14457  CImg<T>& fill(const T val0, const T val1, const T val2) {
14458  if (is_empty()) return *this;
14459  T *ptr, *ptr_end = end()-2;
14460  for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; }
14461  ptr_end+=2;
14462  switch (ptr_end-ptr) {
14463  case 2 : *(--ptr_end) = val1;
14464  case 1 : *(--ptr_end) = val0;
14465  }
14466  return *this;
14467  }
14468 
14469  CImg<T> get_fill(const T val0, const T val1, const T val2) const {
14470  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2);
14471  }
14472 
14474  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3) {
14475  if (is_empty()) return *this;
14476  T *ptr, *ptr_end = end()-3;
14477  for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; }
14478  ptr_end+=3;
14479  switch (ptr_end-ptr) {
14480  case 3 : *(--ptr_end) = val2;
14481  case 2 : *(--ptr_end) = val1;
14482  case 1 : *(--ptr_end) = val0;
14483  }
14484  return *this;
14485  }
14486 
14487  CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3) const {
14488  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3);
14489  }
14490 
14492  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4) {
14493  if (is_empty()) return *this;
14494  T *ptr, *ptr_end = end()-4;
14495  for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; }
14496  ptr_end+=4;
14497  switch (ptr_end-ptr) {
14498  case 4 : *(--ptr_end) = val3;
14499  case 3 : *(--ptr_end) = val2;
14500  case 2 : *(--ptr_end) = val1;
14501  case 1 : *(--ptr_end) = val0;
14502  }
14503  return *this;
14504  }
14505 
14506  CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4) const {
14507  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4);
14508  }
14509 
14511  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) {
14512  if (is_empty()) return *this;
14513  T *ptr, *ptr_end = end()-5;
14514  for (ptr = data; ptr<ptr_end; ) {
14515  *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
14516  }
14517  ptr_end+=5;
14518  switch (ptr_end-ptr) {
14519  case 5 : *(--ptr_end) = val4;
14520  case 4 : *(--ptr_end) = val3;
14521  case 3 : *(--ptr_end) = val2;
14522  case 2 : *(--ptr_end) = val1;
14523  case 1 : *(--ptr_end) = val0;
14524  }
14525  return *this;
14526  }
14527 
14528  CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) const {
14529  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5);
14530  }
14531 
14533  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) {
14534  if (is_empty()) return *this;
14535  T *ptr, *ptr_end = end()-6;
14536  for (ptr = data; ptr<ptr_end; ) {
14537  *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6;
14538  }
14539  ptr_end+=6;
14540  switch (ptr_end-ptr) {
14541  case 6 : *(--ptr_end) = val5;
14542  case 5 : *(--ptr_end) = val4;
14543  case 4 : *(--ptr_end) = val3;
14544  case 3 : *(--ptr_end) = val2;
14545  case 2 : *(--ptr_end) = val1;
14546  case 1 : *(--ptr_end) = val0;
14547  }
14548  return *this;
14549  }
14550 
14551  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 {
14552  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6);
14553  }
14554 
14556  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
14557  const T val7) {
14558  if (is_empty()) return *this;
14559  T *ptr, *ptr_end = end()-7;
14560  for (ptr = data; ptr<ptr_end; ) {
14561  *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3;
14562  *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7;
14563  }
14564  ptr_end+=7;
14565  switch (ptr_end-ptr) {
14566  case 7 : *(--ptr_end) = val6;
14567  case 6 : *(--ptr_end) = val5;
14568  case 5 : *(--ptr_end) = val4;
14569  case 4 : *(--ptr_end) = val3;
14570  case 3 : *(--ptr_end) = val2;
14571  case 2 : *(--ptr_end) = val1;
14572  case 1 : *(--ptr_end) = val0;
14573  }
14574  return *this;
14575  }
14576 
14577  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,
14578  const T val7) const {
14579  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7);
14580  }
14581 
14583  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
14584  const T val7, const T val8) {
14585  if (is_empty()) return *this;
14586  T *ptr, *ptr_end = end()-8;
14587  for (ptr = data; ptr<ptr_end; ) {
14588  *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2;
14589  *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
14590  *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8;
14591  }
14592  ptr_end+=8;
14593  switch (ptr_end-ptr) {
14594  case 8 : *(--ptr_end) = val7;
14595  case 7 : *(--ptr_end) = val6;
14596  case 6 : *(--ptr_end) = val5;
14597  case 5 : *(--ptr_end) = val4;
14598  case 4 : *(--ptr_end) = val3;
14599  case 3 : *(--ptr_end) = val2;
14600  case 2 : *(--ptr_end) = val1;
14601  case 1 : *(--ptr_end) = val0;
14602  }
14603  return *this;
14604  }
14605 
14606  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,
14607  const T val7, const T val8) const {
14608  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);
14609  }
14610 
14612  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
14613  const T val7, const T val8, const T val9) {
14614  if (is_empty()) return *this;
14615  T *ptr, *ptr_end = end()-9;
14616  for (ptr = data; ptr<ptr_end; ) {
14617  *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
14618  *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
14619  }
14620  ptr_end+=9;
14621  switch (ptr_end-ptr) {
14622  case 9 : *(--ptr_end) = val8;
14623  case 8 : *(--ptr_end) = val7;
14624  case 7 : *(--ptr_end) = val6;
14625  case 6 : *(--ptr_end) = val5;
14626  case 5 : *(--ptr_end) = val4;
14627  case 4 : *(--ptr_end) = val3;
14628  case 3 : *(--ptr_end) = val2;
14629  case 2 : *(--ptr_end) = val1;
14630  case 1 : *(--ptr_end) = val0;
14631  }
14632  return *this;
14633  }
14634 
14635  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,
14636  const T val7, const T val8, const T val9) const {
14637  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);
14638  }
14639 
14641  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
14642  const T val7, const T val8, const T val9, const T val10) {
14643  if (is_empty()) return *this;
14644  T *ptr, *ptr_end = end()-10;
14645  for (ptr = data; ptr<ptr_end; ) {
14646  *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
14647  *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
14648  *(ptr++) = val10;
14649  }
14650  ptr_end+=10;
14651  switch (ptr_end-ptr) {
14652  case 10 : *(--ptr_end) = val9;
14653  case 9 : *(--ptr_end) = val8;
14654  case 8 : *(--ptr_end) = val7;
14655  case 7 : *(--ptr_end) = val6;
14656  case 6 : *(--ptr_end) = val5;
14657  case 5 : *(--ptr_end) = val4;
14658  case 4 : *(--ptr_end) = val3;
14659  case 3 : *(--ptr_end) = val2;
14660  case 2 : *(--ptr_end) = val1;
14661  case 1 : *(--ptr_end) = val0;
14662  }
14663  return *this;
14664  }
14665 
14666  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,
14667  const T val7, const T val8, const T val9, const T val10) const {
14668  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10);
14669  }
14670 
14672  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
14673  const T val7, const T val8, const T val9, const T val10, const T val11) {
14674  if (is_empty()) return *this;
14675  T *ptr, *ptr_end = end()-11;
14676  for (ptr = data; ptr<ptr_end; ) {
14677  *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
14678  *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
14679  }
14680  ptr_end+=11;
14681  switch (ptr_end-ptr) {
14682  case 11 : *(--ptr_end) = val10;
14683  case 10 : *(--ptr_end) = val9;
14684  case 9 : *(--ptr_end) = val8;
14685  case 8 : *(--ptr_end) = val7;
14686  case 7 : *(--ptr_end) = val6;
14687  case 6 : *(--ptr_end) = val5;
14688  case 5 : *(--ptr_end) = val4;
14689  case 4 : *(--ptr_end) = val3;
14690  case 3 : *(--ptr_end) = val2;
14691  case 2 : *(--ptr_end) = val1;
14692  case 1 : *(--ptr_end) = val0;
14693  }
14694  return *this;
14695  }
14696 
14697  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,
14698  const T val7, const T val8, const T val9, const T val10, const T val11) const {
14699  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11);
14700  }
14701 
14703  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
14704  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) {
14705  if (is_empty()) return *this;
14706  T *ptr, *ptr_end = end()-12;
14707  for (ptr = data; ptr<ptr_end; ) {
14708  *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
14709  *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
14710  *(ptr++) = val12;
14711  }
14712  ptr_end+=12;
14713  switch (ptr_end-ptr) {
14714  case 12 : *(--ptr_end) = val11;
14715  case 11 : *(--ptr_end) = val10;
14716  case 10 : *(--ptr_end) = val9;
14717  case 9 : *(--ptr_end) = val8;
14718  case 8 : *(--ptr_end) = val7;
14719  case 7 : *(--ptr_end) = val6;
14720  case 6 : *(--ptr_end) = val5;
14721  case 5 : *(--ptr_end) = val4;
14722  case 4 : *(--ptr_end) = val3;
14723  case 3 : *(--ptr_end) = val2;
14724  case 2 : *(--ptr_end) = val1;
14725  case 1 : *(--ptr_end) = val0;
14726  }
14727  return *this;
14728  }
14729 
14730  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,
14731  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) const {
14732  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12);
14733  }
14734 
14736  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
14737  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
14738  const T val13) {
14739  if (is_empty()) return *this;
14740  T *ptr, *ptr_end = end()-13;
14741  for (ptr = data; ptr<ptr_end; ) {
14742  *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
14743  *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
14744  *(ptr++) = val12; *(ptr++) = val13;
14745  }
14746  ptr_end+=13;
14747  switch (ptr_end-ptr) {
14748  case 13 : *(--ptr_end) = val12;
14749  case 12 : *(--ptr_end) = val11;
14750  case 11 : *(--ptr_end) = val10;
14751  case 10 : *(--ptr_end) = val9;
14752  case 9 : *(--ptr_end) = val8;
14753  case 8 : *(--ptr_end) = val7;
14754  case 7 : *(--ptr_end) = val6;
14755  case 6 : *(--ptr_end) = val5;
14756  case 5 : *(--ptr_end) = val4;
14757  case 4 : *(--ptr_end) = val3;
14758  case 3 : *(--ptr_end) = val2;
14759  case 2 : *(--ptr_end) = val1;
14760  case 1 : *(--ptr_end) = val0;
14761  }
14762  return *this;
14763  }
14764 
14765  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,
14766  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
14767  const T val13) const {
14768  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
14769  val13);
14770  }
14771 
14773  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
14774  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
14775  const T val13, const T val14) {
14776  if (is_empty()) return *this;
14777  T *ptr, *ptr_end = end()-14;
14778  for (ptr = data; ptr<ptr_end; ) {
14779  *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
14780  *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
14781  *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14;
14782  }
14783  ptr_end+=14;
14784  switch (ptr_end-ptr) {
14785  case 14 : *(--ptr_end) = val13;
14786  case 13 : *(--ptr_end) = val12;
14787  case 12 : *(--ptr_end) = val11;
14788  case 11 : *(--ptr_end) = val10;
14789  case 10 : *(--ptr_end) = val9;
14790  case 9 : *(--ptr_end) = val8;
14791  case 8 : *(--ptr_end) = val7;
14792  case 7 : *(--ptr_end) = val6;
14793  case 6 : *(--ptr_end) = val5;
14794  case 5 : *(--ptr_end) = val4;
14795  case 4 : *(--ptr_end) = val3;
14796  case 3 : *(--ptr_end) = val2;
14797  case 2 : *(--ptr_end) = val1;
14798  case 1 : *(--ptr_end) = val0;
14799  }
14800  return *this;
14801  }
14802 
14803  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,
14804  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
14805  const T val13, const T val14) const {
14806  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
14807  val13,val14);
14808  }
14809 
14811  CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
14812  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
14813  const T val13, const T val14, const T val15) {
14814  if (is_empty()) return *this;
14815  T *ptr, *ptr_end = end()-15;
14816  for (ptr = data; ptr<ptr_end; ) {
14817  *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
14818  *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
14819  *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14; *(ptr++) = val15;
14820  }
14821  ptr_end+=15;
14822  switch (ptr_end-ptr) {
14823  case 15 : *(--ptr_end) = val14;
14824  case 14 : *(--ptr_end) = val13;
14825  case 13 : *(--ptr_end) = val12;
14826  case 12 : *(--ptr_end) = val11;
14827  case 11 : *(--ptr_end) = val10;
14828  case 10 : *(--ptr_end) = val9;
14829  case 9 : *(--ptr_end) = val8;
14830  case 8 : *(--ptr_end) = val7;
14831  case 7 : *(--ptr_end) = val6;
14832  case 6 : *(--ptr_end) = val5;
14833  case 5 : *(--ptr_end) = val4;
14834  case 4 : *(--ptr_end) = val3;
14835  case 3 : *(--ptr_end) = val2;
14836  case 2 : *(--ptr_end) = val1;
14837  case 1 : *(--ptr_end) = val0;
14838  }
14839  return *this;
14840  }
14841 
14842  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,
14843  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
14844  const T val13, const T val14, const T val15) const {
14845  return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
14846  val13,val14,val15);
14847  }
14848 
14850  CImg<T>& fill(const char *const expression, const bool repeat_flag) {
14851  if (is_empty() || !expression || !*expression) return *this;
14852  const unsigned int omode = cimg::exception_mode();
14853  cimg::exception_mode() = 0;
14854  try { // Try to fill values according to a formula.
14855  _cimg_math_parser mp(expression,"fill");
14856  const CImg<T> _base = std::strstr(expression,"i(")?+*this:CImg<T>(), &base = _base?_base:*this;
14857  T *ptrd = data;
14858  cimg_forXYZV(*this,x,y,z,v) *(ptrd++) = (T)mp.eval(base,(double)x,(double)y,(double)z,(double)v);
14859  } catch (CImgException&) { // If failed, try to recognize a list of values.
14860  char item[16384] = { 0 }, sep = 0; const char *nexpression = expression;
14861  unsigned int nb = 0; const unsigned int siz = size();
14862  T *ptrd = data;
14863  for (double val = 0; *nexpression && nb<siz; ++nb) {
14864  const int err = std::sscanf(nexpression,"%4095[ \n\t0-9.e+-]%c",item,&sep);
14865  if (err>0 && std::sscanf(item,"%lf",&val)==1) {
14866  nexpression += std::strlen(item) + (err>1?1:0);
14867  *(ptrd++) = (T)val;
14868  } else break;
14869  }
14870  cimg::exception_mode() = omode;
14871  if (*nexpression)
14872  throw CImgArgumentException("CImg<%s>::fill() : Invalid expression '%s'.",pixel_type(),expression);
14873  if (repeat_flag && nb) for (T *ptrs = data, *const ptr_end = data + siz; ptrd<ptr_end; ++ptrs) *(ptrd++) = *ptrs;
14874  }
14875  cimg::exception_mode() = omode;
14876  return *this;
14877  }
14878 
14879  CImg<T> get_fill(const char *const values, const bool repeat_values) const {
14880  return (+*this).fill(values,repeat_values);
14881  }
14882 
14884  template<typename t>
14885  CImg<T>& fill(const CImg<t>& values, const bool repeat_values=true) {
14886  if (is_empty() || !values) return *this;
14887  T *ptrd = data, *ptrd_end = ptrd + size();
14888  for (t *ptrs = values.data, *ptrs_end = ptrs + values.size(); ptrs<ptrs_end && ptrd<ptrd_end; ++ptrs) *(ptrd++) = (T)*ptrs;
14889  if (repeat_values && ptrd<ptrd_end) for (T *ptrs = data; ptrd<ptrd_end; ++ptrs) *(ptrd++) = *ptrs;
14890  return *this;
14891  }
14892 
14893  template<typename t>
14894  CImg<T> get_fill(const CImg<t>& values, const bool repeat_values=true) const {
14895  return repeat_values?CImg<T>(width,height,depth,dim).fill(values,repeat_values):(+*this).fill(values,repeat_values);
14896  }
14897 
14899  CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const int a0, ...) {
14900 #define _cimg_fill1(x,y,z,v,off,siz,t) { \
14901  va_list ap; va_start(ap,a0); T *ptrd = ptr(x,y,z,v); *ptrd = (T)a0; \
14902  for (unsigned int k = 1; k<siz; ++k) { ptrd+=off; *ptrd = (T)va_arg(ap,t); } \
14903  va_end(ap); }
14904  if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,int);
14905  return *this;
14906  }
14907 
14908  CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const double a0, ...) {
14909  if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,double);
14910  return *this;
14911  }
14912 
14914  CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const int a0, ...) {
14915  if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,int);
14916  return *this;
14917  }
14918 
14919  CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const double a0, ...) {
14920  if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,double);
14921  return *this;
14922  }
14923 
14925  CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const int a0, ...) {
14926  const unsigned int wh = width*height;
14927  if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,int);
14928  return *this;
14929  }
14930 
14931  CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const double a0, ...) {
14932  const unsigned int wh = width*height;
14933  if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,double);
14934  return *this;
14935  }
14936 
14938  CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) {
14939  const unsigned int whz = width*height*depth;
14940  if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,int);
14941  return *this;
14942  }
14943 
14944  CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) {
14945  const unsigned int whz = width*height*depth;
14946  if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,double);
14947  return *this;
14948  }
14949 
14953  return *this;
14954  }
14955 
14957  return (+*this).invert_endianness();
14958  }
14959 
14961  CImg<T>& rand(const T val_min, const T val_max) {
14962  const float delta = (float)val_max - (float)val_min;
14963  cimg_for(*this,ptr,T) *ptr = (T)(val_min + cimg::rand()*delta);
14964  return *this;
14965  }
14966 
14967  CImg<T> get_rand(const T val_min, const T val_max) const {
14968  return (+*this).rand(val_min,val_max);
14969  }
14970 
14972 
14976  CImg<T>& round(const float x, const int rounding_type=0) {
14977  cimg_for(*this,ptr,T) (*ptr) = (T)cimg::round(*ptr,x,rounding_type);
14978  return *this;
14979  }
14980 
14981  CImg<T> get_round(const float x, const unsigned int rounding_type=0) const {
14982  return (+*this).round(x,rounding_type);
14983  }
14984 
14986 
15000  CImg<T>& noise(const double sigma, const unsigned int noise_type=0) {
15001  if (!is_empty()) {
15002  double nsigma = sigma, max = (double)cimg::type<T>::max(), min = (double)cimg::type<T>::min();
15003  Tfloat m = 0, M = 0;
15004  if (nsigma==0 && noise_type!=3) return *this;
15005  if (nsigma<0 || noise_type==2) m = (Tfloat)minmax(M);
15006  if (nsigma<0) nsigma = -nsigma*(M-m)/100.0;
15007  switch (noise_type) {
15008  case 0 : { // Gaussian noise
15009  cimg_for(*this,ptr,T) {
15010  double val = *ptr + nsigma*cimg::grand();
15011  if (val>max) val = max;
15012  if (val<min) val = min;
15013  *ptr = (T)val;
15014  }
15015  } break;
15016  case 1 : { // Uniform noise
15017  cimg_for(*this,ptr,T) {
15018  double val = *ptr + nsigma*cimg::crand();
15019  if (val>max) val = max;
15020  if (val<min) val = min;
15021  *ptr = (T)val;
15022  }
15023  } break;
15024  case 2 : { // Salt & Pepper noise
15025  if (nsigma<0) nsigma = -nsigma;
15026  if (M==m) { m = 0; M = (float)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); }
15027  cimg_for(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr = (T)(cimg::rand()<0.5?M:m);
15028  } break;
15029 
15030  case 3 : { // Poisson Noise
15031  cimg_for(*this,ptr,T) *ptr = (T)cimg::prand(*ptr);
15032  } break;
15033 
15034  case 4 : { // Rice noise
15035  const double sqrt2 = (double)std::sqrt(2.0);
15036  cimg_for(*this,ptr,T) {
15037  const double
15038  val0 = (double)*ptr/sqrt2,
15039  re = val0 + nsigma*cimg::grand(),
15040  im = val0 + nsigma*cimg::grand();
15041  double val = std::sqrt(re*re + im*im);
15042  if (val>max) val = max;
15043  if (val<min) val = min;
15044  *ptr = (T)val;
15045  }
15046  } break;
15047  default :
15048  throw CImgArgumentException("CImg<%s>::noise() : Invalid noise type %d "
15049  "(should be {0=Gaussian, 1=Uniform, 2=Salt&Pepper, 3=Poisson}).",pixel_type(),noise_type);
15050  }
15051  }
15052  return *this;
15053  }
15054 
15055  CImg<T> get_noise(const double sigma, const unsigned int noise_type=0) const {
15056  return (+*this).noise(sigma,noise_type);
15057  }
15058 
15060 
15073  CImg<T>& normalize(const T value_min, const T value_max) {
15074  if (is_empty()) return *this;
15075  const T a = value_min<value_max?value_min:value_max, b = value_min<value_max?value_max:value_min;
15076  T m, M = maxmin(m);
15077  const Tfloat fm = (Tfloat)m, fM = (Tfloat)M;
15078  if (m==M) return fill(0);
15079  if (m!=a || M!=b) cimg_for(*this,ptr,T) *ptr = (T)((*ptr-fm)/(fM-fm)*(b-a)+a);
15080  return *this;
15081  }
15082 
15083  CImg<Tfloat> get_normalize(const T value_min, const T value_max) const {
15084  return CImg<Tfloat>(*this,false).normalize((Tfloat)value_min,(Tfloat)value_max);
15085  }
15086 
15088 
15100  cimg_forXYZ(*this,x,y,z) {
15101  float n = 0;
15102  cimg_forV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v));
15103  n = (float)std::sqrt(n);
15104  if (n>0) cimg_forV(*this,v) (*this)(x,y,z,v) = (T)((*this)(x,y,z,v)/n);
15105  else cimg_forV(*this,v) (*this)(x,y,z,v) = 0;
15106  }
15107  return *this;
15108  }
15109 
15111  return CImg<Tfloat>(*this,false).normalize();
15112  }
15113 
15115 
15127  CImg<T>& norm(const int norm_type=2) {
15128  return get_norm(norm_type).transfer_to(*this);
15129  }
15130 
15131  CImg<Tfloat> get_norm(const int norm_type=2) const {
15132  if (is_empty()) return *this;
15133  if (dim==1) return get_abs();
15135  switch (norm_type) {
15136  case -1 : { // Linf norm
15137  cimg_forXYZ(*this,x,y,z) {
15138  Tfloat n = 0; cimg_forV(*this,v) {
15139  const Tfloat tmp = (Tfloat)cimg::abs((*this)(x,y,z,v));
15140  if (tmp>n) n=tmp; res(x,y,z) = n;
15141  }
15142  }
15143  } break;
15144  case 1 : { // L1 norm
15145  cimg_forXYZ(*this,x,y,z) {
15146  Tfloat n = 0; cimg_forV(*this,v) n+=cimg::abs((*this)(x,y,z,v)); res(x,y,z) = n;
15147  }
15148  } break;
15149  default : { // L2 norm
15150  cimg_forXYZ(*this,x,y,z) {
15151  Tfloat n = 0; cimg_forV(*this,v) n+=(*this)(x,y,z,v)*(*this)(x,y,z,v); res(x,y,z) = (Tfloat)std::sqrt((double)n);
15152  }
15153  }
15154  }
15155  return res;
15156  }
15157 
15159 
15172  CImg<T>& cut(const T value_min, const T value_max) {
15173  if (is_empty()) return *this;
15174  const T a = value_min<value_max?value_min:value_max, b = value_min<value_max?value_max:value_min;
15175  cimg_for(*this,ptr,T) *ptr = (*ptr<a)?a:((*ptr>b)?b:*ptr);
15176  return *this;
15177  }
15178 
15179  CImg<T> get_cut(const T value_min, const T value_max) const {
15180  return (+*this).cut(value_min,value_max);
15181  }
15182 
15184 
15197  CImg<T>& quantize(const unsigned int nb_levels, const bool keep_range=true) {
15198  if (is_empty()) return *this;
15199  if (!nb_levels)
15200  throw CImgArgumentException("CImg<%s>::quantize() : Cannot quantize image to 0 values.",
15201  pixel_type());
15202  Tfloat m, M = (Tfloat)maxmin(m), range = M - m;
15203  if (range>0) {
15204  if (keep_range) cimg_for(*this,ptr,T) {
15205  const unsigned int val = (unsigned int)((*ptr-m)*nb_levels/range);
15206  *ptr = (T)(m + cimg::min(val,nb_levels-1)*range/nb_levels);
15207  } else cimg_for(*this,ptr,T) {
15208  const unsigned int val = (unsigned int)((*ptr-m)*nb_levels/range);
15209  *ptr = (T)cimg::min(val,nb_levels-1);
15210  }
15211  }
15212  return *this;
15213  }
15214 
15215  CImg<T> get_quantize(const unsigned int n, const bool keep_range=true) const {
15216  return (+*this).quantize(n,keep_range);
15217  }
15218 
15220 
15234  CImg<T>& threshold(const T value, const bool soft_threshold=false, const bool strict_threshold=false) {
15235  if (is_empty()) return *this;
15236  if (strict_threshold) {
15237  if (soft_threshold) cimg_for(*this,ptr,T) { const T v = *ptr; *ptr = v>value?(T)(v-value):v<-(float)value?(T)(v+value):(T)0; }
15238  else cimg_for(*this,ptr,T) *ptr = *ptr>value?(T)1:(T)0;
15239  } else {
15240  if (soft_threshold) cimg_for(*this,ptr,T) { const T v = *ptr; *ptr = v>=value?(T)(v-value):v<=-(float)value?(T)(v+value):(T)0; }
15241  else cimg_for(*this,ptr,T) *ptr = *ptr>=value?(T)1:(T)0;
15242  }
15243  return *this;
15244  }
15245 
15246  CImg<T> get_threshold(const T value, const bool soft_threshold=false, const bool strict_threshold=false) const {
15247  return (+*this).threshold(value,soft_threshold,strict_threshold);
15248  }
15249 
15251 
15269  CImg<T>& histogram(const unsigned int nb_levels, const T value_min=(T)0, const T value_max=(T)0) {
15270  return get_histogram(nb_levels,value_min,value_max).transfer_to(*this);
15271  }
15272 
15273  CImg<floatT> get_histogram(const unsigned int nb_levels, const T value_min=(T)0, const T value_max=(T)0) const {
15274  if (is_empty()) return CImg<floatT>();
15275  if (!nb_levels)
15276  throw CImgArgumentException("CImg<%s>::histogram() : Cannot compute an histogram with 0 levels",
15277  pixel_type());
15278  T vmin = value_min, vmax = value_max;
15279  CImg<floatT> res(nb_levels,1,1,1,0);
15280  if (vmin>=vmax && vmin==0) vmin = minmax(vmax);
15281  if (vmin<vmax) cimg_for(*this,ptr,T) {
15282  const T val = *ptr;
15283  if (val>=vmin && val<=vmax) ++res[val==vmax?nb_levels-1:(int)((val-vmin)*nb_levels/(vmax-vmin))];
15284  } else res[0]+=size();
15285  return res;
15286  }
15287 
15289 
15305  CImg<T>& equalize(const unsigned int nb_levels, const T value_min=(T)0, const T value_max=(T)0) {
15306  if (is_empty()) return *this;
15307  T vmin = value_min, vmax = value_max;
15308  if (vmin==vmax && vmin==0) vmin = minmax(vmax);
15309  if (vmin<vmax) {
15310  CImg<floatT> hist = get_histogram(nb_levels,vmin,vmax);
15311  float cumul = 0;
15312  cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos] = cumul; }
15313  cimg_for(*this,ptr,T) {
15314  const int pos = (unsigned int)((*ptr-vmin)*(nb_levels-1)/(vmax-vmin));
15315  if (pos>=0 && pos<(int)nb_levels) *ptr = (T)(vmin + (vmax-vmin)*hist[pos]/size());
15316  }
15317  }
15318  return *this;
15319  }
15320 
15321  CImg<T> get_equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const {
15322  return (+*this).equalize(nblevels,val_min,val_max);
15323  }
15324 
15326 
15342  template<typename t>
15343  CImg<T>& index(const CImg<t>& palette, const bool dithering=false, const bool map_indexes=false) {
15344  return get_index(palette,dithering,map_indexes).transfer_to(*this);
15345  }
15346 
15347  template<typename t>
15349  get_index(const CImg<t>& palette, const bool dithering=false, const bool map_indexes=true) const {
15350  typedef typename cimg::superset<t,unsigned int>::type tuint;
15351  if (is_empty()) return CImg<tuint>();
15352  if (palette.dim!=dim)
15353  throw CImgArgumentException("CImg<%s>::index() : Palette (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) "
15354  "have incompatible sizes.",pixel_type(),
15355  palette.width,palette.height,palette.depth,palette.dim,palette.data,
15356  width,height,depth,dim,data);
15357  const unsigned int whz = width*height*depth, pwhz = palette.width*palette.height*palette.depth;
15358  CImg<tuint> res(width,height,depth,map_indexes?dim:1);
15359  tuint *ptrd = res.data;
15360  if (dithering) { // Dithered versions.
15361  Tfloat valm = 0, valM = (Tfloat)maxmin(valm);
15362  if (valm==valM && valm>=0 && valM<=255) { valm = 0; valM = 255; }
15363  CImg<Tfloat> cache = get_crop(-1,0,0,0,width,1,0,dim-1);
15364  Tfloat *cache_current = cache.ptr(1,0,0,0), *cache_next = cache.ptr(1,1,0,0);
15365  const unsigned int cwhz = cache.width*cache.height*cache.depth;
15366  switch (dim) {
15367  case 1 : { // Optimized for scalars.
15368  cimg_forYZ(*this,y,z) {
15369  if (y<dimy()-2) {
15370  Tfloat *ptrc0 = cache_next; const T *ptrs0 = ptr(0,y+1,z,0);
15371  cimg_forX(*this,x) *(ptrc0++) = (Tfloat)*(ptrs0++);
15372  }
15373  Tfloat *ptrs0 = cache_current, *ptrsn0 = cache_next;
15374  cimg_forX(*this,x) {
15375  const Tfloat _val0 = (Tfloat)*ptrs0, val0 = _val0<valm?valm:_val0>valM?valM:_val0;
15376  Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette.data;
15377  for (const t *ptrp0 = palette.data, *ptrp_end = ptrp0 + pwhz; ptrp0<ptrp_end; ) {
15378  const Tfloat pval0 = (Tfloat)*(ptrp0++) - val0, dist = pval0*pval0;
15379  if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }
15380  }
15381  const Tfloat err0 = ((*(ptrs0++)=val0) - (Tfloat)*ptrmin0)/16;
15382  *ptrs0 += 7*err0; *(ptrsn0-1) += 3*err0; *(ptrsn0++) += 5*err0; *ptrsn0 += err0;
15383  if (map_indexes) *(ptrd++) = (tuint)*ptrmin0; else *(ptrd++) = (tuint)(ptrmin0 - palette.data);
15384  }
15385  cimg::swap(cache_current,cache_next);
15386  }
15387  } break;
15388  case 2 : { // Optimized for 2D vectors.
15389  tuint *ptrd1 = ptrd + whz;
15390  cimg_forYZ(*this,y,z) {
15391  if (y<dimy()-2) {
15392  Tfloat *ptrc0 = cache_next, *ptrc1 = ptrc0 + cwhz;
15393  const T *ptrs0 = ptr(0,y+1,z,0), *ptrs1 = ptrs0 + whz;
15394  cimg_forX(*this,x) { *(ptrc0++) = (Tfloat)*(ptrs0++); *(ptrc1++) = (Tfloat)*(ptrs1++); }
15395  }
15396  Tfloat
15397  *ptrs0 = cache_current, *ptrs1 = ptrs0 + cwhz,
15398  *ptrsn0 = cache_next, *ptrsn1 = ptrsn0 + cwhz;
15399  cimg_forX(*this,x) {
15400  const Tfloat
15401  _val0 = (Tfloat)*ptrs0, val0 = _val0<valm?valm:_val0>valM?valM:_val0,
15402  _val1 = (Tfloat)*ptrs1, val1 = _val1<valm?valm:_val1>valM?valM:_val1;
15403  Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette.data;
15404  for (const t *ptrp0 = palette.data, *ptrp1 = ptrp0 + pwhz, *ptrp_end = ptrp1; ptrp0<ptrp_end; ) {
15405  const Tfloat
15406  pval0 = (Tfloat)*(ptrp0++) - val0, pval1 = (Tfloat)*(ptrp1++) - val1,
15407  dist = pval0*pval0 + pval1*pval1;
15408  if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }
15409  }
15410  const t *const ptrmin1 = ptrmin0 + pwhz;
15411  const Tfloat
15412  err0 = ((*(ptrs0++)=val0) - (Tfloat)*ptrmin0)/16,
15413  err1 = ((*(ptrs1++)=val1) - (Tfloat)*ptrmin1)/16;
15414  *ptrs0 += 7*err0; *ptrs1 += 7*err1;
15415  *(ptrsn0-1) += 3*err0; *(ptrsn1-1) += 3*err1;
15416  *(ptrsn0++) += 5*err0; *(ptrsn1++) += 5*err1;
15417  *ptrsn0 += err0; *ptrsn1 += err1;
15418  if (map_indexes) { *(ptrd++) = (tuint)*ptrmin0; *(ptrd1++) = (tuint)*ptrmin1; }
15419  else *(ptrd++) = (tuint)(ptrmin0 - palette.data);
15420  }
15421  cimg::swap(cache_current,cache_next);
15422  }
15423  } break;
15424  case 3 : { // Optimized for 3D vectors (colors).
15425  tuint *ptrd1 = ptrd + whz, *ptrd2 = ptrd1 + whz;
15426  cimg_forYZ(*this,y,z) {
15427  if (y<dimy()-2) {
15428  Tfloat *ptrc0 = cache_next, *ptrc1 = ptrc0 + cwhz, *ptrc2 = ptrc1 + cwhz;
15429  const T *ptrs0 = ptr(0,y+1,z,0), *ptrs1 = ptrs0 + whz, *ptrs2 = ptrs1 + whz;
15430  cimg_forX(*this,x) { *(ptrc0++) = (Tfloat)*(ptrs0++); *(ptrc1++) = (Tfloat)*(ptrs1++); *(ptrc2++) = (Tfloat)*(ptrs2++); }
15431  }
15432  Tfloat
15433  *ptrs0 = cache_current, *ptrs1 = ptrs0 + cwhz, *ptrs2 = ptrs1 + cwhz,
15434  *ptrsn0 = cache_next, *ptrsn1 = ptrsn0 + cwhz, *ptrsn2 = ptrsn1 + cwhz;
15435  cimg_forX(*this,x) {
15436  const Tfloat
15437  _val0 = (Tfloat)*ptrs0, val0 = _val0<valm?valm:_val0>valM?valM:_val0,
15438  _val1 = (Tfloat)*ptrs1, val1 = _val1<valm?valm:_val1>valM?valM:_val1,
15439  _val2 = (Tfloat)*ptrs2, val2 = _val2<valm?valm:_val2>valM?valM:_val2;
15440  Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette.data;
15441  for (const t *ptrp0 = palette.data, *ptrp1 = ptrp0 + pwhz, *ptrp2 = ptrp1 + pwhz, *ptrp_end = ptrp1; ptrp0<ptrp_end; ) {
15442  const Tfloat
15443  pval0 = (Tfloat)*(ptrp0++) - val0, pval1 = (Tfloat)*(ptrp1++) - val1, pval2 = (Tfloat)*(ptrp2++) - val2,
15444  dist = pval0*pval0 + pval1*pval1 + pval2*pval2;
15445  if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }
15446  }
15447  const t *const ptrmin1 = ptrmin0 + pwhz, *const ptrmin2 = ptrmin1 + pwhz;
15448  const Tfloat
15449  err0 = ((*(ptrs0++)=val0) - (Tfloat)*ptrmin0)/16,
15450  err1 = ((*(ptrs1++)=val1) - (Tfloat)*ptrmin1)/16,
15451  err2 = ((*(ptrs2++)=val2) - (Tfloat)*ptrmin2)/16;
15452  *ptrs0 += 7*err0; *ptrs1 += 7*err1; *ptrs2 += 7*err2;
15453  *(ptrsn0-1) += 3*err0; *(ptrsn1-1) += 3*err1; *(ptrsn2-1) += 3*err2;
15454  *(ptrsn0++) += 5*err0; *(ptrsn1++) += 5*err1; *(ptrsn2++) += 5*err2;
15455  *ptrsn0 += err0; *ptrsn1 += err1; *ptrsn2 += err2;
15456  if (map_indexes) { *(ptrd++) = (tuint)*ptrmin0; *(ptrd1++) = (tuint)*ptrmin1; *(ptrd2++) = (tuint)*ptrmin2; }
15457  else *(ptrd++) = (tuint)(ptrmin0 - palette.data);
15458  }
15459  cimg::swap(cache_current,cache_next);
15460  }
15461  } break;
15462  default : // Generic version
15463  cimg_forYZ(*this,y,z) {
15464  if (y<dimy()-2) {
15465  Tfloat *ptrc = cache_next;
15466  cimg_forV(*this,k) {
15467  Tfloat *_ptrc = ptrc; const T *_ptrs = ptr(0,y+1,z,k);
15468  cimg_forX(*this,x) *(_ptrc++) = (Tfloat)*(_ptrs++);
15469  ptrc+=cwhz;
15470  }
15471  }
15472  Tfloat *ptrs = cache_current, *ptrsn = cache_next;
15473  cimg_forX(*this,x) {
15474  Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin = palette.data;
15475  for (const t *ptrp = palette.data, *ptrp_end = ptrp + pwhz; ptrp<ptrp_end; ++ptrp) {
15476  Tfloat dist = 0; Tfloat *_ptrs = ptrs; const t *_ptrp = ptrp;
15477  cimg_forV(*this,k) {
15478  const Tfloat _val = *_ptrs, val = _val<valm?valm:_val>valM?valM:_val;
15479  dist += cimg::sqr((*_ptrs=val) - (Tfloat)*_ptrp); _ptrs+=cwhz; _ptrp+=pwhz;
15480  }
15481  if (dist<distmin) { ptrmin = ptrp; distmin = dist; }
15482  }
15483  const t *_ptrmin = ptrmin; Tfloat *_ptrs = ptrs++, *_ptrsn = (ptrsn++)-1;
15484  cimg_forV(*this,k) {
15485  const Tfloat err = (*(_ptrs++) - (Tfloat)*_ptrmin)/16;
15486  *_ptrs += 7*err; *(_ptrsn++) += 3*err; *(_ptrsn++) += 5*err; *_ptrsn += err;
15487  _ptrmin+=pwhz; _ptrs+=cwhz-1; _ptrsn+=cwhz-2;
15488  }
15489  if (map_indexes) { tuint *_ptrd = ptrd++; cimg_forV(*this,k) { *_ptrd = (tuint)*ptrmin; _ptrd+=whz; ptrmin+=pwhz; }}
15490  else *(ptrd++) = (tuint)(ptrmin - palette.data);
15491  }
15492  cimg::swap(cache_current,cache_next);
15493  }
15494  }
15495  } else { // Non-dithered versions
15496  switch (dim) {
15497  case 1 : { // Optimized for scalars.
15498  for (const T *ptrs0 = data, *ptrs_end = ptrs0 + whz; ptrs0<ptrs_end; ) {
15499  const Tfloat val0 = (Tfloat)*(ptrs0++);
15500  Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette.data;
15501  for (const t *ptrp0 = palette.data, *ptrp_end = ptrp0 + pwhz; ptrp0<ptrp_end; ) {
15502  const Tfloat pval0 = (Tfloat)*(ptrp0++) - val0, dist = pval0*pval0;
15503  if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }
15504  }
15505  if (map_indexes) *(ptrd++) = (tuint)*ptrmin0; else *(ptrd++) = (tuint)(ptrmin0 - palette.data);
15506  }
15507  } break;
15508  case 2 : { // Optimized for 2D vectors.
15509  tuint *ptrd1 = ptrd + whz;
15510  for (const T *ptrs0 = data, *ptrs1 = ptrs0 + whz, *ptrs_end = ptrs1; ptrs0<ptrs_end; ) {
15511  const Tfloat val0 = (Tfloat)*(ptrs0++), val1 = (Tfloat)*(ptrs1++);
15512  Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette.data;
15513  for (const t *ptrp0 = palette.data, *ptrp1 = ptrp0 + pwhz, *ptrp_end = ptrp1; ptrp0<ptrp_end; ) {
15514  const Tfloat
15515  pval0 = (Tfloat)*(ptrp0++) - val0, pval1 = (Tfloat)*(ptrp1++) - val1,
15516  dist = pval0*pval0 + pval1*pval1;
15517  if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }
15518  }
15519  if (map_indexes) { *(ptrd++) = (tuint)*ptrmin0; *(ptrd1++) = (tuint)*(ptrmin0 + pwhz); }
15520  else *(ptrd++) = (tuint)(ptrmin0 - palette.data);
15521  }
15522  } break;
15523  case 3 : { // Optimized for 3D vectors (colors).
15524  tuint *ptrd1 = ptrd + whz, *ptrd2 = ptrd1 + whz;
15525  for (const T *ptrs0 = data, *ptrs1 = ptrs0 + whz, *ptrs2 = ptrs1 + whz, *ptrs_end = ptrs1; ptrs0<ptrs_end; ) {
15526  const Tfloat val0 = (Tfloat)*(ptrs0++), val1 = (Tfloat)*(ptrs1++), val2 = (Tfloat)*(ptrs2++);
15527  Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin0 = palette.data;
15528  for (const t *ptrp0 = palette.data, *ptrp1 = ptrp0 + pwhz, *ptrp2 = ptrp1 + pwhz, *ptrp_end = ptrp1; ptrp0<ptrp_end; ) {
15529  const Tfloat
15530  pval0 = (Tfloat)*(ptrp0++) - val0, pval1 = (Tfloat)*(ptrp1++) - val1, pval2 = (Tfloat)*(ptrp2++) - val2,
15531  dist = pval0*pval0 + pval1*pval1 + pval2*pval2;
15532  if (dist<distmin) { ptrmin0 = ptrp0 - 1; distmin = dist; }
15533  }
15534  if (map_indexes) { *(ptrd++) = (tuint)*ptrmin0; *(ptrd1++) = (tuint)*(ptrmin0 + pwhz); *(ptrd2++) = (tuint)*(ptrmin0 + 2*pwhz); }
15535  else *(ptrd++) = (tuint)(ptrmin0 - palette.data);
15536  }
15537  } break;
15538  default : // Generic version.
15539  for (const T *ptrs = data, *ptrs_end = ptrs + whz; ptrs<ptrs_end; ++ptrs) {
15540  Tfloat distmin = cimg::type<Tfloat>::max(); const t *ptrmin = palette.data;
15541  for (const t *ptrp = palette.data, *ptrp_end = ptrp + pwhz; ptrp<ptrp_end; ++ptrp) {
15542  Tfloat dist = 0; const T *_ptrs = ptrs; const t *_ptrp = ptrp;
15543  cimg_forV(*this,k) { dist += cimg::sqr((Tfloat)*_ptrs - (Tfloat)*_ptrp); _ptrs+=whz; _ptrp+=pwhz; }
15544  if (dist<distmin) { ptrmin = ptrp; distmin = dist; }
15545  }
15546  if (map_indexes) { tuint *_ptrd = ptrd++; cimg_forV(*this,k) { *_ptrd = (tuint)*ptrmin; _ptrd+=whz; ptrmin+=pwhz; }}
15547  else *(ptrd++) = (tuint)(ptrmin - palette.data);
15548  }
15549  }
15550  }
15551  return res;
15552  }
15553 
15555 
15570  template<typename t>
15571  CImg<T>& map(const CImg<t>& palette) {
15572  return get_map(palette).transfer_to(*this);
15573  }
15574 
15575  template<typename t>
15576  CImg<t> get_map(const CImg<t>& palette) const {
15577  if (dim!=1 && palette.dim!=1)
15578  throw CImgArgumentException("CImg<%s>::map() : Palette (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) "
15579  "have incompatible sizes.",pixel_type(),
15580  palette.width,palette.height,palette.depth,palette.dim,palette.data,
15581  width,height,depth,dim,data);
15582  const unsigned int whz = width*height*depth, pwhz = palette.width*palette.height*palette.depth;
15583  CImg<t> res(width,height,depth,palette.dim==1?dim:palette.dim);
15584  switch (palette.dim) {
15585  case 1 : { // Optimized for scalars.
15586  const T *ptrs = data + whz*dim;
15587  cimg_for(res,ptrd,t) {
15588  const unsigned int _ind = (unsigned int)*(--ptrs), ind = _ind<pwhz?_ind:0;
15589  *ptrd = palette[ind];
15590  }
15591  } break;
15592  case 2 : { // Optimized for 2D vectors.
15593  const t *const ptrp0 = palette.data, *ptrp1 = ptrp0 + pwhz;
15594  t *ptrd0 = res.data, *ptrd1 = ptrd0 + whz;
15595  for (const T *ptrs = data, *ptrs_end = ptrs + whz; ptrs<ptrs_end; ) {
15596  const unsigned int _ind = (unsigned int)*(ptrs++), ind = _ind<pwhz?_ind:0;
15597  *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind];
15598  }
15599  } break;
15600  case 3 : { // Optimized for 3D vectors (colors).
15601  const t *const ptrp0 = palette.data, *ptrp1 = ptrp0 + pwhz, *ptrp2 = ptrp1 + pwhz;
15602  t *ptrd0 = res.data, *ptrd1 = ptrd0 + whz, *ptrd2 = ptrd1 + whz;
15603  for (const T *ptrs = data, *ptrs_end = ptrs + whz; ptrs<ptrs_end; ) {
15604  const unsigned int _ind = (unsigned int)*(ptrs++), ind = _ind<pwhz?_ind:0;
15605  *(ptrd0++) = ptrp0[ind]; *(ptrd1++) = ptrp1[ind]; *(ptrd2++) = ptrp2[ind];
15606  }
15607  } break;
15608  default : { // Generic version.
15609  t *ptrd = res.data;
15610  for (const T *ptrs = data, *ptrs_end = ptrs + whz; ptrs<ptrs_end; ) {
15611  const unsigned int _ind = (unsigned int)*(ptrs++), ind = _ind<pwhz?_ind:0;
15612  const t *ptrp = palette.data + ind;
15613  t *_ptrd = ptrd++; cimg_forV(res,k) { *_ptrd = *ptrp; _ptrd+=whz; ptrp+=pwhz; }
15614  }
15615  }
15616  }
15617  return res;
15618  }
15619 
15621 
15635  return get_label_regions().transfer_to(*this);
15636  }
15637 
15639 #define _cimg_get_label_test(p,q) { \
15640  flag = true; \
15641  const T *ptr1 = ptr(x,y) + siz, *ptr2 = ptr(p,q) + siz; \
15642  for (unsigned int i = dim; flag && i; --i) { ptr1-=wh; ptr2-=wh; flag = (*ptr1==*ptr2); } \
15643 }
15644  if (depth>1)
15645  throw CImgInstanceException("CImg<%s>::label_regions() : Instance image must be a 2D image");
15646  CImg<uintT> res(width,height,depth,1,0);
15647  unsigned int label = 1;
15648  const unsigned int wh = width*height, siz = width*height*dim;
15649  const int W1 = dimx()-1, H1 = dimy()-1;
15650  bool flag;
15651  cimg_forXY(*this,x,y) {
15652  bool done = false;
15653  if (y) {
15654  _cimg_get_label_test(x,y-1);
15655  if (flag) {
15656  const unsigned int lab = (res(x,y) = res(x,y-1));
15657  done = true;
15658  if (x && res(x-1,y)!=lab) {
15659  _cimg_get_label_test(x-1,y);
15660  if (flag) {
15661  const unsigned int lold = res(x-1,y), *const cptr = res.ptr(x,y);
15662  for (unsigned int *ptr = res.ptr(); ptr<cptr; ++ptr) if (*ptr==lold) *ptr = lab;
15663  }
15664  }
15665  }
15666  }
15667  if (x && !done) { _cimg_get_label_test(x-1,y); if (flag) { res(x,y) = res(x-1,y); done = true; }}
15668  if (!done) res(x,y) = label++;
15669  }
15670  for (int y = H1; y>=0; --y) for (int x=W1; x>=0; --x) {
15671  bool done = false;
15672  if (y<H1) {
15673  _cimg_get_label_test(x,y+1);
15674  if (flag) {
15675  const unsigned int lab = (res(x,y) = res(x,y+1));
15676  done = true;
15677  if (x<W1 && res(x+1,y)!=lab) {
15678  _cimg_get_label_test(x+1,y);
15679  if (flag) {
15680  const unsigned int lold = res(x+1,y), *const cptr = res.ptr(x,y);
15681  for (unsigned int *ptr = res.ptr()+res.size()-1; ptr>cptr; --ptr) if (*ptr==lold) *ptr = lab;
15682  }
15683  }
15684  }
15685  }
15686  if (x<W1 && !done) { _cimg_get_label_test(x+1,y); if (flag) res(x,y) = res(x+1,y); done = true; }
15687  }
15688  const unsigned int lab0 = res.max()+1;
15689  label = lab0;
15690  cimg_foroff(res,off) { // Relabel regions
15691  const unsigned int lab = res[off];
15692  if (lab<lab0) { cimg_for(res,ptr,unsigned int) if (*ptr==lab) *ptr = label; ++label; }
15693  }
15694  return (res-=lab0);
15695  }
15696 
15698  //---------------------------------
15699  //
15701 
15702  //---------------------------------
15703 
15705 
15716  static CImg<Tuchar> palette;
15717  if (!palette) {
15718  palette.assign(1,256,1,3);
15719  for (unsigned int index = 0, r = 16; r<256; r+=32)
15720  for (unsigned int g = 16; g<256; g+=32)
15721  for (unsigned int b = 32; b<256; b+=64) {
15722  palette(0,index,0) = (Tuchar)r;
15723  palette(0,index,1) = (Tuchar)g;
15724  palette(0,index++,2) = (Tuchar)b;
15725  }
15726  }
15727  return palette;
15728  }
15729 
15731 
15739  static CImg<Tuchar> palette;
15740  if (!palette) {
15741  CImg<Tint> tmp(1,256,1,3,1);
15742  tmp.get_shared_channel(0).sequence(0,359);
15743  palette = tmp.HSVtoRGB();
15744  }
15745  return palette;
15746  }
15747 
15749 
15757  static const unsigned char pal[] = {
15758  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,
15759  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,
15760  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,
15761  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,
15762  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,
15763  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,
15764  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,
15765  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,
15766  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,
15767  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,
15768  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,
15769  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,
15770  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,
15771  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,
15772  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,
15773  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,
15774  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,
15775  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,
15776  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,
15777  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,
15778  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,
15779  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,
15780  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,
15781  23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 };
15782  static const CImg<Tuchar> palette(pal,1,256,1,3,false);
15783  return palette;
15784  }
15785 
15788  if (is_empty()) return *this;
15789  if (dim!=3)
15790  throw CImgInstanceException("CImg<%s>::RGBtoHSV() : Input image dimension is dim=%u, "
15791  "should be a (R,G,B) image.",
15792  pixel_type(),dim);
15793  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
15794  for (unsigned int N = width*height*depth; N; --N) {
15795  const Tfloat
15796  R = (Tfloat)*p1,
15797  G = (Tfloat)*p2,
15798  B = (Tfloat)*p3,
15799  nR = (R<0?0:(R>255?255:R))/255,
15800  nG = (G<0?0:(G>255?255:G))/255,
15801  nB = (B<0?0:(B>255?255:B))/255,
15802  m = cimg::min(nR,nG,nB),
15803  M = cimg::max(nR,nG,nB);
15804  Tfloat H = 0, S = 0;
15805  if (M!=m) {
15806  const Tfloat
15807  f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
15808  i = (Tfloat)((nR==m)?3:((nG==m)?5:1));
15809  H = (i-f/(M-m));
15810  if (H>=6) H-=6;
15811  H*=60;
15812  S = (M-m)/M;
15813  }
15814  *(p1++) = (T)H;
15815  *(p2++) = (T)S;
15816  *(p3++) = (T)M;
15817  }
15818  return *this;
15819  }
15820 
15822  return CImg<Tfloat>(*this,false).RGBtoHSV();
15823  }
15824 
15827  if (is_empty()) return *this;
15828  if (dim!=3)
15829  throw CImgInstanceException("CImg<%s>::HSVtoRGB() : Input image dimension is dim=%u, "
15830  "should be a (H,S,V) image",
15831  pixel_type(),dim);
15832  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
15833  for (unsigned int N = width*height*depth; N; --N) {
15834  Tfloat
15835  H = (Tfloat)*p1,
15836  S = (Tfloat)*p2,
15837  V = (Tfloat)*p3,
15838  R = 0, G = 0, B = 0;
15839  if (H==0 && S==0) R = G = B = V;
15840  else {
15841  H/=60;
15842  const int i = (int)std::floor(H);
15843  const Tfloat
15844  f = (i&1)?(H-i):(1-H+i),
15845  m = V*(1-S),
15846  n = V*(1-S*f);
15847  switch (i) {
15848  case 6 :
15849  case 0 : R = V; G = n; B = m; break;
15850  case 1 : R = n; G = V; B = m; break;
15851  case 2 : R = m; G = V; B = n; break;
15852  case 3 : R = m; G = n; B = V; break;
15853  case 4 : R = n; G = m; B = V; break;
15854  case 5 : R = V; G = m; B = n; break;
15855  }
15856  }
15857  R*=255; G*=255; B*=255;
15858  *(p1++) = (T)(R<0?0:(R>255?255:R));
15859  *(p2++) = (T)(G<0?0:(G>255?255:G));
15860  *(p3++) = (T)(B<0?0:(B>255?255:B));
15861  }
15862  return *this;
15863  }
15864 
15866  return CImg<Tuchar>(*this,false).HSVtoRGB();
15867  }
15868 
15871  if (is_empty()) return *this;
15872  if (dim!=3)
15873  throw CImgInstanceException("CImg<%s>::RGBtoHSL() : Input image dimension is dim=%u, "
15874  "should be a (R,G,B) image.",
15875  pixel_type(),dim);
15876  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
15877  for (unsigned int N = width*height*depth; N; --N) {
15878  const Tfloat
15879  R = (Tfloat)*p1,
15880  G = (Tfloat)*p2,
15881  B = (Tfloat)*p3,
15882  nR = (R<0?0:(R>255?255:R))/255,
15883  nG = (G<0?0:(G>255?255:G))/255,
15884  nB = (B<0?0:(B>255?255:B))/255,
15885  m = cimg::min(nR,nG,nB),
15886  M = cimg::max(nR,nG,nB),
15887  L = (m+M)/2;
15888  Tfloat H = 0, S = 0;
15889  if (M==m) H = S = 0;
15890  else {
15891  const Tfloat
15892  f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
15893  i = (nR==m)?3.0f:((nG==m)?5.0f:1.0f);
15894  H = (i-f/(M-m));
15895  if (H>=6) H-=6;
15896  H*=60;
15897  S = (2*L<=1)?((M-m)/(M+m)):((M-m)/(2-M-m));
15898  }
15899  *(p1++) = (T)H;
15900  *(p2++) = (T)S;
15901  *(p3++) = (T)L;
15902  }
15903  return *this;
15904  }
15905 
15907  return CImg< Tfloat>(*this,false).RGBtoHSL();
15908  }
15909 
15912  if (is_empty()) return *this;
15913  if (dim!=3)
15914  throw CImgInstanceException("CImg<%s>::HSLtoRGB() : Input image dimension is dim=%u, "
15915  "should be a (H,S,V) image",
15916  pixel_type(),dim);
15917  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
15918  for (unsigned int N = width*height*depth; N; --N) {
15919  const Tfloat
15920  H = (Tfloat)*p1,
15921  S = (Tfloat)*p2,
15922  L = (Tfloat)*p3,
15923  q = 2*L<1?L*(1+S):(L+S-L*S),
15924  p = 2*L-q,
15925  h = H/360,
15926  tr = h + 1.0f/3,
15927  tg = h,
15928  tb = h - 1.0f/3,
15929  ntr = tr<0?tr+1:(tr>1?tr-1:tr),
15930  ntg = tg<0?tg+1:(tg>1?tg-1:tg),
15931  ntb = tb<0?tb+1:(tb>1?tb-1:tb),
15932  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))),
15933  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))),
15934  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)));
15935  *(p1++) = (T)(R<0?0:(R>255?255:R));
15936  *(p2++) = (T)(G<0?0:(G>255?255:G));
15937  *(p3++) = (T)(B<0?0:(B>255?255:B));
15938  }
15939  return *this;
15940  }
15941 
15943  return CImg<Tuchar>(*this,false).HSLtoRGB();
15944  }
15945 
15949  if (is_empty()) return *this;
15950  if (dim!=3)
15951  throw CImgInstanceException("CImg<%s>::RGBtoHSI() : Input image dimension is dim=%u, "
15952  "should be a (R,G,B) image.",
15953  pixel_type(),dim);
15954  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
15955  for (unsigned int N = width*height*depth; N; --N) {
15956  const Tfloat
15957  R = (Tfloat)*p1,
15958  G = (Tfloat)*p2,
15959  B = (Tfloat)*p3,
15960  nR = (R<0?0:(R>255?255:R))/255,
15961  nG = (G<0?0:(G>255?255:G))/255,
15962  nB = (B<0?0:(B>255?255:B))/255,
15963  m = cimg::min(nR,nG,nB),
15964  theta = (Tfloat)(std::acos(0.5f*((nR-nG)+(nR-nB))/std::sqrt(std::pow(nR-nG,2)+(nR-nB)*(nG-nB)))*180/cimg::valuePI),
15965  sum = nR + nG + nB;
15966  Tfloat H = 0, S = 0, I = 0;
15967  if (theta>0) H = (nB<=nG)?theta:360-theta;
15968  if (sum>0) S = 1 - 3/sum*m;
15969  I = sum/3;
15970  *(p1++) = (T)H;
15971  *(p2++) = (T)S;
15972  *(p3++) = (T)I;
15973  }
15974  return *this;
15975  }
15976 
15978  return CImg<Tfloat>(*this,false).RGBtoHSI();
15979  }
15980 
15983  if (is_empty()) return *this;
15984  if (dim!=3)
15985  throw CImgInstanceException("CImg<%s>::HSItoRGB() : Input image dimension is dim=%u, "
15986  "should be a (H,S,I) image",
15987  pixel_type(),dim);
15988  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
15989  for (unsigned int N = width*height*depth; N; --N) {
15990  Tfloat
15991  H = (Tfloat)*p1,
15992  S = (Tfloat)*p2,
15993  I = (Tfloat)*p3,
15994  a = I*(1-S),
15995  R = 0, G = 0, B = 0;
15996  if (H<120) {
15997  B = a;
15998  R = (Tfloat)(I*(1+S*std::cos(H*cimg::valuePI/180)/std::cos((60-H)*cimg::valuePI/180)));
15999  G = 3*I-(R+B);
16000  } else if (H<240) {
16001  H-=120;
16002  R = a;
16003  G = (Tfloat)(I*(1+S*std::cos(H*cimg::valuePI/180)/std::cos((60-H)*cimg::valuePI/180)));
16004  B = 3*I-(R+G);
16005  } else {
16006  H-=240;
16007  G = a;
16008  B = (Tfloat)(I*(1+S*std::cos(H*cimg::valuePI/180)/std::cos((60-H)*cimg::valuePI/180)));
16009  R = 3*I-(G+B);
16010  }
16011  R*=255; G*=255; B*=255;
16012  *(p1++) = (T)(R<0?0:(R>255?255:R));
16013  *(p2++) = (T)(G<0?0:(G>255?255:G));
16014  *(p3++) = (T)(B<0?0:(B>255?255:B));
16015  }
16016  return *this;
16017  }
16018 
16020  return CImg< Tuchar>(*this,false).HSItoRGB();
16021  }
16022 
16025  if (is_empty()) return *this;
16026  if (dim!=3)
16027  throw CImgInstanceException("CImg<%s>::RGBtoYCbCr() : Input image dimension is dim=%u, "
16028  "should be a (R,G,B) image (dim=3)",
16029  pixel_type(),dim);
16030  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16031  for (unsigned int N = width*height*depth; N; --N) {
16032  const Tfloat
16033  R = (Tfloat)*p1,
16034  G = (Tfloat)*p2,
16035  B = (Tfloat)*p3,
16036  Y = (66*R + 129*G + 25*B + 128)/256 + 16,
16037  Cb = (-38*R - 74*G + 112*B + 128)/256 + 128,
16038  Cr = (112*R - 94*G - 18*B + 128)/256 + 128;
16039  *(p1++) = (T)(Y<0?0:(Y>255?255:Y));
16040  *(p2++) = (T)(Cb<0?0:(Cb>255?255:Cb));
16041  *(p3++) = (T)(Cr<0?0:(Cr>255?255:Cr));
16042  }
16043  return *this;
16044  }
16045 
16047  return CImg<Tuchar>(*this,false).RGBtoYCbCr();
16048  }
16049 
16052  if (is_empty()) return *this;
16053  if (dim!=3)
16054  throw CImgInstanceException("CImg<%s>::YCbCrtoRGB() : Input image dimension is dim=%u, "
16055  "should be a (Y,Cb,Cr)_8 image (dim=3)",
16056  pixel_type(),dim);
16057  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16058  for (unsigned int N = width*height*depth; N; --N) {
16059  const Tfloat
16060  Y = (Tfloat)*p1 - 16,
16061  Cb = (Tfloat)*p2 - 128,
16062  Cr = (Tfloat)*p3 - 128,
16063  R = (298*Y + 409*Cr + 128)/256,
16064  G = (298*Y - 100*Cb - 208*Cr + 128)/256,
16065  B = (298*Y + 516*Cb + 128)/256;
16066  *(p1++) = (T)(R<0?0:(R>255?255:R));
16067  *(p2++) = (T)(G<0?0:(G>255?255:G));
16068  *(p3++) = (T)(B<0?0:(B>255?255:B));
16069  }
16070  return *this;
16071  }
16072 
16074  return CImg<Tuchar>(*this,false).YCbCrtoRGB();
16075  }
16076 
16079  if (is_empty()) return *this;
16080  if (dim!=3)
16081  throw CImgInstanceException("CImg<%s>::RGBtoYUV() : Input image dimension is dim=%u, "
16082  "should be a (R,G,B) image (dim=3)",
16083  pixel_type(),dim);
16084  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16085  for (unsigned int N = width*height*depth; N; --N) {
16086  const Tfloat
16087  R = (Tfloat)*p1/255,
16088  G = (Tfloat)*p2/255,
16089  B = (Tfloat)*p3/255,
16090  Y = 0.299f*R + 0.587f*G + 0.114f*B;
16091  *(p1++) = (T)Y;
16092  *(p2++) = (T)(0.492f*(B-Y));
16093  *(p3++) = (T)(0.877*(R-Y));
16094  }
16095  return *this;
16096  }
16097 
16099  return CImg<Tfloat>(*this,false).RGBtoYUV();
16100  }
16101 
16104  if (is_empty()) return *this;
16105  if (dim!=3)
16106  throw CImgInstanceException("CImg<%s>::YUVtoRGB() : Input image dimension is dim=%u, "
16107  "should be a (Y,U,V) image (dim=3)",
16108  pixel_type(),dim);
16109  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16110  for (unsigned int N = width*height*depth; N; --N) {
16111  const Tfloat
16112  Y = (Tfloat)*p1,
16113  U = (Tfloat)*p2,
16114  V = (Tfloat)*p3,
16115  R = (Y + 1.140f*V)*255,
16116  G = (Y - 0.395f*U - 0.581f*V)*255,
16117  B = (Y + 2.032f*U)*255;
16118  *(p1++) = (T)(R<0?0:(R>255?255:R));
16119  *(p2++) = (T)(G<0?0:(G>255?255:G));
16120  *(p3++) = (T)(B<0?0:(B>255?255:B));
16121  }
16122  return *this;
16123  }
16124 
16126  return CImg< Tuchar>(*this,false).YUVtoRGB();
16127  }
16128 
16131  if (is_empty()) return *this;
16132  if (dim!=3)
16133  throw CImgInstanceException("CImg<%s>::RGBtoCMY() : Input image dimension is dim=%u, "
16134  "should be a (R,G,B) image (dim=3)",
16135  pixel_type(),dim);
16136  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16137  for (unsigned int N = width*height*depth; N; --N) {
16138  const Tfloat
16139  R = (Tfloat)*p1/255,
16140  G = (Tfloat)*p2/255,
16141  B = (Tfloat)*p3/255;
16142  *(p1++) = (T)(1 - R);
16143  *(p2++) = (T)(1 - G);
16144  *(p3++) = (T)(1 - B);
16145  }
16146  return *this;
16147  }
16148 
16150  return CImg<Tfloat>(*this,false).RGBtoCMY();
16151  }
16152 
16155  if (is_empty()) return *this;
16156  if (dim!=3)
16157  throw CImgInstanceException("CImg<%s>::CMYtoRGB() : Input image dimension is dim=%u, "
16158  "should be a (C,M,Y) image (dim=3)",
16159  pixel_type(),dim);
16160  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16161  for (unsigned int N = width*height*depth; N; --N) {
16162  const Tfloat
16163  C = (Tfloat)*p1,
16164  M = (Tfloat)*p2,
16165  Y = (Tfloat)*p3,
16166  R = 255*(1 - C),
16167  G = 255*(1 - M),
16168  B = 255*(1 - Y);
16169  *(p1++) = (T)(R<0?0:(R>255?255:R));
16170  *(p2++) = (T)(G<0?0:(G>255?255:G));
16171  *(p3++) = (T)(B<0?0:(B>255?255:B));
16172  }
16173  return *this;
16174  }
16175 
16177  return CImg<Tuchar>(*this,false).CMYtoRGB();
16178  }
16179 
16182  return get_CMYtoCMYK().transfer_to(*this);
16183  }
16184 
16186  if (is_empty()) return *this;
16187  if (dim!=3)
16188  throw CImgInstanceException("CImg<%s>::CMYtoCMYK() : Input image dimension is dim=%u, "
16189  "should be a (C,M,Y) image (dim=3)",
16190  pixel_type(),dim);
16191  CImg<Tfloat> res(width,height,depth,4);
16192  const T *ps1 = ptr(0,0,0,0), *ps2 = ptr(0,0,0,1), *ps3 = ptr(0,0,0,2);
16193  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);
16194  for (unsigned int N = width*height*depth; N; --N) {
16195  Tfloat
16196  C = (Tfloat)*(ps1++),
16197  M = (Tfloat)*(ps2++),
16198  Y = (Tfloat)*(ps3++),
16199  K = cimg::min(C,M,Y);
16200  if (K==1) C = M = Y = 0;
16201  else { const Tfloat K1 = 1 - K; C = (C - K)/K1; M = (M - K)/K1; Y = (Y - K)/K1; }
16202  *(pd1++) = C;
16203  *(pd2++) = M;
16204  *(pd3++) = Y;
16205  *(pd4++) = K;
16206  }
16207  return res;
16208  }
16209 
16212  return get_CMYKtoCMY().transfer_to(*this);
16213  }
16214 
16216  if (is_empty()) return *this;
16217  if (dim!=4)
16218  throw CImgInstanceException("CImg<%s>::CMYKtoCMY() : Input image dimension is dim=%u, "
16219  "should be a (C,M,Y,K) image (dim=4)",
16220  pixel_type(),dim);
16221  CImg<Tfloat> res(width,height,depth,3);
16222  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);
16223  Tfloat *pd1 = res.ptr(0,0,0,0), *pd2 = res.ptr(0,0,0,1), *pd3 = res.ptr(0,0,0,2);
16224  for (unsigned int N = width*height*depth; N; --N) {
16225  const Tfloat
16226  C = (Tfloat)*ps1,
16227  M = (Tfloat)*ps2,
16228  Y = (Tfloat)*ps3,
16229  K = (Tfloat)*ps4,
16230  K1 = 1 - K;
16231  *(pd1++) = C*K1 + K;
16232  *(pd2++) = M*K1 + K;
16233  *(pd3++) = Y*K1 + K;
16234  }
16235  return res;
16236  }
16237 
16240  if (is_empty()) return *this;
16241  if (dim!=3)
16242  throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, "
16243  "should be a (R,G,B) image (dim=3)",
16244  pixel_type(),dim);
16245  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16246  for (unsigned int N = width*height*depth; N; --N) {
16247  const Tfloat
16248  R = (Tfloat)*p1/255,
16249  G = (Tfloat)*p2/255,
16250  B = (Tfloat)*p3/255;
16251  *(p1++) = (T)(0.412453f*R + 0.357580f*G + 0.180423f*B);
16252  *(p2++) = (T)(0.212671f*R + 0.715160f*G + 0.072169f*B);
16253  *(p3++) = (T)(0.019334f*R + 0.119193f*G + 0.950227f*B);
16254  }
16255  return *this;
16256  }
16257 
16259  return CImg<Tfloat>(*this,false).RGBtoXYZ();
16260  }
16261 
16264  if (is_empty()) return *this;
16265  if (dim!=3)
16266  throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, "
16267  "should be a (X,Y,Z) image (dim=3)",
16268  pixel_type(),dim);
16269  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16270  for (unsigned int N = width*height*depth; N; --N) {
16271  const Tfloat
16272  X = (Tfloat)*p1*255,
16273  Y = (Tfloat)*p2*255,
16274  Z = (Tfloat)*p3*255,
16275  R = 3.240479f*X - 1.537150f*Y - 0.498535f*Z,
16276  G = -0.969256f*X + 1.875992f*Y + 0.041556f*Z,
16277  B = 0.055648f*X - 0.204043f*Y + 1.057311f*Z;
16278  *(p1++) = (T)(R<0?0:(R>255?255:R));
16279  *(p2++) = (T)(G<0?0:(G>255?255:G));
16280  *(p3++) = (T)(B<0?0:(B>255?255:B));
16281  }
16282  return *this;
16283  }
16284 
16286  return CImg<Tuchar>(*this,false).XYZtoRGB();
16287  }
16288 
16291 #define _cimg_Labf(x) ((x)>=0.008856f?(std::pow(x,(Tfloat)1/3)):(7.787f*(x)+16.0f/116))
16292  if (is_empty()) return *this;
16293  if (dim!=3)
16294  throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, "
16295  "should be a (X,Y,Z) image (dim=3)",
16296  pixel_type(),dim);
16297  const Tfloat
16298  Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
16299  Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
16300  Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
16301  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16302  for (unsigned int N = width*height*depth; N; --N) {
16303  const Tfloat
16304  X = (Tfloat)*p1,
16305  Y = (Tfloat)*p2,
16306  Z = (Tfloat)*p3,
16307  XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn,
16308  fX = (Tfloat)_cimg_Labf(XXn),
16309  fY = (Tfloat)_cimg_Labf(YYn),
16310  fZ = (Tfloat)_cimg_Labf(ZZn);
16311  *(p1++) = (T)(116*fY - 16);
16312  *(p2++) = (T)(500*(fX - fY));
16313  *(p3++) = (T)(200*(fY - fZ));
16314  }
16315  return *this;
16316  }
16317 
16319  return CImg<Tfloat>(*this,false).XYZtoLab();
16320  }
16321 
16324 #define _cimg_Labfi(x) ((x)>=0.206893f?((x)*(x)*(x)):(((x)-16.0f/116)/7.787f))
16325  if (is_empty()) return *this;
16326  if (dim!=3)
16327  throw CImgInstanceException("CImg<%s>::LabtoXYZ() : Input image dimension is dim=%u, "
16328  "should be a (X,Y,Z) image (dim=3)",
16329  pixel_type(),dim);
16330  const Tfloat
16331  Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
16332  Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
16333  Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
16334  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16335  for (unsigned int N = width*height*depth; N; --N) {
16336  const Tfloat
16337  L = (Tfloat)*p1,
16338  a = (Tfloat)*p2,
16339  b = (Tfloat)*p3,
16340  cY = (L + 16)/116,
16341  Y = (Tfloat)(Yn*_cimg_Labfi(cY)),
16342  pY = (Tfloat)std::pow(Y/Yn,(Tfloat)1/3),
16343  cX = a/500 + pY,
16344  X = Xn*cX*cX*cX,
16345  cZ = pY - b/200,
16346  Z = Zn*cZ*cZ*cZ;
16347  *(p1++) = (T)(X);
16348  *(p2++) = (T)(Y);
16349  *(p3++) = (T)(Z);
16350  }
16351  return *this;
16352  }
16353 
16355  return CImg<Tfloat>(*this,false).LabtoXYZ();
16356  }
16357 
16360  if (is_empty()) return *this;
16361  if (dim!=3)
16362  throw CImgInstanceException("CImg<%s>::XYZtoxyY() : Input image dimension is dim=%u, "
16363  "should be a (X,Y,Z) image (dim=3)",
16364  pixel_type(),dim);
16365  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16366  for (unsigned int N = width*height*depth; N; --N) {
16367  const Tfloat
16368  X = (Tfloat)*p1,
16369  Y = (Tfloat)*p2,
16370  Z = (Tfloat)*p3,
16371  sum = (X+Y+Z),
16372  nsum = sum>0?sum:1;
16373  *(p1++) = (T)(X/nsum);
16374  *(p2++) = (T)(Y/nsum);
16375  *(p3++) = (T)Y;
16376  }
16377  return *this;
16378  }
16379 
16381  return CImg<Tfloat>(*this,false).XYZtoxyY();
16382  }
16383 
16386  if (is_empty()) return *this;
16387  if (dim!=3)
16388  throw CImgInstanceException("CImg<%s>::xyYtoXYZ() : Input image dimension is dim=%u, "
16389  "should be a (x,y,Y) image (dim=3)",
16390  pixel_type(),dim);
16391  T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
16392  for (unsigned int N = width*height*depth; N; --N) {
16393  const Tfloat
16394  px = (Tfloat)*p1,
16395  py = (Tfloat)*p2,
16396  Y = (Tfloat)*p3,
16397  ny = py>0?py:1;
16398  *(p1++) = (T)(px*Y/ny);
16399  *(p2++) = (T)Y;
16400  *(p3++) = (T)((1-px-py)*Y/ny);
16401  }
16402  return *this;
16403  }
16404 
16406  return CImg<Tfloat>(*this,false).xyYtoXYZ();
16407  }
16408 
16411  return RGBtoXYZ().XYZtoLab();
16412  }
16413 
16415  return CImg<Tfloat>(*this,false).RGBtoLab();
16416  }
16417 
16420  return LabtoXYZ().XYZtoRGB();
16421  }
16422 
16424  return CImg<Tuchar>(*this,false).LabtoRGB();
16425  }
16426 
16429  return RGBtoXYZ().XYZtoxyY();
16430  }
16431 
16433  return CImg<Tfloat>(*this,false).RGBtoxyY();
16434  }
16435 
16438  return xyYtoXYZ().XYZtoRGB();
16439  }
16440 
16442  return CImg<Tuchar>(*this,false).xyYtoRGB();
16443  }
16444 
16447  return RGBtoCMY().CMYtoCMYK();
16448  }
16449 
16451  return CImg<Tfloat>(*this,false).RGBtoCMYK();
16452  }
16453 
16456  return CMYKtoCMY().CMYtoRGB();
16457  }
16458 
16460  return CImg<Tuchar>(*this,false).CMYKtoRGB();
16461  }
16462 
16464 
16468  return get_RGBtoBayer().transfer_to(*this);
16469  }
16470 
16472  if (is_empty()) return *this;
16473  if (dim!=3)
16474  throw CImgInstanceException("CImg<%s>::RGBtoBayer() : Input image dimension is dim=%u, "
16475  "should be a (R,G,B) image (dim=3)",
16476  pixel_type(),dim);
16477  CImg<T> res(width,height,depth,1);
16478  const T *pR = ptr(0,0,0,0), *pG = ptr(0,0,0,1), *pB = ptr(0,0,0,2);
16479  T *ptrd = res.data;
16480  cimg_forXYZ(*this,x,y,z) {
16481  if (y%2) {
16482  if (x%2) *(ptrd++) = *pB;
16483  else *(ptrd++) = *pG;
16484  } else {
16485  if (x%2) *(ptrd++) = *pG;
16486  else *(ptrd++) = *pR;
16487  }
16488  ++pR; ++pG; ++pB;
16489  }
16490  return res;
16491  }
16492 
16494  CImg<T>& BayertoRGB(const unsigned int interpolation_type=3) {
16495  return get_BayertoRGB(interpolation_type).transfer_to(*this);
16496  }
16497 
16498  CImg<Tuchar> get_BayertoRGB(const unsigned int interpolation_type=3) const {
16499  if (is_empty()) return *this;
16500  if (dim!=1)
16501  throw CImgInstanceException("CImg<%s>::BayertoRGB() : Input image dimension is dim=%u, "
16502  "should be a Bayer image (dim=1)",
16503  pixel_type(),dim);
16504  CImg<Tuchar> res(width,height,depth,3);
16505  CImg_3x3(I,T);
16506  Tuchar *pR = res.ptr(0,0,0,0), *pG = res.ptr(0,0,0,1), *pB = res.ptr(0,0,0,2);
16507  switch (interpolation_type) {
16508  case 3 : { // Edge-directed
16509  CImg_3x3(R,T);
16510  CImg_3x3(G,T);
16511  CImg_3x3(B,T);
16512  cimg_forXYZ(*this,x,y,z) {
16513  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;
16514  cimg_get3x3(*this,x,y,z,0,I);
16515  if (y%2) {
16516  if (x%2) {
16517  const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
16518  *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
16519  } else *pG = (Tuchar)Icc;
16520  } else {
16521  if (x%2) *pG = (Tuchar)Icc;
16522  else {
16523  const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
16524  *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
16525  }
16526  }
16527  ++pG;
16528  }
16529  cimg_forXYZ(*this,x,y,z) {
16530  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;
16531  cimg_get3x3(*this,x,y,z,0,I);
16532  cimg_get3x3(res,x,y,z,1,G);
16533  if (y%2) {
16534  if (x%2) *pB = (Tuchar)Icc;
16535  else { *pR = (Tuchar)((Icn+Icp)/2); *pB = (Tuchar)((Inc+Ipc)/2); }
16536  } else {
16537  if (x%2) { *pR = (Tuchar)((Inc+Ipc)/2); *pB = (Tuchar)((Icn+Icp)/2); }
16538  else *pR = (Tuchar)Icc;
16539  }
16540  ++pR; ++pB;
16541  }
16542  pR = res.ptr(0,0,0,0);
16543  pG = res.ptr(0,0,0,1);
16544  pB = res.ptr(0,0,0,2);
16545  cimg_forXYZ(*this,x,y,z) {
16546  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;
16547  cimg_get3x3(res,x,y,z,0,R);
16548  cimg_get3x3(res,x,y,z,1,G);
16549  cimg_get3x3(res,x,y,z,2,B);
16550  if (y%2) {
16551  if (x%2) {
16552  const float alpha = (float)cimg::sqr(Rnc-Rpc), beta = (float)cimg::sqr(Rcn-Rcp), cx = 1/(1+alpha), cy = 1/(1+beta);
16553  *pR = (Tuchar)((cx*(Rnc+Rpc) + cy*(Rcn+Rcp))/(2*(cx+cy)));
16554  }
16555  } else {
16556  if (!(x%2)) {
16557  const float alpha = (float)cimg::sqr(Bnc-Bpc), beta = (float)cimg::sqr(Bcn-Bcp), cx = 1/(1+alpha), cy = 1/(1+beta);
16558  *pB = (Tuchar)((cx*(Bnc+Bpc) + cy*(Bcn+Bcp))/(2*(cx+cy)));
16559  }
16560  }
16561  ++pR; ++pG; ++pB;
16562  }
16563  } break;
16564  case 2 : { // Linear interpolation
16565  cimg_forXYZ(*this,x,y,z) {
16566  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;
16567  cimg_get3x3(*this,x,y,z,0,I);
16568  if (y%2) {
16569  if (x%2) { *pR = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)Icc; }
16570  else { *pR = (Tuchar)((Icp+Icn)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Inc+Ipc)/2); }
16571  } else {
16572  if (x%2) { *pR = (Tuchar)((Ipc+Inc)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Icn+Icp)/2); }
16573  else { *pR = (Tuchar)Icc; *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); }
16574  }
16575  ++pR; ++pG; ++pB;
16576  }
16577  } break;
16578  case 1 : { // Nearest neighbor interpolation
16579  cimg_forXYZ(*this,x,y,z) {
16580  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;
16581  cimg_get3x3(*this,x,y,z,0,I);
16582  if (y%2) {
16583  if (x%2) { *pR = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)Icc; }
16584  else { *pR = (Tuchar)cimg::min(Icn,Icp); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Inc,Ipc); }
16585  } else {
16586  if (x%2) { *pR = (Tuchar)cimg::min(Inc,Ipc); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Icn,Icp); }
16587  else { *pR = (Tuchar)Icc; *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); }
16588  }
16589  ++pR; ++pG; ++pB;
16590  }
16591  } break;
16592  default : { // 0-filling interpolation
16593  const T *ptrs = data;
16594  res.fill(0);
16595  cimg_forXYZ(*this,x,y,z) {
16596  const T val = *(ptrs++);
16597  if (y%2) { if (x%2) *pB = val; else *pG = val; } else { if (x%2) *pG = val; else *pR = val; }
16598  ++pR; ++pG; ++pB;
16599  }
16600  }
16601  }
16602  return res;
16603  }
16604 
16606  //------------------------------------------
16607  //
16609 
16610  //------------------------------------------
16611 
16613 
16630  CImg<T>& resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
16631  const int interpolation_type=1, const int border_condition=-1, const bool center=false) {
16632  if (!pdx || !pdy || !pdz || !pdv) return assign();
16633  const unsigned int
16634  tdx = pdx<0?-pdx*width/100:pdx,
16635  tdy = pdy<0?-pdy*height/100:pdy,
16636  tdz = pdz<0?-pdz*depth/100:pdz,
16637  tdv = pdv<0?-pdv*dim/100:pdv,
16638  dx = tdx?tdx:1,
16639  dy = tdy?tdy:1,
16640  dz = tdz?tdz:1,
16641  dv = tdv?tdv:1;
16642  if (width==dx && height==dy && depth==dz && dim==dv) return *this;
16643  if (interpolation_type==-1 && dx*dy*dz*dv==size()) {
16644  width = dx; height = dy; depth = dz; dim = dv;
16645  return *this;
16646  }
16647  return get_resize(dx,dy,dz,dv,interpolation_type,border_condition,center).transfer_to(*this);
16648  }
16649 
16650  CImg<T> get_resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
16651  const int interpolation_type=1, const int border_condition=-1, const bool center=false) const {
16652  if (!pdx || !pdy || !pdz || !pdv) return CImg<T>();
16653  const unsigned int
16654  tdx = pdx<0?-pdx*width/100:pdx,
16655  tdy = pdy<0?-pdy*height/100:pdy,
16656  tdz = pdz<0?-pdz*depth/100:pdz,
16657  tdv = pdv<0?-pdv*dim/100:pdv,
16658  dx = tdx?tdx:1,
16659  dy = tdy?tdy:1,
16660  dz = tdz?tdz:1,
16661  dv = tdv?tdv:1;
16662  if (width==dx && height==dy && depth==dz && dim==dv) return +*this;
16663  if (is_empty()) return CImg<T>(dx,dy,dz,dv,0);
16664 
16665  CImg<T> res;
16666  switch (interpolation_type) {
16667  case -1 : // Raw resizing
16668  std::memcpy(res.assign(dx,dy,dz,dv,0).data,data,sizeof(T)*cimg::min(size(),(unsigned int)dx*dy*dz*dv));
16669  break;
16670 
16671  case 0 : { // No interpolation
16672  const unsigned int bx = width-1, by = height-1, bz = depth-1, bv = dim-1;
16673  res.assign(dx,dy,dz,dv);
16674  switch (border_condition) {
16675  case 1 : {
16676  if (center) {
16677  const int
16678  x0 = (res.dimx() - dimx())/2,
16679  y0 = (res.dimy() - dimy())/2,
16680  z0 = (res.dimz() - dimz())/2,
16681  v0 = (res.dimv() - dimv())/2,
16682  x1 = x0 + (int)bx,
16683  y1 = y0 + (int)by,
16684  z1 = z0 + (int)bz,
16685  v1 = v0 + (int)bv;
16686  res.draw_image(x0,y0,z0,v0,*this);
16687  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);
16688  } else {
16689  res.draw_image(*this);
16690  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);
16691  }
16692  } break;
16693  case 2 : {
16694  int nx0 = 0, ny0 = 0, nz0 = 0, nv0 = 0;
16695  if (center) {
16696  const int
16697  x0 = (res.dimx() - dimx())/2,
16698  y0 = (res.dimy() - dimy())/2,
16699  z0 = (res.dimz() - dimz())/2,
16700  v0 = (res.dimv() - dimv())/2;
16701  nx0 = x0>0?x0-(1+x0/width)*width:x0;
16702  ny0 = y0>0?y0-(1+y0/height)*height:y0;
16703  nz0 = z0>0?z0-(1+z0/depth)*depth:z0;
16704  nv0 = v0>0?v0-(1+v0/dim)*dim:v0;
16705  }
16706  for (int k = nv0; k<(int)dv; k+=dimv())
16707  for (int z = nz0; z<(int)dz; z+=dimz())
16708  for (int y = ny0; y<(int)dy; y+=dimy())
16709  for (int x = nx0; x<(int)dx; x+=dimx()) res.draw_image(x,y,z,k,*this);
16710  } break;
16711  default : {
16712  res.fill(0);
16713  if (center) res.draw_image((res.dimx()-dimx())/2,(res.dimy()-dimy())/2,(res.dimz()-dimz())/2,(res.dimv()-dimv())/2,*this);
16714  else res.draw_image(*this);
16715  }
16716  }
16717  } break;
16718 
16719  case 1 : { // Nearest-neighbor interpolation
16720  res.assign(dx,dy,dz,dv);
16721  unsigned int
16722  *const offx = new unsigned int[dx],
16723  *const offy = new unsigned int[dy+1],
16724  *const offz = new unsigned int[dz+1],
16725  *const offv = new unsigned int[dv+1],
16726  *poffx, *poffy, *poffz, *poffv,
16727  curr, old;
16728  const unsigned int wh = width*height, whd = width*height*depth, rwh = dx*dy, rwhd = dx*dy*dz;
16729  poffx = offx; curr = 0; cimg_forX(res,x) { old = curr; curr = (x+1)*width/dx; *(poffx++) = (unsigned int)curr - (unsigned int)old; }
16730  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;
16731  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;
16732  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;
16733  T *ptrd = res.data;
16734  const T* ptrv = data;
16735  poffv = offv;
16736  for (unsigned int k = 0; k<dv; ) {
16737  const T *ptrz = ptrv;
16738  poffz = offz;
16739  for (unsigned int z = 0; z<dz; ) {
16740  const T *ptry = ptrz;
16741  poffy = offy;
16742  for (unsigned int y = 0; y<dy; ) {
16743  const T *ptrx = ptry;
16744  poffx = offx;
16745  cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poffx++); }
16746  ++y;
16747  unsigned int dy = *(poffy++);
16748  for (;!dy && y<dy; std::memcpy(ptrd,ptrd - dx,sizeof(T)*dx), ++y, ptrd+=dx, dy=*(poffy++)) {}
16749  ptry+=dy;
16750  }
16751  ++z;
16752  unsigned int dz = *(poffz++);
16753  for (;!dz && z<dz; std::memcpy(ptrd,ptrd-rwh,sizeof(T)*rwh), ++z, ptrd+=rwh, dz=*(poffz++)) {}
16754  ptrz+=dz;
16755  }
16756  ++k;
16757  unsigned int dv = *(poffv++);
16758  for (;!dv && k<dv; std::memcpy(ptrd,ptrd-rwhd,sizeof(T)*rwhd), ++k, ptrd+=rwhd, dv=*(poffv++)) {}
16759  ptrv+=dv;
16760  }
16761  delete[] offx; delete[] offy; delete[] offz; delete[] offv;
16762  } break;
16763 
16764  case 2 : { // Moving average
16765  bool instance_first = true;
16766  if (dx!=width) {
16767  CImg<Tfloat> tmp(dx,height,depth,dim,0);
16768  for (unsigned int a = width*dx, b = width, c = dx, s = 0, t = 0; a; ) {
16769  const unsigned int d = cimg::min(b,c);
16770  a-=d; b-=d; c-=d;
16771  cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d;
16772  if (!b) { cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)/=width; ++t; b = width; }
16773  if (!c) { ++s; c = dx; }
16774  }
16775  tmp.transfer_to(res);
16776  instance_first = false;
16777  }
16778  if (dy!=height) {
16779  CImg<Tfloat> tmp(dx,dy,depth,dim,0);
16780  for (unsigned int a = height*dy, b = height, c = dy, s = 0, t = 0; a; ) {
16781  const unsigned int d = cimg::min(b,c);
16782  a-=d; b-=d; c-=d;
16783  if (instance_first) cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d;
16784  else cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d;
16785  if (!b) { cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)/=height; ++t; b = height; }
16786  if (!c) { ++s; c = dy; }
16787  }
16788  tmp.transfer_to(res);
16789  instance_first = false;
16790  }
16791  if (dz!=depth) {
16792  CImg<Tfloat> tmp(dx,dy,dz,dim,0);
16793  for (unsigned int a = depth*dz, b = depth, c = dz, s = 0, t = 0; a; ) {
16794  const unsigned int d = cimg::min(b,c);
16795  a-=d; b-=d; c-=d;
16796  if (instance_first) cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d;
16797  else cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d;
16798  if (!b) { cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)/=depth; ++t; b = depth; }
16799  if (!c) { ++s; c = dz; }
16800  }
16801  tmp.transfer_to(res);
16802  instance_first = false;
16803  }
16804  if (dv!=dim) {
16805  CImg<Tfloat> tmp(dx,dy,dz,dv,0);
16806  for (unsigned int a = dim*dv, b = dim, c = dv, s = 0, t = 0; a; ) {
16807  const unsigned int d = cimg::min(b,c);
16808  a-=d; b-=d; c-=d;
16809  if (instance_first) cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d;
16810  else cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d;
16811  if (!b) { cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)/=dim; ++t; b = dim; }
16812  if (!c) { ++s; c = dv; }
16813  }
16814  tmp.transfer_to(res);
16815  instance_first = false;
16816  }
16817  } break;
16818 
16819  case 3 : { // Linear interpolation
16820  const unsigned int dimmax = cimg::max(dx,dy,dz,dv);
16821  const float
16822  sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
16823  sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
16824  sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
16825  sv = (border_condition<0 && dv>dim )?(dv>1?(dim-1.0f)/(dv-1) :0):(float)dim/dv;
16826 
16827  unsigned int *const off = new unsigned int[dimmax], *poff;
16828  float *const foff = new float[dimmax], *pfoff, old, curr;
16829  CImg<T> resx, resy, resz, resv;
16830  T *ptrd;
16831 
16832  if (dx!=width) {
16833  if (width==1) resx = get_resize(dx,height,depth,dim,1,0);
16834  else {
16835  resx.assign(dx,height,depth,dim);
16836  curr = old = 0; poff = off; pfoff = foff;
16837  cimg_forX(resx,x) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sx; *(poff++) = (unsigned int)curr-(unsigned int)old; }
16838  ptrd = resx.data;
16839  const T *ptrs0 = data;
16840  cimg_forYZV(resx,y,z,k) {
16841  poff = off; pfoff = foff;
16842  const T *ptrs = ptrs0, *const ptrsmax = ptrs0 + (width-1);
16843  cimg_forX(resx,x) {
16844  const float alpha = *(pfoff++);
16845  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+1):(border_condition?val1:(T)0);
16846  *(ptrd++) = (T)((1-alpha)*val1 + alpha*val2);
16847  ptrs+=*(poff++);
16848  }
16849  ptrs0+=width;
16850  }
16851  }
16852  } else resx.assign(*this,true);
16853 
16854  if (dy!=height) {
16855  if (height==1) resy = resx.get_resize(dx,dy,depth,dim,1,0);
16856  else {
16857  resy.assign(dx,dy,depth,dim);
16858  curr = old = 0; poff = off; pfoff = foff;
16859  cimg_forY(resy,y) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sy; *(poff++) = dx*((unsigned int)curr-(unsigned int)old); }
16860  cimg_forXZV(resy,x,z,k) {
16861  ptrd = resy.ptr(x,0,z,k);
16862  const T *ptrs = resx.ptr(x,0,z,k), *const ptrsmax = ptrs + (height-1)*dx;
16863  poff = off; pfoff = foff;
16864  cimg_forY(resy,y) {
16865  const float alpha = *(pfoff++);
16866  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+dx):(border_condition?val1:(T)0);
16867  *ptrd = (T)((1-alpha)*val1 + alpha*val2);
16868  ptrd+=dx;
16869  ptrs+=*(poff++);
16870  }
16871  }
16872  }
16873  resx.assign();
16874  } else resy.assign(resx,true);
16875 
16876  if (dz!=depth) {
16877  if (depth==1) resz = resy.get_resize(dx,dy,dz,dim,1,0);
16878  else {
16879  const unsigned int wh = dx*dy;
16880  resz.assign(dx,dy,dz,dim);
16881  curr = old = 0; poff = off; pfoff = foff;
16882  cimg_forZ(resz,z) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sz; *(poff++) = wh*((unsigned int)curr-(unsigned int)old); }
16883  cimg_forXYV(resz,x,y,k) {
16884  ptrd = resz.ptr(x,y,0,k);
16885  const T *ptrs = resy.ptr(x,y,0,k), *const ptrsmax = ptrs + (depth-1)*wh;
16886  poff = off; pfoff = foff;
16887  cimg_forZ(resz,z) {
16888  const float alpha = *(pfoff++);
16889  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+wh):(border_condition?val1:(T)0);
16890  *ptrd = (T)((1-alpha)*val1 + alpha*val2);
16891  ptrd+=wh;
16892  ptrs+=*(poff++);
16893  }
16894  }
16895  }
16896  resy.assign();
16897  } else resz.assign(resy,true);
16898 
16899  if (dv!=dim) {
16900  if (dim==1) resv = resz.get_resize(dx,dy,dz,dv,1,0);
16901  else {
16902  const unsigned int whd = dx*dy*dz;
16903  resv.assign(dx,dy,dz,dv);
16904  curr = old = 0; poff = off; pfoff = foff;
16905  cimg_forV(resv,k) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sv; *(poff++) = whd*((unsigned int)curr-(unsigned int)old); }
16906  cimg_forXYZ(resv,x,y,z) {
16907  ptrd = resv.ptr(x,y,z,0);
16908  const T *ptrs = resz.ptr(x,y,z,0), *const ptrsmax = ptrs + (dim-1)*whd;
16909  poff = off; pfoff = foff;
16910  cimg_forV(resv,k) {
16911  const float alpha = *(pfoff++);
16912  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+whd):(border_condition?val1:(T)0);
16913  *ptrd = (T)((1-alpha)*val1 + alpha*val2);
16914  ptrd+=whd;
16915  ptrs+=*(poff++);
16916  }
16917  }
16918  }
16919  resz.assign();
16920  } else resv.assign(resz,true);
16921 
16922  delete[] off; delete[] foff;
16923  return resv.is_shared?(resz.is_shared?(resy.is_shared?(resx.is_shared?(+(*this)):resx):resy):resz):resv;
16924  } break;
16925 
16926  case 4 : { // Grid filling
16927  res.assign(dx,dy,dz,dv,0);
16928  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);
16929  } break;
16930 
16931  case 5 : { // Cubic interpolation
16932  const float
16933  sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
16934  sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
16935  sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
16936  sv = (border_condition<0 && dv>dim )?(dv>1?(dim-1.0f)/(dv-1) :0):(float)dim/dv;
16937  res.assign(dx,dy,dz,dv);
16938  T *ptrd = res.ptr();
16939  float cx, cy, cz, ck = 0;
16940  cimg_forV(res,k) { cz = 0;
16941  cimg_forZ(res,z) { cy = 0;
16942  cimg_forY(res,y) { cx = 0;
16943  cimg_forX(res,x) {
16944  *(ptrd++) = (T)(border_condition?_cubic_atXY(cx,cy,(int)cz,(int)ck):cubic_atXY(cx,cy,(int)cz,(int)ck,0));
16945  cx+=sx;
16946  } cy+=sy;
16947  } cz+=sz;
16948  } ck+=sv;
16949  }
16950  } break;
16951 
16952  default : // Invalid interpolation method
16953  throw CImgArgumentException("CImg<%s>::resize() : Invalid interpolation_type %d "
16954  "(should be { -1=raw, 0=zero, 1=nearest, 2=average, 3=linear, 4=grid, 5=bicubic}).",
16955  pixel_type(),interpolation_type);
16956  }
16957  return res;
16958  }
16959 
16961 
16974  template<typename t>
16975  CImg<T>& resize(const CImg<t>& src, const int interpolation_type=1,
16976  const int border_condition=-1, const bool center=false) {
16977  return resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
16978  }
16979 
16980  template<typename t>
16981  CImg<T> get_resize(const CImg<t>& src, const int interpolation_type=1,
16982  const int border_condition=-1, const bool center=false) const {
16983  return get_resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
16984  }
16985 
16987 
17000  CImg<T>& resize(const CImgDisplay& disp, const int interpolation_type=1,
17001  const int border_condition=-1, const bool center=false) {
17002  return resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
17003  }
17004 
17005  CImg<T> get_resize(const CImgDisplay& disp, const int interpolation_type=1,
17006  const int border_condition=-1, const bool center=false) const {
17007  return get_resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
17008  }
17009 
17012  return get_resize_halfXY().transfer_to(*this);
17013  }
17014 
17016  if (is_empty()) return *this;
17017  const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f,
17018  0.1231940459f, 0.1935127547f, 0.1231940459f,
17019  0.07842776544f, 0.1231940459f, 0.07842776544f };
17020  T I[9] = { 0 };
17021  CImg<T> dest(width/2,height/2,depth,dim);
17022  cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I)
17023  if (x%2 && y%2) dest(x/2,y/2,z,k) = (T)
17024  (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
17025  I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
17026  I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
17027  return dest;
17028  }
17029 
17031 
17036  return get_resize_doubleXY().transfer_to(*this);
17037  }
17038 
17040 #define _cimg_gs2x_for3(bound,i) \
17041  for (int i = 0, _p1##i = 0, \
17042  _n1##i = 1>=(bound)?(int)(bound)-1:1; \
17043  _n1##i<(int)(bound) || i==--_n1##i; \
17044  _p1##i = i++, ++_n1##i, ptrd1+=(res).width, ptrd2+=(res).width)
17045 
17046 #define _cimg_gs2x_for3x3(img,x,y,z,v,I) \
17047  _cimg_gs2x_for3((img).height,y) for (int x = 0, \
17048  _p1##x = 0, \
17049  _n1##x = (int)( \
17050  (I[1] = (img)(0,_p1##y,z,v)), \
17051  (I[3] = I[4] = (img)(0,y,z,v)), \
17052  (I[7] = (img)(0,_n1##y,z,v)), \
17053  1>=(img).width?(int)((img).width)-1:1); \
17054  (_n1##x<(int)((img).width) && ( \
17055  (I[2] = (img)(_n1##x,_p1##y,z,v)), \
17056  (I[5] = (img)(_n1##x,y,z,v)), \
17057  (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
17058  x==--_n1##x; \
17059  I[1] = I[2], \
17060  I[3] = I[4], I[4] = I[5], \
17061  I[7] = I[8], \
17062  _p1##x = x++, ++_n1##x)
17063 
17064  if (is_empty()) return *this;
17065  CImg<T> res(2*width,2*height,depth,dim);
17066  CImg_3x3(I,T);
17067  cimg_forZV(*this,z,k) {
17068  T
17069  *ptrd1 = res.ptr(0,0,0,k),
17070  *ptrd2 = ptrd1 + res.width;
17071  _cimg_gs2x_for3x3(*this,x,y,0,k,I) {
17072  if (Icp!=Icn && Ipc!=Inc) {
17073  *(ptrd1++) = Ipc==Icp?Ipc:Icc;
17074  *(ptrd1++) = Icp==Inc?Inc:Icc;
17075  *(ptrd2++) = Ipc==Icn?Ipc:Icc;
17076  *(ptrd2++) = Icn==Inc?Inc:Icc;
17077  } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; }
17078  }
17079  }
17080  return res;
17081  }
17082 
17084 
17089  return get_resize_tripleXY().transfer_to(*this);
17090  }
17091 
17093 #define _cimg_gs3x_for3(bound,i) \
17094  for (int i = 0, _p1##i = 0, \
17095  _n1##i = 1>=(bound)?(int)(bound)-1:1; \
17096  _n1##i<(int)(bound) || i==--_n1##i; \
17097  _p1##i = i++, ++_n1##i, ptrd1+=2*(res).width, ptrd2+=2*(res).width, ptrd3+=2*(res).width)
17098 
17099 #define _cimg_gs3x_for3x3(img,x,y,z,v,I) \
17100  _cimg_gs3x_for3((img).height,y) for (int x = 0, \
17101  _p1##x = 0, \
17102  _n1##x = (int)( \
17103  (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
17104  (I[3] = I[4] = (img)(0,y,z,v)), \
17105  (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
17106  1>=(img).width?(int)((img).width)-1:1); \
17107  (_n1##x<(int)((img).width) && ( \
17108  (I[2] = (img)(_n1##x,_p1##y,z,v)), \
17109  (I[5] = (img)(_n1##x,y,z,v)), \
17110  (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
17111  x==--_n1##x; \
17112  I[0] = I[1], I[1] = I[2], \
17113  I[3] = I[4], I[4] = I[5], \
17114  I[6] = I[7], I[7] = I[8], \
17115  _p1##x = x++, ++_n1##x)
17116 
17117  if (is_empty()) return *this;
17118  CImg<T> res(3*width,3*height,depth,dim);
17119  CImg_3x3(I,T);
17120  cimg_forZV(*this,z,k) {
17121  T
17122  *ptrd1 = res.ptr(0,0,0,k),
17123  *ptrd2 = ptrd1 + res.width,
17124  *ptrd3 = ptrd2 + res.width;
17125  _cimg_gs3x_for3x3(*this,x,y,0,k,I) {
17126  if (Icp != Icn && Ipc != Inc) {
17127  *(ptrd1++) = Ipc==Icp?Ipc:Icc;
17128  *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc;
17129  *(ptrd1++) = Icp==Inc?Inc:Icc;
17130  *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc;
17131  *(ptrd2++) = Icc;
17132  *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc;
17133  *(ptrd3++) = Ipc==Icn?Ipc:Icc;
17134  *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc;
17135  *(ptrd3++) = Icn==Inc?Inc:Icc;
17136  } else {
17137  *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc;
17138  *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc;
17139  *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc;
17140  }
17141  }
17142  }
17143  return res;
17144  }
17145 
17147  CImg<T>& mirror(const char axis) {
17148  if (is_empty()) return *this;
17149  T *pf, *pb, *buf = 0;
17150  switch (cimg::uncase(axis)) {
17151  case 'x' : {
17152  pf = data; pb = ptr(width-1);
17153  const unsigned int width2 = width/2;
17154  for (unsigned int yzv = 0; yzv<height*depth*dim; ++yzv) {
17155  for (unsigned int x = 0; x<width2; ++x) { const T val = *pf; *(pf++) = *pb; *(pb--) = val; }
17156  pf+=width - width2;
17157  pb+=width + width2;
17158  }
17159  } break;
17160  case 'y' : {
17161  buf = new T[width];
17162  pf = data; pb = ptr(0,height-1);
17163  const unsigned int height2 = height/2;
17164  for (unsigned int zv = 0; zv<depth*dim; ++zv) {
17165  for (unsigned int y = 0; y<height2; ++y) {
17166  std::memcpy(buf,pf,width*sizeof(T));
17167  std::memcpy(pf,pb,width*sizeof(T));
17168  std::memcpy(pb,buf,width*sizeof(T));
17169  pf+=width;
17170  pb-=width;
17171  }
17172  pf+=width*(height - height2);
17173  pb+=width*(height + height2);
17174  }
17175  } break;
17176  case 'z' : {
17177  buf = new T[width*height];
17178  pf = data; pb = ptr(0,0,depth-1);
17179  const unsigned int depth2 = depth/2;
17180  cimg_forV(*this,v) {
17181  for (unsigned int z = 0; z<depth2; ++z) {
17182  std::memcpy(buf,pf,width*height*sizeof(T));
17183  std::memcpy(pf,pb,width*height*sizeof(T));
17184  std::memcpy(pb,buf,width*height*sizeof(T));
17185  pf+=width*height;
17186  pb-=width*height;
17187  }
17188  pf+=width*height*(depth - depth2);
17189  pb+=width*height*(depth + depth2);
17190  }
17191  } break;
17192  case 'v' : {
17193  buf = new T[width*height*depth];
17194  pf = data; pb = ptr(0,0,0,dim-1);
17195  const unsigned int dim2 = dim/2;
17196  for (unsigned int v = 0; v<dim2; ++v) {
17197  std::memcpy(buf,pf,width*height*depth*sizeof(T));
17198  std::memcpy(pf,pb,width*height*depth*sizeof(T));
17199  std::memcpy(pb,buf,width*height*depth*sizeof(T));
17200  pf+=width*height*depth;
17201  pb-=width*height*depth;
17202  }
17203  } break;
17204  default :
17205  throw CImgArgumentException("CImg<%s>::mirror() : unknow axis '%c', must be 'x','y','z' or 'v'.",
17206  pixel_type(),axis);
17207  }
17208  if (buf) delete[] buf;
17209  return *this;
17210  }
17211 
17212  CImg<T> get_mirror(const char axis) const {
17213  return (+*this).mirror(axis);
17214  }
17215 
17217 
17229  CImg<T>& translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
17230  const int border_condition=0) {
17231  if (is_empty()) return *this;
17232  if (deltax) // Translate along X-axis
17233  switch (border_condition) {
17234  case 0 :
17235  if (cimg::abs(deltax)>=dimx()) return fill(0);
17236  if (deltax<0) cimg_forYZV(*this,y,z,k) {
17237  std::memmove(ptr(0,y,z,k),ptr(-deltax,y,z,k),(width+deltax)*sizeof(T));
17238  std::memset(ptr(width+deltax,y,z,k),0,-deltax*sizeof(T));
17239  } else cimg_forYZV(*this,y,z,k) {
17240  std::memmove(ptr(deltax,y,z,k),ptr(0,y,z,k),(width-deltax)*sizeof(T));
17241  std::memset(ptr(0,y,z,k),0,deltax*sizeof(T));
17242  }
17243  break;
17244  case 1 :
17245  if (deltax<0) {
17246  const int ndeltax = (-deltax>=dimx())?width-1:-deltax;
17247  if (!ndeltax) return *this;
17248  cimg_forYZV(*this,y,z,k) {
17249  std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
17250  T *ptrd = ptr(width-1,y,z,k);
17251  const T val = *ptrd;
17252  for (int l = 0; l<ndeltax-1; ++l) *(--ptrd) = val;
17253  }
17254  } else {
17255  const int ndeltax = (deltax>=dimx())?width-1:deltax;
17256  if (!ndeltax) return *this;
17257  cimg_forYZV(*this,y,z,k) {
17258  std::memmove(ptr(ndeltax,y,z,k),ptr(0,y,z,k),(width-ndeltax)*sizeof(T));
17259  T *ptrd = ptr(0,y,z,k);
17260  const T val = *ptrd;
17261  for (int l = 0; l<ndeltax-1; ++l) *(++ptrd) = val;
17262  }
17263  }
17264  break;
17265  case 2 : {
17266  const int ml = cimg::mod(-deltax,dimx()), ndeltax = (ml<=dimx()/2)?ml:(ml-dimx());
17267  if (!ndeltax) return *this;
17268  T* buf = new T[cimg::abs(ndeltax)];
17269  if (ndeltax>0) cimg_forYZV(*this,y,z,k) {
17270  std::memcpy(buf,ptr(0,y,z,k),ndeltax*sizeof(T));
17271  std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
17272  std::memcpy(ptr(width-ndeltax,y,z,k),buf,ndeltax*sizeof(T));
17273  } else cimg_forYZV(*this,y,z,k) {
17274  std::memcpy(buf,ptr(width+ndeltax,y,z,k),-ndeltax*sizeof(T));
17275  std::memmove(ptr(-ndeltax,y,z,k),ptr(0,y,z,k),(width+ndeltax)*sizeof(T));
17276  std::memcpy(ptr(0,y,z,k),buf,-ndeltax*sizeof(T));
17277  }
17278  delete[] buf;
17279  } break;
17280  }
17281 
17282  if (deltay) // Translate along Y-axis
17283  switch (border_condition) {
17284  case 0 :
17285  if (cimg::abs(deltay)>=dimy()) return fill(0);
17286  if (deltay<0) cimg_forZV(*this,z,k) {
17287  std::memmove(ptr(0,0,z,k),ptr(0,-deltay,z,k),width*(height+deltay)*sizeof(T));
17288  std::memset(ptr(0,height+deltay,z,k),0,-deltay*width*sizeof(T));
17289  } else cimg_forZV(*this,z,k) {
17290  std::memmove(ptr(0,deltay,z,k),ptr(0,0,z,k),width*(height-deltay)*sizeof(T));
17291  std::memset(ptr(0,0,z,k),0,deltay*width*sizeof(T));
17292  }
17293  break;
17294  case 1 :
17295  if (deltay<0) {
17296  const int ndeltay = (-deltay>=dimy())?height-1:-deltay;
17297  if (!ndeltay) return *this;
17298  cimg_forZV(*this,z,k) {
17299  std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
17300  T *ptrd = ptr(0,height-ndeltay,z,k), *ptrs = ptr(0,height-1,z,k);
17301  for (int l = 0; l<ndeltay-1; ++l) { std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
17302  }
17303  } else {
17304  const int ndeltay = (deltay>=dimy())?height-1:deltay;
17305  if (!ndeltay) return *this;
17306  cimg_forZV(*this,z,k) {
17307  std::memmove(ptr(0,ndeltay,z,k),ptr(0,0,z,k),width*(height-ndeltay)*sizeof(T));
17308  T *ptrd = ptr(0,1,z,k), *ptrs = ptr(0,0,z,k);
17309  for (int l = 0; l<ndeltay-1; ++l) { std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
17310  }
17311  }
17312  break;
17313  case 2 : {
17314  const int ml = cimg::mod(-deltay,dimy()), ndeltay = (ml<=dimy()/2)?ml:(ml-dimy());
17315  if (!ndeltay) return *this;
17316  T* buf = new T[width*cimg::abs(ndeltay)];
17317  if (ndeltay>0) cimg_forZV(*this,z,k) {
17318  std::memcpy(buf,ptr(0,0,z,k),width*ndeltay*sizeof(T));
17319  std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
17320  std::memcpy(ptr(0,height-ndeltay,z,k),buf,width*ndeltay*sizeof(T));
17321  } else cimg_forZV(*this,z,k) {
17322  std::memcpy(buf,ptr(0,height+ndeltay,z,k),-ndeltay*width*sizeof(T));
17323  std::memmove(ptr(0,-ndeltay,z,k),ptr(0,0,z,k),width*(height+ndeltay)*sizeof(T));
17324  std::memcpy(ptr(0,0,z,k),buf,-ndeltay*width*sizeof(T));
17325  }
17326  delete[] buf;
17327  } break;
17328  }
17329 
17330  if (deltaz) // Translate along Z-axis
17331  switch (border_condition) {
17332  case 0 :
17333  if (cimg::abs(deltaz)>=dimz()) return fill(0);
17334  if (deltaz<0) cimg_forV(*this,k) {
17335  std::memmove(ptr(0,0,0,k),ptr(0,0,-deltaz,k),width*height*(depth+deltaz)*sizeof(T));
17336  std::memset(ptr(0,0,depth+deltaz,k),0,width*height*(-deltaz)*sizeof(T));
17337  } else cimg_forV(*this,k) {
17338  std::memmove(ptr(0,0,deltaz,k),ptr(0,0,0,k),width*height*(depth-deltaz)*sizeof(T));
17339  std::memset(ptr(0,0,0,k),0,deltaz*width*height*sizeof(T));
17340  }
17341  break;
17342  case 1 :
17343  if (deltaz<0) {
17344  const int ndeltaz = (-deltaz>=dimz())?depth-1:-deltaz;
17345  if (!ndeltaz) return *this;
17346  cimg_forV(*this,k) {
17347  std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
17348  T *ptrd = ptr(0,0,depth-ndeltaz,k), *ptrs = ptr(0,0,depth-1,k);
17349  for (int l = 0; l<ndeltaz-1; ++l) { std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
17350  }
17351  } else {
17352  const int ndeltaz = (deltaz>=dimz())?depth-1:deltaz;
17353  if (!ndeltaz) return *this;
17354  cimg_forV(*this,k) {
17355  std::memmove(ptr(0,0,ndeltaz,k),ptr(0,0,0,k),width*height*(depth-ndeltaz)*sizeof(T));
17356  T *ptrd = ptr(0,0,1,k), *ptrs = ptr(0,0,0,k);
17357  for (int l = 0; l<ndeltaz-1; ++l) { std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
17358  }
17359  }
17360  break;
17361  case 2 : {
17362  const int ml = cimg::mod(-deltaz,dimz()), ndeltaz = (ml<=dimz()/2)?ml:(ml-dimz());
17363  if (!ndeltaz) return *this;
17364  T* buf = new T[width*height*cimg::abs(ndeltaz)];
17365  if (ndeltaz>0) cimg_forV(*this,k) {
17366  std::memcpy(buf,ptr(0,0,0,k),width*height*ndeltaz*sizeof(T));
17367  std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
17368  std::memcpy(ptr(0,0,depth-ndeltaz,k),buf,width*height*ndeltaz*sizeof(T));
17369  } else cimg_forV(*this,k) {
17370  std::memcpy(buf,ptr(0,0,depth+ndeltaz,k),-ndeltaz*width*height*sizeof(T));
17371  std::memmove(ptr(0,0,-ndeltaz,k),ptr(0,0,0,k),width*height*(depth+ndeltaz)*sizeof(T));
17372  std::memcpy(ptr(0,0,0,k),buf,-ndeltaz*width*height*sizeof(T));
17373  }
17374  delete[] buf;
17375  } break;
17376  }
17377 
17378  if (deltav) // Translate along V-axis
17379  switch (border_condition) {
17380  case 0 :
17381  if (cimg::abs(deltav)>=dimv()) return fill(0);
17382  if (-deltav>0) {
17383  std::memmove(data,ptr(0,0,0,-deltav),width*height*depth*(dim+deltav)*sizeof(T));
17384  std::memset(ptr(0,0,0,dim+deltav),0,width*height*depth*(-deltav)*sizeof(T));
17385  } else cimg_forV(*this,k) {
17386  std::memmove(ptr(0,0,0,deltav),data,width*height*depth*(dim-deltav)*sizeof(T));
17387  std::memset(data,0,deltav*width*height*depth*sizeof(T));
17388  }
17389  break;
17390  case 1 :
17391  if (deltav<0) {
17392  const int ndeltav = (-deltav>=dimv())?dim-1:-deltav;
17393  if (!ndeltav) return *this;
17394  std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
17395  T *ptrd = ptr(0,0,0,dim-ndeltav), *ptrs = ptr(0,0,0,dim-1);
17396  for (int l = 0; l<ndeltav-1; ++l) { std::memcpy(ptrd,ptrs,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
17397  } else {
17398  const int ndeltav = (deltav>=dimv())?dim-1:deltav;
17399  if (!ndeltav) return *this;
17400  std::memmove(ptr(0,0,0,ndeltav),data,width*height*depth*(dim-ndeltav)*sizeof(T));
17401  T *ptrd = ptr(0,0,0,1);
17402  for (int l = 0; l<ndeltav-1; ++l) { std::memcpy(ptrd,data,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
17403  }
17404  break;
17405  case 2 : {
17406  const int ml = cimg::mod(-deltav,dimv()), ndeltav = (ml<=dimv()/2)?ml:(ml-dimv());
17407  if (!ndeltav) return *this;
17408  T* buf = new T[width*height*depth*cimg::abs(ndeltav)];
17409  if (ndeltav>0) {
17410  std::memcpy(buf,data,width*height*depth*ndeltav*sizeof(T));
17411  std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
17412  std::memcpy(ptr(0,0,0,dim-ndeltav),buf,width*height*depth*ndeltav*sizeof(T));
17413  } else {
17414  std::memcpy(buf,ptr(0,0,0,dim+ndeltav),-ndeltav*width*height*depth*sizeof(T));
17415  std::memmove(ptr(0,0,0,-ndeltav),data,width*height*depth*(dim+ndeltav)*sizeof(T));
17416  std::memcpy(data,buf,-ndeltav*width*height*depth*sizeof(T));
17417  }
17418  delete[] buf;
17419  } break;
17420  }
17421  return *this;
17422  }
17423 
17424  CImg<T> get_translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
17425  const int border_condition=0) const {
17426  return (+*this).translate(deltax,deltay,deltaz,deltav,border_condition);
17427  }
17428 
17429  // Permute axes order (internal).
17430  template<typename t>
17431  CImg<t> _get_permute_axes(const char *permut, const t&) const {
17432  if (is_empty() || !permut) return CImg<t>(*this,false);
17433  CImg<t> res;
17434  const T* ptrs = data;
17435  if (!cimg::strncasecmp(permut,"xyzv",4)) return (+*this);
17436  if (!cimg::strncasecmp(permut,"xyvz",4)) {
17437  res.assign(width,height,dim,depth);
17438  cimg_forXYZV(*this,x,y,z,v) res(x,y,v,z) = (t)*(ptrs++);
17439  }
17440  if (!cimg::strncasecmp(permut,"xzyv",4)) {
17441  res.assign(width,depth,height,dim);
17442  cimg_forXYZV(*this,x,y,z,v) res(x,z,y,v) = (t)*(ptrs++);
17443  }
17444  if (!cimg::strncasecmp(permut,"xzvy",4)) {
17445  res.assign(width,depth,dim,height);
17446  cimg_forXYZV(*this,x,y,z,v) res(x,z,v,y) = (t)*(ptrs++);
17447  }
17448  if (!cimg::strncasecmp(permut,"xvyz",4)) {
17449  res.assign(width,dim,height,depth);
17450  cimg_forXYZV(*this,x,y,z,v) res(x,v,y,z) = (t)*(ptrs++);
17451  }
17452  if (!cimg::strncasecmp(permut,"xvzy",4)) {
17453  res.assign(width,dim,depth,height);
17454  cimg_forXYZV(*this,x,y,z,v) res(x,v,z,y) = (t)*(ptrs++);
17455  }
17456  if (!cimg::strncasecmp(permut,"yxzv",4)) {
17457  res.assign(height,width,depth,dim);
17458  cimg_forXYZV(*this,x,y,z,v) res(y,x,z,v) = (t)*(ptrs++);
17459  }
17460  if (!cimg::strncasecmp(permut,"yxvz",4)) {
17461  res.assign(height,width,dim,depth);
17462  cimg_forXYZV(*this,x,y,z,v) res(y,x,v,z) = (t)*(ptrs++);
17463  }
17464  if (!cimg::strncasecmp(permut,"yzxv",4)) {
17465  res.assign(height,depth,width,dim);
17466  cimg_forXYZV(*this,x,y,z,v) res(y,z,x,v) = (t)*(ptrs++);
17467  }
17468  if (!cimg::strncasecmp(permut,"yzvx",4)) {
17469  res.assign(height,depth,dim,width);
17470  switch (width) {
17471  case 1 : {
17472  t *ptrR = res.ptr(0,0,0,0);
17473  for (unsigned int siz = height*depth*dim; siz; --siz) {
17474  *(ptrR++) = (t)*(ptrs++);
17475  }
17476  } break;
17477  case 2 : {
17478  t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1);
17479  for (unsigned int siz = height*depth*dim; siz; --siz) {
17480  *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++);
17481  }
17482  } break;
17483  case 3 : { // Optimization for the classical conversion from interleaved RGB to planar RGB
17484  t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1), *ptrB = res.ptr(0,0,0,2);
17485  for (unsigned int siz = height*depth*dim; siz; --siz) {
17486  *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++);
17487  }
17488  } break;
17489  case 4 : { // Optimization for the classical conversion from interleaved RGBA to planar RGBA
17490  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);
17491  for (unsigned int siz = height*depth*dim; siz; --siz) {
17492  *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++); *(ptrA++) = (t)*(ptrs++);
17493  }
17494  } break;
17495  default : {
17496  cimg_forXYZV(*this,x,y,z,v) res(y,z,v,x) = *(ptrs++);
17497  return res;
17498  }
17499  }
17500  }
17501  if (!cimg::strncasecmp(permut,"yvxz",4)) {
17502  res.assign(height,dim,width,depth);
17503  cimg_forXYZV(*this,x,y,z,v) res(y,v,x,z) = (t)*(ptrs++);
17504  }
17505  if (!cimg::strncasecmp(permut,"yvzx",4)) {
17506  res.assign(height,dim,depth,width);
17507  cimg_forXYZV(*this,x,y,z,v) res(y,v,z,x) = (t)*(ptrs++);
17508  }
17509  if (!cimg::strncasecmp(permut,"zxyv",4)) {
17510  res.assign(depth,width,height,dim);
17511  cimg_forXYZV(*this,x,y,z,v) res(z,x,y,v) = (t)*(ptrs++);
17512  }
17513  if (!cimg::strncasecmp(permut,"zxvy",4)) {
17514  res.assign(depth,width,dim,height);
17515  cimg_forXYZV(*this,x,y,z,v) res(z,x,v,y) = (t)*(ptrs++);
17516  }
17517  if (!cimg::strncasecmp(permut,"zyxv",4)) {
17518  res.assign(depth,height,width,dim);
17519  cimg_forXYZV(*this,x,y,z,v) res(z,y,x,v) = (t)*(ptrs++);
17520  }
17521  if (!cimg::strncasecmp(permut,"zyvx",4)) {
17522  res.assign(depth,height,dim,width);
17523  cimg_forXYZV(*this,x,y,z,v) res(z,y,v,x) = (t)*(ptrs++);
17524  }
17525  if (!cimg::strncasecmp(permut,"zvxy",4)) {
17526  res.assign(depth,dim,width,height);
17527  cimg_forXYZV(*this,x,y,z,v) res(z,v,x,y) = (t)*(ptrs++);
17528  }
17529  if (!cimg::strncasecmp(permut,"zvyx",4)) {
17530  res.assign(depth,dim,height,width);
17531  cimg_forXYZV(*this,x,y,z,v) res(z,v,y,x) = (t)*(ptrs++);
17532  }
17533  if (!cimg::strncasecmp(permut,"vxyz",4)) {
17534  res.assign(dim,width,height,depth);
17535  switch (dim) {
17536  case 1 : {
17537  const T *ptrR = ptr(0,0,0,0);
17538  t *ptrd = res.ptr();
17539  for (unsigned int siz = width*height*depth; siz; --siz) {
17540  *(ptrd++) = (t)*(ptrR++);
17541  }
17542  } break;
17543  case 2 : {
17544  const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1);
17545  t *ptrd = res.ptr();
17546  for (unsigned int siz = width*height*depth; siz; --siz) {
17547  *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++);
17548  }
17549  } break;
17550  case 3 : { // Optimization for the classical conversion from planar RGB to interleaved RGB
17551  const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1), *ptrB = ptr(0,0,0,2);
17552  t *ptrd = res.ptr();
17553  for (unsigned int siz = width*height*depth; siz; --siz) {
17554  *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++);
17555  }
17556  } break;
17557  case 4 : { // Optimization for the classical conversion from planar RGBA to interleaved RGBA
17558  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);
17559  t *ptrd = res.ptr();
17560  for (unsigned int siz = width*height*depth; siz; --siz) {
17561  *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++); *(ptrd++) = (t)*(ptrA++);
17562  }
17563  } break;
17564  default : {
17565  cimg_forXYZV(*this,x,y,z,v) res(v,x,y,z) = (t)*(ptrs++);
17566  }
17567  }
17568  }
17569  if (!cimg::strncasecmp(permut,"vxzy",4)) {
17570  res.assign(dim,width,depth,height);
17571  cimg_forXYZV(*this,x,y,z,v) res(v,x,z,y) = (t)*(ptrs++);
17572  }
17573  if (!cimg::strncasecmp(permut,"vyxz",4)) {
17574  res.assign(dim,height,width,depth);
17575  cimg_forXYZV(*this,x,y,z,v) res(v,y,x,z) = (t)*(ptrs++);
17576  }
17577  if (!cimg::strncasecmp(permut,"vyzx",4)) {
17578  res.assign(dim,height,depth,width);
17579  cimg_forXYZV(*this,x,y,z,v) res(v,y,z,x) = (t)*(ptrs++);
17580  }
17581  if (!cimg::strncasecmp(permut,"vzxy",4)) {
17582  res.assign(dim,depth,width,height);
17583  cimg_forXYZV(*this,x,y,z,v) res(v,z,x,y) = (t)*(ptrs++);
17584  }
17585  if (!cimg::strncasecmp(permut,"vzyx",4)) {
17586  res.assign(dim,depth,height,width);
17587  cimg_forXYZV(*this,x,y,z,v) res(v,z,y,x) = (t)*(ptrs++);
17588  }
17589  if (!res)
17590  throw CImgArgumentException("CImg<%s>::permute_axes() : Invalid permutation '%s'.",
17591  pixel_type(),permut);
17592  return res;
17593  }
17594 
17596 
17600  CImg<T>& permute_axes(const char *order) {
17601  return get_permute_axes(order).transfer_to(*this);
17602  }
17603 
17604  CImg<T> get_permute_axes(const char *order) const {
17605  const T foo = (T)0;
17606  return _get_permute_axes(order,foo);
17607  }
17608 
17610  CImg<T>& unroll(const char axis) {
17611  const unsigned int siz = size();
17612  if (siz) switch (axis) {
17613  case 'x' : width = siz; height=depth=dim=1; break;
17614  case 'y' : height = siz; width=depth=dim=1; break;
17615  case 'z' : depth = siz; width=height=dim=1; break;
17616  case 'v' : dim = siz; width=height=depth=1; break;
17617  default :
17618  throw CImgArgumentException("CImg<%s>::unroll() : Given axis is '%c' which is not 'x','y','z' or 'v'",
17619  pixel_type(),axis);
17620  }
17621  return *this;
17622  }
17623 
17624  CImg<T> get_unroll(const char axis) const {
17625  return (+*this).unroll(axis);
17626  }
17627 
17629 
17637  CImg<T>& rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) {
17638  return get_rotate(angle,border_conditions,interpolation).transfer_to(*this);
17639  }
17640 
17641  CImg<T> get_rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
17642  if (is_empty()) return *this;
17643  CImg<T> dest;
17644  const float nangle = cimg::mod(angle,360.0f);
17645  if (border_conditions!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
17646  const int wm1 = dimx()-1, hm1 = dimy()-1;
17647  const int iangle = (int)nangle/90;
17648  switch (iangle) {
17649  case 1 : {
17650  dest.assign(height,width,depth,dim);
17651  cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,hm1-x,z,v);
17652  } break;
17653  case 2 : {
17654  dest.assign(width,height,depth,dim);
17655  cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-x,hm1-y,z,v);
17656  } break;
17657  case 3 : {
17658  dest.assign(height,width,depth,dim);
17659  cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-y,x,z,v);
17660  } break;
17661  default :
17662  return *this;
17663  }
17664  } else { // generic version
17665  const float
17666  rad = (float)(nangle*cimg::valuePI/180.0),
17667  ca = (float)std::cos(rad),
17668  sa = (float)std::sin(rad),
17669  ux = cimg::abs(width*ca), uy = cimg::abs(width*sa),
17670  vx = cimg::abs(height*sa), vy = cimg::abs(height*ca),
17671  w2 = 0.5f*width, h2 = 0.5f*height,
17672  dw2 = 0.5f*(ux+vx), dh2 = 0.5f*(uy+vy);
17673  dest.assign((int)(ux+vx), (int)(uy+vy),depth,dim);
17674  switch (border_conditions) {
17675  case 0 : {
17676  switch (interpolation) {
17677  case 2 : {
17678  cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
17679  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);
17680  } break;
17681  case 1 : {
17682  cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
17683  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);
17684  } break;
17685  default : {
17686  cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
17687  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);
17688  }
17689  }
17690  } break;
17691  case 1 : {
17692  switch (interpolation) {
17693  case 2 : {
17694  cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
17695  dest(x,y,z,v) = (T)cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
17696  } break;
17697  case 1 : {
17698  cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
17699  dest(x,y,z,v) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
17700  } break;
17701  default : {
17702  cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
17703  dest(x,y,z,v) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v);
17704  }
17705  }
17706  } break;
17707  case 2 : {
17708  switch (interpolation) {
17709  case 2 : {
17710  cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
17711  dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
17712  cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
17713  } break;
17714  case 1 : {
17715  cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
17716  dest(x,y,z,v) = (T)linear_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
17717  cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
17718  } break;
17719  default : {
17720  cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
17721  dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),dimx()),
17722  cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),dimy()),z,v);
17723  }
17724  }
17725  } break;
17726  default :
17727  throw CImgArgumentException("CImg<%s>::rotate() : Invalid border conditions %d (should be 0,1 or 2).",
17728  pixel_type(),border_conditions);
17729  }
17730  }
17731  return dest;
17732  }
17733 
17735 
17745  CImg<T>& rotate(const float angle, const float cx, const float cy, const float zoom,
17746  const unsigned int border_conditions=3, const unsigned int interpolation=1) {
17747  return get_rotate(angle,cx,cy,zoom,border_conditions,interpolation).transfer_to(*this);
17748  }
17749 
17750  CImg<T> get_rotate(const float angle, const float cx, const float cy, const float zoom,
17751  const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
17752  if (interpolation>2)
17753  throw CImgArgumentException("CImg<%s>::rotate() : Invalid interpolation parameter %d (should be {0=none, 1=linear or 2=cubic}).",
17754  pixel_type(),interpolation);
17755  if (is_empty()) return *this;
17756  CImg<T> dest(width,height,depth,dim);
17757  const float nangle = cimg::mod(angle,360.0f);
17758  if (border_conditions!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
17759  const int iangle = (int)nangle/90;
17760  switch (iangle) {
17761  case 1 : {
17762  dest.fill(0);
17763  const unsigned int
17764  xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
17765  ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
17766  xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
17767  yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
17768  cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
17769  dest(x,y,z,v) = (*this)(y-yoff,height-1-x+xoff,z,v);
17770  } break;
17771  case 2 : {
17772  cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v);
17773  } break;
17774  case 3 : {
17775  dest.fill(0);
17776  const unsigned int
17777  xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
17778  ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
17779  xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
17780  yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
17781  cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
17782  dest(x,y,z,v) = (*this)(width-1-y+yoff,x-xoff,z,v);
17783  } break;
17784  default :
17785  return *this;
17786  }
17787  } else {
17788  const float
17789  rad = (float)((nangle*cimg::valuePI)/180.0),
17790  ca = (float)std::cos(rad)/zoom,
17791  sa = (float)std::sin(rad)/zoom;
17792  switch (border_conditions) { // generic version
17793  case 0 : {
17794  switch (interpolation) {
17795  case 2 : {
17796  cimg_forXY(dest,x,y)
17797  cimg_forZV(*this,z,v)
17798  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);
17799  } break;
17800  case 1 : {
17801  cimg_forXY(dest,x,y)
17802  cimg_forZV(*this,z,v)
17803  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);
17804  } break;
17805  default : {
17806  cimg_forXY(dest,x,y)
17807  cimg_forZV(*this,z,v)
17808  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);
17809  }
17810  }
17811  } break;
17812  case 1 : {
17813  switch (interpolation) {
17814  case 2 : {
17815  cimg_forXY(dest,x,y)
17816  cimg_forZV(*this,z,v)
17817  dest(x,y,z,v) = (T)cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
17818  } break;
17819  case 1 : {
17820  cimg_forXY(dest,x,y)
17821  cimg_forZV(*this,z,v)
17822  dest(x,y,z,v) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
17823  } break;
17824  default : {
17825  cimg_forXY(dest,x,y)
17826  cimg_forZV(*this,z,v)
17827  dest(x,y,z,v) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v);
17828  }
17829  }
17830  } break;
17831  case 2 : {
17832  switch (interpolation) {
17833  case 2 : {
17834  cimg_forXY(dest,x,y)
17835  cimg_forZV(*this,z,v)
17836  dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
17837  cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
17838  } break;
17839  case 1 : {
17840  cimg_forXY(dest,x,y)
17841  cimg_forZV(*this,z,v)
17842  dest(x,y,z,v) = (T)linear_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
17843  cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
17844  } break;
17845  default : {
17846  cimg_forXY(dest,x,y)
17847  cimg_forZV(*this,z,v)
17848  dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),dimx()),
17849  cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),dimy()),z,v);
17850  }
17851  }
17852  } break;
17853  default :
17854  throw CImgArgumentException("CImg<%s>::rotate() : Incorrect border conditions %d (should be 0,1 or 2).",
17855  pixel_type(),border_conditions);
17856  }
17857  }
17858  return dest;
17859  }
17860 
17862  template<typename t>
17863  CImg<T>& warp(const CImg<t>& warp, const bool relative=false,
17864  const bool interpolation=true, const unsigned int border_conditions=0) {
17865  return get_warp(warp,relative,interpolation,border_conditions).transfer_to(*this);
17866  }
17867 
17868  template<typename t>
17869  CImg<T> get_warp(const CImg<t>& warp, const bool relative=false,
17870  const bool interpolation=true, const unsigned int border_conditions=0) const {
17871  if (is_empty() || !warp) return *this;
17872  if (relative && !is_sameXYZ(warp))
17873  throw CImgArgumentException("CImg<%s>::warp() : Instance image (%u,%u,%u,%u,%p) and relative warping field (%u,%u,%u,%u,%p) "
17874  "have different XYZ dimensions.",
17876  warp.width,warp.height,warp.depth,warp.dim,warp.data);
17877  CImg<T> res(warp.width,warp.height,warp.depth,dim);
17878  switch (warp.dim) {
17879  case 1 : // 1D warping.
17880  if (relative) { // Relative warp coordinates
17881  if (interpolation) switch (border_conditions) {
17882  case 2 : {
17883  cimg_forXYZV(res,x,y,z,v)
17884  res(x,y,z,v) = (T)_linear_atX(cimg::mod(x-(float)warp(x,y,z,0),(float)width),y,z,v);
17885  } break;
17886  case 1 : {
17887  cimg_forXYZV(res,x,y,z,v)
17888  res(x,y,z,v) = (T)_linear_atX(x-(float)warp(x,y,z,0),y,z,v);
17889  } break;
17890  default : {
17891  cimg_forXYZV(res,x,y,z,v)
17892  res(x,y,z,v) = (T)linear_atX(x-(float)warp(x,y,z,0),y,z,v,0);
17893  }
17894  } else switch (border_conditions) {
17895  case 2 : {
17896  cimg_forXYZV(res,x,y,z,v)
17897  res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),y,z,v);
17898  } break;
17899  case 1 : {
17900  cimg_forXYZV(res,x,y,z,v)
17901  res(x,y,z,v) = _atX(x-(int)warp(x,y,z,0),y,z,v);
17902  } break;
17903  default : {
17904  cimg_forXYZV(res,x,y,z,v)
17905  res(x,y,z,v) = atX(x-(int)warp(x,y,z,0),y,z,v,0);
17906  }
17907  }
17908  } else { // Absolute warp coordinates
17909  if (interpolation) switch (border_conditions) {
17910  case 2 : {
17911  cimg_forXYZV(res,x,y,z,v)
17912  res(x,y,z,v) = (T)_linear_atX(cimg::mod((float)warp(x,y,z,0),(float)width),y,z,v);
17913  } break;
17914  case 1 : {
17915  cimg_forXYZV(res,x,y,z,v)
17916  res(x,y,z,v) = (T)_linear_atX((float)warp(x,y,z,0),y,z,v);
17917  } break;
17918  default : {
17919  cimg_forXYZV(res,x,y,z,v)
17920  res(x,y,z,v) = (T)linear_atX((float)warp(x,y,z,0),y,z,v,0);
17921  }
17922  } else switch (border_conditions) {
17923  case 2 : {
17924  cimg_forXYZV(res,x,y,z,v)
17925  res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),y,z,v);
17926  } break;
17927  case 1 : {
17928  cimg_forXYZV(res,x,y,z,v)
17929  res(x,y,z,v) = _atX((int)warp(x,y,z,0),y,z,v);
17930  } break;
17931  default : {
17932  cimg_forXYZV(res,x,y,z,v)
17933  res(x,y,z,v) = atX((int)warp(x,y,z,0),y,z,v,0);
17934  }
17935  }
17936  }
17937  break;
17938 
17939  case 2 : // 2D warping
17940  if (relative) { // Relative warp coordinates
17941  if (interpolation) switch (border_conditions) {
17942  case 2 : {
17943  cimg_forXYZV(res,x,y,z,v)
17944  res(x,y,z,v) = (T)_linear_atXY(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
17945  cimg::mod(y-(float)warp(x,y,z,1),(float)height),z,v);
17946  } break;
17947  case 1 : {
17948  cimg_forXYZV(res,x,y,z,v)
17949  res(x,y,z,v) = (T)_linear_atXY(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z,v);
17950  } break;
17951  default : {
17952  cimg_forXYZV(res,x,y,z,v)
17953  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);
17954  }
17955  } else switch (border_conditions) {
17956  case 2 : {
17957  cimg_forXYZV(res,x,y,z,v)
17958  res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
17959  cimg::mod(y-(int)warp(x,y,z,1),(int)height),z,v);
17960  } break;
17961  case 1 : {
17962  cimg_forXYZV(res,x,y,z,v)
17963  res(x,y,z,v) = _atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v);
17964  } break;
17965  default : {
17966  cimg_forXYZV(res,x,y,z,v)
17967  res(x,y,z,v) = atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v,0);
17968  }
17969  }
17970  } else { // Absolute warp coordinates
17971  if (interpolation) switch (border_conditions) {
17972  case 2 : {
17973  cimg_forXYZV(res,x,y,z,v)
17974  res(x,y,z,v) = (T)_linear_atXY(cimg::mod((float)warp(x,y,z,0),(float)width),
17975  cimg::mod((float)warp(x,y,z,1),(float)height),z,v);
17976  } break;
17977  case 1 : {
17978  cimg_forXYZV(res,x,y,z,v)
17979  res(x,y,z,v) = (T)_linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v);
17980  } break;
17981  default : {
17982  cimg_forXYZV(res,x,y,z,v)
17983  res(x,y,z,v) = (T)linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v,0);
17984  }
17985  } else switch (border_conditions) {
17986  case 2 : {
17987  cimg_forXYZV(res,x,y,z,v)
17988  res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
17989  cimg::mod((int)warp(x,y,z,1),(int)height),z,v);
17990  } break;
17991  case 1 : {
17992  cimg_forXYZV(res,x,y,z,v)
17993  res(x,y,z,v) = _atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v);
17994  } break;
17995  default : {
17996  cimg_forXYZV(res,x,y,z,v)
17997  res(x,y,z,v) = atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v,0);
17998  }
17999  }
18000  }
18001  break;
18002 
18003  case 3 : // 3D warping
18004  if (relative) { // Relative warp coordinates
18005  if (interpolation) switch (border_conditions) {
18006  case 2 : {
18007  cimg_forXYZV(res,x,y,z,v)
18008  res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
18009  cimg::mod(y-(float)warp(x,y,z,1),(float)height),
18010  cimg::mod(z-(float)warp(x,y,z,2),(float)depth),v);
18011  } break;
18012  case 1 : {
18013  cimg_forXYZV(res,x,y,z,v)
18014  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);
18015  } break;
18016  default : {
18017  cimg_forXYZV(res,x,y,z,v)
18018  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);
18019  }
18020  } else switch (border_conditions) {
18021  case 2 : {
18022  cimg_forXYZV(res,x,y,z,v)
18023  res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
18024  cimg::mod(y-(int)warp(x,y,z,1),(int)height),
18025  cimg::mod(z-(int)warp(x,y,z,2),(int)depth),v);
18026  } break;
18027  case 1 : {
18028  cimg_forXYZV(res,x,y,z,v)
18029  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);
18030  } break;
18031  default : {
18032  cimg_forXYZV(res,x,y,z,v)
18033  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);
18034  }
18035  }
18036  } else { // Absolute warp coordinates
18037  if (interpolation) switch (border_conditions) {
18038  case 2 : {
18039  cimg_forXYZV(res,x,y,z,v)
18040  res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod((float)warp(x,y,z,0),(float)width),
18041  cimg::mod((float)warp(x,y,z,1),(float)height),
18042  cimg::mod((float)warp(x,y,z,2),(float)depth),v);
18043  } break;
18044  case 1 : {
18045  cimg_forXYZV(res,x,y,z,v)
18046  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);
18047  } break;
18048  default : {
18049  cimg_forXYZV(res,x,y,z,v)
18050  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);
18051  }
18052  } else switch (border_conditions) {
18053  case 2 : {
18054  cimg_forXYZV(res,x,y,z,v)
18055  res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
18056  cimg::mod((int)warp(x,y,z,1),(int)height),
18057  cimg::mod((int)warp(x,y,z,2),(int)depth),v);
18058  } break;
18059  case 1 : {
18060  cimg_forXYZV(res,x,y,z,v)
18061  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);
18062  } break;
18063  default : {
18064  cimg_forXYZV(res,x,y,z,v)
18065  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);
18066  }
18067  }
18068  }
18069  break;
18070 
18071  default : // 4D warping
18072  if (relative) { // Relative warp coordinates
18073  if (interpolation) switch (border_conditions) {
18074  case 2 : {
18075  cimg_forXYZV(res,x,y,z,v)
18076  res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
18077  cimg::mod(y-(float)warp(x,y,z,1),(float)height),
18078  cimg::mod(z-(float)warp(x,y,z,2),(float)depth),
18079  cimg::mod(z-(float)warp(x,y,z,3),(float)dim));
18080  } break;
18081  case 1 : {
18082  cimg_forXYZV(res,x,y,z,v)
18083  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));
18084  } break;
18085  default : {
18086  cimg_forXYZV(res,x,y,z,v)
18087  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);
18088  }
18089  } else switch (border_conditions) {
18090  case 2 : {
18091  cimg_forXYZV(res,x,y,z,v)
18092  res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
18093  cimg::mod(y-(int)warp(x,y,z,1),(int)height),
18094  cimg::mod(z-(int)warp(x,y,z,2),(int)depth),
18095  cimg::mod(v-(int)warp(x,y,z,3),(int)dim));
18096  } break;
18097  case 1 : {
18098  cimg_forXYZV(res,x,y,z,v)
18099  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));
18100  } break;
18101  default : {
18102  cimg_forXYZV(res,x,y,z,v)
18103  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);
18104  }
18105  }
18106  } else { // Absolute warp coordinates
18107  if (interpolation) switch (border_conditions) {
18108  case 2 : {
18109  cimg_forXYZV(res,x,y,z,v)
18110  res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod((float)warp(x,y,z,0),(float)width),
18111  cimg::mod((float)warp(x,y,z,1),(float)height),
18112  cimg::mod((float)warp(x,y,z,2),(float)depth),
18113  cimg::mod((float)warp(x,y,z,3),(float)dim));
18114  } break;
18115  case 1 : {
18116  cimg_forXYZV(res,x,y,z,v)
18117  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));
18118  } break;
18119  default : {
18120  cimg_forXYZV(res,x,y,z,v)
18121  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);
18122  }
18123  } else switch (border_conditions) {
18124  case 2 : {
18125  cimg_forXYZV(res,x,y,z,v)
18126  res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
18127  cimg::mod((int)warp(x,y,z,1),(int)height),
18128  cimg::mod((int)warp(x,y,z,2),(int)depth),
18129  cimg::mod((int)warp(x,y,z,3),(int)dim));
18130  } break;
18131  case 1 : {
18132  cimg_forXYZV(res,x,y,z,v)
18133  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));
18134  } break;
18135  default : {
18136  cimg_forXYZV(res,x,y,z,v)
18137  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);
18138  }
18139  }
18140  }
18141  }
18142  return res;
18143  }
18144 
18146  CImg<T>& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
18147  const int dx=-100, const int dy=-100, const int dz=-100) {
18148  return get_projections2d(x0,y0,z0,dx,dy,dz).transfer_to(*this);
18149  }
18150 
18151  CImg<T> get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
18152  const int dx=-100, const int dy=-100, const int dz=-100) const {
18153  if (is_empty()) return *this;
18154  const unsigned int
18155  nx0 = (x0>=width)?width-1:x0,
18156  ny0 = (y0>=height)?height-1:y0,
18157  nz0 = (z0>=depth)?depth-1:z0;
18158  CImg<T>
18159  imgxy(width,height,1,dim),
18160  imgzy(depth,height,1,dim),
18161  imgxz(width,depth,1,dim);
18162  cimg_forXYV(*this,x,y,k) imgxy(x,y,k) = (*this)(x,y,nz0,k);
18163  cimg_forYZV(*this,y,z,k) imgzy(z,y,k) = (*this)(nx0,y,z,k);
18164  cimg_forXZV(*this,x,z,k) imgxz(x,z,k) = (*this)(x,ny0,z,k);
18165  imgxy.resize(dx,dy,1,dim,1);
18166  imgzy.resize(dz,dy,1,dim,1);
18167  imgxz.resize(dx,dz,1,dim,1);
18168  return CImg<T>(imgxy.width + imgzy.width,imgxy.height + imgxz.height,1,dim,0).
18169  draw_image(imgxy).draw_image(imgxy.width,imgzy).draw_image(0,imgxy.height,imgxz);
18170  }
18171 
18173 
18184  CImg<T>& crop(const int x0, const int y0, const int z0, const int v0,
18185  const int x1, const int y1, const int z1, const int v1,
18186  const bool border_condition=false) {
18187  return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).transfer_to(*this);
18188  }
18189 
18190  CImg<T> get_crop(const int x0, const int y0, const int z0, const int v0,
18191  const int x1, const int y1, const int z1, const int v1,
18192  const bool border_condition=false) const {
18193  if (is_empty()) return *this;
18194  const int
18195  nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
18196  ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0,
18197  nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0,
18198  nv0 = v0<v1?v0:v1, nv1 = v0^v1^nv0;
18199  CImg<T> dest(1U+nx1-nx0,1U+ny1-ny0,1U+nz1-nz0,1U+nv1-nv0);
18200  if (nx0<0 || nx1>=dimx() || ny0<0 || ny1>=dimy() || nz0<0 || nz1>=dimz() || nv0<0 || nv1>=dimv()) {
18201  if (border_condition) cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = _atXYZV(nx0+x,ny0+y,nz0+z,nv0+v);
18202  else dest.fill(0).draw_image(-nx0,-ny0,-nz0,-nv0,*this);
18203  } else dest.draw_image(-nx0,-ny0,-nz0,-nv0,*this);
18204  return dest;
18205  }
18206 
18208 
18218  CImg<T>& crop(const int x0, const int y0, const int z0,
18219  const int x1, const int y1, const int z1,
18220  const bool border_condition=false) {
18221  return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
18222  }
18223 
18224  CImg<T> get_crop(const int x0, const int y0, const int z0,
18225  const int x1, const int y1, const int z1,
18226  const bool border_condition=false) const {
18227  return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
18228  }
18229 
18231 
18239  CImg<T>& crop(const int x0, const int y0,
18240  const int x1, const int y1,
18241  const bool border_condition=false) {
18242  return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
18243  }
18244 
18245  CImg<T> get_crop(const int x0, const int y0,
18246  const int x1, const int y1,
18247  const bool border_condition=false) const {
18248  return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
18249  }
18250 
18252 
18258  CImg<T>& crop(const int x0, const int x1, const bool border_condition=false) {
18259  return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
18260  }
18261 
18262  CImg<T> get_crop(const int x0, const int x1, const bool border_condition=false) const {
18263  return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
18264  }
18265 
18267  CImg<T>& autocrop(const T value, const char *const axes="vzyx") {
18268  if (is_empty()) return *this;
18269  for (const char *s = axes; *s; ++s) {
18270  const char axis = cimg::uncase(*s);
18271  const CImg<intT> coords = _autocrop(value,axis);
18272  switch (axis) {
18273  case 'x' : {
18274  const int x0 = coords[0], x1 = coords[1];
18275  if (x0>=0 && x1>=0) crop(x0,x1);
18276  } break;
18277  case 'y' : {
18278  const int y0 = coords[0], y1 = coords[1];
18279  if (y0>=0 && y1>=0) crop(0,y0,width-1,y1);
18280  } break;
18281  case 'z' : {
18282  const int z0 = coords[0], z1 = coords[1];
18283  if (z0>=0 && z1>=0) crop(0,0,z0,width-1,height-1,z1);
18284  } break;
18285  case 'v' : {
18286  const int v0 = coords[0], v1 = coords[1];
18287  if (v0>=0 && v1>=0) crop(0,0,0,v0,width-1,height-1,depth-1,v1);
18288  } break;
18289  default :
18290  throw CImgArgumentException("CImg<%s>::autocrop() : Invalid axis '%c' (should be 'x','y','z' or 'v').",
18291  pixel_type(),*s);
18292  }
18293  }
18294  return *this;
18295  }
18296 
18297  CImg<T> get_autocrop(const T value, const char *const axes="vzyx") const {
18298  return (+*this).autocrop(value,axes);
18299  }
18300 
18302  CImg<T>& autocrop(const T *const color, const char *const axes="zyx") {
18303  if (is_empty()) return *this;
18304  for (const char *s = axes; *s; ++s) {
18305  const char axis = cimg::uncase(*s);
18306  switch (axis) {
18307  case 'x' : {
18308  int x0 = width, x1 = -1;
18309  cimg_forV(*this,k) {
18310  const CImg<intT> coords = get_shared_channel(k)._autocrop(color[k],'x');
18311  const int nx0 = coords[0], nx1 = coords[1];
18312  if (nx0>=0 && nx1>=0) { x0 = cimg::min(x0,nx0); x1 = cimg::max(x1,nx1); }
18313  }
18314  if (x0<=x1) crop(x0,x1);
18315  } break;
18316  case 'y' : {
18317  int y0 = height, y1 = -1;
18318  cimg_forV(*this,k) {
18319  const CImg<intT> coords = get_shared_channel(k)._autocrop(color[k],'y');
18320  const int ny0 = coords[0], ny1 = coords[1];
18321  if (ny0>=0 && ny1>=0) { y0 = cimg::min(y0,ny0); y1 = cimg::max(y1,ny1); }
18322  }
18323  if (y0<=y1) crop(0,y0,width-1,y1);
18324  } break;
18325  case 'z' : {
18326  int z0 = depth, z1 = -1;
18327  cimg_forV(*this,k) {
18328  const CImg<intT> coords = get_shared_channel(k)._autocrop(color[k],'z');
18329  const int nz0 = coords[0], nz1 = coords[1];
18330  if (nz0>=0 && nz1>=0) { z0 = cimg::min(z0,nz0); z1 = cimg::max(z1,nz1); }
18331  }
18332  if (z0<=z1) crop(0,0,z0,width-1,height-1,z1);
18333  } break;
18334  default :
18335  throw CImgArgumentException("CImg<%s>::autocrop() : Invalid axis '%c' (should be 'x','y' or 'z').",
18336  pixel_type(),*s);
18337  }
18338  }
18339  return *this;
18340  }
18341 
18342  CImg<T> get_autocrop(const T *const color, const char *const axes="zyx") const {
18343  return (+*this).autocrop(color,axes);
18344  }
18345 
18347  template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char *const axes="zyx") {
18348  return get_autocrop(color,axes).transfer_to(*this);
18349  }
18350 
18351  template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char *const axes="zyx") const {
18352  return get_autocrop(color.data,axes);
18353  }
18354 
18355  CImg<intT> _autocrop(const T value, const char axis) const {
18356  CImg<intT> res;
18357  int x0 = -1, y0 = -1, z0 = -1, v0 = -1, x1 = -1, y1 = -1, z1 = -1, v1 = -1;
18358  switch (cimg::uncase(axis)) {
18359  case 'x' : {
18360  cimg_forX(*this,x) cimg_forYZV(*this,y,z,v)
18361  if ((*this)(x,y,z,v)!=value) { x0 = x; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
18362  if (x0>=0) {
18363  for (int x = dimx()-1; x>=0; --x) cimg_forYZV(*this,y,z,v)
18364  if ((*this)(x,y,z,v)!=value) { x1 = x; x = 0; y = dimy(); z = dimz(); v = dimv(); }
18365  }
18366  res = CImg<intT>::vector(x0,x1);
18367  } break;
18368  case 'y' : {
18369  cimg_forY(*this,y) cimg_forXZV(*this,x,z,v)
18370  if ((*this)(x,y,z,v)!=value) { y0 = y; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
18371  if (y0>=0) {
18372  for (int y = dimy()-1; y>=0; --y) cimg_forXZV(*this,x,z,v)
18373  if ((*this)(x,y,z,v)!=value) { y1 = y; x = dimx(); y = 0; z = dimz(); v = dimv(); }
18374  }
18375  res = CImg<intT>::vector(y0,y1);
18376  } break;
18377  case 'z' : {
18378  cimg_forZ(*this,z) cimg_forXYV(*this,x,y,v)
18379  if ((*this)(x,y,z,v)!=value) { z0 = z; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
18380  if (z0>=0) {
18381  for (int z = dimz()-1; z>=0; --z) cimg_forXYV(*this,x,y,v)
18382  if ((*this)(x,y,z,v)!=value) { z1 = z; x = dimx(); y = dimy(); z = 0; v = dimv(); }
18383  }
18384  res = CImg<intT>::vector(z0,z1);
18385  } break;
18386  case 'v' : {
18387  cimg_forV(*this,v) cimg_forXYZ(*this,x,y,z)
18388  if ((*this)(x,y,z,v)!=value) { v0 = v; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
18389  if (v0>=0) {
18390  for (int v = dimv()-1; v>=0; --v) cimg_forXYZ(*this,x,y,z)
18391  if ((*this)(x,y,z,v)!=value) { v1 = v; x = dimx(); y = dimy(); z = dimz(); v = 0; }
18392  }
18393  res = CImg<intT>::vector(v0,v1);
18394  } break;
18395  default :
18396  throw CImgArgumentException("CImg<%s>::autocrop() : unknow axis '%c', must be 'x','y','z' or 'v'",
18397  pixel_type(),axis);
18398  }
18399  return res;
18400  }
18401 
18403  CImg<T>& column(const unsigned int x0) {
18404  return columns(x0,x0);
18405  }
18406 
18407  CImg<T> get_column(const unsigned int x0) const {
18408  return get_columns(x0,x0);
18409  }
18410 
18412  CImg<T>& columns(const unsigned int x0, const unsigned int x1) {
18413  return get_columns(x0,x1).transfer_to(*this);
18414  }
18415 
18416  CImg<T> get_columns(const unsigned int x0, const unsigned int x1) const {
18417  return get_crop((int)x0,0,0,0,(int)x1,dimy()-1,dimz()-1,dimv()-1);
18418  }
18419 
18421  CImg<T>& line(const unsigned int y0) {
18422  return lines(y0,y0);
18423  }
18424 
18425  CImg<T> get_line(const unsigned int y0) const {
18426  return get_lines(y0,y0);
18427  }
18428 
18430  CImg<T>& lines(const unsigned int y0, const unsigned int y1) {
18431  return get_lines(y0,y1).transfer_to(*this);
18432  }
18433 
18434  CImg<T> get_lines(const unsigned int y0, const unsigned int y1) const {
18435  return get_crop(0,(int)y0,0,0,dimx()-1,(int)y1,dimz()-1,dimv()-1);
18436  }
18437 
18439  CImg<T>& slice(const unsigned int z0) {
18440  return slices(z0,z0);
18441  }
18442 
18443  CImg<T> get_slice(const unsigned int z0) const {
18444  return get_slices(z0,z0);
18445  }
18446 
18448  CImg<T>& slices(const unsigned int z0, const unsigned int z1) {
18449  return get_slices(z0,z1).transfer_to(*this);
18450  }
18451 
18452  CImg<T> get_slices(const unsigned int z0, const unsigned int z1) const {
18453  return get_crop(0,0,(int)z0,0,dimx()-1,dimy()-1,(int)z1,dimv()-1);
18454  }
18455 
18457  CImg<T>& channel(const unsigned int v0) {
18458  return channels(v0,v0);
18459  }
18460 
18461  CImg<T> get_channel(const unsigned int v0) const {
18462  return get_channels(v0,v0);
18463  }
18464 
18466  CImg<T>& channels(const unsigned int v0, const unsigned int v1) {
18467  return get_channels(v0,v1).transfer_to(*this);
18468  }
18469 
18470  CImg<T> get_channels(const unsigned int v0, const unsigned int v1) const {
18471  return get_crop(0,0,0,(int)v0,dimx()-1,dimy()-1,dimz()-1,(int)v1);
18472  }
18473 
18475  CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
18476  const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) {
18477  const unsigned int beg = (unsigned int)offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
18478  if (beg>end || beg>=size() || end>=size())
18479  throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
18480  "a (%u,%u,%u,%u) image.",
18481  pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
18482  return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
18483  }
18484 
18485  const CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
18486  const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const {
18487  const unsigned int beg = (unsigned int)offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
18488  if (beg>end || beg>=size() || end>=size())
18489  throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
18490  "a (%u,%u,%u,%u) image.",
18491  pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
18492  return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
18493  }
18494 
18496  CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
18497  const unsigned int z0=0, const unsigned int v0=0) {
18498  const unsigned int beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
18499  if (beg>end || beg>=size() || end>=size())
18500  throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
18501  "a (%u,%u,%u,%u) image.",
18502  pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
18503  return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
18504  }
18505 
18506  const CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
18507  const unsigned int z0=0, const unsigned int v0=0) const {
18508  const unsigned int beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
18509  if (beg>end || beg>=size() || end>=size())
18510  throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
18511  "a (%u,%u,%u,%u) image.",
18512  pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
18513  return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
18514  }
18515 
18517  CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) {
18518  return get_shared_lines(y0,y0,z0,v0);
18519  }
18520 
18521  const CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) const {
18522  return get_shared_lines(y0,y0,z0,v0);
18523  }
18524 
18526  CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) {
18527  const unsigned int beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
18528  if (beg>end || beg>=size() || end>=size())
18529  throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
18530  "a (%u,%u,%u,%u) image.",
18531  pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
18532  return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
18533  }
18534 
18535  const CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const {
18536  const unsigned int beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
18537  if (beg>end || beg>=size() || end>=size())
18538  throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
18539  "a (%u,%u,%u,%u) image.",
18540  pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
18541  return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
18542  }
18543 
18545  CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) {
18546  return get_shared_planes(z0,z0,v0);
18547  }
18548 
18549  const CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) const {
18550  return get_shared_planes(z0,z0,v0);
18551  }
18552 
18554  CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) {
18555  const unsigned int beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
18556  if (beg>end || beg>=size() || end>=size())
18557  throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
18558  "a (%u,%u,%u,%u) image.",
18559  pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
18560  return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
18561  }
18562 
18563  const CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) const {
18564  const unsigned int beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
18565  if (beg>end || beg>=size() || end>=size())
18566  throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
18567  "a (%u,%u,%u,%u) image.",
18568  pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
18569  return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
18570  }
18571 
18573  CImg<T> get_shared_channel(const unsigned int v0) {
18574  return get_shared_channels(v0,v0);
18575  }
18576 
18577  const CImg<T> get_shared_channel(const unsigned int v0) const {
18578  return get_shared_channels(v0,v0);
18579  }
18580 
18582  CImgList<T> get_split(const char axis, const int nb=0) const {
18583  CImgList<T> res;
18584  const char naxis = cimg::uncase(axis);
18585  const unsigned int nnb = (unsigned int)(nb==0?1:(nb>0?nb:-nb));
18586  if (nb<=0) switch (naxis) { // Split by bloc size
18587  case 'x': {
18588  for (unsigned int p = 0; p<width; p+=nnb) get_crop(p,0,0,0,cimg::min(p+nnb-1,width-1),height-1,depth-1,dim-1).transfer_to(res);
18589  } break;
18590  case 'y': {
18591  for (unsigned int p = 0; p<height; p+=nnb) get_crop(0,p,0,0,width-1,cimg::min(p+nnb-1,height-1),depth-1,dim-1).transfer_to(res);
18592  } break;
18593  case 'z': {
18594  for (unsigned int p = 0; p<depth; p+=nnb) get_crop(0,0,p,0,width-1,height-1,cimg::min(p+nnb-1,depth-1),dim-1).transfer_to(res);
18595  } break;
18596  default: {
18597  for (unsigned int p = 0; p<dim; p+=nnb) get_crop(0,0,0,p,width-1,height-1,depth-1,cimg::min(p+nnb-1,dim-1)).transfer_to(res);
18598  }} else { // Split by number of blocs
18599  const unsigned int siz = naxis=='x'?width:naxis=='y'?height:naxis=='z'?depth:naxis=='v'?dim:0;
18600  if (nnb>siz) throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along axis '%c' into %u blocs.",
18601  pixel_type(),width,height,depth,dim,data,axis,nnb);
18602  res.assign(nnb);
18603  switch (naxis) {
18604  case 'x' : {
18605  cimglist_for(res,p) get_crop(p*siz/nnb,0,0,0,(p+1)*siz/nnb-1,height-1,depth-1,dim-1).transfer_to(res[p]);
18606  } break;
18607  case 'y' : {
18608  cimglist_for(res,p) get_crop(0,p*siz/nnb,0,0,width-1,(p+1)*siz/nnb-1,depth-1,dim-1).transfer_to(res[p]);
18609  } break;
18610  case 'z' : {
18611  cimglist_for(res,p) get_crop(0,0,p*siz/nnb,0,width-1,height-1,(p+1)*siz/nnb-1,dim-1).transfer_to(res[p]);
18612  } break;
18613  default : {
18614  cimglist_for(res,p) get_crop(0,0,0,p*siz/nnb,width-1,height-1,depth-1,(p+1)*siz/nnb-1).transfer_to(res[p]);
18615  }
18616  }
18617  }
18618  return res;
18619  }
18620 
18621  // Split image into a list of vectors, according to a given splitting value.
18622  CImgList<T> get_split(const T value, const bool keep_values, const bool shared, const char axis='y') const {
18623  CImgList<T> res;
18624  const T *ptr0 = data, *const ptr_end = data + size();
18625  while (ptr0<ptr_end) {
18626  const T *ptr1 = ptr0;
18627  while (ptr1<ptr_end && *ptr1==value) ++ptr1;
18628  const unsigned int siz0 = ptr1 - ptr0;
18629  if (siz0 && keep_values) res.insert(CImg<T>(ptr0,1,siz0,1,1,shared));
18630  ptr0 = ptr1;
18631  while (ptr1<ptr_end && *ptr1!=value) ++ptr1;
18632  const unsigned int siz1 = ptr1 - ptr0;
18633  if (siz1) res.insert(CImg<T>(ptr0,1,siz1,1,1,shared),~0U,shared);
18634  ptr0 = ptr1;
18635  }
18636  cimglist_apply(res,unroll)(axis);
18637  return res;
18638  }
18639 
18641  template<typename t>
18642  CImg<T>& append(const CImg<t>& img, const char axis='x', const char align='p') {
18643  if (is_empty()) return assign(img,false);
18644  if (!img) return *this;
18645  return CImgList<T>(*this,img).get_append(axis,align).transfer_to(*this);
18646  }
18647 
18648  CImg<T>& append(const CImg<T>& img, const char axis='x', const char align='p') {
18649  if (is_empty()) return assign(img,false);
18650  if (!img) return *this;
18651  return CImgList<T>(*this,img,true).get_append(axis,align).transfer_to(*this);
18652  }
18653 
18654  template<typename t>
18655  CImg<_cimg_Tt> get_append(const CImg<T>& img, const char axis='x', const char align='p') const {
18656  if (is_empty()) return +img;
18657  if (!img) return +*this;
18658  return CImgList<_cimg_Tt>(*this,img).get_append(axis,align);
18659  }
18660 
18661  CImg<T> get_append(const CImg<T>& img, const char axis='x', const char align='p') const {
18662  if (is_empty()) return +img;
18663  if (!img) return +*this;
18664  return CImgList<T>(*this,img,true).get_append(axis,align);
18665  }
18666 
18668  //---------------------------------------
18669  //
18671 
18672  //---------------------------------------
18673 
18675 
18684  template<typename t>
18685  CImg<T>& correlate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_correl=false) {
18686  return get_correlate(mask,cond,weighted_correl).transfer_to(*this);
18687  }
18688 
18689  template<typename t>
18690  CImg<_cimg_Ttfloat> get_correlate(const CImg<t>& mask, const unsigned int cond=1,
18691  const bool weighted_correl=false) const {
18692  if (is_empty()) return *this;
18693  if (!mask || mask.dim!=1)
18694  throw CImgArgumentException("CImg<%s>::correlate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
18695  pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
18696  typedef _cimg_Ttfloat Ttfloat;
18697  CImg<Ttfloat> dest(width,height,depth,dim);
18698  if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) {
18699  // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with cond=1)
18700  switch (mask.depth) {
18701  case 3 : {
18702  T I[27] = { 0 };
18703  cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
18704  (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] +
18705  I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
18706  I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] +
18707  I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
18708  I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
18709  I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
18710  I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] +
18711  I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
18712  I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26]);
18713  if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) {
18714  const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] +
18715  I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +
18716  I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] +
18717  I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
18718  I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
18719  I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
18720  I[18]*I[18] + I[19]*I[19] + I[20]*I[20] +
18721  I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
18722  I[24]*I[24] + I[25]*I[25] + I[26]*I[26]);
18723  if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
18724  }
18725  } break;
18726  case 2 : {
18727  T I[8] = { 0 };
18728  cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
18729  (I[0]*mask[0] + I[1]*mask[1] +
18730  I[2]*mask[2] + I[3]*mask[3] +
18731  I[4]*mask[4] + I[5]*mask[5] +
18732  I[6]*mask[6] + I[7]*mask[7]);
18733  if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) {
18734  const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
18735  I[2]*I[2] + I[3]*I[3] +
18736  I[4]*I[4] + I[5]*I[5] +
18737  I[6]*I[6] + I[7]*I[7]);
18738  if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
18739  }
18740  } break;
18741  default :
18742  case 1 :
18743  switch (mask.width) {
18744  case 6 : {
18745  T I[36] = { 0 };
18746  cimg_forZV(*this,z,v) cimg_for6x6(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
18747  (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
18748  I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
18749  I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
18750  I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
18751  I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26] + I[27]*mask[27] + I[28]*mask[28] + I[29]*mask[29] +
18752  I[30]*mask[30] + I[31]*mask[31] + I[32]*mask[32] + I[33]*mask[33] + I[34]*mask[34] + I[35]*mask[35]);
18753  if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
18754  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] +
18755  I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
18756  I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
18757  I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
18758  I[24]*I[24] + I[25]*I[25] + I[26]*I[26] + I[27]*I[27] + I[28]*I[28] + I[29]*I[29] +
18759  I[30]*I[30] + I[31]*I[31] + I[32]*I[32] + I[33]*I[33] + I[34]*I[34] + I[35]*I[35]);
18760  if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
18761  }
18762  } break;
18763  case 5 : {
18764  T I[25] = { 0 };
18765  cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
18766  (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] +
18767  I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] +
18768  I[10]*mask[10] + I[11]*mask[11] + I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
18769  I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] + I[18]*mask[18] + I[19]*mask[19] +
18770  I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] + I[24]*mask[24]);
18771  if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
18772  const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] +
18773  I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] +
18774  I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
18775  I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] +
18776  I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24]);
18777  if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
18778  }
18779  } break;
18780  case 4 : {
18781  T I[16] = { 0 };
18782  cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
18783  (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] +
18784  I[ 4]*mask[ 4] + I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] +
18785  I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
18786  I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15]);
18787  if (weighted_correl) cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) {
18788  const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] +
18789  I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] +
18790  I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
18791  I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15]);
18792  if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
18793  }
18794  } break;
18795  case 3 : {
18796  T I[9] = { 0 };
18797  cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
18798  (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
18799  I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
18800  I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
18801  if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) {
18802  const double weight = (double)(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] +
18803  I[3]*I[3] + I[4]*I[4] + I[5]*I[5] +
18804  I[6]*I[6] + I[7]*I[7] + I[8]*I[8]);
18805  if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
18806  }
18807  } break;
18808  case 2 : {
18809  T I[4] = { 0 };
18810  cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
18811  (I[0]*mask[0] + I[1]*mask[1] +
18812  I[2]*mask[2] + I[3]*mask[3]);
18813  if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) {
18814  const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
18815  I[2]*I[2] + I[3]*I[3]);
18816  if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
18817  }
18818  } break;
18819  case 1 : (dest.assign(*this))*=mask(0); break;
18820  }
18821  }
18822  } else { // Generic version for other masks
18823  const int
18824  mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
18825  mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
18826  mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
18827  cimg_forV(*this,v)
18828  if (!weighted_correl) { // Classical correlation
18829  for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
18830  Ttfloat val = 0;
18831  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
18832  val+=(*this)(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
18833  dest(x,y,z,v) = (Ttfloat)val;
18834  }
18835  if (cond)
18836  cimg_forYZV(*this,y,z,v)
18837  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
18838  Ttfloat val = 0;
18839  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
18840  val+=_atXYZ(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
18841  dest(x,y,z,v) = (Ttfloat)val;
18842  }
18843  else
18844  cimg_forYZV(*this,y,z,v)
18845  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
18846  Ttfloat val = 0;
18847  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
18848  val+=atXYZ(x+xm,y+ym,z+zm,v,0)*mask(mx1+xm,my1+ym,mz1+zm);
18849  dest(x,y,z,v) = (Ttfloat)val;
18850  }
18851  } else { // Weighted correlation
18852  for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
18853  Ttfloat val = 0, weight = 0;
18854  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
18855  const Ttfloat cval = (Ttfloat)(*this)(x+xm,y+ym,z+zm,v);
18856  val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
18857  weight+=cval*cval;
18858  }
18859  dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/std::sqrt((double)weight)):(Ttfloat)0;
18860  }
18861  if (cond)
18862  cimg_forYZV(*this,y,z,v)
18863  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
18864  Ttfloat val = 0, weight = 0;
18865  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
18866  const Ttfloat cval = (Ttfloat)_atXYZ(x+xm,y+ym,z+zm,v);
18867  val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
18868  weight+=cval*cval;
18869  }
18870  dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/std::sqrt((double)weight)):(Ttfloat)0;
18871  }
18872  else
18873  cimg_forYZV(*this,y,z,v)
18874  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
18875  Ttfloat val = 0, weight = 0;
18876  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
18877  const Ttfloat cval = (Ttfloat)atXYZ(x+xm,y+ym,z+zm,v,0);
18878  val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
18879  weight+=cval*cval;
18880  }
18881  dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/std::sqrt((double)weight)):(Ttfloat)0;
18882  }
18883  }
18884  }
18885  return dest;
18886  }
18887 
18889 
18898  template<typename t>
18899  CImg<T>& convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) {
18900  return get_convolve(mask,cond,weighted_convol).transfer_to(*this);
18901  }
18902 
18903  template<typename t>
18904  CImg<_cimg_Ttfloat> get_convolve(const CImg<t>& mask, const unsigned int cond=1,
18905  const bool weighted_convol=false) const {
18906  if (is_empty()) return *this;
18907  if (!mask || mask.dim!=1)
18908  throw CImgArgumentException("CImg<%s>::convolve() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
18909  pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
18910  return get_correlate(CImg<t>(mask.ptr(),mask.size(),1,1,1,true).get_mirror('x').resize(mask,-1),cond,weighted_convol);
18911  }
18912 
18914  template<typename t>
18915  CImg<T>& erode(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) {
18916  return get_erode(mask,cond,weighted_erosion).transfer_to(*this);
18917  }
18918 
18919  template<typename t>
18920  CImg<_cimg_Tt> get_erode(const CImg<t>& mask, const unsigned int cond=1,
18921  const bool weighted_erosion=false) const {
18922  if (is_empty()) return *this;
18923  if (!mask || mask.dim!=1)
18924  throw CImgArgumentException("CImg<%s>::erode() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
18925  pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
18926  typedef _cimg_Tt Tt;
18927  CImg<Tt> dest(width,height,depth,dim);
18928  const int
18929  mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
18930  mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
18931  mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
18932  cimg_forV(*this,v)
18933  if (!weighted_erosion) { // Classical erosion
18934  for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
18935  Tt min_val = cimg::type<Tt>::max();
18936  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
18937  const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
18938  if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
18939  }
18940  dest(x,y,z,v) = min_val;
18941  }
18942  if (cond)
18943  cimg_forYZV(*this,y,z,v)
18944  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
18945  Tt min_val = cimg::type<Tt>::max();
18946  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
18947  const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
18948  if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
18949  }
18950  dest(x,y,z,v) = min_val;
18951  }
18952  else
18953  cimg_forYZV(*this,y,z,v)
18954  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
18955  Tt min_val = cimg::type<Tt>::max();
18956  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
18957  const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
18958  if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
18959  }
18960  dest(x,y,z,v) = min_val;
18961  }
18962  } else { // Weighted erosion
18963  for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
18964  Tt min_val = cimg::type<Tt>::max();
18965  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
18966  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
18967  const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) + mval);
18968  if (mval && cval<min_val) min_val = cval;
18969  }
18970  dest(x,y,z,v) = min_val;
18971  }
18972  if (cond)
18973  cimg_forYZV(*this,y,z,v)
18974  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
18975  Tt min_val = cimg::type<Tt>::max();
18976  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
18977  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
18978  const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) + mval);
18979  if (mval && cval<min_val) min_val = cval;
18980  }
18981  dest(x,y,z,v) = min_val;
18982  }
18983  else
18984  cimg_forYZV(*this,y,z,v)
18985  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
18986  Tt min_val = cimg::type<Tt>::max();
18987  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
18988  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
18989  const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) + mval);
18990  if (mval && cval<min_val) min_val = cval;
18991  }
18992  dest(x,y,z,v) = min_val;
18993  }
18994  }
18995  return dest;
18996  }
18997 
18999  CImg<T>& erode(const unsigned int n, const unsigned int cond=1) {
19000  if (n<2) return *this;
19001  return get_erode(n,cond).transfer_to(*this);
19002  }
19003 
19004  CImg<T> get_erode(const unsigned int n, const unsigned int cond=1) const {
19005  static CImg<T> mask;
19006  if (n<2) return *this;
19007  if (mask.width!=n) mask.assign(n,n,1,1,1);
19008  const CImg<T> res = get_erode(mask,cond,false);
19009  if (n>20) mask.assign();
19010  return res;
19011  }
19012 
19014  template<typename t>
19015  CImg<T>& dilate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) {
19016  return get_dilate(mask,cond,weighted_dilatation).transfer_to(*this);
19017  }
19018 
19019  template<typename t>
19020  CImg<_cimg_Tt> get_dilate(const CImg<t>& mask, const unsigned int cond=1,
19021  const bool weighted_dilatation=false) const {
19022  if (is_empty()) return *this;
19023  if (!mask || mask.dim!=1)
19024  throw CImgArgumentException("CImg<%s>::dilate() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
19025  pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
19026  typedef _cimg_Tt Tt;
19027  CImg<Tt> dest(width,height,depth,dim);
19028  const int
19029  mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
19030  mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
19031  mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
19032  cimg_forV(*this,v)
19033  if (!weighted_dilatation) { // Classical dilatation
19034  for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
19035  Tt max_val = cimg::type<Tt>::min();
19036  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
19037  const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
19038  if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
19039  }
19040  dest(x,y,z,v) = max_val;
19041  }
19042  if (cond)
19043  cimg_forYZV(*this,y,z,v)
19044  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
19045  Tt max_val = cimg::type<Tt>::min();
19046  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
19047  const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
19048  if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
19049  }
19050  dest(x,y,z,v) = max_val;
19051  }
19052  else
19053  cimg_forYZV(*this,y,z,v)
19054  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
19055  Tt max_val = cimg::type<Tt>::min();
19056  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
19057  const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
19058  if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
19059  }
19060  dest(x,y,z,v) = max_val;
19061  }
19062  } else { // Weighted dilatation
19063  for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
19064  Tt max_val = cimg::type<Tt>::min();
19065  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
19066  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
19067  const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) - mval);
19068  if (mval && cval>max_val) max_val = cval;
19069  }
19070  dest(x,y,z,v) = max_val;
19071  }
19072  if (cond)
19073  cimg_forYZV(*this,y,z,v)
19074  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
19075  Tt max_val = cimg::type<Tt>::min();
19076  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
19077  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
19078  const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) - mval);
19079  if (mval && cval>max_val) max_val = cval;
19080  }
19081  dest(x,y,z,v) = max_val;
19082  }
19083  else
19084  cimg_forYZV(*this,y,z,v)
19085  for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
19086  Tt max_val = cimg::type<Tt>::min();
19087  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
19088  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
19089  const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) - mval);
19090  if (mval && cval>max_val) max_val = cval;
19091  }
19092  dest(x,y,z,v) = max_val;
19093  }
19094  }
19095  return dest;
19096  }
19097 
19099  CImg<T>& dilate(const unsigned int n, const unsigned int cond=1) {
19100  if (n<2) return *this;
19101  return get_dilate(n,cond).transfer_to(*this);
19102  }
19103 
19104  CImg<T> get_dilate(const unsigned int n, const unsigned int cond=1) const {
19105  static CImg<T> mask;
19106  if (n<2) return *this;
19107  if (mask.width!=n) mask.assign(n,n,1,1,1);
19108  const CImg<T> res = get_dilate(mask,cond,false);
19109  if (n>20) mask.assign();
19110  return res;
19111  }
19112 
19114 
19118  CImg<T>& deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) {
19119 #define _cimg_deriche2_apply \
19120  Tfloat *ptrY = Y.data, yb = 0, yp = 0; \
19121  T xp = (T)0; \
19122  if (cond) { xp = *ptrX; yb = yp = (Tfloat)(coefp*xp); } \
19123  for (int m = 0; m<N; ++m) { \
19124  const T xc = *ptrX; ptrX+=off; \
19125  const Tfloat yc = *(ptrY++) = (Tfloat)(a0*xc + a1*xp - b1*yp - b2*yb); \
19126  xp = xc; yb = yp; yp = yc; \
19127  } \
19128  T xn = (T)0, xa = (T)0; \
19129  Tfloat yn = 0, ya = 0; \
19130  if (cond) { xn = xa = *(ptrX-off); yn = ya = (Tfloat)coefn*xn; } \
19131  for (int n = N-1; n>=0; --n) { \
19132  const T xc = *(ptrX-=off); \
19133  const Tfloat yc = (Tfloat)(a2*xn + a3*xa - b1*yn - b2*ya); \
19134  xa = xn; xn = xc; ya = yn; yn = yc; \
19135  *ptrX = (T)(*(--ptrY)+yc); \
19136  }
19137  const char naxis = cimg::uncase(axis);
19138  const float nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?width:naxis=='y'?height:naxis=='z'?depth:dim)/100;
19139  if (is_empty() || (nsigma<0.1 && !order)) return *this;
19140  const float
19141  nnsigma = nsigma<0.1f?0.1f:nsigma,
19142  alpha = 1.695f/nnsigma,
19143  ema = (float)std::exp(-alpha),
19144  ema2 = (float)std::exp(-2*alpha),
19145  b1 = -2*ema,
19146  b2 = ema2;
19147  float a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0;
19148  switch (order) {
19149  case 0 : {
19150  const float k = (1-ema)*(1-ema)/(1+2*alpha*ema-ema2);
19151  a0 = k;
19152  a1 = k*(alpha-1)*ema;
19153  a2 = k*(alpha+1)*ema;
19154  a3 = -k*ema2;
19155  } break;
19156  case 1 : {
19157  const float k = (1-ema)*(1-ema)/ema;
19158  a0 = k*ema;
19159  a1 = a3 = 0;
19160  a2 = -a0;
19161  } break;
19162  case 2 : {
19163  const float
19164  ea = (float)std::exp(-alpha),
19165  k = -(ema2-1)/(2*alpha*ema),
19166  kn = (-2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea));
19167  a0 = kn;
19168  a1 = -kn*(1+k*alpha)*ema;
19169  a2 = kn*(1-k*alpha)*ema;
19170  a3 = -kn*ema2;
19171  } break;
19172  default :
19173  throw CImgArgumentException("CImg<%s>::deriche() : Given filter order (order = %u) must be 0,1 or 2",
19174  pixel_type(),order);
19175  }
19176  coefp = (a0+a1)/(1+b1+b2);
19177  coefn = (a2+a3)/(1+b1+b2);
19178  switch (naxis) {
19179  case 'x' : {
19180  const int N = width, off = 1;
19181  CImg<Tfloat> Y(N);
19182  cimg_forYZV(*this,y,z,v) { T *ptrX = ptr(0,y,z,v); _cimg_deriche2_apply; }
19183  } break;
19184  case 'y' : {
19185  const int N = height, off = width;
19186  CImg<Tfloat> Y(N);
19187  cimg_forXZV(*this,x,z,v) { T *ptrX = ptr(x,0,z,v); _cimg_deriche2_apply; }
19188  } break;
19189  case 'z' : {
19190  const int N = depth, off = width*height;
19191  CImg<Tfloat> Y(N);
19192  cimg_forXYV(*this,x,y,v) { T *ptrX = ptr(x,y,0,v); _cimg_deriche2_apply; }
19193  } break;
19194  case 'v' : {
19195  const int N = dim, off = width*height*depth;
19196  CImg<Tfloat> Y(N);
19197  cimg_forXYZ(*this,x,y,z) { T *ptrX = ptr(x,y,z,0); _cimg_deriche2_apply; }
19198  } break;
19199  }
19200  return *this;
19201  }
19202 
19203  CImg<Tfloat> get_deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) const {
19204  return CImg<Tfloat>(*this,false).deriche(sigma,order,axis,cond);
19205  }
19206 
19208 
19211  CImg<T>& blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) {
19212  if (!is_empty()) {
19213  if (width>1) deriche(sigmax,0,'x',cond);
19214  if (height>1) deriche(sigmay,0,'y',cond);
19215  if (depth>1) deriche(sigmaz,0,'z',cond);
19216  }
19217  return *this;
19218  }
19219 
19220  CImg<Tfloat> get_blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) const {
19221  return CImg<Tfloat>(*this,false).blur(sigmax,sigmay,sigmaz,cond);
19222  }
19223 
19225  CImg<T>& blur(const float sigma, const bool cond=true) {
19226  const float nsigma = sigma>=0?sigma:-sigma*cimg::max(width,height,depth)/100;
19227  return blur(nsigma,nsigma,nsigma,cond);
19228  }
19229 
19230  CImg<Tfloat> get_blur(const float sigma, const bool cond=true) const {
19231  return CImg<Tfloat>(*this,false).blur(sigma,cond);
19232  }
19233 
19235 
19245  template<typename t>
19247  const float amplitude=60, const float dl=0.8f, const float da=30,
19248  const float gauss_prec=2, const unsigned int interpolation_type=0,
19249  const unsigned int fast_approx=1) {
19250 
19251  // Check arguments and init variables
19252  if (is_empty() || amplitude<=0 || dl<0) return *this;
19253  if (!is_sameXYZ(G) || (G.dim!=3 && G.dim!=6))
19254  throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Invalid diffusion tensor field (%u,%u,%u,%u,%p) "
19255  "for instance image (%u,%u,%u,%u,%p).",
19256  pixel_type(),G.width,G.height,G.depth,G.dim,G.data,width,height,depth,dim,data);
19257  const bool threed = G.dim==6;
19258 
19259  if (da<=0) { // Iterated oriented Laplacians
19260  CImg<Tfloat> veloc(width,height,depth,dim);
19261  for (unsigned int iter = 0; iter<(unsigned int)amplitude; ++iter) {
19262  Tfloat *ptrd = veloc.fill(0).ptr(), betamax = 0;
19263  if (threed) { // 3D version
19264  CImg_3x3x3(I,T);
19265  cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
19266  const Tfloat
19267  ixx = (Tfloat)(Incc + Ipcc - 2*Iccc),
19268  iyy = (Tfloat)(Icnc + Icpc - 2*Iccc),
19269  izz = (Tfloat)(Iccn + Iccp - 2*Iccc),
19270  ixy = (Tfloat)(0.25f*(Innc + Ippc - Inpc - Ipnc)),
19271  ixz = (Tfloat)(0.25f*(Incn + Ipcp - Incp - Ipcn)),
19272  iyz = (Tfloat)(0.25f*(Icnn + Icpp - Icnp - Icpn)),
19273  beta = (Tfloat)(G(x,y,z,0)*ixx + 2*G(x,y,z,1)*ixy + 2*G(x,y,z,2)*ixz + G(x,y,z,3)*iyy + 2*G(x,y,z,4)*iyz + G(x,y,z,5)*izz);
19274  *(ptrd++) = beta;
19275  betamax = beta>betamax?beta:(-beta>betamax?-beta:betamax);
19276  }
19277  } else { // 2D version
19278  CImg_3x3(I,T);
19279  Tfloat *ptrd = veloc.ptr();
19280  betamax = 0;
19281  if (G.dim==3) cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) { // Tensor field
19282  const Tfloat
19283  ixx = (Tfloat)(Inc + Ipc - 2*Icc),
19284  iyy = (Tfloat)(Icn + Icp - 2*Icc),
19285  ixy = (Tfloat)(0.25f*(Inn + Ipp - Inp - Ipn)),
19286  beta = (Tfloat)(G(x,y,0,0)*ixx + G(x,y,0,1)*ixy + G(x,y,0,2)*iyy);
19287  *(ptrd++) = beta;
19288  betamax = beta>betamax?beta:(-beta>betamax?-beta:betamax);
19289  }
19290  }
19291  if (betamax>0) (*this)+=(veloc*=dl/betamax);
19292  }
19293  } else { // LIC-based smoothing.
19294 #define _cimg_valign2d(i,j) { Tfloat &u = W(i,j,0,0), &v = W(i,j,0,1); if (u*curru + v*currv<0) { u=-u; v=-v; }}
19295 #define _cimg_valign3d(i,j,k) { Tfloat &u = W(i,j,k,0), &v = W(i,j,k,1), &w = W(i,j,k,2); if (u*curru + v*currv + w*currw<0) { u=-u; v=-v; w=-w; }}
19296 
19297  const float sqrt2amplitude = (float)std::sqrt(2*amplitude);
19298  const int dx1 = dimx()-1, dy1 = dimy()-1, dz1 = dimz()-1;
19299  CImg<Tfloat> dest(width,height,depth,dim,0), W(width,height,depth,threed?4:3), tmp(dim);
19300  int N = 0;
19301  if (threed) { // 3D version
19302  for (float phi = (180%(int)da)/2.0f; phi<=180; phi+=da) {
19303  const float phir = (float)(phi*cimg::valuePI/180), datmp = (float)(da/std::cos(phir)), da2 = datmp<1?360.0f:datmp;
19304  for (float theta = 0; theta<360; (theta+=da2),++N) {
19305  const float
19306  thetar = (float)(theta*cimg::valuePI/180),
19307  vx = (float)(std::cos(thetar)*std::cos(phir)),
19308  vy = (float)(std::sin(thetar)*std::cos(phir)),
19309  vz = (float)std::sin(phir);
19310  const t
19311  *pa = G.ptr(0,0,0,0), *pb = G.ptr(0,0,0,1), *pc = G.ptr(0,0,0,2),
19312  *pd = G.ptr(0,0,0,3), *pe = G.ptr(0,0,0,4), *pf = G.ptr(0,0,0,5);
19313  Tfloat *pd0 = W.ptr(0,0,0,0), *pd1 = W.ptr(0,0,0,1), *pd2 = W.ptr(0,0,0,2), *pd3 = W.ptr(0,0,0,3);
19314  cimg_forXYZ(G,xg,yg,zg) {
19315  const t a = *(pa++), b = *(pb++), c = *(pc++), d = *(pd++), e = *(pe++), f = *(pf++);
19316  const float u = (float)(a*vx + b*vy + c*vz), v = (float)(b*vx + d*vy + e*vz), w = (float)(c*vx + e*vy + f*vz),
19317  n = (float)std::sqrt(1e-5+u*u+v*v+w*w), dln = dl/n;
19318  *(pd0++) = (Tfloat)(u*dln);
19319  *(pd1++) = (Tfloat)(v*dln);
19320  *(pd2++) = (Tfloat)(w*dln);
19321  *(pd3++) = (Tfloat)n;
19322  }
19323 
19324  cimg_forXYZ(*this,x,y,z) {
19325  tmp.fill(0);
19326  const float cu = (float)W(x,y,z,0), cv = (float)W(x,y,z,1), cw = (float)W(x,y,z,2), n = (float)W(x,y,z,3),
19327  fsigma = (float)(n*sqrt2amplitude), length = gauss_prec*fsigma, fsigma2 = 2*fsigma*fsigma;
19328  float S = 0, pu = cu, pv = cv, pw = cw, X = (float)x, Y = (float)y, Z = (float)z;
19329  switch (interpolation_type) {
19330  case 0 : { // Nearest neighbor
19331  for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
19332  const int cx = (int)(X+0.5f), cy = (int)(Y+0.5f), cz = (int)(Z+0.5f);
19333  float u = (float)W(cx,cy,cz,0), v = (float)W(cx,cy,cz,1), w = (float)W(cx,cy,cz,2);
19334  if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
19335  if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,cz,k); ++S; }
19336  else {
19337  const float coef = (float)std::exp(-l*l/fsigma2);
19338  cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,cz,k));
19339  S+=coef;
19340  }
19341  X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
19342  }
19343  } break;
19344  case 1 : { // Linear interpolation
19345  for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
19346  const int
19347  cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
19348  cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
19349  cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
19350  const float curru = (float)W(cx,cy,cz,0), currv = (float)W(cx,cy,cz,1), currw = (float)W(cx,cy,cz,2);
19351  _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
19352  _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
19353  _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
19354  _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
19355  _cimg_valign3d(px,cy,cz); _cimg_valign3d(nx,cy,cz);
19356  _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
19357  _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
19358  _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
19359  _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
19360  float u = (float)(W._linear_atXYZ(X,Y,Z,0)), v = (float)(W._linear_atXYZ(X,Y,Z,1)), w = (float)(W._linear_atXYZ(X,Y,Z,2));
19361  if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
19362  if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
19363  else {
19364  const float coef = (float)std::exp(-l*l/fsigma2);
19365  cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
19366  S+=coef;
19367  }
19368  X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
19369  }
19370  } break;
19371  default : { // 2nd order Runge Kutta
19372  for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
19373  const int
19374  cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
19375  cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
19376  cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
19377  const float curru = (float)W(cx,cy,cz,0), currv = (float)W(cx,cy,cz,1), currw = (float)W(cx,cy,cz,2);
19378  _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
19379  _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
19380  _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
19381  _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
19382  _cimg_valign3d(px,cy,cz); _cimg_valign3d(nx,cy,cz);
19383  _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
19384  _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
19385  _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
19386  _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
19387  const float
19388  u0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,0)),
19389  v0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,1)),
19390  w0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,2));
19391  float
19392  u = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,0)),
19393  v = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,1)),
19394  w = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,2));
19395  if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
19396  if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
19397  else {
19398  const float coef = (float)std::exp(-l*l/fsigma2);
19399  cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
19400  S+=coef;
19401  }
19402  X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
19403  }
19404  } break;
19405  }
19406  if (S>0) cimg_forV(dest,k) dest(x,y,z,k)+=tmp[k]/S;
19407  else cimg_forV(dest,k) dest(x,y,z,k)+=(Tfloat)((*this)(x,y,z,k));
19408  }
19409  }
19410  }
19411  } else { // 2D LIC algorithm
19412  for (float theta = (360%(int)da)/2.0f; theta<360; (theta+=da),++N) {
19413  const float thetar = (float)(theta*cimg::valuePI/180), vx = (float)(std::cos(thetar)), vy = (float)(std::sin(thetar));
19414  const t *pa = G.ptr(0,0,0,0), *pb = G.ptr(0,0,0,1), *pc = G.ptr(0,0,0,2);
19415  Tfloat *pd0 = W.ptr(0,0,0,0), *pd1 = W.ptr(0,0,0,1), *pd2 = W.ptr(0,0,0,2);
19416  cimg_forXY(G,xg,yg) {
19417  const t a = *(pa++), b = *(pb++), c = *(pc++);
19418  const float u = (float)(a*vx + b*vy), v = (float)(b*vx + c*vy), n = (float)std::sqrt(1e-5+u*u+v*v), dln = dl/n;
19419  *(pd0++) = (Tfloat)(u*dln);
19420  *(pd1++) = (Tfloat)(v*dln);
19421  *(pd2++) = (Tfloat)n;
19422  }
19423  cimg_forXY(*this,x,y) {
19424  tmp.fill(0);
19425  const float
19426  cu = (float)W(x,y,0,0), cv = (float)W(x,y,0,1), n = (float)W(x,y,0,2),
19427  fsigma = (float)(n*sqrt2amplitude), length = gauss_prec*fsigma, fsigma2 = 2*fsigma*fsigma;
19428  float S = 0, pu = cu, pv = cv, X = (float)x, Y = (float)y;
19429 
19430  switch (interpolation_type) {
19431  case 0 : { // Nearest-neighbor
19432  for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
19433  const int cx = (int)(X+0.5f), cy = (int)(Y+0.5f);
19434  float u = (float)W(cx,cy,0,0), v = (float)W(cx,cy,0,1);
19435  if ((pu*u + pv*v)<0) { u=-u; v=-v; }
19436  if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,0,k); ++S; }
19437  else {
19438  const float coef = (float)std::exp(-l*l/fsigma2);
19439  cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,0,k));
19440  S+=coef;
19441  }
19442  X+=(pu=u); Y+=(pv=v);
19443  }
19444  } break;
19445  case 1 : { // Linear interpolation
19446  for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
19447  const int
19448  cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
19449  cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
19450  const float curru = (float)W(cx,cy,0,0), currv = (float)W(cx,cy,0,1);
19451  _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
19452  _cimg_valign2d(px,cy); _cimg_valign2d(nx,cy);
19453  _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
19454  float u = (float)(W._linear_atXY(X,Y,0,0)), v = (float)(W._linear_atXY(X,Y,0,1));
19455  if ((pu*u + pv*v)<0) { u=-u; v=-v; }
19456  if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
19457  else {
19458  const float coef = (float)std::exp(-l*l/fsigma2);
19459  cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
19460  S+=coef;
19461  }
19462  X+=(pu=u); Y+=(pv=v);
19463  }
19464  } break;
19465  default : { // 2nd-order Runge-kutta interpolation
19466  for (float l = 0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
19467  const int
19468  cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
19469  cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
19470  const float curru = (float)W(cx,cy,0,0), currv = (float)W(cx,cy,0,1);
19471  _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
19472  _cimg_valign2d(px,cy); _cimg_valign2d(nx,cy);
19473  _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
19474  const float u0 = (float)(0.5f*W._linear_atXY(X,Y,0,0)), v0 = (float)(0.5f*W._linear_atXY(X,Y,0,1));
19475  float u = (float)(W._linear_atXY(X+u0,Y+v0,0,0)), v = (float)(W._linear_atXY(X+u0,Y+v0,0,1));
19476  if ((pu*u + pv*v)<0) { u=-u; v=-v; }
19477  if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
19478  else {
19479  const float coef = (float)std::exp(-l*l/fsigma2);
19480  cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
19481  S+=coef;
19482  }
19483  X+=(pu=u); Y+=(pv=v);
19484  }
19485  }
19486  }
19487  if (S>0) cimg_forV(dest,k) dest(x,y,0,k)+=tmp[k]/S;
19488  else cimg_forV(dest,k) dest(x,y,0,k)+=(Tfloat)((*this)(x,y,0,k));
19489  }
19490  }
19491  }
19492  const Tfloat *ptrs = dest.data + dest.size();
19493  const T m = cimg::type<T>::min(), M = cimg::type<T>::max();
19494  cimg_for(*this,ptrd,T) { const Tfloat val = *(--ptrs)/N; *ptrd = val<m?m:(val>M?M:(T)val); }
19495  }
19496  return *this;
19497  }
19498 
19499  template<typename t>
19501  const float amplitude=60, const float dl=0.8f, const float da=30,
19502  const float gauss_prec=2, const unsigned int interpolation_type=0,
19503  const unsigned int fast_approx=1) const {
19504  return (+*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
19505  }
19506 
19508  CImg<T>& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
19509  const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,
19510  const float gauss_prec=2, const unsigned int interpolation_type=0,
19511  const unsigned int fast_approx=1) {
19512  return blur_anisotropic(get_edge_tensors(sharpness,anisotropy,alpha,sigma,interpolation_type!=3),
19513  amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
19514  }
19515 
19516  CImg<T> get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
19517  const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
19518  const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0,
19519  const unsigned int fast_approx=1) const {
19520  return (+*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx);
19521  }
19522 
19524 
19537  CImg<T>& blur_bilateral(const float sigma_x, const float sigma_y, const float sigma_z, const float sigma_r,
19538  const int bgrid_x, const int bgrid_y, const int bgrid_z, const int bgrid_r,
19539  const bool interpolation_type=true) {
19540  if (is_empty()) return *this;
19541  T m, M = maxmin(m);
19542  const float range = (float)(1.0f+M-m);
19543  const unsigned int
19544  bx0 = bgrid_x>=0?bgrid_x:width*(-bgrid_x)/100,
19545  by0 = bgrid_y>=0?bgrid_y:height*(-bgrid_y)/100,
19546  bz0 = bgrid_z>=0?bgrid_z:depth*(-bgrid_z)/100,
19547  br0 = bgrid_r>=0?bgrid_r:(int)(-range*bgrid_r/100),
19548  bx = bx0>0?bx0:1,
19549  by = by0>0?by0:1,
19550  bz = bz0>0?bz0:1,
19551  br = br0>0?br0:1;
19552  const float
19553  _sigma_x = sigma_x>=0?sigma_x:-sigma_x*width/100,
19554  _sigma_y = sigma_y>=0?sigma_y:-sigma_y*height/100,
19555  _sigma_z = sigma_z>=0?sigma_z:-sigma_z*depth/100,
19556  nsigma_x = _sigma_x*bx/width,
19557  nsigma_y = _sigma_y*by/height,
19558  nsigma_z = _sigma_z*bz/depth,
19559  nsigma_r = sigma_r*br/range;
19560  if (nsigma_x>0 || nsigma_y>0 || nsigma_z>0 || nsigma_r>0) {
19561  const bool threed = depth>1;
19562  if (threed) { // 3d version of the algorithm
19563  CImg<floatT> bgrid(bx,by,bz,br), bgridw(bx,by,bz,br);
19564  cimg_forV(*this,k) {
19565  bgrid.fill(0); bgridw.fill(0);
19566  cimg_forXYZ(*this,x,y,z) {
19567  const T val = (*this)(x,y,z,k);
19568  const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
19569  bgrid(X,Y,Z,R) = (float)val;
19570  bgridw(X,Y,Z,R) = 1;
19571  }
19572  bgrid.blur(nsigma_x,nsigma_y,nsigma_z,true).deriche(nsigma_r,0,'v',false);
19573  bgridw.blur(nsigma_x,nsigma_y,nsigma_z,true).deriche(nsigma_r,0,'v',false);
19574  if (interpolation_type) cimg_forXYZ(*this,x,y,z) {
19575  const T val = (*this)(x,y,z,k);
19576  const float X = (float)x*bx/width, Y = (float)y*by/height, Z = (float)z*bz/depth, R = (float)((val-m)*br/range),
19577  bval0 = bgrid._linear_atXYZV(X,Y,Z,R), bval1 = bgridw._linear_atXYZV(X,Y,Z,R);
19578  (*this)(x,y,z,k) = (T)(bval0/bval1);
19579  } else cimg_forXYZ(*this,x,y,z) {
19580  const T val = (*this)(x,y,z,k);
19581  const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
19582  const float bval0 = bgrid(X,Y,Z,R), bval1 = bgridw(X,Y,Z,R);
19583  (*this)(x,y,z,k) = (T)(bval0/bval1);
19584  }
19585  }
19586  } else { // 2d version of the algorithm
19587  CImg<floatT> bgrid(bx,by,br,2);
19588  cimg_forV(*this,k) {
19589  bgrid.fill(0);
19590  cimg_forXY(*this,x,y) {
19591  const T val = (*this)(x,y,k);
19592  const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
19593  bgrid(X,Y,R,0) = (float)val;
19594  bgrid(X,Y,R,1) = 1;
19595  }
19596  bgrid.blur(nsigma_x,nsigma_y,0,true).blur(0,0,nsigma_r,false);
19597  if (interpolation_type) cimg_forXY(*this,x,y) {
19598  const T val = (*this)(x,y,k);
19599  const float X = (float)x*bx/width, Y = (float)y*by/height, R = (float)((val-m)*br/range),
19600  bval0 = bgrid._linear_atXYZ(X,Y,R,0), bval1 = bgrid._linear_atXYZ(X,Y,R,1);
19601  (*this)(x,y,k) = (T)(bval0/bval1);
19602  } else cimg_forXY(*this,x,y) {
19603  const T val = (*this)(x,y,k);
19604  const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
19605  const float bval0 = bgrid(X,Y,R,0), bval1 = bgrid(X,Y,R,1);
19606  (*this)(x,y,k) = (T)(bval0/bval1);
19607  }
19608  }
19609  }
19610  }
19611  return *this;
19612  }
19613 
19614  CImg<T> get_blur_bilateral(const float sigma_x, const float sigma_y, const float sigma_z, const float sigma_r,
19615  const int bgrid_x, const int bgrid_y, const int bgrid_z, const int bgrid_r,
19616  const bool interpolation_type=true) const {
19617  return (+*this).blur_bilateral(sigma_x,sigma_y,sigma_z,sigma_r,bgrid_x,bgrid_y,bgrid_z,bgrid_r,interpolation_type);
19618  }
19619 
19621  CImg<T>& blur_bilateral(const float sigma_s, const float sigma_r, const int bgrid_s=-33, const int bgrid_r=32,
19622  const bool interpolation_type=true) {
19623  const float nsigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(width,height,depth)/100;
19624  return blur_bilateral(nsigma_s,nsigma_s,nsigma_s,sigma_r,bgrid_s,bgrid_s,bgrid_s,bgrid_r,interpolation_type);
19625  }
19626 
19627  CImg<T> get_blur_bilateral(const float sigma_s, const float sigma_r, const int bgrid_s=-33, const int bgrid_r=32,
19628  const bool interpolation_type=true) const {
19629  return (+*this).blur_bilateral(sigma_s,sigma_s,sigma_s,sigma_r,bgrid_s,bgrid_s,bgrid_s,bgrid_r,interpolation_type);
19630  }
19631 
19633  CImg<T>& blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3,
19634  const unsigned int lookup_size=4, const float smoothness=0, const bool fast_approx=true) {
19635  return get_blur_patch(sigma_s,sigma_p,patch_size,lookup_size,smoothness,fast_approx).transfer_to(*this);
19636  }
19637 
19638  CImg<T> get_blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3,
19639  const unsigned int lookup_size=4, const float smoothness=0, const bool fast_approx=true) const {
19640 
19641 #define _cimg_blur_patch3d_fast(N) \
19642  cimg_for##N##XYZ(res,x,y,z) { \
19643  cimg_forV(res,k) cimg_get##N##x##N##x##N(img,x,y,z,k,P.ptr(N3*k)); \
19644  const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \
19645  float sum_weights = 0; \
19646  cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (cimg::abs(img(x,y,z,0)-img(p,q,r,0))<sigma_p3) { \
19647  cimg_forV(res,k) cimg_get##N##x##N##x##N(img,p,q,r,k,Q.ptr(N3*k)); \
19648  float distance2 = 0; \
19649  const T *pQ = Q.end(); cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(--pQ); distance2+=dI*dI; } \
19650  distance2/=Pnorm; \
19651  const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \
19652  alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = alldist>3?0.0f:1.0f; \
19653  sum_weights+=weight; \
19654  cimg_forV(res,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k); \
19655  } \
19656  if (sum_weights>0) cimg_forV(res,k) res(x,y,z,k)/=sum_weights; \
19657  else cimg_forV(res,k) res(x,y,z,k) = (Tfloat)((*this)(x,y,z,k)); \
19658  }
19659 
19660 #define _cimg_blur_patch3d(N) \
19661  cimg_for##N##XYZ(res,x,y,z) { \
19662  cimg_forV(res,k) cimg_get##N##x##N##x##N(img,x,y,z,k,P.ptr(N3*k)); \
19663  const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \
19664  float sum_weights = 0; \
19665  cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) { \
19666  cimg_forV(res,k) cimg_get##N##x##N##x##N(img,p,q,r,k,Q.ptr(N3*k)); \
19667  float distance2 = 0; \
19668  const T *pQ = Q.end(); cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(--pQ); distance2+=dI*dI; } \
19669  distance2/=Pnorm; \
19670  const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \
19671  alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = (float)std::exp(-alldist); \
19672  sum_weights+=weight; \
19673  cimg_forV(res,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k); \
19674  } \
19675  if (sum_weights>0) cimg_forV(res,k) res(x,y,z,k)/=sum_weights; \
19676  else cimg_forV(res,k) res(x,y,z,k) = (Tfloat)((*this)(x,y,z,k)); \
19677  }
19678 
19679 #define _cimg_blur_patch2d_fast(N) \
19680  cimg_for##N##XY(res,x,y) { \
19681  cimg_forV(res,k) cimg_get##N##x##N(img,x,y,0,k,P.ptr(N2*k)); \
19682  const int x0 = x-rsize1, y0 = y-rsize1, x1 = x+rsize2, y1 = y+rsize2; \
19683  float sum_weights = 0; \
19684  cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) if (cimg::abs(img(x,y,0,0)-img(p,q,0,0))<sigma_p3) { \
19685  cimg_forV(res,k) cimg_get##N##x##N(img,p,q,0,k,Q.ptr(N2*k)); \
19686  float distance2 = 0; \
19687  const T *pQ = Q.end(); cimg_for(P,pP,T) { const float dI = (float)*pP-(float)*(--pQ); distance2+=dI*dI; } \
19688  distance2/=Pnorm; \
19689  const float dx = (float)p-x, dy = (float)q-y, \
19690  alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = alldist>3?0.0f:1.0f; \
19691  sum_weights+=weight; \
19692  cimg_forV(res,k) res(x,y,k)+=weight*(*this)(p,q,k); \
19693  } \
19694  if (sum_weights>0) cimg_forV(res,k) res(x,y,k)/=sum_weights; \
19695  else cimg_forV(res,k) res(x,y,k) = (Tfloat)((*this)(x,y,k)); \
19696  }
19697 
19698 #define _cimg_blur_patch2d(N) \
19699  cimg_for##N##XY(res,x,y) { \
19700  cimg_forV(res,k) cimg_get##N##x##N(img,x,y,0,k,P.ptr(N2*k)); \
19701  const int x0 = x-rsize1, y0 = y-rsize1, x1 = x+rsize2, y1 = y+rsize2; \
19702  float sum_weights = 0; \
19703  cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) { \
19704  cimg_forV(res,k) cimg_get##N##x##N(img,p,q,0,k,Q.ptr(N2*k)); \
19705  float distance2 = 0; \
19706  const T *pQ = Q.end(); cimg_for(P,pP,T) { const float dI = (float)*pP-(float)*(--pQ); distance2+=dI*dI; } \
19707  distance2/=Pnorm; \
19708  const float dx = (float)p-x, dy = (float)q-y, \
19709  alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = (float)std::exp(-alldist); \
19710  sum_weights+=weight; \
19711  cimg_forV(res,k) res(x,y,k)+=weight*(*this)(p,q,k); \
19712  } \
19713  if (sum_weights>0) cimg_forV(res,k) res(x,y,k)/=sum_weights; \
19714  else cimg_forV(res,k) res(x,y,k) = (Tfloat)((*this)(x,y,k)); \
19715  }
19716 
19717  CImg<Tfloat> res(width,height,depth,dim,0);
19718  const CImg<T> _img = smoothness>0?get_blur(smoothness):CImg<Tfloat>(),&img = smoothness>0?_img:*this;
19719  CImg<T> P(patch_size*patch_size*dim), Q(P);
19720  const float
19721  nsigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(width,height,depth)/100,
19722  sigma_s2 = nsigma_s*nsigma_s, sigma_p2 = sigma_p*sigma_p, sigma_p3 = 3*sigma_p,
19723  Pnorm = P.size()*sigma_p2;
19724  const int rsize2 = (int)lookup_size/2, rsize1 = rsize2-1+(lookup_size%2);
19725  const unsigned int N2 = patch_size*patch_size, N3 = N2*patch_size;
19726  if (depth>1) switch (patch_size) { // 3D version
19727  case 2 : if (fast_approx) _cimg_blur_patch3d_fast(2) else _cimg_blur_patch3d(2) break;
19728  case 3 : if (fast_approx) _cimg_blur_patch3d_fast(3) else _cimg_blur_patch3d(3) break;
19729  default : {
19730  const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
19731  if (fast_approx) cimg_forXYZ(res,x,y,z) { // 3D fast approximation.
19732  P = img.get_crop(x - psize0,y - psize0,z - psize0,x + psize1,y + psize1,z + psize1,true);
19733  const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2;
19734  float sum_weights = 0;
19735  cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (cimg::abs(img(x,y,z,0)-img(p,q,r,0))<sigma_p3) {
19736  (Q = img.get_crop(p - psize0,q - psize0,r - psize0,p + psize1,q + psize1,r + psize1,true))-=P;
19737  const float
19738  dx = (float)x - p, dy = (float)y - q, dz = (float)z - r,
19739  distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),
19740  weight = distance2>3?0.0f:1.0f;
19741  sum_weights+=weight;
19742  cimg_forV(res,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k);
19743  }
19744  if (sum_weights>0) cimg_forV(res,k) res(x,y,z,k)/=sum_weights;
19745  else cimg_forV(res,k) res(x,y,z,k) = (Tfloat)((*this)(x,y,z,k));
19746  } else cimg_forXYZ(res,x,y,z) { // 3D exact algorithm.
19747  P = img.get_crop(x - psize0,y - psize0,z - psize0,x + psize1,y + psize1,z + psize1,true);
19748  const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2;
19749  float sum_weights = 0;
19750  cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) {
19751  (Q = img.get_crop(p - psize0,q - psize0,r - psize0,p + psize1,q + psize1,r + psize1,true))-=P;
19752  const float
19753  dx = (float)x - p, dy = (float)y - q, dz = (float)z - r,
19754  distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),
19755  weight = (float)std::exp(-distance2);
19756  sum_weights+=weight;
19757  cimg_forV(res,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k);
19758  }
19759  if (sum_weights>0) cimg_forV(res,k) res(x,y,z,k)/=sum_weights;
19760  else cimg_forV(res,k) res(x,y,z,k) = (Tfloat)((*this)(x,y,z,k));
19761  }
19762  }
19763  } else switch (patch_size) { // 2D version
19764  case 2 : if (fast_approx) _cimg_blur_patch2d_fast(2) else _cimg_blur_patch2d(2) break;
19765  case 3 : if (fast_approx) _cimg_blur_patch2d_fast(3) else _cimg_blur_patch2d(3) break;
19766  case 4 : if (fast_approx) _cimg_blur_patch2d_fast(4) else _cimg_blur_patch2d(4) break;
19767  case 5 : if (fast_approx) _cimg_blur_patch2d_fast(5) else _cimg_blur_patch2d(5) break;
19768  case 6 : if (fast_approx) _cimg_blur_patch2d_fast(6) else _cimg_blur_patch2d(6) break;
19769  case 7 : if (fast_approx) _cimg_blur_patch2d_fast(7) else _cimg_blur_patch2d(7) break;
19770  case 8 : if (fast_approx) _cimg_blur_patch2d_fast(8) else _cimg_blur_patch2d(8) break;
19771  case 9 : if (fast_approx) _cimg_blur_patch2d_fast(9) else _cimg_blur_patch2d(9) break;
19772  default : {
19773  const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
19774  if (fast_approx) cimg_forXY(res,x,y) { // 2D fast approximation.
19775  P = img.get_crop(x - psize0,y - psize0,x + psize1,y + psize1,true);
19776  const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2;
19777  float sum_weights = 0;
19778  cimg_for_inXY(res,x0,y0,x1,y1,p,q) if (cimg::abs(img(x,y,0,0)-img(p,q,0,0))<sigma_p3) {
19779  (Q = img.get_crop(p - psize0,q - psize0,p + psize1,q + psize1,true))-=P;
19780  const float
19781  dx = (float)x - p, dy = (float)y - q,
19782  distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),
19783  weight = distance2>3?0.0f:1.0f;
19784  sum_weights+=weight;
19785  cimg_forV(res,k) res(x,y,0,k)+=weight*(*this)(p,q,0,k);
19786  }
19787  if (sum_weights>0) cimg_forV(res,k) res(x,y,0,k)/=sum_weights;
19788  else cimg_forV(res,k) res(x,y,0,k) = (Tfloat)((*this)(x,y,0,k));
19789  } else cimg_forXY(res,x,y) { // 2D exact algorithm.
19790  P = img.get_crop(x - psize0,y - psize0,x + psize1,y + psize1,true);
19791  const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2;
19792  float sum_weights = 0;
19793  cimg_for_inXY(res,x0,y0,x1,y1,p,q) {
19794  (Q = img.get_crop(p - psize0,q - psize0,p + psize1,q + psize1,true))-=P;
19795  const float
19796  dx = (float)x - p, dy = (float)y - q,
19797  distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),
19798  weight = (float)std::exp(-distance2);
19799  sum_weights+=weight;
19800  cimg_forV(res,k) res(x,y,0,k)+=weight*(*this)(p,q,0,k);
19801  }
19802  if (sum_weights>0) cimg_forV(res,k) res(x,y,0,k)/=sum_weights;
19803  else cimg_forV(res,k) res(x,y,0,k) = (Tfloat)((*this)(x,y,0,k));
19804  }
19805  }
19806  }
19807  return res;
19808  }
19809 
19811  CImg<T>& blur_median(const unsigned int n) {
19812  return get_blur_median(n).transfer_to(*this);
19813  }
19814 
19815  CImg<T> get_blur_median(const unsigned int n) const {
19816  CImg<T> res(width,height,depth,dim);
19817  if (!n || n==1) return *this;
19818  const int hl=n/2, hr=hl-1+n%2;
19819  if (res.depth!=1) { // 3D median filter
19820  CImg<T> vois;
19821  cimg_forXYZV(*this,x,y,z,k) {
19822  const int
19823  x0 = x - hl, y0 = y - hl, z0 = z-hl, x1 = x + hr, y1 = y + hr, z1 = z+hr,
19824  nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,
19825  nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1, nz1 = z1>=dimz()?dimz()-1:z1;
19826  vois = get_crop(nx0,ny0,nz0,k,nx1,ny1,nz1,k);
19827  res(x,y,z,k) = vois.median();
19828  }
19829  } else {
19830 #define _cimg_median_sort(a,b) if ((a)>(b)) cimg::swap(a,b)
19831  if (res.height!=1) switch (n) { // 2D median filter
19832  case 3 : {
19833  T I[9] = { 0 };
19834  CImg_3x3(J,T);
19835  cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
19836  std::memcpy(J,I,9*sizeof(T));
19837  _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
19838  _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jpn, Jcn);
19839  _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
19840  _cimg_median_sort(Jpp, Jpc); _cimg_median_sort(Jnc, Jnn); _cimg_median_sort(Jcc, Jcn);
19841  _cimg_median_sort(Jpc, Jpn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jnp, Jnc);
19842  _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcc, Jnp); _cimg_median_sort(Jpn, Jcc);
19843  _cimg_median_sort(Jcc, Jnp);
19844  res(x,y,0,k) = Jcc;
19845  }
19846  } break;
19847  case 5 : {
19848  T I[25] = { 0 };
19849  CImg_5x5(J,T);
19850  cimg_forV(*this,k) cimg_for5x5(*this,x,y,0,k,I) {
19851  std::memcpy(J,I,25*sizeof(T));
19852  _cimg_median_sort(Jbb, Jpb); _cimg_median_sort(Jnb, Jab); _cimg_median_sort(Jcb, Jab); _cimg_median_sort(Jcb, Jnb);
19853  _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbp, Jcp); _cimg_median_sort(Jbp, Jpp); _cimg_median_sort(Jap, Jbc);
19854  _cimg_median_sort(Jnp, Jbc); _cimg_median_sort(Jnp, Jap); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jpc, Jnc);
19855  _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jbn, Jpn); _cimg_median_sort(Jac, Jpn); _cimg_median_sort(Jac, Jbn);
19856  _cimg_median_sort(Jnn, Jan); _cimg_median_sort(Jcn, Jan); _cimg_median_sort(Jcn, Jnn); _cimg_median_sort(Jpa, Jca);
19857  _cimg_median_sort(Jba, Jca); _cimg_median_sort(Jba, Jpa); _cimg_median_sort(Jna, Jaa); _cimg_median_sort(Jcb, Jbp);
19858  _cimg_median_sort(Jnb, Jpp); _cimg_median_sort(Jbb, Jpp); _cimg_median_sort(Jbb, Jnb); _cimg_median_sort(Jab, Jcp);
19859  _cimg_median_sort(Jpb, Jcp); _cimg_median_sort(Jpb, Jab); _cimg_median_sort(Jpc, Jac); _cimg_median_sort(Jnp, Jac);
19860  _cimg_median_sort(Jnp, Jpc); _cimg_median_sort(Jcc, Jbn); _cimg_median_sort(Jap, Jbn); _cimg_median_sort(Jap, Jcc);
19861  _cimg_median_sort(Jnc, Jpn); _cimg_median_sort(Jbc, Jpn); _cimg_median_sort(Jbc, Jnc); _cimg_median_sort(Jba, Jna);
19862  _cimg_median_sort(Jcn, Jna); _cimg_median_sort(Jcn, Jba); _cimg_median_sort(Jpa, Jaa); _cimg_median_sort(Jnn, Jaa);
19863  _cimg_median_sort(Jnn, Jpa); _cimg_median_sort(Jan, Jca); _cimg_median_sort(Jnp, Jcn); _cimg_median_sort(Jap, Jnn);
19864  _cimg_median_sort(Jbb, Jnn); _cimg_median_sort(Jbb, Jap); _cimg_median_sort(Jbc, Jan); _cimg_median_sort(Jpb, Jan);
19865  _cimg_median_sort(Jpb, Jbc); _cimg_median_sort(Jpc, Jba); _cimg_median_sort(Jcb, Jba); _cimg_median_sort(Jcb, Jpc);
19866  _cimg_median_sort(Jcc, Jpa); _cimg_median_sort(Jnb, Jpa); _cimg_median_sort(Jnb, Jcc); _cimg_median_sort(Jnc, Jca);
19867  _cimg_median_sort(Jab, Jca); _cimg_median_sort(Jab, Jnc); _cimg_median_sort(Jac, Jna); _cimg_median_sort(Jbp, Jna);
19868  _cimg_median_sort(Jbp, Jac); _cimg_median_sort(Jbn, Jaa); _cimg_median_sort(Jpp, Jaa); _cimg_median_sort(Jpp, Jbn);
19869  _cimg_median_sort(Jcp, Jpn); _cimg_median_sort(Jcp, Jan); _cimg_median_sort(Jnc, Jpa); _cimg_median_sort(Jbn, Jna);
19870  _cimg_median_sort(Jcp, Jnc); _cimg_median_sort(Jcp, Jbn); _cimg_median_sort(Jpb, Jap); _cimg_median_sort(Jnb, Jpc);
19871  _cimg_median_sort(Jbp, Jcn); _cimg_median_sort(Jpc, Jcn); _cimg_median_sort(Jap, Jcn); _cimg_median_sort(Jab, Jbc);
19872  _cimg_median_sort(Jpp, Jcc); _cimg_median_sort(Jcp, Jac); _cimg_median_sort(Jab, Jpp); _cimg_median_sort(Jab, Jcp);
19873  _cimg_median_sort(Jcc, Jac); _cimg_median_sort(Jbc, Jac); _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbc, Jcc);
19874  _cimg_median_sort(Jpp, Jbc); _cimg_median_sort(Jpp, Jcn); _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcp, Jcn);
19875  _cimg_median_sort(Jcp, Jbc); _cimg_median_sort(Jcc, Jnn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jbc, Jnn);
19876  _cimg_median_sort(Jcc, Jba); _cimg_median_sort(Jbc, Jba); _cimg_median_sort(Jbc, Jcc);
19877  res(x,y,0,k) = Jcc;
19878  }
19879  } break;
19880  default : {
19881  CImg<T> vois;
19882  cimg_forXYV(*this,x,y,k) {
19883  const int
19884  x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,
19885  nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,
19886  nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1;
19887  vois = get_crop(nx0,ny0,0,k,nx1,ny1,0,k);
19888  res(x,y,0,k) = vois.median();
19889  }
19890  }
19891  } else switch (n) { // 1D median filter
19892  case 2 : {
19893  T I[4] = { 0 };
19894  cimg_forV(*this,k) cimg_for2x2(*this,x,y,0,k,I) res(x,0,0,k) = (T)(0.5f*(I[0]+I[1]));
19895  } break;
19896  case 3 : {
19897  T I[9] = { 0 };
19898  cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
19899  res(x,0,0,k) = I[3]<I[4]?
19900  (I[4]<I[5]?I[4]:
19901  (I[3]<I[5]?I[5]:I[3])):
19902  (I[3]<I[5]?I[3]:
19903  (I[4]<I[5]?I[5]:I[4]));
19904  }
19905  } break;
19906  default : {
19907  CImg<T> vois;
19908  cimg_forXV(*this,x,k) {
19909  const int
19910  x0 = x - hl, x1 = x + hr,
19911  nx0 = x0<0?0:x0, nx1 = x1>=dimx()?dimx()-1:x1;
19912  vois = get_crop(nx0,0,0,k,nx1,0,0,k);
19913  res(x,0,0,k) = vois.median();
19914  }
19915  }
19916  }
19917  }
19918  return res;
19919  }
19920 
19922  CImg<T>& sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) {
19923  if (is_empty()) return *this;
19924  T valm, valM = maxmin(valm);
19925  const bool threed = (depth>1);
19926  const float nedge = 0.5f*edge;
19927  CImg<Tfloat> val, vec, veloc(width,height,depth,dim);
19928 
19929  if (threed) {
19930  CImg_3x3x3(I,T);
19931  if (sharpen_type) { // 3D Shock filter.
19932  CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
19933  if (sigma>0) G.blur(sigma);
19934 
19935  cimg_forXYZ(G,x,y,z) {
19936  G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
19937  G(x,y,z,0) = vec(0,0);
19938  G(x,y,z,1) = vec(0,1);
19939  G(x,y,z,2) = vec(0,2);
19940  G(x,y,z,3) = 1 - (Tfloat)std::pow(1+val[0]+val[1]+val[2],-(Tfloat)nedge);
19941  }
19942  cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
19943  const Tfloat
19944  u = G(x,y,z,0),
19945  v = G(x,y,z,1),
19946  w = G(x,y,z,2),
19947  amp = G(x,y,z,3),
19948  ixx = (Tfloat)Incc + Ipcc - 2*Iccc,
19949  ixy = 0.25f*((Tfloat)Innc + Ippc - Inpc - Ipnc),
19950  ixz = 0.25f*((Tfloat)Incn + Ipcp - Incp - Ipcn),
19951  iyy = (Tfloat)Icnc + Icpc - 2*Iccc,
19952  iyz = 0.25f*((Tfloat)Icnn + Icpp - Icnp - Icpn),
19953  izz = (Tfloat)Iccn + Iccp - 2*Iccc,
19954  ixf = (Tfloat)Incc - Iccc,
19955  ixb = (Tfloat)Iccc - Ipcc,
19956  iyf = (Tfloat)Icnc - Iccc,
19957  iyb = (Tfloat)Iccc - Icpc,
19958  izf = (Tfloat)Iccn - Iccc,
19959  izb = (Tfloat)Iccc - Iccp,
19960  itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz,
19961  it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb);
19962  veloc(x,y,z,k) = -amp*cimg::sign(itt)*cimg::abs(it);
19963  }
19964  } 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.
19965  } else {
19966  CImg_3x3(I,T);
19967  if (sharpen_type) { // 2D Shock filter.
19968  CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
19969  if (sigma>0) G.blur(sigma);
19970  cimg_forXY(G,x,y) {
19971  G.get_tensor_at(x,y).symmetric_eigen(val,vec);
19972  G(x,y,0) = vec(0,0);
19973  G(x,y,1) = vec(0,1);
19974  G(x,y,2) = 1 - (Tfloat)std::pow(1+val[0]+val[1],-(Tfloat)nedge);
19975  }
19976  cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
19977  const Tfloat
19978  u = G(x,y,0),
19979  v = G(x,y,1),
19980  amp = G(x,y,2),
19981  ixx = (Tfloat)Inc + Ipc - 2*Icc,
19982  ixy = 0.25f*((Tfloat)Inn + Ipp - Inp - Ipn),
19983  iyy = (Tfloat)Icn + Icp - 2*Icc,
19984  ixf = (Tfloat)Inc - Icc,
19985  ixb = (Tfloat)Icc - Ipc,
19986  iyf = (Tfloat)Icn - Icc,
19987  iyb = (Tfloat)Icc - Icp,
19988  itt = u*u*ixx + v*v*iyy + 2*u*v*ixy,
19989  it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb);
19990  veloc(x,y,k) = -amp*cimg::sign(itt)*cimg::abs(it);
19991  }
19992  } 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.
19993  }
19994  float m, M = (float)veloc.maxmin(m);
19995  const float vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
19996  if (vmax!=0) { veloc*=amplitude/vmax; (*this)+=veloc; }
19997  return cut(valm,valM);
19998  }
19999 
20000  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 {
20001  return (+*this).sharpen(amplitude,sharpen_type,edge,alpha,sigma);
20002  }
20003 
20005 
20014  CImgList<Tfloat> get_gradient(const char *const axes=0, const int scheme=3) const {
20015  CImgList<Tfloat> grad(2,width,height,depth,dim);
20016  bool threed = false;
20017  if (axes) {
20018  for (unsigned int a = 0; axes[a]; ++a) {
20019  const char axis = cimg::uncase(axes[a]);
20020  switch (axis) {
20021  case 'x' : case 'y' : break;
20022  case 'z' : threed = true; break;
20023  default :
20024  throw CImgArgumentException("CImg<%s>::get_gradient() : Unknown specified axis '%c'.",
20025  pixel_type(),axis);
20026  }
20027  }
20028  } else threed = (depth>1);
20029  if (threed) {
20031  switch (scheme) { // Compute 3D gradient
20032  case -1 : { // backward finite differences
20033  CImg_3x3x3(I,T);
20034  cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
20035  grad[0](x,y,z,k) = (Tfloat)Iccc - Ipcc;
20036  grad[1](x,y,z,k) = (Tfloat)Iccc - Icpc;
20037  grad[2](x,y,z,k) = (Tfloat)Iccc - Iccp;
20038  }
20039  } break;
20040  case 1 : { // forward finite differences
20041  CImg_2x2x2(I,T);
20042  cimg_forV(*this,k) cimg_for2x2x2(*this,x,y,z,k,I) {
20043  grad[0](x,y,z,k) = (Tfloat)Incc - Iccc;
20044  grad[1](x,y,z,k) = (Tfloat)Icnc - Iccc;
20045  grad[2](x,y,z,k) = (Tfloat)Iccn - Iccc;
20046  }
20047  } break;
20048  case 4 : { // using Deriche filter with low standard variation
20049  grad[0] = get_deriche(0,1,'x');
20050  grad[1] = get_deriche(0,1,'y');
20051  grad[2] = get_deriche(0,1,'z');
20052  } break;
20053  default : { // central finite differences
20054  CImg_3x3x3(I,T);
20055  cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
20056  grad[0](x,y,z,k) = 0.5f*((Tfloat)Incc - Ipcc);
20057  grad[1](x,y,z,k) = 0.5f*((Tfloat)Icnc - Icpc);
20058  grad[2](x,y,z,k) = 0.5f*((Tfloat)Iccn - Iccp);
20059  }
20060  }
20061  }
20062  } else switch (scheme) { // Compute 2D-gradient
20063  case -1 : { // backward finite differences
20064  CImg_3x3(I,T);
20065  cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
20066  grad[0](x,y,z,k) = (Tfloat)Icc - Ipc;
20067  grad[1](x,y,z,k) = (Tfloat)Icc - Icp;
20068  }
20069  } break;
20070  case 1 : { // forward finite differences
20071  CImg_2x2(I,T);
20072  cimg_forZV(*this,z,k) cimg_for2x2(*this,x,y,z,k,I) {
20073  grad[0](x,y,0,k) = (Tfloat)Inc - Icc;
20074  grad[1](x,y,z,k) = (Tfloat)Icn - Icc;
20075  }
20076  } break;
20077  case 2 : { // using Sobel mask
20078  CImg_3x3(I,T);
20079  const Tfloat a = 1, b = 2;
20080  cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
20081  grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
20082  grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
20083  }
20084  } break;
20085  case 3 : { // using rotation invariant mask
20086  CImg_3x3(I,T);
20087  const Tfloat a = (Tfloat)(0.25f*(2-std::sqrt(2.0f))), b = (Tfloat)(0.5f*(std::sqrt(2.0f)-1));
20088  cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
20089  grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
20090  grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
20091  }
20092  } break;
20093  case 4 : { // using Deriche filter with low standard variation
20094  grad[0] = get_deriche(0,1,'x');
20095  grad[1] = get_deriche(0,1,'y');
20096  } break;
20097  default : { // central finite differences
20098  CImg_3x3(I,T);
20099  cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
20100  grad[0](x,y,z,k) = 0.5f*((Tfloat)Inc - Ipc);
20101  grad[1](x,y,z,k) = 0.5f*((Tfloat)Icn - Icp);
20102  }
20103  }
20104  }
20105  if (!axes) return grad;
20106  CImgList<Tfloat> res;
20107  for (unsigned int l = 0; axes[l]; ++l) {
20108  const char axis = cimg::uncase(axes[l]);
20109  switch (axis) {
20110  case 'x' : res.insert(grad[0]); break;
20111  case 'y' : res.insert(grad[1]); break;
20112  case 'z' : res.insert(grad[2]); break;
20113  }
20114  }
20115  grad.assign();
20116  return res;
20117  }
20118 
20120  CImgList<Tfloat> get_hessian(const char *const axes=0) const {
20121  const char *naxes = axes, *const def_axes2d = "xxxyyy", *const def_axes3d = "xxxyxzyyyzzz";
20122  if (!axes) naxes = depth>1?def_axes3d:def_axes2d;
20123  CImgList<Tfloat> res;
20124  const unsigned int lmax = std::strlen(naxes);
20125  if (lmax%2)
20126  throw CImgArgumentException("CImg<%s>::get_hessian() : Incomplete parameter axes = '%s'.",
20127  pixel_type(),naxes);
20128  res.assign(lmax/2,width,height,depth,dim);
20129  if (!cimg::strcasecmp(naxes,def_axes3d)) { // Default 3D version
20130  CImg_3x3x3(I,T);
20131  cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
20132  res[0](x,y,z,k) = (Tfloat)Ipcc + Incc - 2*Iccc; // Ixx
20133  res[1](x,y,z,k) = 0.25f*((Tfloat)Ippc + Innc - Ipnc - Inpc); // Ixy
20134  res[2](x,y,z,k) = 0.25f*((Tfloat)Ipcp + Incn - Ipcn - Incp); // Ixz
20135  res[3](x,y,z,k) = (Tfloat)Icpc + Icnc - 2*Iccc; // Iyy
20136  res[4](x,y,z,k) = 0.25f*((Tfloat)Icpp + Icnn - Icpn - Icnp); // Iyz
20137  res[5](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc; // Izz
20138  }
20139  } else if (!cimg::strcasecmp(naxes,def_axes2d)) { // Default 2D version
20140  CImg_3x3(I,T);
20141  cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
20142  res[0](x,y,0,k) = (Tfloat)Ipc + Inc - 2*Icc; // Ixx
20143  res[1](x,y,0,k) = 0.25f*((Tfloat)Ipp + Inn - Ipn - Inp); // Ixy
20144  res[2](x,y,0,k) = (Tfloat)Icp + Icn - 2*Icc; // Iyy
20145  }
20146  } else for (unsigned int l = 0; l<lmax; ) { // Version with custom axes.
20147  const unsigned int l2 = l/2;
20148  char axis1 = naxes[l++], axis2 = naxes[l++];
20149  if (axis1>axis2) cimg::swap(axis1,axis2);
20150  bool valid_axis = false;
20151  if (axis1=='x' && axis2=='x') { // Ixx
20152  valid_axis = true; CImg_3x3(I,T);
20153  cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Ipc + Inc - 2*Icc;
20154  }
20155  else if (axis1=='x' && axis2=='y') { // Ixy
20156  valid_axis = true; CImg_3x3(I,T);
20157  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);
20158  }
20159  else if (axis1=='x' && axis2=='z') { // Ixz
20160  valid_axis = true; CImg_3x3x3(I,T);
20161  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);
20162  }
20163  else if (axis1=='y' && axis2=='y') { // Iyy
20164  valid_axis = true; CImg_3x3(I,T);
20165  cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Icp + Icn - 2*Icc;
20166  }
20167  else if (axis1=='y' && axis2=='z') { // Iyz
20168  valid_axis = true; CImg_3x3x3(I,T);
20169  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);
20170  }
20171  else if (axis1=='z' && axis2=='z') { // Izz
20172  valid_axis = true; CImg_3x3x3(I,T);
20173  cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc;
20174  }
20175  else if (!valid_axis) throw CImgArgumentException("CImg<%s>::get_hessian() : Invalid parameter axes = '%s'.",
20176  pixel_type(),naxes);
20177  }
20178  return res;
20179  }
20180 
20182  CImg<T>& structure_tensor(const unsigned int scheme=1) {
20183  return get_structure_tensor(scheme).transfer_to(*this);
20184  }
20185 
20186  CImg<Tfloat> get_structure_tensor(const unsigned int scheme=1) const {
20187  if (is_empty()) return *this;
20188  CImg<Tfloat> res;
20189  if (depth>1) { // 3D version
20190  res.assign(width,height,depth,6,0);
20191  CImg_3x3x3(I,T);
20192  switch (scheme) {
20193  case 0 : { // classical central finite differences
20194  cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
20195  const Tfloat
20196  ix = 0.5f*((Tfloat)Incc - Ipcc),
20197  iy = 0.5f*((Tfloat)Icnc - Icpc),
20198  iz = 0.5f*((Tfloat)Iccn - Iccp);
20199  res(x,y,z,0)+=ix*ix;
20200  res(x,y,z,1)+=ix*iy;
20201  res(x,y,z,2)+=ix*iz;
20202  res(x,y,z,3)+=iy*iy;
20203  res(x,y,z,4)+=iy*iz;
20204  res(x,y,z,5)+=iz*iz;
20205  }
20206  } break;
20207  case 1 : { // Forward/backward finite differences (version 1).
20208  cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
20209  const Tfloat
20210  ixf = (Tfloat)Incc - Iccc, ixb = (Tfloat)Iccc - Ipcc,
20211  iyf = (Tfloat)Icnc - Iccc, iyb = (Tfloat)Iccc - Icpc,
20212  izf = (Tfloat)Iccn - Iccc, izb = (Tfloat)Iccc - Iccp;
20213  res(x,y,z,0) += 0.25f*(ixf*ixf + ixf*ixb + ixb*ixf + ixb*ixb);
20214  res(x,y,z,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb);
20215  res(x,y,z,2) += 0.25f*(ixf*izf + ixf*izb + ixb*izf + ixb*izb);
20216  res(x,y,z,3) += 0.25f*(iyf*iyf + iyf*iyb + iyb*iyf + iyb*iyb);
20217  res(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb);
20218  res(x,y,z,5) += 0.25f*(izf*izf + izf*izb + izb*izf + izb*izb);
20219  }
20220  } break;
20221  default : { // Forward/backward finite differences (version 2).
20222  cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
20223  const Tfloat
20224  ixf = (Tfloat)Incc - Iccc, ixb = (Tfloat)Iccc - Ipcc,
20225  iyf = (Tfloat)Icnc - Iccc, iyb = (Tfloat)Iccc - Icpc,
20226  izf = (Tfloat)Iccn - Iccc, izb = (Tfloat)Iccc - Iccp;
20227  res(x,y,z,0) += 0.5f*(ixf*ixf + ixb*ixb);
20228  res(x,y,z,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb);
20229  res(x,y,z,2) += 0.25f*(ixf*izf + ixf*izb + ixb*izf + ixb*izb);
20230  res(x,y,z,3) += 0.5f*(iyf*iyf + iyb*iyb);
20231  res(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb);
20232  res(x,y,z,5) += 0.5f*(izf*izf + izb*izb);
20233  }
20234  } break;
20235  }
20236  } else { // 2D version
20237  res.assign(width,height,depth,3,0);
20238  CImg_3x3(I,T);
20239  switch (scheme) {
20240  case 0 : { // classical central finite differences
20241  cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
20242  const Tfloat
20243  ix = 0.5f*((Tfloat)Inc - Ipc),
20244  iy = 0.5f*((Tfloat)Icn - Icp);
20245  res(x,y,0,0)+=ix*ix;
20246  res(x,y,0,1)+=ix*iy;
20247  res(x,y,0,2)+=iy*iy;
20248  }
20249  } break;
20250  case 1 : { // Forward/backward finite differences (version 1).
20251  cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
20252  const Tfloat
20253  ixf = (Tfloat)Inc - Icc, ixb = (Tfloat)Icc - Ipc,
20254  iyf = (Tfloat)Icn - Icc, iyb = (Tfloat)Icc - Icp;
20255  res(x,y,0,0) += 0.25f*(ixf*ixf + ixf*ixb + ixb*iyf + ixb*ixb);
20256  res(x,y,0,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb);
20257  res(x,y,0,2) += 0.25f*(iyf*iyf + iyf*iyb + iyb*iyf + iyb*iyb);
20258  }
20259  } break;
20260  default : { // Forward/backward finite differences (version 2).
20261  cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
20262  const Tfloat
20263  ixf = (Tfloat)Inc - Icc, ixb = (Tfloat)Icc - Ipc,
20264  iyf = (Tfloat)Icn - Icc, iyb = (Tfloat)Icc - Icp;
20265  res(x,y,0,0) += 0.5f*(ixf*ixf + ixb*ixb);
20266  res(x,y,0,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb);
20267  res(x,y,0,2) += 0.5f*(iyf*iyf + iyb*iyb);
20268  }
20269  } break;
20270  }
20271  }
20272  return res;
20273  }
20274 
20276  CImg<T>& edge_tensors(const float sharpness=0.7f, const float anisotropy=0.3f,
20277  const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) {
20278  CImg<Tfloat> dest;
20279  const float nsharpness = cimg::max(sharpness,1e-5f), power1 = (is_sqrt?0.5f:1)*nsharpness, power2 = power1/(1e-7f+1-anisotropy);
20280  blur(alpha).normalize(0,(T)255);
20281 
20282  if (depth>1) { // for 3D volumes
20283  CImg<floatT> val(3), vec(3,3);
20284  get_structure_tensor().transfer_to(dest).blur(sigma);
20285  cimg_forXYZ(*this,x,y,z) {
20286  dest.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
20287  const float
20288  _l1 = val[2], _l2 = val[1], _l3 = val[0],
20289  l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0, l3 = _l3>0?_l3:0,
20290  ux = vec(0,0), uy = vec(0,1), uz = vec(0,2),
20291  vx = vec(1,0), vy = vec(1,1), vz = vec(1,2),
20292  wx = vec(2,0), wy = vec(2,1), wz = vec(2,2),
20293  n1 = (float)std::pow(1+l1+l2+l3,-power1),
20294  n2 = (float)std::pow(1+l1+l2+l3,-power2);
20295  dest(x,y,z,0) = n1*(ux*ux + vx*vx) + n2*wx*wx;
20296  dest(x,y,z,1) = n1*(ux*uy + vx*vy) + n2*wx*wy;
20297  dest(x,y,z,2) = n1*(ux*uz + vx*vz) + n2*wx*wz;
20298  dest(x,y,z,3) = n1*(uy*uy + vy*vy) + n2*wy*wy;
20299  dest(x,y,z,4) = n1*(uy*uz + vy*vz) + n2*wy*wz;
20300  dest(x,y,z,5) = n1*(uz*uz + vz*vz) + n2*wz*wz;
20301  }
20302  } else { // for 2D images
20303  CImg<floatT> val(2), vec(2,2);
20304  get_structure_tensor().transfer_to(dest).blur(sigma);
20305  cimg_forXY(*this,x,y) {
20306  dest.get_tensor_at(x,y).symmetric_eigen(val,vec);
20307  const float
20308  _l1 = val[1], _l2 = val[0],
20309  l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0,
20310  ux = vec(1,0), uy = vec(1,1),
20311  vx = vec(0,0), vy = vec(0,1),
20312  n1 = (float)std::pow(1+l1+l2,-power1),
20313  n2 = (float)std::pow(1+l1+l2,-power2);
20314  dest(x,y,0,0) = n1*ux*ux + n2*vx*vx;
20315  dest(x,y,0,1) = n1*ux*uy + n2*vx*vy;
20316  dest(x,y,0,2) = n1*uy*uy + n2*vy*vy;
20317  }
20318  }
20319  return dest.transfer_to(*this);
20320  }
20321 
20322  CImg<T> get_edge_tensors(const float sharpness=0.7f, const float anisotropy=0.3f,
20323  const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) const {
20324  return (+*this).edge_tensors(sharpness,anisotropy,alpha,sigma,is_sqrt);
20325  }
20326 
20328 
20331  CImg<T>& displacement_field(const CImg<T>& target, const float smooth=0.1f, const float precision=0.1f,
20332  const unsigned int nb_scales=0, const unsigned int itermax=1000,
20333  const bool backward = true) {
20334  return get_displacement_field(target,smooth,precision,nb_scales,itermax,backward).transfer_to(*this);
20335  }
20336 
20338  const float smoothness=0.1f, const float precision=0.1f,
20339  const unsigned int nb_scales=0, const unsigned int itermax=1000,
20340  const bool backward = true) const {
20341  if (is_empty() || !target) return *this;
20342  if (!is_sameXYZV(target))
20343  throw CImgArgumentException("CImg<%s>::displacement_field() : Instance image (%u,%u,%u,%u,%p) and target image (%u,%u,%u,%u,%p) "
20344  "have different size.",
20346  target.width,target.height,target.depth,target.dim,target.data);
20347  if (smoothness<0)
20348  throw CImgArgumentException("CImg<%s>::displacement_field() : Smoothness parameter %g is negative.",
20349  pixel_type(),smoothness);
20350  if (precision<0)
20351  throw CImgArgumentException("CImg<%s>::displacement_field() : Precision parameter %g is negative.",
20352  pixel_type(),precision);
20353 
20354  const unsigned int nscales = nb_scales>0?nb_scales:(unsigned int)(2*std::log((double)(cimg::max(width,height,depth))));
20355  Tfloat m1, M1 = (Tfloat)maxmin(m1), m2, M2 = (Tfloat)target.maxmin(m2);
20356  const Tfloat factor = cimg::max(cimg::abs(m1),cimg::abs(M1),cimg::abs(m2),cimg::abs(M2));
20357  CImg<Tfloat> U0;
20358  const bool threed = (depth>1);
20359 
20360  // Begin multi-scale motion estimation
20361  for (int scale = (int)nscales-1; scale>=0; --scale) {
20362  const float sfactor = (float)std::pow(1.5f,(float)scale), sprecision = (float)(precision/std::pow(2.25,1+scale));
20363  const int
20364  sw = (int)(width/sfactor), sh = (int)(height/sfactor), sd = (int)(depth/sfactor),
20365  swidth = sw?sw:1, sheight = sh?sh:1, sdepth = sd?sd:1;
20366  CImg<Tfloat>
20367  I1 = get_resize(swidth,sheight,sdepth,-100,2),
20368  I2 = target.get_resize(swidth,sheight,sdepth,-100,2);
20369  I1/=factor; I2/=factor;
20370  CImg<Tfloat> U;
20371  if (U0) U = (U0*=1.5f).get_resize(I1.dimx(),I1.dimy(),I1.dimz(),-100,3);
20372  else U.assign(I1.dimx(),I1.dimy(),I1.dimz(),threed?3:2,0);
20373 
20374  // Begin single-scale motion estimation
20375  CImg<Tfloat> veloc(U);
20376  float dt = 2, energy = cimg::type<float>::max();
20377  const CImgList<Tfloat> dI = backward?I1.get_gradient():I2.get_gradient();
20378  for (unsigned int iter = 0; iter<itermax; iter++) {
20379  veloc.fill(0);
20380  float nenergy = 0;
20381  if (threed) {
20382  cimg_for3XYZ(U,x,y,z) {
20383  const float
20384  sgnU = backward?-1.0f:1.0f,
20385  X = (float)(x + sgnU * U(x,y,z,0)),
20386  Y = (float)(y + sgnU * U(x,y,z,1)),
20387  Z = (float)(z + sgnU * U(x,y,z,2));
20388  cimg_forV(U,k) {
20389  const Tfloat
20390  Ux = 0.5f*(U(_n1x,y,z,k) - U(_p1x,y,z,k)),
20391  Uy = 0.5f*(U(x,_n1y,z,k) - U(x,_p1y,z,k)),
20392  Uz = 0.5f*(U(x,y,_n1z,k) - U(x,y,_p1z,k)),
20393  Uxx = U(_n1x,y,z,k) + U(_p1x,y,z,k) - 2*U(x,y,z,k),
20394  Uyy = U(x,_n1y,z,k) + U(x,_p1y,z,k) - 2*U(x,y,z,k),
20395  Uzz = U(x,y,_n1z,k) + U(x,y,_n1z,k) - 2*U(x,y,z,k);
20396  nenergy += (float)(smoothness*(Ux*Ux + Uy*Uy + Uz*Uz));
20397  Tfloat deltaIgrad = 0;
20398  cimg_forV(I1,i) {
20399  const Tfloat deltaIi = (float)(backward?I2(x,y,z,i)-I1._linear_atXYZ(X,Y,Z,i):I2._linear_atXYZ(X,Y,Z,i)-I1(x,y,z,i));
20400  nenergy += (float)(deltaIi*deltaIi/2);
20401  deltaIgrad+=-deltaIi*dI[k]._linear_atXYZ(X,Y,Z,i);
20402  }
20403  veloc(x,y,z,k) = deltaIgrad + smoothness*(Uxx + Uyy + Uzz);
20404  }
20405  }
20406  } else {
20407  cimg_for3XY(U,x,y) {
20408  const float
20409  sgnU = backward?-1.0f:1.0f,
20410  X = (float)(x + sgnU * U(x,y,0)),
20411  Y = (float)(y + sgnU * U(x,y,1));
20412  cimg_forV(U,k) {
20413  const Tfloat
20414  Ux = 0.5f*(U(_n1x,y,k) - U(_p1x,y,k)),
20415  Uy = 0.5f*(U(x,_n1y,k) - U(x,_p1y,k)),
20416  Uxx = U(_n1x,y,k) + U(_p1x,y,k) - 2*U(x,y,k),
20417  Uyy = U(x,_n1y,k) + U(x,_p1y,k) - 2*U(x,y,k);
20418  nenergy += (float)(smoothness*(Ux*Ux + Uy*Uy));
20419  Tfloat deltaIgrad = 0;
20420  cimg_forV(I1,i) {
20421  const Tfloat deltaIi = (float)(backward?I2(x,y,i)-I1.linear_atXY(X,Y,i):I2._linear_atXY(X,Y,i)-I1(x,y,i));
20422  nenergy += (float)(deltaIi*deltaIi/2);
20423  deltaIgrad+=-deltaIi*dI[k]._linear_atXY(X,Y,i);
20424  }
20425  veloc(x,y,k) = deltaIgrad + smoothness*(Uxx + Uyy);
20426  }
20427  }
20428  }
20429  const Tfloat vmax = cimg::max(cimg::abs(veloc.min()), cimg::abs(veloc.max()));
20430  U+=(veloc*=dt/(1e-6+vmax));
20431  if (cimg::abs(nenergy-energy)<sprecision) break;
20432  if (nenergy<energy) dt*=0.5f;
20433  energy = nenergy;
20434  }
20435  U.transfer_to(U0);
20436  }
20437  return U0;
20438  }
20439 
20441  CImg<T>& distance(const T isovalue,
20442  const float sizex=1, const float sizey=1, const float sizez=1,
20443  const bool compute_sqrt=true) {
20444  return get_distance(isovalue,sizex,sizey,sizez,compute_sqrt).transfer_to(*this);
20445  }
20446 
20447  CImg<floatT> get_distance(const T isovalue,
20448  const float sizex=1, const float sizey=1, const float sizez=1,
20449  const bool compute_sqrt=true) const {
20450  if (is_empty()) return *this;
20451  const int dx = dimx(), dy = dimy(), dz = dimz();
20452  CImg<floatT> res(dx,dy,dz,dim);
20453  const float maxdist = (float)std::sqrt((float)dx*dx + dy*dy + dz*dz);
20454  cimg_forV(*this,k) {
20455  bool is_isophote = false;
20456 
20457  if (depth>1) { // 3D version
20458  cimg_forYZ(*this,y,z) {
20459  if ((*this)(0,y,z,k)==isovalue) { is_isophote = true; res(0,y,z,k) = 0; } else res(0,y,z,k) = maxdist;
20460  for (int x = 1; x<dx; ++x) if ((*this)(x,y,z,k)==isovalue) { is_isophote = true; res(x,y,z,k) = 0; }
20461  else res(x,y,z,k) = res(x-1,y,z,k) + sizex;
20462  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;
20463  }
20464  if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<floatT>::max()); continue; }
20465  CImg<floatT> tmp(cimg::max(dy,dz));
20466  CImg<intT> s(tmp.width), t(s.width);
20467  cimg_forXZ(*this,x,z) {
20468  cimg_forY(*this,y) tmp[y] = res(x,y,z,k);
20469  int q = s[0] = t[0] = 0;
20470  for (int y = 1; y<dy; ++y) {
20471  const float val = tmp[y], val2 = val*val;
20472  while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizey)>_distance_f(t[q],y,val2,sizey)) --q;
20473  if (q<0) { q = 0; s[0] = y; }
20474  else {
20475  const int w = 1 + _distance_sep(s[q],y,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizey);
20476  if (w<dy) { s[++q] = y; t[q] = w; }
20477  }
20478  }
20479  for (int y = dy - 1; y>=0; --y) {
20480  res(x,y,z,k) = _distance_f(y,s[q],cimg::sqr(tmp[s[q]]),sizey);
20481  if (y==t[q]) --q;
20482  }
20483  }
20484  cimg_forXY(*this,x,y) {
20485  cimg_forZ(*this,z) tmp[z] = res(x,y,z,k);
20486  int q = s[0] = t[0] = 0;
20487  for (int z = 1; z<dz; ++z) {
20488  const float val = tmp[z];
20489  while (q>=0 && _distance_f(t(q),s[q],tmp[s[q]],sizez)>_distance_f(t[q],z,tmp[z],sizez)) --q;
20490  if (q<0) { q = 0; s[0] = z; }
20491  else {
20492  const int w = 1 + _distance_sep(s[q],z,(int)tmp[s[q]],(int)val,sizez);
20493  if (w<dz) { s[++q] = z; t[q] = w; }
20494  }
20495  }
20496  for (int z = dz - 1; z>=0; --z) {
20497  const float val = _distance_f(z,s[q],tmp[s[q]],sizez);
20498  res(x,y,z,k) = compute_sqrt?(float)std::sqrt(val):val;
20499  if (z==t[q]) --q;
20500  }
20501  }
20502  } else { // 2D version (with small optimizations)
20503  cimg_forX(*this,x) {
20504  const T *ptrs = ptr(x,0,0,k);
20505  float *ptrd = res.ptr(x,0,0,k), d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:maxdist;
20506  for (int y = 1; y<dy; ++y) { ptrs+=width; ptrd+=width; d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:d+sizey; }
20507  for (int y = dy - 2; y>=0; --y) { ptrd-=width; if (d<*ptrd) *ptrd = (d+=sizey); else d = *ptrd; }
20508  }
20509  if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<floatT>::max()); continue; }
20510  CImg<floatT> tmp(dx);
20511  CImg<intT> s(dx), t(dx);
20512  cimg_forY(*this,y) {
20513  float *ptmp = tmp.ptr();
20514  std::memcpy(ptmp,res.ptr(0,y,0,k),sizeof(float)*dx);
20515  int q = s[0] = t[0] = 0;
20516  for (int x = 1; x<dx; ++x) {
20517  const float val = *(++ptmp), val2 = val*val;
20518  while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizex)>_distance_f(t[q],x,val2,sizex)) --q;
20519  if (q<0) { q = 0; s[0] = x; }
20520  else {
20521  const int w = 1 + _distance_sep(s[q],x,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizex);
20522  if (w<dx) { q++; s[q] = x; t[q] = w; }
20523  }
20524  }
20525  float *pres = res.ptr(0,y,0,k) + width;
20526  for (int x = dx - 1; x>=0; --x) {
20527  const float val = _distance_f(x,s[q],cimg::sqr(tmp[s[q]]),sizex);
20528  *(--pres) = compute_sqrt?(float)std::sqrt(val):val;
20529  if (x==t[q]) --q;
20530  }
20531  }
20532  }
20533  }
20534  return res;
20535  }
20536 
20537  static float _distance_f(const int x, const int i, const float gi2, const float fact) {
20538  const float xmi = fact*((float)x - i);
20539  return xmi*xmi + gi2;
20540  }
20541  static int _distance_sep(const int i, const int u, const int gi2, const int gu2, const float fact) {
20542  const float fact2 = fact*fact;
20543  return (int)(fact2*(u*u - i*i) + gu2 - gi2)/(int)(2*fact2*(u - i));
20544  }
20545 
20547  CImg<T>& distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) {
20548  if (is_empty()) return *this;
20549  CImg<Tfloat> veloc(*this);
20550  for (unsigned int iter = 0; iter<nb_iter; ++iter) {
20551  veloc.fill(0);
20552  if (depth>1) { // 3D version
20553  CImg_3x3x3(I,T);
20554  cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) if (band_size<=0 || cimg::abs(Iccc)<band_size) {
20555  const Tfloat
20556  gx = 0.5f*((Tfloat)Incc - Ipcc),
20557  gy = 0.5f*((Tfloat)Icnc - Icpc),
20558  gz = 0.5f*((Tfloat)Iccn - Iccp),
20559  sgn = -cimg::sign((Tfloat)Iccc),
20560  ix = gx*sgn>0?(Tfloat)Incc - Iccc:(Tfloat)Iccc - Ipcc,
20561  iy = gy*sgn>0?(Tfloat)Icnc - Iccc:(Tfloat)Iccc - Icpc,
20562  iz = gz*sgn>0?(Tfloat)Iccn - Iccc:(Tfloat)Iccc - Iccp,
20563  ng = 1e-5f + (Tfloat)std::sqrt(gx*gx + gy*gy + gz*gz),
20564  ngx = gx/ng,
20565  ngy = gy/ng,
20566  ngz = gz/ng;
20567  veloc(x,y,z,k) = sgn*(ngx*ix + ngy*iy + ngz*iz - 1);
20568  }
20569  } else { // 2D version
20570  CImg_3x3(I,T);
20571  cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) if (band_size<=0 || cimg::abs(Icc)<band_size) {
20572  const Tfloat
20573  gx = 0.5f*((Tfloat)Inc - Ipc),
20574  gy = 0.5f*((Tfloat)Icn - Icp),
20575  sgn = -cimg::sign((Tfloat)Icc),
20576  ix = gx*sgn>0?(Tfloat)Inc - Icc:(Tfloat)Icc - Ipc,
20577  iy = gy*sgn>0?(Tfloat)Icn - Icc:(Tfloat)Icc - Icp,
20578  ng = 1e-5f + (Tfloat)std::sqrt(gx*gx + gy*gy),
20579  ngx = gx/ng,
20580  ngy = gy/ng;
20581  veloc(x,y,k) = sgn*(ngx*ix + ngy*iy - 1);
20582  }
20583  }
20584  float m, M = (float)veloc.maxmin(m), xdt = precision/(float)cimg::max(cimg::abs(m),cimg::abs(M));
20585  *this+=(veloc*=xdt);
20586  }
20587  return *this;
20588  }
20589 
20590  CImg<Tfloat> get_distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) const {
20591  return CImg<Tfloat>(*this,false).distance_hamilton(nb_iter,band_size,precision);
20592  }
20593 
20595 
20600  CImg<T>& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) {
20601  return get_haar(axis,invert,nb_scales).transfer_to(*this);
20602  }
20603 
20604  CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const {
20605  if (is_empty() || !nb_scales) return *this;
20606  CImg<Tfloat> res;
20607 
20608  if (nb_scales==1) {
20609  switch (cimg::uncase(axis)) { // Single scale transform
20610  case 'x' : {
20611  const unsigned int w = width/2;
20612  if (w) {
20613  if (w%2)
20614  throw CImgInstanceException("CImg<%s>::haar() : Sub-image width = %u is not even at a particular scale (=%u).",
20615  pixel_type(),w);
20616  res.assign(width,height,depth,dim);
20617  if (invert) cimg_forYZV(*this,y,z,v) { // Inverse transform along X
20618  for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) {
20619  const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(xw,y,z,v);
20620  res(x2++,y,z,v) = val0 - val1;
20621  res(x2++,y,z,v) = val0 + val1;
20622  }
20623  } else cimg_forYZV(*this,y,z,v) { // Direct transform along X
20624  for (unsigned int x = 0, xw = w, x2 = 0; x<w; ++x, ++xw) {
20625  const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,v), val1 = (Tfloat)(*this)(x2++,y,z,v);
20626  res(x,y,z,v) = (val0 + val1)/2;
20627  res(xw,y,z,v) = (val1 - val0)/2;
20628  }
20629  }
20630  } else return *this;
20631  } break;
20632  case 'y' : {
20633  const unsigned int h = height/2;
20634  if (h) {
20635  if (h%2)
20636  throw CImgInstanceException("CImg<%s>::haar() : Sub-image height = %u is not even at a particular scale.",
20637  pixel_type(),h);
20638  res.assign(width,height,depth,dim);
20639  if (invert) cimg_forXZV(*this,x,z,v) { // Inverse transform along Y
20640  for (unsigned int y = 0, yh = h, y2 = 0; y<h; ++y, ++yh) {
20641  const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,yh,z,v);
20642  res(x,y2++,z,v) = val0 - val1;
20643  res(x,y2++,z,v) = val0 + val1;
20644  }
20645  } else cimg_forXZV(*this,x,z,v) {
20646  for (unsigned int y = 0, yh = h, y2 = 0; y<h; ++y, ++yh) { // Direct transform along Y
20647  const Tfloat val0 = (Tfloat)(*this)(x,y2++,z,v), val1 = (Tfloat)(*this)(x,y2++,z,v);
20648  res(x,y,z,v) = (val0 + val1)/2;
20649  res(x,yh,z,v) = (val1 - val0)/2;
20650  }
20651  }
20652  } else return *this;
20653  } break;
20654  case 'z' : {
20655  const unsigned int d = depth/2;
20656  if (d) {
20657  if (d%2)
20658  throw CImgInstanceException("CImg<%s>::haar() : Sub-image depth = %u is not even at a particular scale.",
20659  pixel_type(),d);
20660  res.assign(width,height,depth,dim);
20661  if (invert) cimg_forXYV(*this,x,y,v) { // Inverse transform along Z
20662  for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) {
20663  const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,y,zd,v);
20664  res(x,y,z2++,v) = val0 - val1;
20665  res(x,y,z2++,v) = val0 + val1;
20666  }
20667  } else cimg_forXYV(*this,x,y,v) {
20668  for (unsigned int z = 0, zd = d, z2 = 0; z<d; ++z, ++zd) { // Direct transform along Z
20669  const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,v), val1 = (Tfloat)(*this)(x,y,z2++,v);
20670  res(x,y,z,v) = (val0 + val1)/2;
20671  res(x,y,zd,v) = (val1 - val0)/2;
20672  }
20673  }
20674  } else return *this;
20675  } break;
20676  default :
20677  throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
20678  pixel_type(),axis);
20679  }
20680  } else { // Multi-scale version
20681  if (invert) {
20682  res.assign(*this);
20683  switch (cimg::uncase(axis)) {
20684  case 'x' : {
20685  unsigned int w = width;
20686  for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
20687  for (w=w?w:1; w<=width; w*=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',true,1));
20688  } break;
20689  case 'y' : {
20690  unsigned int h = width;
20691  for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
20692  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));
20693  } break;
20694  case 'z' : {
20695  unsigned int d = depth;
20696  for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
20697  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));
20698  } break;
20699  default :
20700  throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
20701  pixel_type(),axis);
20702  }
20703  } else { // Direct transform
20704  res = get_haar(axis,false,1);
20705  switch (cimg::uncase(axis)) {
20706  case 'x' : {
20707  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));
20708  } break;
20709  case 'y' : {
20710  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));
20711  } break;
20712  case 'z' : {
20713  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));
20714  } break;
20715  default :
20716  throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
20717  pixel_type(),axis);
20718  }
20719  }
20720  }
20721  return res;
20722  }
20723 
20725 
20729  CImg<T>& haar(const bool invert=false, const unsigned int nb_scales=1) {
20730  return get_haar(invert,nb_scales).transfer_to(*this);
20731  }
20732 
20733  CImg<Tfloat> get_haar(const bool invert=false, const unsigned int nb_scales=1) const {
20734  CImg<Tfloat> res;
20735 
20736  if (nb_scales==1) { // Single scale transform
20737  if (width>1) get_haar('x',invert,1).transfer_to(res);
20738  if (height>1) { if (res) res.get_haar('y',invert,1).transfer_to(res); else get_haar('y',invert,1).transfer_to(res); }
20739  if (depth>1) { if (res) res.get_haar('z',invert,1).transfer_to(res); else get_haar('z',invert,1).transfer_to(res); }
20740  if (res) return res;
20741  } else { // Multi-scale transform
20742  if (invert) { // Inverse transform
20743  res.assign(*this);
20744  if (width>1) {
20745  if (height>1) {
20746  if (depth>1) {
20747  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; }
20748  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)
20749  res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).get_haar(true,1));
20750  } else {
20751  unsigned int w = width, h = height; for (unsigned int s=1; w && h && s<nb_scales; ++s) { w/=2; h/=2; }
20752  for (w=w?w:1, h=h?h:1; w<=width && h<=height; w*=2, h*=2)
20753  res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).get_haar(true,1));
20754  }
20755  } else {
20756  if (depth>1) {
20757  unsigned int w = width, d = depth; for (unsigned int s=1; w && d && s<nb_scales; ++s) { w/=2; d/=2; }
20758  for (w=w?w:1, d=d?d:1; w<=width && d<=depth; w*=2, d*=2)
20759  res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).get_haar(true,1));
20760  } else {
20761  unsigned int w = width; for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
20762  for (w=w?w:1; w<=width; w*=2)
20763  res.draw_image(res.get_crop(0,0,0,w-1,0,0).get_haar(true,1));
20764  }
20765  }
20766  } else {
20767  if (height>1) {
20768  if (depth>1) {
20769  unsigned int h = height, d = depth; for (unsigned int s=1; h && d && s<nb_scales; ++s) { h/=2; d/=2; }
20770  for (h=h?h:1, d=d?d:1; h<=height && d<=depth; h*=2, d*=2)
20771  res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).get_haar(true,1));
20772  } else {
20773  unsigned int h = height; for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
20774  for (h=h?h:1; h<=height; h*=2)
20775  res.draw_image(res.get_crop(0,0,0,0,h-1,0).get_haar(true,1));
20776  }
20777  } else {
20778  if (depth>1) {
20779  unsigned int d = depth; for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
20780  for (d=d?d:1; d<=depth; d*=2)
20781  res.draw_image(res.get_crop(0,0,0,0,0,d-1).get_haar(true,1));
20782  } else return *this;
20783  }
20784  }
20785  } else { // Direct transform
20786  res = get_haar(false,1);
20787  if (width>1) {
20788  if (height>1) {
20789  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)
20790  res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).haar(false,1));
20791  else for (unsigned int s=1, w=width/2, h=height/2; w && h && s<nb_scales; ++s, w/=2, h/=2)
20792  res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).haar(false,1));
20793  } else {
20794  if (depth>1) for (unsigned int s=1, w=width/2, d=depth/2; w && d && s<nb_scales; ++s, w/=2, d/=2)
20795  res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).haar(false,1));
20796  else for (unsigned int s=1, w=width/2; w && s<nb_scales; ++s, w/=2)
20797  res.draw_image(res.get_crop(0,0,0,w-1,0,0).haar(false,1));
20798  }
20799  } else {
20800  if (height>1) {
20801  if (depth>1) for (unsigned int s=1, h=height/2, d=depth/2; h && d && s<nb_scales; ++s, h/=2, d/=2)
20802  res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).haar(false,1));
20803  else for (unsigned int s=1, h=height/2; h && s<nb_scales; ++s, h/=2)
20804  res.draw_image(res.get_crop(0,0,0,0,h-1,0).haar(false,1));
20805  } else {
20806  if (depth>1) for (unsigned int s=1, d=depth/2; d && s<nb_scales; ++s, d/=2)
20807  res.draw_image(res.get_crop(0,0,0,0,0,d-1).haar(false,1));
20808  else return *this;
20809  }
20810  }
20811  }
20812  return res;
20813  }
20814  return *this;
20815  }
20816 
20818  CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
20819  CImgList<Tfloat> res(*this,CImg<Tfloat>());
20820  CImg<Tfloat>::FFT(res[0],res[1],axis,invert);
20821  return res;
20822  }
20823 
20825  CImgList<Tfloat> get_FFT(const bool invert=false) const {
20826  CImgList<Tfloat> res(*this,CImg<Tfloat>());
20827  CImg<Tfloat>::FFT(res[0],res[1],invert);
20828  return res;
20829  }
20830 
20832  static void FFT(CImg<T>& real, CImg<T>& imag, const char axis, const bool invert=false) {
20833  if (!real) throw CImgInstanceException("CImg<%s>::FFT() : Input real image is empty.",pixel_type());
20834  if (!imag) imag.assign(real.width,real.height,real.depth,real.dim,0);
20835  if (!real.is_sameXYZV(imag))
20836  throw CImgInstanceException("CImg<%s>::FFT() : Real image (%u,%u,%u,%u,%p) and imaginary image (%u,%u,%u,%u,%p) "
20837  "have different dimensions",
20838  pixel_type(),real.width,real.height,real.depth,real.dim,real.data,
20839  imag.width,imag.height,imag.depth,imag.dim,imag.data);
20840 #ifdef cimg_use_fftw3
20841  fftw_complex *data_in;
20842  fftw_plan data_plan;
20843 
20844  switch (cimg::uncase(axis)) {
20845  case 'x' : { // Fourier along X, using FFTW library.
20846  data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real.width);
20847  data_plan = fftw_plan_dft_1d(real.width,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
20848  cimg_forYZV(real,y,z,k) {
20849  T *ptrr = real.ptr(0,y,z,k), *ptri = imag.ptr(0,y,z,k);
20850  double *ptrd = (double*)data_in;
20851  cimg_forX(real,x) { *(ptrd++) = (double)*(ptrr++); *(ptrd++) = (double)*(ptri++); }
20852  fftw_execute(data_plan);
20853  const unsigned int fact = real.width;
20854  if (invert) cimg_forX(real,x) { *(--ptri) = (T)(*(--ptrd)/fact); *(--ptrr) = (T)(*(--ptrd)/fact); }
20855  else cimg_forX(real,x) { *(--ptri) = (T)*(--ptrd); *(--ptrr) = (T)*(--ptrd); }
20856  }
20857  } break;
20858  case 'y' : { // Fourier along Y, using FFTW library.
20859  data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real.height);
20860  data_plan = fftw_plan_dft_1d(real.height,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
20861  const unsigned int off = real.width;
20862  cimg_forXZV(real,x,z,k) {
20863  T *ptrr = real.ptr(x,0,z,k), *ptri = imag.ptr(x,0,z,k);
20864  double *ptrd = (double*)data_in;
20865  cimg_forY(real,y) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
20866  fftw_execute(data_plan);
20867  const unsigned int fact = real.height;
20868  if (invert) cimg_forY(real,y) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }
20869  else cimg_forY(real,y) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }
20870  }
20871  } break;
20872  case 'z' : { // Fourier along Z, using FFTW library.
20873  data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real.depth);
20874  data_plan = fftw_plan_dft_1d(real.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
20875  const unsigned int off = real.width*real.height;
20876  cimg_forXYV(real,x,y,k) {
20877  T *ptrr = real.ptr(x,y,0,k), *ptri = imag.ptr(x,y,0,k);
20878  double *ptrd = (double*)data_in;
20879  cimg_forZ(real,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
20880  fftw_execute(data_plan);
20881  const unsigned int fact = real.depth;
20882  if (invert) cimg_forZ(real,z) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }
20883  else cimg_forZ(real,z) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }
20884  }
20885  } break;
20886  case 'v' : { // Fourier along V, using FFTW library.
20887  data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * real.dim);
20888  data_plan = fftw_plan_dft_1d(real.dim,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
20889  const unsigned int off = real.width*real.height*real.depth;
20890  cimg_forXYZ(real,x,y,z) {
20891  T *ptrr = real.ptr(x,y,z,0), *ptri = imag.ptr(x,y,z,0);
20892  double *ptrd = (double*)data_in;
20893  cimg_forV(real,k) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
20894  fftw_execute(data_plan);
20895  const unsigned int fact = real.dim;
20896  if (invert) cimg_forV(real,k) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }
20897  else cimg_forV(real,k) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }
20898  }
20899  } break;
20900  }
20901  fftw_destroy_plan(data_plan);
20902  fftw_free(data_in);
20903 #else
20904  switch (cimg::uncase(axis)) {
20905  case 'x' : { // Fourier along X, using built-in functions.
20906  const unsigned int N = real.width, N2 = (N>>1);
20907  if (((N-1)&N) && N!=1)
20908  throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image along 'x' is %d != 2^N",
20909  pixel_type(),N);
20910  for (unsigned int i = 0, j = 0; i<N2; ++i) {
20911  if (j>i) cimg_forYZV(real,y,z,v) { cimg::swap(real(i,y,z,v),real(j,y,z,v)); cimg::swap(imag(i,y,z,v),imag(j,y,z,v));
20912  if (j<N2) {
20913  const unsigned int ri = N-1-i, rj = N-1-j;
20914  cimg::swap(real(ri,y,z,v),real(rj,y,z,v)); cimg::swap(imag(ri,y,z,v),imag(rj,y,z,v));
20915  }}
20916  for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}
20917  }
20918  for (unsigned int delta = 2; delta<=N; delta<<=1) {
20919  const unsigned int delta2 = (delta>>1);
20920  for (unsigned int i = 0; i<N; i+=delta) {
20921  float wr = 1, wi = 0;
20922  const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
20923  ca = (float)std::cos(angle),
20924  sa = (float)std::sin(angle);
20925  for (unsigned int k = 0; k<delta2; ++k) {
20926  const unsigned int j = i + k, nj = j + delta2;
20927  cimg_forYZV(real,y,z,k) {
20928  T &ir = real(j,y,z,k), &ii = imag(j,y,z,k), &nir = real(nj,y,z,k), &nii = imag(nj,y,z,k);
20929  const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
20930  nir = (T)(ir - tmpr);
20931  nii = (T)(ii - tmpi);
20932  ir += (T)tmpr;
20933  ii += (T)tmpi;
20934  }
20935  const float nwr = wr*ca-wi*sa;
20936  wi = wi*ca + wr*sa;
20937  wr = nwr;
20938  }
20939  }
20940  }
20941  if (invert) { real/=N; imag/=N; }
20942  } break;
20943  case 'y' : { // Fourier along Y, using built-in functions.
20944  const unsigned int N = real.height, N2 = (N>>1);
20945  if (((N-1)&N) && N!=1)
20946  throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'y' is %d != 2^N",
20947  pixel_type(),N);
20948  for (unsigned int i = 0, j = 0; i<N2; ++i) {
20949  if (j>i) cimg_forXZV(real,x,z,v) { cimg::swap(real(x,i,z,v),real(x,j,z,v)); cimg::swap(imag(x,i,z,v),imag(x,j,z,v));
20950  if (j<N2) {
20951  const unsigned int ri = N-1-i, rj = N-1-j;
20952  cimg::swap(real(x,ri,z,v),real(x,rj,z,v)); cimg::swap(imag(x,ri,z,v),imag(x,rj,z,v));
20953  }}
20954  for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}
20955  }
20956  for (unsigned int delta = 2; delta<=N; delta<<=1) {
20957  const unsigned int delta2 = (delta>>1);
20958  for (unsigned int i = 0; i<N; i+=delta) {
20959  float wr = 1, wi = 0;
20960  const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
20961  ca = (float)std::cos(angle), sa = (float)std::sin(angle);
20962  for (unsigned int k = 0; k<delta2; ++k) {
20963  const unsigned int j = i + k, nj = j + delta2;
20964  cimg_forXZV(real,x,z,k) {
20965  T &ir = real(x,j,z,k), &ii = imag(x,j,z,k), &nir = real(x,nj,z,k), &nii = imag(x,nj,z,k);
20966  const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
20967  nir = (T)(ir - tmpr);
20968  nii = (T)(ii - tmpi);
20969  ir += (T)tmpr;
20970  ii += (T)tmpi;
20971  }
20972  const float nwr = wr*ca-wi*sa;
20973  wi = wi*ca + wr*sa;
20974  wr = nwr;
20975  }
20976  }
20977  }
20978  if (invert) { real/=N; imag/=N; }
20979  } break;
20980  case 'z' : { // Fourier along Z, using built-in functions.
20981  const unsigned int N = real.depth, N2 = (N>>1);
20982  if (((N-1)&N) && N!=1)
20983  throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'z' is %d != 2^N",
20984  pixel_type(),N);
20985  for (unsigned int i = 0, j = 0; i<N2; ++i) {
20986  if (j>i) cimg_forXYV(real,x,y,v) { cimg::swap(real(x,y,i,v),real(x,y,j,v)); cimg::swap(imag(x,y,i,v),imag(x,y,j,v));
20987  if (j<N2) {
20988  const unsigned int ri = N-1-i, rj = N-1-j;
20989  cimg::swap(real(x,y,ri,v),real(x,y,rj,v)); cimg::swap(imag(x,y,ri,v),imag(x,y,rj,v));
20990  }}
20991  for (unsigned int m = N, n = N2; (j+=n)>=m; j-=m, m = n, n>>=1) {}
20992  }
20993  for (unsigned int delta = 2; delta<=N; delta<<=1) {
20994  const unsigned int delta2 = (delta>>1);
20995  for (unsigned int i = 0; i<N; i+=delta) {
20996  float wr = 1, wi = 0;
20997  const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
20998  ca = (float)std::cos(angle), sa = (float)std::sin(angle);
20999  for (unsigned int k = 0; k<delta2; ++k) {
21000  const unsigned int j = i + k, nj = j + delta2;
21001  cimg_forXYV(real,x,y,k) {
21002  T &ir = real(x,y,j,k), &ii = imag(x,y,j,k), &nir = real(x,y,nj,k), &nii = imag(x,y,nj,k);
21003  const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
21004  nir = (T)(ir - tmpr);
21005  nii = (T)(ii - tmpi);
21006  ir += (T)tmpr;
21007  ii += (T)tmpi;
21008  }
21009  const float nwr = wr*ca-wi*sa;
21010  wi = wi*ca + wr*sa;
21011  wr = nwr;
21012  }
21013  }
21014  }
21015  if (invert) { real/=N; imag/=N; }
21016  } break;
21017  default :
21018  throw CImgArgumentException("CImgList<%s>::FFT() : Invalid axis '%c', must be 'x','y' or 'z'.");
21019  }
21020 #endif
21021  }
21022 
21024  static void FFT(CImg<T>& real, CImg<T>& imag, const bool invert=false) {
21025  if (!real) throw CImgInstanceException("CImgList<%s>::FFT() : Input real image is empty.",pixel_type());
21026  if (!imag) imag.assign(real.width,real.height,real.depth,real.dim,0);
21027  if (!real.is_sameXYZV(imag))
21028  throw CImgInstanceException("CImgList<%s>::FFT() : Real image (%u,%u,%u,%u,%p) and imaginary image (%u,%u,%u,%u,%p) "
21029  "have different dimensions",
21030  pixel_type(),real.width,real.height,real.depth,real.dim,real.data,
21031  imag.width,imag.height,imag.depth,imag.dim,imag.data);
21032 #ifdef cimg_use_fftw3
21033  fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real.width*real.height*real.depth);
21034  fftw_plan data_plan;
21035  const unsigned int w = real.width, wh = w*real.height, whd = wh*real.depth;
21036  data_plan = fftw_plan_dft_3d(real.width,real.height,real.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
21037  cimg_forV(real,k) {
21038  T *ptrr = real.ptr(0,0,0,k), *ptri = imag.ptr(0,0,0,k);
21039  double *ptrd = (double*)data_in;
21040  for (unsigned int x = 0; x<real.width; ++x, ptrr-=wh-1, ptri-=wh-1)
21041  for (unsigned int y = 0; y<real.height; ++y, ptrr-=whd-w, ptri-=whd-w)
21042  for (unsigned int z = 0; z<real.depth; ++z, ptrr+=wh, ptri+=wh) {
21043  *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri;
21044  }
21045  fftw_execute(data_plan);
21046  ptrd = (double*)data_in;
21047  ptrr = real.ptr(0,0,0,k);
21048  ptri = imag.ptr(0,0,0,k);
21049  if (!invert) for (unsigned int x = 0; x<real.width; ++x, ptrr-=wh-1, ptri-=wh-1)
21050  for (unsigned int y = 0; y<real.height; ++y, ptrr-=whd-w, ptri-=whd-w)
21051  for (unsigned int z = 0; z<real.depth; ++z, ptrr+=wh, ptri+=wh) {
21052  *ptrr = (T)*(ptrd++); *ptri = (T)*(ptrd++);
21053  }
21054  else for (unsigned int x = 0; x<real.width; ++x, ptrr-=wh-1, ptri-=wh-1)
21055  for (unsigned int y = 0; y<real.height; ++y, ptrr-=whd-w, ptri-=whd-w)
21056  for (unsigned int z = 0; z<real.depth; ++z, ptrr+=wh, ptri+=wh) {
21057  *ptrr = (T)(*(ptrd++)/whd); *ptri = (T)(*(ptrd++)/whd);
21058  }
21059  }
21060  fftw_destroy_plan(data_plan);
21061  fftw_free(data_in);
21062 #else
21063  if (real.depth>1) FFT(real,imag,'z',invert);
21064  if (real.height>1) FFT(real,imag,'y',invert);
21065  if (real.width>1) FFT(real,imag,'x',invert);
21066 #endif
21067  }
21068 
21070  //-------------------------------------
21071  //
21073 
21074  //-------------------------------------
21075 
21077  CImg<T>& translate_object3d(const float tx, const float ty=0, const float tz=0) {
21078  if (is_empty()) return *this;
21079  if (height!=3 || depth>1 || dim>1)
21080  throw CImgInstanceException("CImg<%s>::translate_object3d() : Instance image (%u,%u,%u,%u,%p) is not a set of 3D vertices.",
21081  pixel_type(),width,height,depth,dim,data);
21082  get_shared_line(0)+=tx; get_shared_line(1)+=ty; get_shared_line(2)+=tz;
21083  return *this;
21084  }
21085 
21086  CImg<Tfloat> get_translate_object3d(const float tx, const float ty=0, const float tz=0) const {
21087  return CImg<Tfloat>(*this,false).translate_object3d(tx,ty,tz);
21088  }
21089 
21092  if (is_empty()) return *this;
21093  if (height!=3 || depth>1 || dim>1)
21094  throw CImgInstanceException("CImg<%s>::translate_object3d() : Instance image (%u,%u,%u,%u,%p) is not a set of 3D vertices.",
21095  pixel_type(),width,height,depth,dim,data);
21096  CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
21097  float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
21098  xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2;
21099  return *this;
21100  }
21101 
21103  return CImg<Tfloat>(*this,false).translate_object3d();
21104  }
21105 
21107  CImg<T>& resize_object3d(const float sx, const float sy=-100, const float sz=-100) {
21108  if (is_empty()) return *this;
21109  if (height!=3 || depth>1 || dim>1)
21110  throw CImgInstanceException("CImg<%s>::resize_object3d() : Instance image (%u,%u,%u,%u,%p) is not a set of 3D vertices.",
21111  pixel_type(),width,height,depth,dim,data);
21112  CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
21113  float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
21114  if (xm<xM) { if (sx>0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; }
21115  if (ym<yM) { if (sy>0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; }
21116  if (zm<zM) { if (sz>0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; }
21117  return *this;
21118  }
21119 
21120  CImg<Tfloat> get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const {
21121  return CImg<Tfloat>(*this,false).resize_object3d(sx,sy,sz);
21122  }
21123 
21126  if (is_empty()) return *this;
21127  if (height!=3 || depth>1 || dim>1)
21128  throw CImgInstanceException("CImg<%s>::resize_object3d() : Instance image (%u,%u,%u,%u,%p) is not a set of 3D vertices.",
21129  pixel_type(),width,height,depth,dim,data);
21130  CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
21131  float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
21132  const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz);
21133  if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; }
21134  return *this;
21135  }
21136 
21138  return CImg<Tfloat>(*this,false).resize_object3d();
21139  }
21140 
21142  template<typename tf, typename tp, typename tff>
21143  CImg<T>& append_object3d(CImgList<tf>& primitives, const CImg<tp>& obj_vertices, const CImgList<tff>& obj_primitives) {
21144  if (!obj_vertices || !obj_primitives) return *this;
21145  if (obj_vertices.height!=3 || obj_vertices.depth>1 || obj_vertices.dim>1)
21146  throw CImgInstanceException("CImg<%s>::append_object3d() : Vertice image argument (%u,%u,%u,%u,%p) is not a set of 3D vertices.",
21147  pixel_type(),obj_vertices.width,obj_vertices.height,obj_vertices.depth,obj_vertices.dim,obj_vertices.data);
21148  if (is_empty()) { primitives.assign(obj_primitives); return assign(obj_vertices); }
21149  if (height!=3 || depth>1 || dim>1)
21150  throw CImgInstanceException("CImg<%s>::append_object3d() : Instance image (%u,%u,%u,%u,%p) is not a set of 3D vertices.",
21151  pixel_type(),width,height,depth,dim,data);
21152  const unsigned int P = width;
21153  append(obj_vertices,'x');
21154  const unsigned int N = primitives.width;
21155  primitives.insert(obj_primitives);
21156  for (unsigned int i = N; i<primitives.width; ++i) {
21157  CImg<tf> &p = primitives[i];
21158  switch (p.size()) {
21159  case 1 : p[0]+=P; break; // Point.
21160  case 5 : p[0]+=P; if (!p[2]) p[1]+=P; break; // Sphere.
21161  case 2 : case 6 : p[0]+=P; p[1]+=P; break; // Segment.
21162  case 3 : case 9 : p[0]+=P; p[1]+=P; p[2]+=P; break; // Triangle.
21163  case 4 : case 12 : p[0]+=P; p[1]+=P; p[2]+=P; p[3]+=P; break; // Rectangle.
21164  }
21165  }
21166  return *this;
21167  }
21168 
21170 
21186  template<typename tf, typename tc, typename te>
21187  CImg<floatT> get_elevation3d(CImgList<tf>& primitives, CImgList<tc>& colors, const CImg<te>& elevation) const {
21188  if (is_empty()) return *this;
21189  if (!is_sameXY(elevation) || elevation.depth>1 || elevation.dim>1)
21190  throw CImgArgumentException("CImg<%s>::get_elevation3d() : Elevation image (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) "
21191  "have incompatible sizes.",pixel_type(),
21192  elevation.width,elevation.height,elevation.depth,elevation.dim,elevation.data,
21193  width,height,depth,dim,data,pixel_type());
21194  float m, M = (float)maxmin(m);
21195  if (M==m) ++M;
21196  colors.assign();
21197  const unsigned int size_x1 = width - 1, size_y1 = height - 1;
21198  for (unsigned int y = 0; y<size_y1; ++y)
21199  for (unsigned int x = 0; x<size_x1; x++) {
21200  const unsigned char
21201  r = (unsigned char)(((*this)(x,y,0) - m)*255/(M-m)),
21202  g = dim>1?(unsigned char)(((*this)(x,y,1) - m)*255/(M-m)):r,
21203  b = dim>2?(unsigned char)(((*this)(x,y,2) - m)*255/(M-m)):(dim>1?0:r);
21204  CImg<tc>::vector((tc)r,(tc)g,(tc)b).transfer_to(colors);
21205  }
21206  const typename CImg<te>::_marching2d_func func(elevation);
21207  return elevation3d(primitives,func,0,0,width-1.0f,height-1.0f,width,height);
21208  }
21209 
21211 
21227  template<typename tf>
21229  const float isovalue, const int size_x=-100, const int size_y=-100) const {
21230  if (dim>1)
21231  throw CImgInstanceException("CImg<%s>::get_isocurve3d() : Instance image (%u,%u,%u,%u,%p) is not scalar.",
21232  pixel_type(),width,height,depth,dim,data);
21233  primitives.assign();
21234  if (is_empty()) return *this;
21235  CImg<floatT> vertices;
21236  if ((size_x==-100 && size_y==-100) || (size_x==dimx() && size_y==dimy())) {
21237  const _marching2d_func func(*this);
21238  vertices = isocurve3d(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,size_x,size_y);
21239  } else {
21240  const _marching2d_func_float func(*this);
21241  vertices = isocurve3d(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,size_x,size_y);
21242  }
21243  return vertices;
21244  }
21245 
21247 
21263  template<typename tf>
21264  CImg<floatT> get_isosurface3d(CImgList<tf>& primitives, const float isovalue,
21265  const int size_x=-100, const int size_y=-100, const int size_z=-100) const {
21266  if (dim>1)
21267  throw CImgInstanceException("CImg<%s>::get_isosurface3d() : Instance image (%u,%u,%u,%u,%p) is not scalar.",
21268  pixel_type(),width,height,depth,dim,data);
21269  primitives.assign();
21270  if (is_empty()) return *this;
21271  CImg<floatT> vertices;
21272  if ((size_x==-100 && size_y==-100 && size_z==-100) || (size_x==dimx() && size_y==dimy() && size_z==dimz())) {
21273  const _marching3d_func func(*this);
21274  vertices = isosurface3d(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,size_x,size_y,size_z);
21275  } else {
21276  const _marching3d_func_float func(*this);
21277  vertices = isosurface3d(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,size_x,size_y,size_z);
21278  }
21279  return vertices;
21280  }
21281 
21283  template<typename tf, typename tfunc>
21284  static CImg<floatT> elevation3d(CImgList<tf>& primitives, const tfunc& func,
21285  const float x0, const float y0, const float x1, const float y1,
21286  const int size_x=256, const int size_y=256) {
21287  const float
21288  nx0 = x0<x1?x0:x1, ny0 = y0<y1?y0:y1,
21289  nx1 = x0<x1?x1:x0, ny1 = y0<y1?y1:y0;
21290  const unsigned int
21291  _nsize_x = (unsigned int)(size_x>=0?size_x:(nx1-nx0)*-size_x/100), nsize_x = _nsize_x?_nsize_x:1, nsize_x1 = nsize_x - 1,
21292  _nsize_y = (unsigned int)(size_y>=0?size_y:(ny1-ny0)*-size_y/100), nsize_y = _nsize_y?_nsize_y:1, nsize_y1 = nsize_y - 1;
21293  if (nsize_x<2 || nsize_y<2)
21294  throw CImgArgumentException("CImg<%s>::elevation3d() : Invalid requested size (%d,%d).",
21295  pixel_type(),nsize_x,nsize_y);
21296  CImg<floatT> vertices(nsize_x*nsize_y,3);
21297  floatT *ptr_x = vertices.ptr(0,0), *ptr_y = vertices.ptr(0,1), *ptr_z = vertices.ptr(0,2);
21298  for (unsigned int y = 0; y<nsize_y; ++y) {
21299  const float Y = ny0 + y*(ny1-ny0)/nsize_y1;
21300  for (unsigned int x = 0; x<nsize_x; ++x) {
21301  const float X = nx0 + x*(nx1-nx0)/nsize_x1;
21302  *(ptr_x++) = (float)x;
21303  *(ptr_y++) = (float)y;
21304  *(ptr_z++) = (float)func(X,Y);
21305  }
21306  }
21307  primitives.assign(nsize_x1*nsize_y1,1,4);
21308  for (unsigned int p = 0, y = 0; y<nsize_y1; ++y) {
21309  const unsigned int yw = y*nsize_x;
21310  for (unsigned int x = 0; x<nsize_x1; ++x) {
21311  const unsigned int xpyw = x + yw, xpyww = xpyw + nsize_x;
21312  primitives[p++].fill(xpyw,xpyww,xpyww+1,xpyw+1);
21313  }
21314  }
21315  return vertices;
21316  }
21317 
21318  template<typename tf>
21319  static CImg<floatT> elevation3d(CImgList<tf>& primitives, const char *const expression,
21320  const float x0, const float y0, const float x1, const float y1,
21321  const int sizex=256, const int sizey=256) {
21322  const _marching2d_func_expr func(expression);
21323  return elevation3d(primitives,func,x0,y0,x1,y1,sizex,sizey);
21324  }
21325 
21327  template<typename tf, typename tfunc>
21328  static CImg<floatT> isocurve3d(CImgList<tf>& primitives, const tfunc& func, const float isovalue,
21329  const float x0, const float y0, const float x1, const float y1,
21330  const int sizex=256, const int sizey=256) {
21331  static const unsigned int edges[16] = { 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc, 0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 };
21332  static const int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 },
21333  { 1,2,-1,-1 }, { 0,1,2,3 }, { 0,2,-1,-1 }, { 2,3,-1,-1 },
21334  { 2,3,-1,-1 }, { 0,2,-1,-1}, { 0,3,1,2 }, { 1,2,-1,-1 },
21335  { 1,3,-1,-1 }, { 0,1,-1,-1}, { 0,3,-1,-1}, { -1,-1,-1,-1 } };
21336  const unsigned int
21337  _nx = (unsigned int)(sizex>=0?sizex:((x1-x0)*-sizex/100 + 1)),
21338  _ny = (unsigned int)(sizey>=0?sizey:((y1-y0)*-sizey/100 + 1)),
21339  nx = _nx?_nx:1,
21340  ny = _ny?_ny:1,
21341  nxm1 = nx - 1,
21342  nym1 = ny - 1;
21343  primitives.assign();
21344  if (!nxm1 || !nym1) return CImg<floatT>();
21345  const float dx = (x1 - x0)/nxm1, dy = (y1 - y0)/nym1;
21346  CImgList<floatT> vertices;
21347  CImg<intT> indices1(nx,1,1,2,-1), indices2(nx,1,1,2);
21348  CImg<floatT> values1(nx), values2(nx);
21349  float X = x0, Y = y0, nX = X + dx, nY = Y + dy;
21350 
21351  // Fill first line with values
21352  cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=dx; }
21353 
21354  // Run the marching squares algorithm
21355  for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y=nY, nY+=dy) {
21356  X = x0; nX = X + dx;
21357  indices2.fill(-1);
21358  for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X=nX, nX+=dx) {
21359 
21360  // Determine square configuration
21361  const float
21362  val0 = values1(xi),
21363  val1 = values1(nxi),
21364  val2 = values2(nxi) = (float)func(nX,nY),
21365  val3 = values2(xi) = (float)func(X,nY);
21366  const unsigned int
21367  configuration = (val0<isovalue?1:0) | (val1<isovalue?2:0) | (val2<isovalue?4:0) | (val3<isovalue?8:0),
21368  edge = edges[configuration];
21369 
21370  // Compute intersection vertices
21371  if (edge) {
21372  if ((edge&1) && indices1(xi,0)<0) {
21373  const float Xi = X + (isovalue-val0)*dx/(val1-val0);
21374  indices1(xi,0) = vertices.width;
21375  CImg<floatT>::vector(Xi,Y,0).transfer_to(vertices);
21376  }
21377  if ((edge&2) && indices1(nxi,1)<0) {
21378  const float Yi = Y + (isovalue-val1)*dy/(val2-val1);
21379  indices1(nxi,1) = vertices.width;
21380  CImg<floatT>::vector(nX,Yi,0).transfer_to(vertices);
21381  }
21382  if ((edge&4) && indices2(xi,0)<0) {
21383  const float Xi = X + (isovalue-val3)*dx/(val2-val3);
21384  indices2(xi,0) = vertices.width;
21385  CImg<floatT>::vector(Xi,nY,0).transfer_to(vertices);
21386  }
21387  if ((edge&8) && indices1(xi,1)<0) {
21388  const float Yi = Y + (isovalue-val0)*dy/(val3-val0);
21389  indices1(xi,1) = vertices.width;
21390  CImg<floatT>::vector(X,Yi,0).transfer_to(vertices);
21391  }
21392 
21393  // Create segments
21394  for (const int *segment = segments[configuration]; *segment!=-1; ) {
21395  const unsigned int p0 = *(segment++), p1 = *(segment++);
21396  const tf
21397  i0 = (tf)(_marching2d_indice(p0,indices1,indices2,xi,nxi)),
21398  i1 = (tf)(_marching2d_indice(p1,indices1,indices2,xi,nxi));
21399  CImg<tf>::vector(i0,i1).transfer_to(primitives);
21400  }
21401  }
21402  }
21403  values1.swap(values2);
21404  indices1.swap(indices2);
21405  }
21406  return vertices>'x';
21407  }
21408 
21409  template<typename tf>
21410  static CImg<floatT> isocurve3d(CImgList<tf>& primitives, const char *const expression, const float isovalue,
21411  const float x0, const float y0, const float x1, const float y1,
21412  const int sizex=256, const int sizey=256) {
21413  const _marching2d_func_expr func(expression);
21414  return isocurve3d(primitives,func,isovalue,x0,y0,x1,y1,sizex,sizey);
21415  }
21416 
21417  template<typename t>
21418  static int _marching2d_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
21419  const unsigned int x, const unsigned int nx) {
21420  switch (edge) {
21421  case 0 : return (int)indices1(x,0);
21422  case 1 : return (int)indices1(nx,1);
21423  case 2 : return (int)indices2(x,0);
21424  case 3 : return (int)indices1(x,1);
21425  }
21426  return 0;
21427  }
21428 
21430  const CImg<T>& ref;
21431  _marching2d_func(const CImg<T>& pref):ref(pref) {}
21432  float operator()(const float x, const float y) const {
21433  return (float)ref((int)x,(int)y);
21434  }
21435  };
21436 
21438  const CImg<T>& ref;
21439  _marching2d_func_float(const CImg<T>& pref):ref(pref) {}
21440  float operator()(const float x, const float y) const {
21441  return (float)ref._linear_atXY(x,y);
21442  }
21443  };
21444 
21447  _marching2d_func_expr(const char *const expr):mp(0) {
21448  mp = new _cimg_math_parser(expr,"isovalue2d");
21449  }
21450  float operator()(const float x, const float y) const {
21451  return (float)mp->eval(x,y,0,0);
21452  }
21454  if (mp) delete mp;
21455  }
21456  };
21457 
21459  template<typename tf, typename tfunc>
21460  static CImg<floatT> isosurface3d(CImgList<tf>& primitives, const tfunc& func, const float isovalue,
21461  const float x0, const float y0, const float z0,
21462  const float x1, const float y1, const float z1,
21463  const int size_x=32, const int size_y=32, const int size_z=32) {
21464  static unsigned int edges[256] = {
21465  0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
21466  0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
21467  0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
21468  0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
21469  0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
21470  0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
21471  0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
21472  0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
21473  0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
21474  0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
21475  0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
21476  0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
21477  0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
21478  0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
21479  0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
21480  0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 };
21481 
21482  static int triangles[256][16] =
21483  {{ -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 },
21484  { 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 },
21485  { 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 },
21486  { 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 },
21487  { 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 },
21488  { 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 },
21489  { 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 },
21490  { 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 },
21491  { 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 },
21492  { 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 },
21493  { 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 },
21494  { 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 },
21495  { 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 },
21496  { 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 },
21497  { 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 },
21498  { 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 },
21499  { 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 },
21500  { 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 },
21501  { 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 },
21502  { 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 },
21503  { 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 },
21504  { 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 },
21505  { 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 },
21506  { 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 },
21507  { 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 },
21508  { 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 },
21509  { 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 },
21510  { 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 },
21511  { 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 },
21512  { 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 },
21513  { 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 },
21514  { 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 },
21515  { 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 },
21516  { 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 },
21517  { 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 },
21518  { 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 },
21519  { 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 },
21520  { 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 },
21521  { 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 },
21522  { 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 },
21523  { 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 },
21524  { 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 },
21525  { 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 },
21526  { 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 },
21527  { 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 },
21528  { 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 },
21529  { 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 },
21530  { 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 },
21531  { 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 },
21532  { 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 },
21533  { 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 },
21534  { 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 },
21535  { 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 },
21536  { 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 },
21537  { 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 },
21538  { 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 },
21539  { 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 },
21540  { 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 },
21541  { 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 },
21542  { 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 },
21543  { 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 },
21544  { 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 },
21545  { 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 },
21546  { 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 },
21547  { 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 },
21548  { 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 },
21549  { 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 },
21550  { 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 },
21551  { 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 },
21552  { 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 },
21553  { 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 },
21554  { 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 },
21555  { 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 },
21556  { 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 },
21557  { 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 },
21558  { 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 },
21559  { 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 },
21560  { 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 },
21561  { 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 },
21562  { 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 },
21563  { 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 },
21564  { 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 },
21565  { 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 },
21566  { 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 },
21567  { 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 },
21568  { 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 },
21569  { 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 },
21570  { 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 },
21571  { 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 },
21572  { 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 },
21573  { 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 },
21574  { 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 },
21575  { 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 },
21576  { 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 },
21577  { 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 },
21578  { 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 },
21579  { 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 },
21580  { 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 },
21581  { 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 },
21582  { 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 },
21583  { 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 },
21584  { 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 },
21585  { 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 },
21586  { 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 },
21587  { 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 },
21588  { 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 },
21589  { 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 },
21590  { 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 },
21591  { 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 },
21592  { 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 },
21593  { 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 },
21594  { 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 },
21595  { 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 },
21596  { 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 },
21597  { 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 },
21598  { 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 },
21599  { 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 },
21600  { 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 },
21601  { 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 },
21602  { 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 },
21603  { 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 },
21604  { 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 },
21605  { 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 },
21606  { 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 },
21607  { 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 },
21608  { 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 },
21609  { 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 },
21610  { 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 }};
21611 
21612  const unsigned int
21613  _nx = (unsigned int)(size_x>=0?size_x:((x1-x0)*-size_x/100 + 1)),
21614  _ny = (unsigned int)(size_y>=0?size_y:((y1-y0)*-size_y/100 + 1)),
21615  _nz = (unsigned int)(size_z>=0?size_y:((z1-z0)*-size_z/100 + 1)),
21616  nx = _nx?_nx:1,
21617  ny = _ny?_ny:1,
21618  nz = _nz?_nz:1,
21619  nxm1 = nx - 1,
21620  nym1 = ny - 1,
21621  nzm1 = nz - 1;
21622  primitives.assign();
21623  if (!nxm1 || !nym1 || !nzm1) return CImg<floatT>();
21624  const float dx = (x1 - x0)/nxm1, dy = (y1 - y0)/nym1, dz = (z1 - z0)/nzm1;
21625  CImgList<floatT> vertices;
21626  CImg<intT> indices1(nx,ny,1,3,-1), indices2(indices1);
21627  CImg<floatT> values1(nx,ny), values2(nx,ny);
21628  float X = 0, Y = 0, Z = 0, nX = 0, nY = 0, nZ = 0;
21629 
21630  // Fill the first plane with function values
21631  Y = y0;
21632  cimg_forY(values1,y) {
21633  X = x0;
21634  cimg_forX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=dx; }
21635  Y+=dy;
21636  }
21637 
21638  // Run Marching Cubes algorithm
21639  Z = z0; nZ = Z + dz;
21640  for (unsigned int zi = 0; zi<nzm1; ++zi, Z = nZ, nZ+=dz) {
21641  Y = y0; nY = Y + dy;
21642  indices2.fill(-1);
21643  for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y = nY, nY+=dy) {
21644  X = x0; nX = X + dx;
21645  for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X = nX, nX+=dx) {
21646 
21647  // Determine cube configuration
21648  const float
21649  val0 = values1(xi,yi),
21650  val1 = values1(nxi,yi),
21651  val2 = values1(nxi,nyi),
21652  val3 = values1(xi,nyi),
21653  val4 = values2(xi,yi) = (float)func(X,Y,nZ),
21654  val5 = values2(nxi,yi) = (float)func(nX,Y,nZ),
21655  val6 = values2(nxi,nyi) = (float)func(nX,nY,nZ),
21656  val7 = values2(xi,nyi) = (float)func(X,nY,nZ);
21657 
21658  const unsigned int configuration =
21659  (val0<isovalue?1:0) | (val1<isovalue?2:0) | (val2<isovalue?4:0) | (val3<isovalue?8:0) |
21660  (val4<isovalue?16:0) | (val5<isovalue?32:0) | (val6<isovalue?64:0) | (val7<isovalue?128:0),
21661  edge = edges[configuration];
21662 
21663  // Compute intersection vertices
21664  if (edge) {
21665  if ((edge&1) && indices1(xi,yi,0)<0) {
21666  const float Xi = X + (isovalue-val0)*dx/(val1-val0);
21667  indices1(xi,yi,0) = vertices.width;
21668  CImg<floatT>::vector(Xi,Y,Z).transfer_to(vertices);
21669  }
21670  if ((edge&2) && indices1(nxi,yi,1)<0) {
21671  const float Yi = Y + (isovalue-val1)*dy/(val2-val1);
21672  indices1(nxi,yi,1) = vertices.width;
21673  CImg<floatT>::vector(nX,Yi,Z).transfer_to(vertices);
21674  }
21675  if ((edge&4) && indices1(xi,nyi,0)<0) {
21676  const float Xi = X + (isovalue-val3)*dx/(val2-val3);
21677  indices1(xi,nyi,0) = vertices.width;
21678  CImg<floatT>::vector(Xi,nY,Z).transfer_to(vertices);
21679  }
21680  if ((edge&8) && indices1(xi,yi,1)<0) {
21681  const float Yi = Y + (isovalue-val0)*dy/(val3-val0);
21682  indices1(xi,yi,1) = vertices.width;
21683  CImg<floatT>::vector(X,Yi,Z).transfer_to(vertices);
21684  }
21685  if ((edge&16) && indices2(xi,yi,0)<0) {
21686  const float Xi = X + (isovalue-val4)*dx/(val5-val4);
21687  indices2(xi,yi,0) = vertices.width;
21688  CImg<floatT>::vector(Xi,Y,nZ).transfer_to(vertices);
21689  }
21690  if ((edge&32) && indices2(nxi,yi,1)<0) {
21691  const float Yi = Y + (isovalue-val5)*dy/(val6-val5);
21692  indices2(nxi,yi,1) = vertices.width;
21693  CImg<floatT>::vector(nX,Yi,nZ).transfer_to(vertices);
21694  }
21695  if ((edge&64) && indices2(xi,nyi,0)<0) {
21696  const float Xi = X + (isovalue-val7)*dx/(val6-val7);
21697  indices2(xi,nyi,0) = vertices.width;
21698  CImg<floatT>::vector(Xi,nY,nZ).transfer_to(vertices);
21699  }
21700  if ((edge&128) && indices2(xi,yi,1)<0) {
21701  const float Yi = Y + (isovalue-val4)*dy/(val7-val4);
21702  indices2(xi,yi,1) = vertices.width;
21703  CImg<floatT>::vector(X,Yi,nZ).transfer_to(vertices);
21704  }
21705  if ((edge&256) && indices1(xi,yi,2)<0) {
21706  const float Zi = Z+ (isovalue-val0)*dz/(val4-val0);
21707  indices1(xi,yi,2) = vertices.width;
21708  CImg<floatT>::vector(X,Y,Zi).transfer_to(vertices);
21709  }
21710  if ((edge&512) && indices1(nxi,yi,2)<0) {
21711  const float Zi = Z + (isovalue-val1)*dz/(val5-val1);
21712  indices1(nxi,yi,2) = vertices.width;
21713  CImg<floatT>::vector(nX,Y,Zi).transfer_to(vertices);
21714  }
21715  if ((edge&1024) && indices1(nxi,nyi,2)<0) {
21716  const float Zi = Z + (isovalue-val2)*dz/(val6-val2);
21717  indices1(nxi,nyi,2) = vertices.width;
21718  CImg<floatT>::vector(nX,nY,Zi).transfer_to(vertices);
21719  }
21720  if ((edge&2048) && indices1(xi,nyi,2)<0) {
21721  const float Zi = Z + (isovalue-val3)*dz/(val7-val3);
21722  indices1(xi,nyi,2) = vertices.width;
21723  CImg<floatT>::vector(X,nY,Zi).transfer_to(vertices);
21724  }
21725 
21726  // Create triangles
21727  for (const int *triangle = triangles[configuration]; *triangle!=-1; ) {
21728  const unsigned int p0 = *(triangle++), p1 = *(triangle++), p2 = *(triangle++);
21729  const tf
21730  i0 = (tf)(_marching3d_indice(p0,indices1,indices2,xi,yi,nxi,nyi)),
21731  i1 = (tf)(_marching3d_indice(p1,indices1,indices2,xi,yi,nxi,nyi)),
21732  i2 = (tf)(_marching3d_indice(p2,indices1,indices2,xi,yi,nxi,nyi));
21733  CImg<tf>::vector(i0,i2,i1).transfer_to(primitives);
21734  }
21735  }
21736  }
21737  }
21738  cimg::swap(values1,values2);
21739  cimg::swap(indices1,indices2);
21740  }
21741  return vertices>'x';
21742  }
21743 
21744  template<typename tf>
21745  static CImg<floatT> isosurface3d(CImgList<tf>& primitives, const char *const expression, const float isovalue,
21746  const float x0, const float y0, const float z0,
21747  const float x1, const float y1, const float z1,
21748  const int dx=32, const int dy=32, const int dz=32) {
21749  const _marching3d_func_expr func(expression);
21750  return isosurface3d(primitives,func,isovalue,x0,y0,z0,x1,y1,z1,dx,dy,dz);
21751  }
21752 
21753  template<typename t>
21754  static int _marching3d_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
21755  const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny) {
21756  switch (edge) {
21757  case 0 : return indices1(x,y,0);
21758  case 1 : return indices1(nx,y,1);
21759  case 2 : return indices1(x,ny,0);
21760  case 3 : return indices1(x,y,1);
21761  case 4 : return indices2(x,y,0);
21762  case 5 : return indices2(nx,y,1);
21763  case 6 : return indices2(x,ny,0);
21764  case 7 : return indices2(x,y,1);
21765  case 8 : return indices1(x,y,2);
21766  case 9 : return indices1(nx,y,2);
21767  case 10 : return indices1(nx,ny,2);
21768  case 11 : return indices1(x,ny,2);
21769  }
21770  return 0;
21771  }
21772 
21774  const CImg<T>& ref;
21775  _marching3d_func(const CImg<T>& pref):ref(pref) {}
21776  float operator()(const float x, const float y, const float z) const {
21777  return (float)ref((int)x,(int)y,(int)z);
21778  }
21779  };
21780 
21782  const CImg<T>& ref;
21783  _marching3d_func_float(const CImg<T>& pref):ref(pref) {}
21784  float operator()(const float x, const float y, const float z) const {
21785  return (float)ref._linear_atXYZ(x,y,z);
21786  }
21787  };
21788 
21791  _marching3d_func_expr(const char *const expr):mp(0) {
21792  mp = new _cimg_math_parser(expr,"isovalue3d");
21793  }
21794  float operator()(const float x, const float y, const float z) const {
21795  return (float)mp->eval(x,y,z,0);
21796  }
21798  if (mp) delete mp;
21799  }
21800  };
21801 
21803 
21818  template<typename tf>
21819  static CImg<floatT> box3d(CImgList<tf>& primitives,
21820  const float size_x=200, const float size_y=100, const float size_z=100) {
21821  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);
21822  return CImg<floatT>(8,3,1,1,
21823  0.,size_x,size_x, 0., 0.,size_x,size_x, 0.,
21824  0., 0.,size_y,size_y, 0., 0.,size_y,size_y,
21825  0., 0., 0., 0.,size_z,size_z,size_z,size_z);
21826  }
21827 
21829 
21844  template<typename tf>
21845  static CImg<floatT> cone3d(CImgList<tf>& primitives,
21846  const float radius=50, const float size_z=100, const unsigned int subdivisions=24) {
21847  primitives.assign();
21848  if (!subdivisions) return CImg<floatT>();
21849  CImgList<floatT> vertices(2,1,3,1,1,
21850  0.,0.,size_z,
21851  0.,0.,0.);
21852  for (float delta = 360.0f/subdivisions, angle = 0; angle<360; angle+=delta) {
21853  const float a = (float)(angle*cimg::valuePI/180);
21854  CImg<floatT>::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0).transfer_to(vertices);
21855  }
21856  const unsigned int nbr = vertices.width - 2;
21857  for (unsigned int p = 0; p<nbr; ++p) {
21858  const unsigned int curr = 2 + p, next = 2 + ((p+1)%nbr);
21859  CImg<tf>::vector(1,next,curr).transfer_to(primitives);
21860  CImg<tf>::vector(0,curr,next).transfer_to(primitives);
21861  }
21862  return vertices>'x';
21863  }
21864 
21866 
21881  template<typename tf>
21883  const float radius=50, const float size_z=100, const unsigned int subdivisions=24) {
21884  primitives.assign();
21885  if (!subdivisions) return CImg<floatT>();
21886  CImgList<floatT> vertices(2,1,3,1,1,
21887  0.,0.,0.,
21888  0.,0.,size_z);
21889  for (float delta = 360.0f/subdivisions, angle = 0; angle<360; angle+=delta) {
21890  const float a = (float)(angle*cimg::valuePI/180);
21891  CImg<floatT>::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0.0f).transfer_to(vertices);
21892  CImg<floatT>::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),size_z).transfer_to(vertices);
21893  }
21894  const unsigned int nbr = (vertices.width - 2)/2;
21895  for (unsigned int p = 0; p<nbr; ++p) {
21896  const unsigned int curr = 2+2*p, next = 2+(2*((p+1)%nbr));
21897  CImg<tf>::vector(0,next,curr).transfer_to(primitives);
21898  CImg<tf>::vector(1,curr+1,next+1).transfer_to(primitives);
21899  CImg<tf>::vector(curr,next,next+1,curr+1).transfer_to(primitives);
21900  }
21901  return vertices>'x';
21902  }
21903 
21905 
21921  template<typename tf>
21922  static CImg<floatT> torus3d(CImgList<tf>& primitives,
21923  const float radius1=100, const float radius2=30,
21924  const unsigned int subdivisions1=24, const unsigned int subdivisions2=12) {
21925  primitives.assign();
21926  if (!subdivisions1 || !subdivisions2) return CImg<floatT>();
21927  CImgList<floatT> vertices;
21928  for (unsigned int v = 0; v<subdivisions1; ++v) {
21929  const float
21930  beta = (float)(v*2*cimg::valuePI/subdivisions1),
21931  xc = radius1*(float)std::cos(beta),
21932  yc = radius1*(float)std::sin(beta);
21933  for (unsigned int u = 0; u<subdivisions2; ++u) {
21934  const float
21935  alpha = (float)(u*2*cimg::valuePI/subdivisions2),
21936  x = xc + radius2*(float)(std::cos(alpha)*std::cos(beta)),
21937  y = yc + radius2*(float)(std::cos(alpha)*std::sin(beta)),
21938  z = radius2*(float)std::sin(alpha);
21939  CImg<floatT>::vector(x,y,z).transfer_to(vertices);
21940  }
21941  }
21942  for (unsigned int vv = 0; vv<subdivisions1; ++vv) {
21943  const unsigned int nv = (vv+1)%subdivisions1;
21944  for (unsigned int uu = 0; uu<subdivisions2; ++uu) {
21945  const unsigned int nu = (uu+1)%subdivisions2, svv = subdivisions2*vv, snv = subdivisions2*nv;
21946  CImg<tf>::vector(svv+nu,svv+uu,snv+uu).transfer_to(primitives);
21947  CImg<tf>::vector(svv+nu,snv+uu,snv+nu).transfer_to(primitives);
21948  }
21949  }
21950  return vertices>'x';
21951  }
21952 
21954 
21971  template<typename tf>
21972  static CImg<floatT> plane3d(CImgList<tf>& primitives,
21973  const float size_x=100, const float size_y=100,
21974  const unsigned int subdivisions_x=10, const unsigned int subdivisions_y=10,
21975  const bool double_sided=false) {
21976  primitives.assign();
21977  if (!subdivisions_x || !subdivisions_y) return CImg<floatT>();
21978  CImgList<floatT> vertices;
21979  const unsigned int w = subdivisions_x + 1, h = subdivisions_y + 1;
21980  const float fx = (float)size_x/w, fy = (float)size_y/h;
21981  for (unsigned int y = 0; y<h; ++y) for (unsigned int x = 0; x<w; ++x)
21982  CImg<floatT>::vector(fx*x,fy*y,0).transfer_to(vertices);
21983  for (unsigned int y = 0; y<subdivisions_y; ++y) for (unsigned int x = 0; x<subdivisions_x; ++x) {
21984  const int off1 = x+y*w, off2 = x+1+y*w, off3 = x+1+(y+1)*w, off4 = x+(y+1)*w;
21985  CImg<tf>::vector(off1,off4,off3,off2).transfer_to(primitives);
21986  if (double_sided) CImg<tf>::vector(off1,off2,off3,off4).transfer_to(primitives);
21987  }
21988  return vertices>'x';
21989  }
21990 
21992 
22006  template<typename tf>
22007  static CImg<floatT> sphere3d(CImgList<tf>& primitives, const float radius=50, const unsigned int subdivisions=3) {
22008 
22009  // Create initial icosahedron
22010  primitives.assign();
22011  const double tmp = (1+std::sqrt(5.0f))/2, a = 1.0/std::sqrt(1+tmp*tmp), b = tmp*a;
22012  CImgList<floatT> vertices(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,
22013  -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a);
22014  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,
22015  8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3,
22016  5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2);
22017 
22018  // Recurse subdivisions
22019  for (unsigned int i = 0; i<subdivisions; ++i) {
22020  const unsigned int L = primitives.width;
22021  for (unsigned int l = 0; l<L; ++l) {
22022  const unsigned int
22023  p0 = (unsigned int)primitives(0,0), p1 = (unsigned int)primitives(0,1), p2 = (unsigned int)primitives(0,2);
22024  const float
22025  x0 = vertices(p0,0), y0 = vertices(p0,1), z0 = vertices(p0,2),
22026  x1 = vertices(p1,0), y1 = vertices(p1,1), z1 = vertices(p1,2),
22027  x2 = vertices(p2,0), y2 = vertices(p2,1), z2 = vertices(p2,2),
22028  tnx0 = (x0+x1)/2, tny0 = (y0+y1)/2, tnz0 = (z0+z1)/2, nn0 = (float)std::sqrt(tnx0*tnx0+tny0*tny0+tnz0*tnz0),
22029  tnx1 = (x0+x2)/2, tny1 = (y0+y2)/2, tnz1 = (z0+z2)/2, nn1 = (float)std::sqrt(tnx1*tnx1+tny1*tny1+tnz1*tnz1),
22030  tnx2 = (x1+x2)/2, tny2 = (y1+y2)/2, tnz2 = (z1+z2)/2, nn2 = (float)std::sqrt(tnx2*tnx2+tny2*tny2+tnz2*tnz2),
22031  nx0 = tnx0/nn0, ny0 = tny0/nn0, nz0 = tnz0/nn0,
22032  nx1 = tnx1/nn1, ny1 = tny1/nn1, nz1 = tnz1/nn1,
22033  nx2 = tnx2/nn2, ny2 = tny2/nn2, nz2 = tnz2/nn2;
22034  int i0 = -1, i1 = -1, i2 = -1;
22035  cimglist_for(vertices,p) {
22036  const float x = (float)vertices(p,0), y = (float)vertices(p,1), z = (float)vertices(p,2);
22037  if (x==nx0 && y==ny0 && z==nz0) i0 = p;
22038  if (x==nx1 && y==ny1 && z==nz1) i1 = p;
22039  if (x==nx2 && y==ny2 && z==nz2) i2 = p;
22040  }
22041  if (i0<0) { CImg<floatT>::vector(nx0,ny0,nz0).transfer_to(vertices); i0 = vertices.width - 1; }
22042  if (i1<0) { CImg<floatT>::vector(nx1,ny1,nz1).transfer_to(vertices); i1 = vertices.width - 1; }
22043  if (i2<0) { CImg<floatT>::vector(nx2,ny2,nz2).transfer_to(vertices); i2 = vertices.width - 1; }
22044  primitives.remove(0);
22045  CImg<tf>::vector(p0,i0,i1).transfer_to(primitives);
22046  CImg<tf>::vector((tf)i0,(tf)p1,(tf)i2).transfer_to(primitives);
22047  CImg<tf>::vector((tf)i1,(tf)i2,(tf)p2).transfer_to(primitives);
22048  CImg<tf>::vector((tf)i1,(tf)i0,(tf)i2).transfer_to(primitives);
22049  }
22050  }
22051  return (vertices>'x')*=radius;
22052  }
22053 
22055 
22070  template<typename tf, typename t>
22072  const CImg<t>& tensor, const unsigned int subdivisions=3) {
22073  primitives.assign();
22074  if (!subdivisions) return CImg<floatT>();
22075  CImg<floatT> S,V;
22076  tensor.symmetric_eigen(S,V);
22077  const float l0 = S[0], l1 = S[1], l2 = S[2];
22078  CImg<floatT> vertices = sphere(primitives,subdivisions);
22079  vertices.get_shared_line(0)*=l0;
22080  vertices.get_shared_line(1)*=l1;
22081  vertices.get_shared_line(2)*=l2;
22082  return V.transpose()*vertices;
22083  }
22084 
22086  //---------------------------
22087  //
22089 
22090  //---------------------------
22091 
22092  // The following _draw_scanline() routines are *non user-friendly functions*, used only for internal purpose.
22093  // Pre-requisites : x0<x1, y-coordinate is valid, col is valid.
22094  template<typename tc>
22095  CImg<T>& _draw_scanline(const int x0, const int x1, const int y,
22096  const tc *const color, const float opacity=1,
22097  const float brightness=1, const bool init=false) {
22098  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
22099  static float nopacity = 0, copacity = 0;
22100  static unsigned int whz = 0;
22101  static const tc *col = 0;
22102  if (init) {
22103  nopacity = cimg::abs(opacity);
22104  copacity = 1 - cimg::max(opacity,0);
22105  whz = width*height*depth;
22106  } else {
22107  const int nx0 = x0>0?x0:0, nx1 = x1<dimx()?x1:dimx()-1, dx = nx1 - nx0;
22108  if (dx>=0) {
22109  col = color;
22110  const unsigned int off = whz-dx-1;
22111  T *ptrd = ptr(nx0,y);
22112  if (opacity>=1) { // ** Opaque drawing **
22113  if (brightness==1) { // Brightness==1
22114  if (sizeof(T)!=1) cimg_forV(*this,k) {
22115  const T val = (T)*(col++);
22116  for (int x = dx; x>=0; --x) *(ptrd++) = val;
22117  ptrd+=off;
22118  } else cimg_forV(*this,k) {
22119  const T val = (T)*(col++);
22120  std::memset(ptrd,(int)val,dx+1);
22121  ptrd+=whz;
22122  }
22123  } else if (brightness<1) { // Brightness<1
22124  if (sizeof(T)!=1) cimg_forV(*this,k) {
22125  const T val = (T)(*(col++)*brightness);
22126  for (int x = dx; x>=0; --x) *(ptrd++) = val;
22127  ptrd+=off;
22128  } else cimg_forV(*this,k) {
22129  const T val = (T)(*(col++)*brightness);
22130  std::memset(ptrd,(int)val,dx+1);
22131  ptrd+=whz;
22132  }
22133  } else { // Brightness>1
22134  if (sizeof(T)!=1) cimg_forV(*this,k) {
22135  const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
22136  for (int x = dx; x>=0; --x) *(ptrd++) = val;
22137  ptrd+=off;
22138  } else cimg_forV(*this,k) {
22139  const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
22140  std::memset(ptrd,(int)val,dx+1);
22141  ptrd+=whz;
22142  }
22143  }
22144  } else { // ** Transparent drawing **
22145  if (brightness==1) { // Brightness==1
22146  cimg_forV(*this,k) {
22147  const T val = (T)*(col++);
22148  for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
22149  ptrd+=off;
22150  }
22151  } else if (brightness<=1) { // Brightness<1
22152  cimg_forV(*this,k) {
22153  const T val = (T)(*(col++)*brightness);
22154  for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
22155  ptrd+=off;
22156  }
22157  } else { // Brightness>1
22158  cimg_forV(*this,k) {
22159  const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
22160  for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
22161  ptrd+=off;
22162  }
22163  }
22164  }
22165  }
22166  }
22167  return *this;
22168  }
22169 
22170  template<typename tc>
22171  CImg<T>& _draw_scanline(const tc *const color, const float opacity=1) {
22172  return _draw_scanline(0,0,0,color,opacity,0,true);
22173  }
22174 
22176 
22191  template<typename tc>
22192  CImg<T>& draw_point(const int x0, const int y0,
22193  const tc *const color, const float opacity=1) {
22194  return draw_point(x0,y0,0,color,opacity);
22195  }
22196 
22198  template<typename tc>
22199  CImg<T>& draw_point(const int x0, const int y0,
22200  const CImg<tc>& color, const float opacity=1) {
22201  return draw_point(x0,y0,color.data,opacity);
22202  }
22203 
22205  template<typename tc>
22206  CImg<T>& draw_point(const int x0, const int y0, const int z0,
22207  const tc *const color, const float opacity=1) {
22208  if (is_empty()) return *this;
22209  if (!color)
22210  throw CImgArgumentException("CImg<%s>::draw_point() : Specified color is (null)",
22211  pixel_type());
22212  if (x0>=0 && y0>=0 && z0>=0 && x0<dimx() && y0<dimy() && z0<dimz()) {
22213  const unsigned int whz = width*height*depth;
22214  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
22215  T *ptrd = ptr(x0,y0,z0,0);
22216  const tc *col = color;
22217  if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
22218  else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
22219  }
22220  return *this;
22221  }
22222 
22224  template<typename tc>
22225  CImg<T>& draw_point(const int x0, const int y0, const int z0,
22226  const CImg<tc>& color, const float opacity=1) {
22227  return draw_point(x0,y0,z0,color.data,opacity);
22228  }
22229 
22230  // Draw a cloud of colored point (internal).
22231  template<typename t, typename tc>
22232  CImg<T>& _draw_point(const t& points, const unsigned int W, const unsigned int H,
22233  const tc *const color, const float opacity) {
22234  if (is_empty() || !points || !W) return *this;
22235  switch (H) {
22236  case 0 : case 1 :
22237  throw CImgArgumentException("CImg<%s>::draw_point() : Given list of points is not valid.",
22238  pixel_type());
22239  case 2 : {
22240  for (unsigned int i = 0; i<W; ++i) {
22241  const int x = (int)points(i,0), y = (int)points(i,1);
22242  draw_point(x,y,color,opacity);
22243  }
22244  } break;
22245  default : {
22246  for (unsigned int i = 0; i<W; ++i) {
22247  const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
22248  draw_point(x,y,z,color,opacity);
22249  }
22250  }
22251  }
22252  return *this;
22253  }
22254 
22256 
22275  template<typename t, typename tc>
22277  const tc *const color, const float opacity=1) {
22278  unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
22279  return _draw_point(points,points.width,H,color,opacity);
22280  }
22281 
22283  template<typename t, typename tc>
22285  const CImg<tc>& color, const float opacity=1) {
22286  return draw_point(points,color.data,opacity);
22287  }
22288 
22290 
22295  template<typename t, typename tc>
22297  const tc *const color, const float opacity=1) {
22298  return _draw_point(points,points.width,points.height,color,opacity);
22299  }
22300 
22302  template<typename t, typename tc>
22304  const CImg<tc>& color, const float opacity=1) {
22305  return draw_point(points,color.data,opacity);
22306  }
22307 
22309 
22329  template<typename tc>
22330  CImg<T>& draw_line(const int x0, const int y0,
22331  const int x1, const int y1,
22332  const tc *const color, const float opacity=1,
22333  const unsigned int pattern=~0U, const bool init_hatch=true) {
22334  if (is_empty()) return *this;
22335  if (!color)
22336  throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
22337  pixel_type());
22338  static unsigned int hatch = ~0U - (~0U>>1);
22339  if (init_hatch) hatch = ~0U - (~0U>>1);
22340  const bool xdir = x0<x1, ydir = y0<y1;
22341  int
22342  nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
22343  &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
22344  &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
22345  &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
22346  &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
22347  if (xright<0 || xleft>=dimx()) return *this;
22348  if (xleft<0) { yleft-=xleft*(yright - yleft)/(xright - xleft); xleft = 0; }
22349  if (xright>=dimx()) { yright-=(xright - dimx())*(yright - yleft)/(xright - xleft); xright = dimx()-1; }
22350  if (ydown<0 || yup>=dimy()) return *this;
22351  if (yup<0) { xup-=yup*(xdown - xup)/(ydown - yup); yup = 0; }
22352  if (ydown>=dimy()) { xdown-=(ydown - dimy())*(xdown - xup)/(ydown - yup); ydown = dimy()-1; }
22353  T *ptrd0 = ptr(nx0,ny0);
22354  int dx = xright - xleft, dy = ydown - yup;
22355  const bool steep = dy>dx;
22356  if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
22357  const int
22358  offx = (nx0<nx1?1:-1)*(steep?width:1),
22359  offy = (ny0<ny1?1:-1)*(steep?1:width),
22360  wh = width*height;
22361  if (opacity>=1) {
22362  if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
22363  if (pattern&hatch) { T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }}
22364  hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
22365  ptrd0+=offx;
22366  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22367  } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
22368  T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
22369  ptrd0+=offx;
22370  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22371  }
22372  } else {
22373  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
22374  if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
22375  if (pattern&hatch) {
22376  T *ptrd = ptrd0; const tc* col = color;
22377  cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
22378  }
22379  hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
22380  ptrd0+=offx;
22381  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22382  } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
22383  T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
22384  ptrd0+=offx;
22385  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22386  }
22387  }
22388  return *this;
22389  }
22390 
22392  template<typename tc>
22393  CImg<T>& draw_line(const int x0, const int y0,
22394  const int x1, const int y1,
22395  const CImg<tc>& color, const float opacity=1,
22396  const unsigned int pattern=~0U, const bool init_hatch=true) {
22397  return draw_line(x0,y0,x1,y1,color.data,opacity,pattern,init_hatch);
22398  }
22399 
22401  template<typename tc>
22403  const int x0, const int y0, const float z0,
22404  const int x1, const int y1, const float z1,
22405  const tc *const color, const float opacity=1,
22406  const unsigned int pattern=~0U, const bool init_hatch=true) {
22407  if (is_empty() || z0<=0 || z1<=0) return *this;
22408  if (!color)
22409  throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null).",
22410  pixel_type());
22411  if (!is_sameXY(zbuffer))
22412  throw CImgArgumentException("CImg<%s>::draw_line() : Z-buffer (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) have different dimensions.",
22413  pixel_type(),zbuffer.width,zbuffer.height,zbuffer.depth,zbuffer.dim,zbuffer.data,width,height,depth,dim,data);
22414  static unsigned int hatch = ~0U - (~0U>>1);
22415  if (init_hatch) hatch = ~0U - (~0U>>1);
22416  const bool xdir = x0<x1, ydir = y0<y1;
22417  int
22418  nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
22419  &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
22420  &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
22421  &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
22422  &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
22423  float
22424  Z0 = 1/z0, Z1 = 1/z1, nz0 = Z0, nz1 = Z1, dz = Z1 - Z0,
22425  &zleft = xdir?nz0:nz1,
22426  &zright = xdir?nz1:nz0,
22427  &zup = ydir?nz0:nz1,
22428  &zdown = ydir?nz1:nz0;
22429  if (xright<0 || xleft>=dimx()) return *this;
22430  if (xleft<0) {
22431  const int D = xright - xleft;
22432  yleft-=xleft*(yright - yleft)/D;
22433  zleft-=xleft*(zright - zleft)/D;
22434  xleft = 0;
22435  }
22436  if (xright>=dimx()) {
22437  const int d = xright - dimx(), D = xright - xleft;
22438  yright-=d*(yright - yleft)/D;
22439  zright-=d*(zright - zleft)/D;
22440  xright = dimx()-1;
22441  }
22442  if (ydown<0 || yup>=dimy()) return *this;
22443  if (yup<0) {
22444  const int D = ydown - yup;
22445  xup-=yup*(xdown - xup)/D;
22446  zup-=yup*(zdown - zup)/D;
22447  yup = 0;
22448  }
22449  if (ydown>=dimy()) {
22450  const int d = ydown - dimy(), D = ydown - yup;
22451  xdown-=d*(xdown - xup)/D;
22452  zdown-=d*(zdown - zup)/D;
22453  ydown = dimy()-1;
22454  }
22455  T *ptrd0 = ptr(nx0,ny0);
22456  float *ptrz = zbuffer.ptr(nx0,ny0);
22457  int dx = xright - xleft, dy = ydown - yup;
22458  const bool steep = dy>dx;
22459  if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
22460  const int
22461  offx = (nx0<nx1?1:-1)*(steep?width:1),
22462  offy = (ny0<ny1?1:-1)*(steep?1:width),
22463  wh = width*height,
22464  ndx = dx>0?dx:1;
22465  if (opacity>=1) {
22466  if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
22467  const float z = Z0 + x*dz/ndx;
22468  if (z>*ptrz && pattern&hatch) {
22469  *ptrz = z;
22470  T *ptrd = ptrd0; const tc *col = color;
22471  cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
22472  }
22473  hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
22474  ptrd0+=offx; ptrz+=offx;
22475  if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
22476  } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
22477  const float z = Z0 + x*dz/ndx;
22478  if (z>*ptrz) {
22479  *ptrz = z;
22480  T *ptrd = ptrd0; const tc *col = color;
22481  cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
22482  }
22483  ptrd0+=offx; ptrz+=offx;
22484  if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
22485  }
22486  } else {
22487  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
22488  if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
22489  const float z = Z0 + x*dz/ndx;
22490  if (z>*ptrz && pattern&hatch) {
22491  *ptrz = z;
22492  T *ptrd = ptrd0; const tc *col = color;
22493  cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
22494  }
22495  hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
22496  ptrd0+=offx; ptrz+=offx;
22497  if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
22498  } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
22499  const float z = Z0 + x*dz/ndx;
22500  if (z>*ptrz) {
22501  *ptrz = z;
22502  T *ptrd = ptrd0; const tc *col = color;
22503  cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
22504  }
22505  ptrd0+=offx; ptrz+=offx;
22506  if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
22507  }
22508  }
22509  return *this;
22510  }
22511 
22513  template<typename tc>
22515  const int x0, const int y0, const float z0,
22516  const int x1, const int y1, const float z1,
22517  const CImg<tc>& color, const float opacity=1,
22518  const unsigned int pattern=~0U, const bool init_hatch=true) {
22519  return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
22520  }
22521 
22523  template<typename tc>
22524  CImg<T>& draw_line(const int x0, const int y0, const int z0,
22525  const int x1, const int y1, const int z1,
22526  const tc *const color, const float opacity=1,
22527  const unsigned int pattern=~0U, const bool init_hatch=true) {
22528  if (is_empty()) return *this;
22529  if (!color)
22530  throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
22531  pixel_type());
22532  static unsigned int hatch = ~0U - (~0U>>1);
22533  if (init_hatch) hatch = ~0U - (~0U>>1);
22534  int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1;
22535  if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
22536  if (nx1<0 || nx0>=dimx()) return *this;
22537  if (nx0<0) { const int D = 1 + nx1 - nx0; ny0-=nx0*(1 + ny1 - ny0)/D; nz0-=nx0*(1 + nz1 - nz0)/D; nx0 = 0; }
22538  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; }
22539  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
22540  if (ny1<0 || ny0>=dimy()) return *this;
22541  if (ny0<0) { const int D = 1 + ny1 - ny0; nx0-=ny0*(1 + nx1 - nx0)/D; nz0-=ny0*(1 + nz1 - nz0)/D; ny0 = 0; }
22542  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; }
22543  if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
22544  if (nz1<0 || nz0>=dimz()) return *this;
22545  if (nz0<0) { const int D = 1 + nz1 - nz0; nx0-=nz0*(1 + nx1 - nx0)/D; ny0-=nz0*(1 + ny1 - ny0)/D; nz0 = 0; }
22546  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; }
22547  const unsigned int dmax = cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0), whz = width*height*depth;
22548  const float px = (nx1 - nx0)/(float)dmax, py = (ny1 - ny0)/(float)dmax, pz = (nz1 - nz0)/(float)dmax;
22549  float x = (float)nx0, y = (float)ny0, z = (float)nz0;
22550  if (opacity>=1) for (unsigned int t = 0; t<=dmax; ++t) {
22551  if (!(~pattern) || (~pattern && pattern&hatch)) {
22552  T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
22553  const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
22554  }
22555  x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
22556  } else {
22557  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
22558  for (unsigned int t = 0; t<=dmax; ++t) {
22559  if (!(~pattern) || (~pattern && pattern&hatch)) {
22560  T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
22561  const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
22562  }
22563  x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
22564  }
22565  }
22566  return *this;
22567  }
22568 
22570  template<typename tc>
22571  CImg<T>& draw_line(const int x0, const int y0, const int z0,
22572  const int x1, const int y1, const int z1,
22573  const CImg<tc>& color, const float opacity=1,
22574  const unsigned int pattern=~0U, const bool init_hatch=true) {
22575  return draw_line(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
22576  }
22577 
22579 
22602  template<typename tc>
22603  CImg<T>& draw_line(const int x0, const int y0,
22604  const int x1, const int y1,
22605  const CImg<tc>& texture,
22606  const int tx0, const int ty0,
22607  const int tx1, const int ty1,
22608  const float opacity=1,
22609  const unsigned int pattern=~0U, const bool init_hatch=true) {
22610  if (is_empty()) return *this;
22611  if (!texture || texture.dim<dim)
22612  throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
22613  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
22614  if (is_overlapped(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
22615  static unsigned int hatch = ~0U - (~0U>>1);
22616  if (init_hatch) hatch = ~0U - (~0U>>1);
22617  const bool xdir = x0<x1, ydir = y0<y1;
22618  int
22619  dtx = tx1-tx0, dty = ty1-ty0,
22620  nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
22621  tnx0 = tx0, tnx1 = tx1, tny0 = ty0, tny1 = ty1,
22622  &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
22623  &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
22624  &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0,
22625  &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
22626  if (xright<0 || xleft>=dimx()) return *this;
22627  if (xleft<0) {
22628  const int D = xright - xleft;
22629  yleft-=xleft*(yright - yleft)/D;
22630  txleft-=xleft*(txright - txleft)/D;
22631  tyleft-=xleft*(tyright - tyleft)/D;
22632  xleft = 0;
22633  }
22634  if (xright>=dimx()) {
22635  const int d = xright - dimx(), D = xright - xleft;
22636  yright-=d*(yright - yleft)/D;
22637  txright-=d*(txright - txleft)/D;
22638  tyright-=d*(tyright - tyleft)/D;
22639  xright = dimx()-1;
22640  }
22641  if (ydown<0 || yup>=dimy()) return *this;
22642  if (yup<0) {
22643  const int D = ydown - yup;
22644  xup-=yup*(xdown - xup)/D;
22645  txup-=yup*(txdown - txup)/D;
22646  tyup-=yup*(tydown - tyup)/D;
22647  yup = 0;
22648  }
22649  if (ydown>=dimy()) {
22650  const int d = ydown - dimy(), D = ydown - yup;
22651  xdown-=d*(xdown - xup)/D;
22652  txdown-=d*(txdown - txup)/D;
22653  tydown-=d*(tydown - tyup)/D;
22654  ydown = dimy()-1;
22655  }
22656  T *ptrd0 = ptr(nx0,ny0);
22657  int dx = xright - xleft, dy = ydown - yup;
22658  const bool steep = dy>dx;
22659  if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
22660  const int
22661  offx = (nx0<nx1?1:-1)*(steep?width:1),
22662  offy = (ny0<ny1?1:-1)*(steep?1:width),
22663  wh = width*height,
22664  ndx = dx>0?dx:1;
22665  if (opacity>=1) {
22666  if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
22667  if (pattern&hatch) {
22668  T *ptrd = ptrd0;
22669  const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
22670  cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
22671  }
22672  hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
22673  ptrd0+=offx;
22674  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22675  } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
22676  T *ptrd = ptrd0;
22677  const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
22678  cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
22679  ptrd0+=offx;
22680  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22681  }
22682  } else {
22683  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
22684  if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
22685  T *ptrd = ptrd0;
22686  if (pattern&hatch) {
22687  const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
22688  cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
22689  }
22690  hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
22691  ptrd0+=offx;
22692  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22693  } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
22694  T *ptrd = ptrd0;
22695  const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
22696  cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
22697  ptrd0+=offx;
22698  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22699  }
22700  }
22701  return *this;
22702  }
22703 
22705  template<typename tc>
22706  CImg<T>& draw_line(const int x0, const int y0, const float z0,
22707  const int x1, const int y1, const float z1,
22708  const CImg<tc>& texture,
22709  const int tx0, const int ty0,
22710  const int tx1, const int ty1,
22711  const float opacity=1,
22712  const unsigned int pattern=~0U, const bool init_hatch=true) {
22713  if (is_empty() && z0<=0 && z1<=0) return *this;
22714  if (!texture || texture.dim<dim)
22715  throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
22716  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
22717  if (is_overlapped(texture)) return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
22718  static unsigned int hatch = ~0U - (~0U>>1);
22719  if (init_hatch) hatch = ~0U - (~0U>>1);
22720  const bool xdir = x0<x1, ydir = y0<y1;
22721  int
22722  nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
22723  &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
22724  &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
22725  &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
22726  &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
22727  float
22728  Tx0 = tx0/z0, Tx1 = tx1/z1,
22729  Ty0 = ty0/z0, Ty1 = ty1/z1,
22730  Z0 = 1/z0, Z1 = 1/z1,
22731  dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
22732  tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
22733  &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
22734  &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
22735  &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
22736  &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
22737  if (xright<0 || xleft>=dimx()) return *this;
22738  if (xleft<0) {
22739  const int D = xright - xleft;
22740  yleft-=xleft*(yright - yleft)/D;
22741  zleft-=xleft*(zright - zleft)/D;
22742  txleft-=xleft*(txright - txleft)/D;
22743  tyleft-=xleft*(tyright - tyleft)/D;
22744  xleft = 0;
22745  }
22746  if (xright>=dimx()) {
22747  const int d = xright - dimx(), D = xright - xleft;
22748  yright-=d*(yright - yleft)/D;
22749  zright-=d*(zright - zleft)/D;
22750  txright-=d*(txright - txleft)/D;
22751  tyright-=d*(tyright - tyleft)/D;
22752  xright = dimx()-1;
22753  }
22754  if (ydown<0 || yup>=dimy()) return *this;
22755  if (yup<0) {
22756  const int D = ydown - yup;
22757  xup-=yup*(xdown - xup)/D;
22758  zup-=yup*(zdown - zup)/D;
22759  txup-=yup*(txdown - txup)/D;
22760  tyup-=yup*(tydown - tyup)/D;
22761  yup = 0;
22762  }
22763  if (ydown>=dimy()) {
22764  const int d = ydown - dimy(), D = ydown - yup;
22765  xdown-=d*(xdown - xup)/D;
22766  zdown-=d*(zdown - zup)/D;
22767  txdown-=d*(txdown - txup)/D;
22768  tydown-=d*(tydown - tyup)/D;
22769  ydown = dimy()-1;
22770  }
22771  T *ptrd0 = ptr(nx0,ny0);
22772  int dx = xright - xleft, dy = ydown - yup;
22773  const bool steep = dy>dx;
22774  if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
22775  const int
22776  offx = (nx0<nx1?1:-1)*(steep?width:1),
22777  offy = (ny0<ny1?1:-1)*(steep?1:width),
22778  wh = width*height,
22779  ndx = dx>0?dx:1;
22780  if (opacity>=1) {
22781  if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
22782  if (pattern&hatch) {
22783  const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
22784  T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
22785  }
22786  hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
22787  ptrd0+=offx;
22788  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22789  } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
22790  const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
22791  T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
22792  ptrd0+=offx;
22793  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22794  }
22795  } else {
22796  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
22797  if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
22798  if (pattern&hatch) {
22799  const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
22800  T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
22801  }
22802  hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
22803  ptrd0+=offx;
22804  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22805  } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
22806  const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
22807  T *ptrd = ptrd0;
22808  cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
22809  ptrd0+=offx;
22810  if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
22811  }
22812  }
22813  return *this;
22814  }
22815 
22817  template<typename tc>
22819  const int x0, const int y0, const float z0,
22820  const int x1, const int y1, const float z1,
22821  const CImg<tc>& texture,
22822  const int tx0, const int ty0,
22823  const int tx1, const int ty1,
22824  const float opacity=1,
22825  const unsigned int pattern=~0U, const bool init_hatch=true) {
22826  if (is_empty() || z0<=0 || z1<=0) return *this;
22827  if (!is_sameXY(zbuffer))
22828  throw CImgArgumentException("CImg<%s>::draw_line() : Z-buffer (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) have different dimensions.",
22829  pixel_type(),zbuffer.width,zbuffer.height,zbuffer.depth,zbuffer.dim,zbuffer.data,width,height,depth,dim,data);
22830  if (!texture || texture.dim<dim)
22831  throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
22832  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
22833  if (is_overlapped(texture)) return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
22834  static unsigned int hatch = ~0U - (~0U>>1);
22835  if (init_hatch) hatch = ~0U - (~0U>>1);
22836  const bool xdir = x0<x1, ydir = y0<y1;
22837  int
22838  nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
22839  &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
22840  &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
22841  &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
22842  &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
22843  float
22844  Tx0 = tx0/z0, Tx1 = tx1/z1,
22845  Ty0 = ty0/z0, Ty1 = ty1/z1,
22846  Z0 = 1/z0, Z1 = 1/z1,
22847  dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
22848  tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
22849  &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
22850  &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
22851  &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
22852  &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
22853  if (xright<0 || xleft>=dimx()) return *this;
22854  if (xleft<0) {
22855  const int D = xright - xleft;
22856  yleft-=xleft*(yright - yleft)/D;
22857  zleft-=xleft*(zright - zleft)/D;
22858  txleft-=xleft*(txright - txleft)/D;
22859  tyleft-=xleft*(tyright - tyleft)/D;
22860  xleft = 0;
22861  }
22862  if (xright>=dimx()) {
22863  const int d = xright - dimx(), D = xright - xleft;
22864  yright-=d*(yright - yleft)/D;
22865  zright-=d*(zright - zleft)/D;
22866  txright-=d*(txright - txleft)/D;
22867  tyright-=d*(tyright - tyleft)/D;
22868  xright = dimx()-1;
22869  }
22870  if (ydown<0 || yup>=dimy()) return *this;
22871  if (yup<0) {
22872  const int D = ydown - yup;
22873  xup-=yup*(xdown - xup)/D;
22874  zup-=yup*(zdown - zup)/D;
22875  txup-=yup*(txdown - txup)/D;
22876  tyup-=yup*(tydown - tyup)/D;
22877  yup = 0;
22878  }
22879  if (ydown>=dimy()) {
22880  const int d = ydown - dimy(), D = ydown - yup;
22881  xdown-=d*(xdown - xup)/D;
22882  zdown-=d*(zdown - zup)/D;
22883  txdown-=d*(txdown - txup)/D;
22884  tydown-=d*(tydown - tyup)/D;
22885  ydown = dimy()-1;
22886  }
22887  T *ptrd0 = ptr(nx0,ny0);
22888  float *ptrz = zbuffer.ptr(nx0,ny0);
22889  int dx = xright - xleft, dy = ydown - yup;
22890  const bool steep = dy>dx;
22891  if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
22892  const int
22893  offx = (nx0<nx1?1:-1)*(steep?width:1),
22894  offy = (ny0<ny1?1:-1)*(steep?1:width),
22895  wh = width*height,
22896  ndx = dx>0?dx:1;
22897  if (opacity>=1) {
22898  if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
22899  if (pattern&hatch) {
22900  const float z = Z0 + x*dz/ndx;
22901  if (z>*ptrz) {
22902  *ptrz = z;
22903  const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
22904  T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
22905  }
22906  }
22907  hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
22908  ptrd0+=offx; ptrz+=offx;
22909  if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
22910  } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
22911  const float z = Z0 + x*dz/ndx;
22912  if (z>*ptrz) {
22913  *ptrz = z;
22914  const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
22915  T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
22916  }
22917  ptrd0+=offx; ptrz+=offx;
22918  if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
22919  }
22920  } else {
22921  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
22922  if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
22923  if (pattern&hatch) {
22924  const float z = Z0 + x*dz/ndx;
22925  if (z>*ptrz) {
22926  *ptrz = z;
22927  const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
22928  T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
22929  }
22930  }
22931  hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
22932  ptrd0+=offx; ptrz+=offx;
22933  if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
22934  } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
22935  const float z = Z0 + x*dz/ndx;
22936  if (z>*ptrz) {
22937  *ptrz = z;
22938  const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
22939  T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
22940  }
22941  ptrd0+=offx; ptrz+=offx;
22942  if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offx; error+=dx; }
22943  }
22944  }
22945  return *this;
22946  }
22947 
22948  // Inner routine for drawing set of consecutive lines with generic type for coordinates.
22949  template<typename t, typename tc>
22950  CImg<T>& _draw_line(const t& points, const unsigned int W, const unsigned int H,
22951  const tc *const color, const float opacity,
22952  const unsigned int pattern, const bool init_hatch) {
22953  if (is_empty() || !points || W<2) return *this;
22954  bool ninit_hatch = init_hatch;
22955  switch (H) {
22956  case 0 : case 1 :
22957  throw CImgArgumentException("CImg<%s>::draw_line() : Given list of points is not valid.",
22958  pixel_type());
22959  case 2 : {
22960  const int x0 = (int)points(0,0), y0 = (int)points(0,1);
22961  int ox = x0, oy = y0;
22962  for (unsigned int i = 1; i<W; ++i) {
22963  const int x = (int)points(i,0), y = (int)points(i,1);
22964  draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
22965  ninit_hatch = false;
22966  ox = x; oy = y;
22967  }
22968  } break;
22969  default : {
22970  const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
22971  int ox = x0, oy = y0, oz = z0;
22972  for (unsigned int i = 1; i<W; ++i) {
22973  const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
22974  draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
22975  ninit_hatch = false;
22976  ox = x; oy = y; oz = z;
22977  }
22978  }
22979  }
22980  return *this;
22981  }
22982 
22984 
23005  template<typename t, typename tc>
23007  const tc *const color, const float opacity=1,
23008  const unsigned int pattern=~0U, const bool init_hatch=true) {
23009  unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
23010  return _draw_line(points,points.width,H,color,opacity,pattern,init_hatch);
23011  }
23012 
23014  template<typename t, typename tc>
23016  const CImg<tc>& color, const float opacity=1,
23017  const unsigned int pattern=~0U, const bool init_hatch=true) {
23018  return draw_line(points,color.data,opacity,pattern,init_hatch);
23019  }
23020 
23022 
23027  template<typename t, typename tc>
23029  const tc *const color, const float opacity=1,
23030  const unsigned int pattern=~0U, const bool init_hatch=true) {
23031  return _draw_line(points,points.width,points.height,color,opacity,pattern,init_hatch);
23032  }
23033 
23035  template<typename t, typename tc>
23037  const CImg<tc>& color, const float opacity=1,
23038  const unsigned int pattern=~0U, const bool init_hatch=true) {
23039  return draw_line(points,color.data,opacity,pattern,init_hatch);
23040  }
23041 
23043 
23056  template<typename tc>
23057  CImg<T>& draw_arrow(const int x0, const int y0,
23058  const int x1, const int y1,
23059  const tc *const color, const float opacity=1,
23060  const float angle=30, const float length=-10,
23061  const unsigned int pattern=~0U) {
23062  if (is_empty()) return *this;
23063  const float u = (float)(x0 - x1), v = (float)(y0 - y1), sq = u*u + v*v,
23064  deg = (float)(angle*cimg::valuePI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f,
23065  l = (length>=0)?length:-length*(float)std::sqrt(sq)/100;
23066  if (sq>0) {
23067  const float
23068  cl = (float)std::cos(ang - deg), sl = (float)std::sin(ang - deg),
23069  cr = (float)std::cos(ang + deg), sr = (float)std::sin(ang + deg);
23070  const int
23071  xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl),
23072  xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr),
23073  xc = x1 + (int)((l+1)*(cl+cr))/2, yc = y1 + (int)((l+1)*(sl+sr))/2;
23074  draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);
23075  } else draw_point(x0,y0,color,opacity);
23076  return *this;
23077  }
23078 
23080  template<typename tc>
23081  CImg<T>& draw_arrow(const int x0, const int y0,
23082  const int x1, const int y1,
23083  const CImg<tc>& color, const float opacity=1,
23084  const float angle=30, const float length=-10,
23085  const unsigned int pattern=~0U) {
23086  return draw_arrow(x0,y0,x1,y1,color.data,opacity,angle,length,pattern);
23087  }
23088 
23090 
23121  template<typename tc>
23122  CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
23123  const int x1, const int y1, const float u1, const float v1,
23124  const tc *const color, const float opacity=1,
23125  const float precision=4, const unsigned int pattern=~0U,
23126  const bool init_hatch=true) {
23127  if (is_empty()) return *this;
23128  if (!color)
23129  throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
23130  pixel_type());
23131  bool ninit_hatch = init_hatch;
23132  const float
23133  dx = (float)(x1 - x0),
23134  dy = (float)(y1 - y0),
23135  dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
23136  ax = -2*dx + u0 + u1,
23137  bx = 3*dx - 2*u0 - u1,
23138  ay = -2*dy + v0 + v1,
23139  by = 3*dy - 2*v0 - v1,
23140  xprecision = dmax>0?precision/dmax:1.0f,
23141  tmax = 1 + (dmax>0?xprecision:0.0f);
23142  int ox = x0, oy = y0;
23143  for (float t = 0; t<tmax; t+=xprecision) {
23144  const float
23145  t2 = t*t,
23146  t3 = t2*t;
23147  const int
23148  nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
23149  ny = (int)(ay*t3 + by*t2 + v0*t + y0);
23150  draw_line(ox,oy,nx,ny,color,opacity,pattern,ninit_hatch);
23151  ninit_hatch = false;
23152  ox = nx; oy = ny;
23153  }
23154  return *this;
23155  }
23156 
23158  template<typename tc>
23159  CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
23160  const int x1, const int y1, const float u1, const float v1,
23161  const CImg<tc>& color, const float opacity=1,
23162  const float precision=4, const unsigned int pattern=~0U,
23163  const bool init_hatch=true) {
23164  return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,color.data,opacity,precision,pattern,init_hatch);
23165  }
23166 
23168 
23172  template<typename tc>
23173  CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
23174  const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
23175  const tc *const color, const float opacity=1,
23176  const float precision=4, const unsigned int pattern=~0U,
23177  const bool init_hatch=true) {
23178  if (is_empty()) return *this;
23179  if (!color)
23180  throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
23181  pixel_type());
23182  bool ninit_hatch = init_hatch;
23183  const float
23184  dx = (float)(x1 - x0),
23185  dy = (float)(y1 - y0),
23186  dz = (float)(z1 - z0),
23187  dmax = cimg::max(cimg::abs(dx),cimg::abs(dy),cimg::abs(dz)),
23188  ax = -2*dx + u0 + u1,
23189  bx = 3*dx - 2*u0 - u1,
23190  ay = -2*dy + v0 + v1,
23191  by = 3*dy - 2*v0 - v1,
23192  az = -2*dz + w0 + w1,
23193  bz = 3*dz - 2*w0 - w1,
23194  xprecision = dmax>0?precision/dmax:1.0f,
23195  tmax = 1 + (dmax>0?xprecision:0.0f);
23196  int ox = x0, oy = y0, oz = z0;
23197  for (float t = 0; t<tmax; t+=xprecision) {
23198  const float
23199  t2 = t*t,
23200  t3 = t2*t;
23201  const int
23202  nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
23203  ny = (int)(ay*t3 + by*t2 + v0*t + y0),
23204  nz = (int)(az*t3 + bz*t2 + w0*t + z0);
23205  draw_line(ox,oy,oz,nx,ny,nz,color,opacity,pattern,ninit_hatch);
23206  ninit_hatch = false;
23207  ox = nx; oy = ny; oz = nz;
23208  }
23209  return *this;
23210  }
23211 
23213  template<typename tc>
23214  CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
23215  const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
23216  const CImg<tc>& color, const float opacity=1,
23217  const float precision=4, const unsigned int pattern=~0U,
23218  const bool init_hatch=true) {
23219  return draw_spline(x0,y0,z0,u0,v0,w0,x1,y1,z1,u1,v1,w1,color.data,opacity,precision,pattern,init_hatch);
23220  }
23221 
23223 
23242  template<typename t>
23243  CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
23244  const int x1, const int y1, const float u1, const float v1,
23245  const CImg<t>& texture,
23246  const int tx0, const int ty0, const int tx1, const int ty1,
23247  const float opacity=1,
23248  const float precision=4, const unsigned int pattern=~0U,
23249  const bool init_hatch=true) {
23250  if (is_empty()) return *this;
23251  if (!texture || texture.dim<dim)
23252  throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
23253  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
23254  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);
23255  bool ninit_hatch = true;
23256  const float
23257  dx = (float)(x1 - x0),
23258  dy = (float)(y1 - y0),
23259  dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
23260  ax = -2*dx + u0 + u1,
23261  bx = 3*dx - 2*u0 - u1,
23262  ay = -2*dy + v0 + v1,
23263  by = 3*dy - 2*v0 - v1,
23264  xprecision = dmax>0?precision/dmax:1.0f,
23265  tmax = 1 + (dmax>0?xprecision:0.0f);
23266  int ox = x0, oy = y0, otx = tx0, oty = ty0;
23267  for (float t1 = 0; t1<tmax; t1+=xprecision) {
23268  const float
23269  t2 = t1*t1,
23270  t3 = t2*t1;
23271  const int
23272  nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0),
23273  ny = (int)(ay*t3 + by*t2 + v0*t1 + y0),
23274  ntx = tx0 + (int)((tx1-tx0)*t1/tmax),
23275  nty = ty0 + (int)((ty1-ty0)*t1/tmax);
23276  draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch);
23277  ninit_hatch = false;
23278  ox = nx; oy = ny; otx = ntx; oty = nty;
23279  }
23280  return *this;
23281  }
23282 
23283  // Draw a set of connected spline curves in the instance image (internal).
23284  template<typename tp, typename tt, typename tc>
23285  CImg<T>& _draw_spline(const tp& points, const tt& tangents, const unsigned int W, const unsigned int H,
23286  const tc *const color, const float opacity,
23287  const bool close_set, const float precision,
23288  const unsigned int pattern, const bool init_hatch) {
23289  if (is_empty() || !points || !tangents || W<2) return *this;
23290  bool ninit_hatch = init_hatch;
23291  switch (H) {
23292  case 0 : case 1 :
23293  throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
23294  pixel_type());
23295  case 2 : {
23296  const int x0 = (int)points(0,0), y0 = (int)points(0,1);
23297  const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1);
23298  int ox = x0, oy = y0;
23299  float ou = u0, ov = v0;
23300  for (unsigned int i = 1; i<W; ++i) {
23301  const int x = (int)points(i,0), y = (int)points(i,1);
23302  const float u = (float)tangents(i,0), v = (float)tangents(i,1);
23303  draw_spline(ox,oy,ou,ov,x,y,u,v,color,precision,opacity,pattern,ninit_hatch);
23304  ninit_hatch = false;
23305  ox = x; oy = y; ou = u; ov = v;
23306  }
23307  if (close_set) draw_spline(ox,oy,ou,ov,x0,y0,u0,v0,color,precision,opacity,pattern,false);
23308  } break;
23309  default : {
23310  const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
23311  const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1), w0 = (float)tangents(0,2);
23312  int ox = x0, oy = y0, oz = z0;
23313  float ou = u0, ov = v0, ow = w0;
23314  for (unsigned int i = 1; i<W; ++i) {
23315  const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
23316  const float u = (float)tangents(i,0), v = (float)tangents(i,1), w = (float)tangents(i,2);
23317  draw_spline(ox,oy,oz,ou,ov,ow,x,y,z,u,v,w,color,opacity,pattern,ninit_hatch);
23318  ninit_hatch = false;
23319  ox = x; oy = y; oz = z; ou = u; ov = v; ow = w;
23320  }
23321  if (close_set) draw_spline(ox,oy,oz,ou,ov,ow,x0,y0,z0,u0,v0,w0,color,precision,opacity,pattern,false);
23322  }
23323  }
23324  return *this;
23325  }
23326 
23327  // Draw a set of connected spline curves in the instance image (internal).
23328  template<typename tp, typename tc>
23329  CImg<T>& _draw_spline(const tp& points, const unsigned int W, const unsigned int H,
23330  const tc *const color, const float opacity,
23331  const bool close_set, const float precision,
23332  const unsigned int pattern, const bool init_hatch) {
23333  if (is_empty() || !points || W<2) return *this;
23334  CImg<Tfloat> tangents;
23335  switch (H) {
23336  case 0 : case 1 :
23337  throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
23338  pixel_type());
23339  case 2 : {
23340  tangents.assign(W,H);
23341  for (unsigned int p = 0; p<W; ++p) {
23342  const unsigned int
23343  p0 = close_set?(p+W-1)%W:(p?p-1:0),
23344  p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
23345  const float
23346  x = (float)points(p,0),
23347  y = (float)points(p,1),
23348  x0 = (float)points(p0,0),
23349  y0 = (float)points(p0,1),
23350  x1 = (float)points(p1,0),
23351  y1 = (float)points(p1,1),
23352  u0 = x - x0,
23353  v0 = y - y0,
23354  n0 = 1e-8f + (float)std::sqrt(u0*u0 + v0*v0),
23355  u1 = x1 - x,
23356  v1 = y1 - y,
23357  n1 = 1e-8f + (float)std::sqrt(u1*u1 + v1*v1),
23358  u = u0/n0 + u1/n1,
23359  v = v0/n0 + v1/n1,
23360  n = 1e-8f + (float)std::sqrt(u*u + v*v),
23361  fact = 0.5f*(n0 + n1);
23362  tangents(p,0) = (Tfloat)(fact*u/n);
23363  tangents(p,1) = (Tfloat)(fact*v/n);
23364  }
23365  } break;
23366  default : {
23367  tangents.assign(W,H);
23368  for (unsigned int p = 0; p<W; ++p) {
23369  const unsigned int
23370  p0 = close_set?(p+W-1)%W:(p?p-1:0),
23371  p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
23372  const float
23373  x = (float)points(p,0),
23374  y = (float)points(p,1),
23375  z = (float)points(p,2),
23376  x0 = (float)points(p0,0),
23377  y0 = (float)points(p0,1),
23378  z0 = (float)points(p0,2),
23379  x1 = (float)points(p1,0),
23380  y1 = (float)points(p1,1),
23381  z1 = (float)points(p1,2),
23382  u0 = x - x0,
23383  v0 = y - y0,
23384  w0 = z - z0,
23385  n0 = 1e-8f + (float)std::sqrt(u0*u0 + v0*v0 + w0*w0),
23386  u1 = x1 - x,
23387  v1 = y1 - y,
23388  w1 = z1 - z,
23389  n1 = 1e-8f + (float)std::sqrt(u1*u1 + v1*v1 + w1*w1),
23390  u = u0/n0 + u1/n1,
23391  v = v0/n0 + v1/n1,
23392  w = w0/n0 + w1/n1,
23393  n = 1e-8f + (float)std::sqrt(u*u + v*v + w*w),
23394  fact = 0.5f*(n0 + n1);
23395  tangents(p,0) = (Tfloat)(fact*u/n);
23396  tangents(p,1) = (Tfloat)(fact*v/n);
23397  tangents(p,2) = (Tfloat)(fact*w/n);
23398  }
23399  }
23400  }
23401  return _draw_spline(points,tangents,W,H,color,opacity,close_set,precision,pattern,init_hatch);
23402  }
23403 
23405  template<typename tp, typename tt, typename tc>
23407  const tc *const color, const float opacity=1,
23408  const bool close_set=false, const float precision=4,
23409  const unsigned int pattern=~0U, const bool init_hatch=true) {
23410  unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()),(unsigned int)(tangents[p].size()));
23411  return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.width,H);
23412  }
23413 
23415  template<typename tp, typename tt, typename tc>
23417  const CImg<tc>& color, const float opacity=1,
23418  const bool close_set=false, const float precision=4,
23419  const unsigned int pattern=~0U, const bool init_hatch=true) {
23420  return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
23421  }
23422 
23424  template<typename tp, typename tt, typename tc>
23425  CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
23426  const tc *const color, const float opacity=1,
23427  const bool close_set=false, const float precision=4,
23428  const unsigned int pattern=~0U, const bool init_hatch=true) {
23429  return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
23430  }
23431 
23433  template<typename tp, typename tt, typename tc>
23434  CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
23435  const CImg<tc>& color, const float opacity=1,
23436  const bool close_set=false, const float precision=4,
23437  const unsigned int pattern=~0U, const bool init_hatch=true) {
23438  return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
23439  }
23440 
23442  template<typename t, typename tc>
23444  const tc *const color, const float opacity=1,
23445  const bool close_set=false, const float precision=4,
23446  const unsigned int pattern=~0U, const bool init_hatch=true) {
23447  unsigned int H = ~0U;
23448  cimglist_for(points,p) { const unsigned int s = points[p].size(); if (s<H) H = s; }
23449  return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.width,H);
23450  }
23451 
23453  template<typename t, typename tc>
23455  CImg<tc>& color, const float opacity=1,
23456  const bool close_set=false, const float precision=4,
23457  const unsigned int pattern=~0U, const bool init_hatch=true) {
23458  return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
23459  }
23460 
23462  template<typename t, typename tc>
23464  const tc *const color, const float opacity=1,
23465  const bool close_set=false, const float precision=4,
23466  const unsigned int pattern=~0U, const bool init_hatch=true) {
23467  return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
23468  }
23469 
23471  template<typename t, typename tc>
23473  const CImg<tc>& color, const float opacity=1,
23474  const bool close_set=false, const float precision=4,
23475  const unsigned int pattern=~0U, const bool init_hatch=true) {
23476  return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
23477  }
23478 
23479  // Inner macro for drawing triangles.
23480 #define _cimg_for_triangle1(img,xl,xr,y,x0,y0,x1,y1,x2,y2) \
23481  for (int y = y0<0?0:y0, \
23482  xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
23483  xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
23484  _sxn=1, \
23485  _sxr=1, \
23486  _sxl=1, \
23487  _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
23488  _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
23489  _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
23490  _dyn = y2-y1, \
23491  _dyr = y2-y0, \
23492  _dyl = y1-y0, \
23493  _counter = (_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
23494  _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
23495  _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
23496  cimg::min((int)(img).height-y-1,y2-y)), \
23497  _errn = _dyn/2, \
23498  _errr = _dyr/2, \
23499  _errl = _dyl/2, \
23500  _rxn = _dyn?(x2-x1)/_dyn:0, \
23501  _rxr = _dyr?(x2-x0)/_dyr:0, \
23502  _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
23503  (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn); \
23504  _counter>=0; --_counter, ++y, \
23505  xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
23506  xl+=(y!=y1)?_rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0): \
23507  (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
23508 
23509 #define _cimg_for_triangle2(img,xl,cl,xr,cr,y,x0,y0,c0,x1,y1,c1,x2,y2,c2) \
23510  for (int y = y0<0?0:y0, \
23511  xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
23512  cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
23513  xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
23514  cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
23515  _sxn=1, _scn=1, \
23516  _sxr=1, _scr=1, \
23517  _sxl=1, _scl=1, \
23518  _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
23519  _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
23520  _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
23521  _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
23522  _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
23523  _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
23524  _dyn = y2-y1, \
23525  _dyr = y2-y0, \
23526  _dyl = y1-y0, \
23527  _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
23528  _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
23529  _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
23530  _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
23531  _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
23532  _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
23533  cimg::min((int)(img).height-y-1,y2-y)), \
23534  _errn = _dyn/2, _errcn = _errn, \
23535  _errr = _dyr/2, _errcr = _errr, \
23536  _errl = _dyl/2, _errcl = _errl, \
23537  _rxn = _dyn?(x2-x1)/_dyn:0, \
23538  _rcn = _dyn?(c2-c1)/_dyn:0, \
23539  _rxr = _dyr?(x2-x0)/_dyr:0, \
23540  _rcr = _dyr?(c2-c0)/_dyr:0, \
23541  _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
23542  (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
23543  _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
23544  (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ); \
23545  _counter>=0; --_counter, ++y, \
23546  xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
23547  cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
23548  xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
23549  _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
23550  (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
23551  _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
23552 
23553 #define _cimg_for_triangle3(img,xl,txl,tyl,xr,txr,tyr,y,x0,y0,tx0,ty0,x1,y1,tx1,ty1,x2,y2,tx2,ty2) \
23554  for (int y = y0<0?0:y0, \
23555  xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
23556  txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
23557  tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
23558  xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
23559  txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
23560  tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
23561  _sxn=1, _stxn=1, _styn=1, \
23562  _sxr=1, _stxr=1, _styr=1, \
23563  _sxl=1, _stxl=1, _styl=1, \
23564  _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
23565  _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
23566  _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
23567  _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
23568  _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
23569  _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
23570  _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
23571  _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
23572  _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
23573  _dyn = y2-y1, \
23574  _dyr = y2-y0, \
23575  _dyl = y1-y0, \
23576  _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
23577  _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
23578  _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
23579  _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
23580  _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
23581  _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
23582  _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
23583  _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
23584  _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
23585  cimg::min((int)(img).height-y-1,y2-y)), \
23586  _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, \
23587  _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, \
23588  _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, \
23589  _rxn = _dyn?(x2-x1)/_dyn:0, \
23590  _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
23591  _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
23592  _rxr = _dyr?(x2-x0)/_dyr:0, \
23593  _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
23594  _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
23595  _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
23596  (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
23597  _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
23598  (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
23599  _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
23600  (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
23601  _counter>=0; --_counter, ++y, \
23602  xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
23603  txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
23604  tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
23605  xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
23606  tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
23607  _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
23608  (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
23609  _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1,\
23610  _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
23611 
23612 #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) \
23613  for (int y = y0<0?0:y0, \
23614  xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
23615  cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
23616  txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
23617  tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
23618  xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
23619  cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
23620  txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
23621  tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
23622  _sxn=1, _scn=1, _stxn=1, _styn=1, \
23623  _sxr=1, _scr=1, _stxr=1, _styr=1, \
23624  _sxl=1, _scl=1, _stxl=1, _styl=1, \
23625  _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
23626  _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
23627  _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
23628  _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
23629  _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
23630  _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
23631  _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
23632  _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
23633  _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
23634  _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
23635  _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
23636  _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
23637  _dyn = y2-y1, \
23638  _dyr = y2-y0, \
23639  _dyl = y1-y0, \
23640  _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
23641  _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
23642  _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
23643  _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
23644  _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
23645  _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
23646  _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
23647  _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
23648  _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
23649  _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
23650  _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
23651  _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
23652  cimg::min((int)(img).height-y-1,y2-y)), \
23653  _errn = _dyn/2, _errcn = _errn, _errtxn = _errn, _errtyn = _errn, \
23654  _errr = _dyr/2, _errcr = _errr, _errtxr = _errr, _errtyr = _errr, \
23655  _errl = _dyl/2, _errcl = _errl, _errtxl = _errl, _errtyl = _errl, \
23656  _rxn = _dyn?(x2-x1)/_dyn:0, \
23657  _rcn = _dyn?(c2-c1)/_dyn:0, \
23658  _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
23659  _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
23660  _rxr = _dyr?(x2-x0)/_dyr:0, \
23661  _rcr = _dyr?(c2-c0)/_dyr:0, \
23662  _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
23663  _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
23664  _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
23665  (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
23666  _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
23667  (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ), \
23668  _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
23669  (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
23670  _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
23671  (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
23672  _counter>=0; --_counter, ++y, \
23673  xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
23674  cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
23675  txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
23676  tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
23677  xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
23678  txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
23679  tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
23680  _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
23681  (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
23682  _errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
23683  _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
23684  _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
23685 
23686 #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) \
23687  for (int y = y0<0?0:y0, \
23688  xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
23689  txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
23690  tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
23691  lxr = y0>=0?lx0:(lx0-y0*(lx2-lx0)/(y2-y0)), \
23692  lyr = y0>=0?ly0:(ly0-y0*(ly2-ly0)/(y2-y0)), \
23693  xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
23694  txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
23695  tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
23696  lxl = y1>=0?(y0>=0?(y0==y1?lx1:lx0):(lx0-y0*(lx1-lx0)/(y1-y0))):(lx1-y1*(lx2-lx1)/(y2-y1)), \
23697  lyl = y1>=0?(y0>=0?(y0==y1?ly1:ly0):(ly0-y0*(ly1-ly0)/(y1-y0))):(ly1-y1*(ly2-ly1)/(y2-y1)), \
23698  _sxn=1, _stxn=1, _styn=1, _slxn=1, _slyn=1, \
23699  _sxr=1, _stxr=1, _styr=1, _slxr=1, _slyr=1, \
23700  _sxl=1, _stxl=1, _styl=1, _slxl=1, _slyl=1, \
23701  _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), _dyn = y2-y1, \
23702  _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), _dyr = y2-y0, \
23703  _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), _dyl = y1-y0, \
23704  _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
23705  _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
23706  _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
23707  _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
23708  _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
23709  _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
23710  _dlxn = lx2>lx1?lx2-lx1:(_slxn=-1,lx1-lx2), \
23711  _dlxr = lx2>lx0?lx2-lx0:(_slxr=-1,lx0-lx2), \
23712  _dlxl = lx1>lx0?lx1-lx0:(_slxl=-1,lx0-lx1), \
23713  _dlyn = ly2>ly1?ly2-ly1:(_slyn=-1,ly1-ly2), \
23714  _dlyr = ly2>ly0?ly2-ly0:(_slyr=-1,ly0-ly2), \
23715  _dlyl = ly1>ly0?ly1-ly0:(_slyl=-1,ly0-ly1), \
23716  _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
23717  _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
23718  _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
23719  _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
23720  _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
23721  _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
23722  _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
23723  _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
23724  _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
23725  _dlxn-=_dyn?_dyn*(_dlxn/_dyn):0, \
23726  _dlxr-=_dyr?_dyr*(_dlxr/_dyr):0, \
23727  _dlxl-=_dyl?_dyl*(_dlxl/_dyl):0, \
23728  _dlyn-=_dyn?_dyn*(_dlyn/_dyn):0, \
23729  _dlyr-=_dyr?_dyr*(_dlyr/_dyr):0, \
23730  _dlyl-=_dyl?_dyl*(_dlyl/_dyl):0, \
23731  cimg::min((int)(img).height-y-1,y2-y)), \
23732  _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, _errlxn = _errn, _errlyn = _errn, \
23733  _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, _errlxr = _errr, _errlyr = _errr, \
23734  _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, _errlxl = _errl, _errlyl = _errl, \
23735  _rxn = _dyn?(x2-x1)/_dyn:0, \
23736  _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
23737  _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
23738  _rlxn = _dyn?(lx2-lx1)/_dyn:0, \
23739  _rlyn = _dyn?(ly2-ly1)/_dyn:0, \
23740  _rxr = _dyr?(x2-x0)/_dyr:0, \
23741  _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
23742  _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
23743  _rlxr = _dyr?(lx2-lx0)/_dyr:0, \
23744  _rlyr = _dyr?(ly2-ly0)/_dyr:0, \
23745  _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
23746  (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
23747  _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
23748  (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
23749  _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
23750  (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ), \
23751  _rlxl = (y0!=y1 && y1>0)?(_dyl?(lx1-lx0)/_dyl:0): \
23752  (_errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxn ), \
23753  _rlyl = (y0!=y1 && y1>0)?(_dyl?(ly1-ly0)/_dyl:0): \
23754  (_errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyn ); \
23755  _counter>=0; --_counter, ++y, \
23756  xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
23757  txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
23758  tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
23759  lxr+=_rlxr+((_errlxr-=_dlxr)<0?_errlxr+=_dyr,_slxr:0), \
23760  lyr+=_rlyr+((_errlyr-=_dlyr)<0?_errlyr+=_dyr,_slyr:0), \
23761  xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
23762  tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
23763  lxl+=_rlxl+((_errlxl-=_dlxl)<0?(_errlxl+=_dyl,_slxl):0), \
23764  lyl+=_rlyl+((_errlyl-=_dlyl)<0?(_errlyl+=_dyl,_slyl):0), \
23765  _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
23766  (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
23767  _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
23768  _errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxl=_rlxn, lxl=lx1, \
23769  _errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyl=_rlyn, lyl=ly1, \
23770  _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
23771 
23772  // Draw a colored triangle (inner routine, uses bresenham's algorithm).
23773  template<typename tc>
23774  CImg<T>& _draw_triangle(const int x0, const int y0,
23775  const int x1, const int y1,
23776  const int x2, const int y2,
23777  const tc *const color, const float opacity,
23778  const float brightness) {
23779  _draw_scanline(color,opacity);
23780  const float nbrightness = brightness<0?0:(brightness>2?2:brightness);
23781  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
23782  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
23783  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);
23784  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);
23785  if (ny0<dimy() && ny2>=0) {
23786  if ((nx1 - nx0)*(ny2 - ny0) - (nx2 - nx0)*(ny1 - ny0)<0)
23787  _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xl,xr,y,color,opacity,nbrightness);
23788  else
23789  _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xr,xl,y,color,opacity,nbrightness);
23790  }
23791  return *this;
23792  }
23793 
23795  template<typename tc>
23796  CImg<T>& draw_triangle(const int x0, const int y0,
23797  const int x1, const int y1,
23798  const int x2, const int y2,
23799  const tc *const color, const float opacity=1) {
23800  if (is_empty()) return *this;
23801  if (!color)
23802  throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
23803  pixel_type());
23804  _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1);
23805  return *this;
23806  }
23807 
23809  template<typename tc>
23810  CImg<T>& draw_triangle(const int x0, const int y0,
23811  const int x1, const int y1,
23812  const int x2, const int y2,
23813  const CImg<tc>& color, const float opacity=1) {
23814  return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity);
23815  }
23816 
23818  template<typename tc>
23819  CImg<T>& draw_triangle(const int x0, const int y0,
23820  const int x1, const int y1,
23821  const int x2, const int y2,
23822  const tc *const color, const float opacity,
23823  const unsigned int pattern) {
23824  if (is_empty()) return *this;
23825  if (!color)
23826  throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
23827  pixel_type());
23828  draw_line(x0,y0,x1,y1,color,opacity,pattern,true).
23829  draw_line(x1,y1,x2,y2,color,opacity,pattern,false).
23830  draw_line(x2,y2,x0,y0,color,opacity,pattern,false);
23831  return *this;
23832  }
23833 
23835  template<typename tc>
23836  CImg<T>& draw_triangle(const int x0, const int y0,
23837  const int x1, const int y1,
23838  const int x2, const int y2,
23839  const CImg<tc>& color, const float opacity,
23840  const unsigned int pattern) {
23841  return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity,pattern);
23842  }
23843 
23845  template<typename tc>
23847  const int x0, const int y0, const float z0,
23848  const int x1, const int y1, const float z1,
23849  const int x2, const int y2, const float z2,
23850  const tc *const color, const float opacity=1,
23851  const float brightness=1) {
23852  if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
23853  if (!color)
23854  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
23855  pixel_type());
23856  if (!is_sameXY(zbuffer))
23857  throw CImgArgumentException("CImg<%s>::draw_line() : Z-buffer (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) have different dimensions.",
23858  pixel_type(),zbuffer.width,zbuffer.height,zbuffer.depth,zbuffer.dim,zbuffer.data,width,height,depth,dim,data);
23859  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
23860  const float
23861  nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
23862  nbrightness = brightness<0?0:(brightness>2?2:brightness);
23863  const int whz = width*height*depth, offx = dim*whz;
23864  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
23865  float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
23866  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
23867  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2);
23868  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2);
23869  if (ny0>=dimy() || ny2<0) return *this;
23870  float
23871  pzl = (nz1 - nz0)/(ny1 - ny0),
23872  pzr = (nz2 - nz0)/(ny2 - ny0),
23873  pzn = (nz2 - nz1)/(ny2 - ny1),
23874  zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
23875  zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
23876  _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
23877  if (y==ny1) { zl = nz1; pzl = pzn; }
23878  int xleft = xleft0, xright = xright0;
23879  float zleft = zl, zright = zr;
23880  if (xright<xleft) cimg::swap(xleft,xright,zleft,zright);
23881  const int dx = xright - xleft;
23882  const float pentez = (zright - zleft)/dx;
23883  if (xleft<0 && dx) zleft-=xleft*(zright - zleft)/dx;
23884  if (xleft<0) xleft = 0;
23885  if (xright>=dimx()-1) xright = dimx()-1;
23886  T* ptrd = ptr(xleft,y,0,0);
23887  float *ptrz = zbuffer.ptr(xleft,y);
23888  if (opacity>=1) {
23889  if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
23890  if (zleft>*ptrz) {
23891  *ptrz = zleft;
23892  const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
23893  ptrd-=offx;
23894  }
23895  zleft+=pentez;
23896  } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
23897  if (zleft>*ptrz) {
23898  *ptrz = zleft;
23899  const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nbrightness*(*col++)); ptrd+=whz; }
23900  ptrd-=offx;
23901  }
23902  zleft+=pentez;
23903  } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
23904  if (zleft>*ptrz) {
23905  *ptrz = zleft;
23906  const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); ptrd+=whz; }
23907  ptrd-=offx;
23908  }
23909  zleft+=pentez;
23910  }
23911  } else {
23912  if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
23913  if (zleft>*ptrz) {
23914  *ptrz = zleft;
23915  const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=whz; }
23916  ptrd-=offx;
23917  }
23918  zleft+=pentez;
23919  } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
23920  if (zleft>*ptrz) {
23921  *ptrz = zleft;
23922  const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity*nbrightness**(col++) + *ptrd*copacity); ptrd+=whz; }
23923  ptrd-=offx;
23924  }
23925  zleft+=pentez;
23926  } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
23927  if (zleft>*ptrz) {
23928  *ptrz = zleft;
23929  const tc *col = color;
23930  cimg_forV(*this,k) {
23931  const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
23932  *ptrd = (T)(nopacity*val + *ptrd*copacity);
23933  ptrd+=whz;
23934  }
23935  ptrd-=offx;
23936  }
23937  zleft+=pentez;
23938  }
23939  }
23940  zr+=pzr; zl+=pzl;
23941  }
23942  return *this;
23943  }
23944 
23946  template<typename tc>
23948  const int x0, const int y0, const float z0,
23949  const int x1, const int y1, const float z1,
23950  const int x2, const int y2, const float z2,
23951  const CImg<tc>& color, const float opacity=1,
23952  const float brightness=1) {
23953  return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opacity,brightness);
23954  }
23955 
23957 
23971  template<typename tc>
23972  CImg<T>& draw_triangle(const int x0, const int y0,
23973  const int x1, const int y1,
23974  const int x2, const int y2,
23975  const tc *const color,
23976  const float brightness0,
23977  const float brightness1,
23978  const float brightness2,
23979  const float opacity=1) {
23980  if (is_empty()) return *this;
23981  if (!color)
23982  throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
23983  pixel_type());
23984  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
23985  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
23986  const int whz = width*height*depth, offx = dim*whz-1;
23987  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
23988  nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),
23989  nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),
23990  nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);
23991  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1);
23992  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2);
23993  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2);
23994  if (ny0>=dimy() || ny2<0) return *this;
23995  _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
23996  int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
23997  if (xright<xleft) cimg::swap(xleft,xright,cleft,cright);
23998  const int
23999  dx = xright - xleft,
24000  dc = cright>cleft?cright - cleft:cleft - cright,
24001  rc = dx?(cright - cleft)/dx:0,
24002  sc = cright>cleft?1:-1,
24003  ndc = dc-(dx?dx*(dc/dx):0);
24004  int errc = dx>>1;
24005  if (xleft<0 && dx) cleft-=xleft*(cright - cleft)/dx;
24006  if (xleft<0) xleft = 0;
24007  if (xright>=dimx()-1) xright = dimx()-1;
24008  T* ptrd = ptr(xleft,y);
24009  if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
24010  const tc *col = color;
24011  cimg_forV(*this,k) {
24012  *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
24013  ptrd+=whz;
24014  }
24015  ptrd-=offx;
24016  cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
24017  } else for (int x = xleft; x<=xright; ++x) {
24018  const tc *col = color;
24019  cimg_forV(*this,k) {
24020  const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
24021  *ptrd = (T)(nopacity*val + *ptrd*copacity);
24022  ptrd+=whz;
24023  }
24024  ptrd-=offx;
24025  cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
24026  }
24027  }
24028  return *this;
24029  }
24030 
24032  template<typename tc>
24033  CImg<T>& draw_triangle(const int x0, const int y0,
24034  const int x1, const int y1,
24035  const int x2, const int y2,
24036  const CImg<tc>& color,
24037  const float brightness0,
24038  const float brightness1,
24039  const float brightness2,
24040  const float opacity=1) {
24041  return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,brightness0,brightness1,brightness2,opacity);
24042  }
24043 
24045  template<typename tc>
24047  const int x0, const int y0, const float z0,
24048  const int x1, const int y1, const float z1,
24049  const int x2, const int y2, const float z2,
24050  const tc *const color,
24051  const float brightness0,
24052  const float brightness1,
24053  const float brightness2,
24054  const float opacity=1) {
24055  if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
24056  if (!color)
24057  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
24058  pixel_type());
24059  if (!is_sameXY(zbuffer))
24060  throw CImgArgumentException("CImg<%s>::draw_line() : Z-buffer (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) have different dimensions.",
24061  pixel_type(),zbuffer.width,zbuffer.height,zbuffer.depth,zbuffer.dim,zbuffer.data,width,height,depth,dim,data);
24062  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
24063  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
24064  const int whz = width*height*depth, offx = dim*whz;
24065  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
24066  nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),
24067  nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),
24068  nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);
24069  float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
24070  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1,nc0,nc1);
24071  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2,nc0,nc2);
24072  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2,nc1,nc2);
24073  if (ny0>=dimy() || ny2<0) return *this;
24074  float
24075  pzl = (nz1 - nz0)/(ny1 - ny0),
24076  pzr = (nz2 - nz0)/(ny2 - ny0),
24077  pzn = (nz2 - nz1)/(ny2 - ny1),
24078  zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
24079  zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
24080  _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
24081  if (y==ny1) { zl = nz1; pzl = pzn; }
24082  int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
24083  float zleft = zl, zright = zr;
24084  if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,cleft,cright);
24085  const int
24086  dx = xright - xleft,
24087  dc = cright>cleft?cright - cleft:cleft - cright,
24088  rc = dx?(cright-cleft)/dx:0,
24089  sc = cright>cleft?1:-1,
24090  ndc = dc-(dx?dx*(dc/dx):0);
24091  const float pentez = (zright - zleft)/dx;
24092  int errc = dx>>1;
24093  if (xleft<0 && dx) {
24094  cleft-=xleft*(cright - cleft)/dx;
24095  zleft-=xleft*(zright - zleft)/dx;
24096  }
24097  if (xleft<0) xleft = 0;
24098  if (xright>=dimx()-1) xright = dimx()-1;
24099  T *ptrd = ptr(xleft,y);
24100  float *ptrz = zbuffer.ptr(xleft,y);
24101  if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
24102  if (zleft>*ptrz) {
24103  *ptrz = zleft;
24104  const tc *col = color;
24105  cimg_forV(*this,k) {
24106  *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
24107  ptrd+=whz;
24108  }
24109  ptrd-=offx;
24110  }
24111  zleft+=pentez;
24112  cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
24113  } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
24114  if (zleft>*ptrz) {
24115  *ptrz = zleft;
24116  const tc *col = color;
24117  cimg_forV(*this,k) {
24118  const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
24119  *ptrd = (T)(nopacity*val + *ptrd*copacity);
24120  ptrd+=whz;
24121  }
24122  ptrd-=offx;
24123  }
24124  zleft+=pentez;
24125  cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
24126  }
24127  zr+=pzr; zl+=pzl;
24128  }
24129  return *this;
24130  }
24131 
24133  template<typename tc>
24135  const int x0, const int y0, const float z0,
24136  const int x1, const int y1, const float z1,
24137  const int x2, const int y2, const float z2,
24138  const CImg<tc>& color,
24139  const float brightness0,
24140  const float brightness1,
24141  const float brightness2,
24142  const float opacity=1) {
24143  return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,brightness0,brightness1,brightness2,opacity);
24144  }
24145 
24147  template<typename tc1, typename tc2, typename tc3>
24148  CImg<T>& draw_triangle(const int x0, const int y0,
24149  const int x1, const int y1,
24150  const int x2, const int y2,
24151  const tc1 *const color1,
24152  const tc2 *const color2,
24153  const tc3 *const color3,
24154  const float opacity=1) {
24155  const unsigned char one = 1;
24156  cimg_forV(*this,k) get_shared_channel(k).draw_triangle(x0,y0,x1,y1,x2,y2,&one,color1[k],color2[k],color3[k],opacity);
24157  return *this;
24158  }
24159 
24160  template<typename tc1, typename tc2, typename tc3>
24161  CImg<T>& draw_triangle(const int x0, const int y0,
24162  const int x1, const int y1,
24163  const int x2, const int y2,
24164  const CImg<tc1>& color1,
24165  const CImg<tc2>& color2,
24166  const CImg<tc3>& color3,
24167  const float opacity=1) {
24168  return draw_triangle(x0,y0,x1,y1,x2,y2,color1.data,color2.data,color3.data,opacity);
24169  }
24170 
24172 
24190  template<typename tc>
24191  CImg<T>& draw_triangle(const int x0, const int y0,
24192  const int x1, const int y1,
24193  const int x2, const int y2,
24194  const CImg<tc>& texture,
24195  const int tx0, const int ty0,
24196  const int tx1, const int ty1,
24197  const int tx2, const int ty2,
24198  const float opacity=1,
24199  const float brightness=1) {
24200  if (is_empty()) return *this;
24201  if (!texture || texture.dim<dim)
24202  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
24203  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
24204  if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
24205  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
24206  const float
24207  nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
24208  nbrightness = brightness<0?0:(brightness>2?2:brightness);
24209  const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
24210  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
24211  ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2;
24212  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
24213  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2);
24214  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2);
24215  if (ny0>=dimy() || ny2<0) return *this;
24216  _cimg_for_triangle3(*this,xleft0,txleft0,tyleft0,xright0,txright0,tyright0,y,
24217  nx0,ny0,ntx0,nty0,nx1,ny1,ntx1,nty1,nx2,ny2,ntx2,nty2) {
24218  int
24219  xleft = xleft0, xright = xright0,
24220  txleft = txleft0, txright = txright0,
24221  tyleft = tyleft0, tyright = tyright0;
24222  if (xright<xleft) cimg::swap(xleft,xright,txleft,txright,tyleft,tyright);
24223  const int
24224  dx = xright - xleft,
24225  dtx = txright>txleft?txright - txleft:txleft - txright,
24226  dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
24227  rtx = dx?(txright - txleft)/dx:0,
24228  rty = dx?(tyright - tyleft)/dx:0,
24229  stx = txright>txleft?1:-1,
24230  sty = tyright>tyleft?1:-1,
24231  ndtx = dtx - (dx?dx*(dtx/dx):0),
24232  ndty = dty - (dx?dx*(dty/dx):0);
24233  int errtx = dx>>1, errty = errtx;
24234  if (xleft<0 && dx) {
24235  txleft-=xleft*(txright - txleft)/dx;
24236  tyleft-=xleft*(tyright - tyleft)/dx;
24237  }
24238  if (xleft<0) xleft = 0;
24239  if (xright>=dimx()-1) xright = dimx()-1;
24240  T* ptrd = ptr(xleft,y,0,0);
24241  if (opacity>=1) {
24242  if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
24243  const tc *col = texture.ptr(txleft,tyleft);
24244  cimg_forV(*this,k) {
24245  *ptrd = (T)*col;
24246  ptrd+=whz; col+=twhz;
24247  }
24248  ptrd-=offx;
24249  txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
24250  tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
24251  } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
24252  const tc *col = texture.ptr(txleft,tyleft);
24253  cimg_forV(*this,k) {
24254  *ptrd = (T)(nbrightness**col);
24255  ptrd+=whz; col+=twhz;
24256  }
24257  ptrd-=offx;
24258  txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
24259  tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
24260  } else for (int x = xleft; x<=xright; ++x) {
24261  const tc *col = texture.ptr(txleft,tyleft);
24262  cimg_forV(*this,k) {
24263  *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
24264  ptrd+=whz; col+=twhz;
24265  }
24266  ptrd-=offx;
24267  txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
24268  tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
24269  }
24270  } else {
24271  if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
24272  const tc *col = texture.ptr(txleft,tyleft);
24273  cimg_forV(*this,k) {
24274  *ptrd = (T)(nopacity**col + *ptrd*copacity);
24275  ptrd+=whz; col+=twhz;
24276  }
24277  ptrd-=offx;
24278  txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
24279  tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
24280  } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
24281  const tc *col = texture.ptr(txleft,tyleft);
24282  cimg_forV(*this,k) {
24283  *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
24284  ptrd+=whz; col+=twhz;
24285  }
24286  ptrd-=offx;
24287  txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
24288  tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
24289  } else for (int x = xleft; x<=xright; ++x) {
24290  const tc *col = texture.ptr(txleft,tyleft);
24291  cimg_forV(*this,k) {
24292  const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
24293  *ptrd = (T)(nopacity*val + *ptrd*copacity);
24294  ptrd+=whz; col+=twhz;
24295  }
24296  ptrd-=offx;
24297  txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
24298  tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
24299  }
24300  }
24301  }
24302  return *this;
24303  }
24304 
24306  template<typename tc>
24307  CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
24308  const int x1, const int y1, const float z1,
24309  const int x2, const int y2, const float z2,
24310  const CImg<tc>& texture,
24311  const int tx0, const int ty0,
24312  const int tx1, const int ty1,
24313  const int tx2, const int ty2,
24314  const float opacity=1,
24315  const float brightness=1) {
24316  if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
24317  if (!texture || texture.dim<dim)
24318  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
24319  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
24320  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);
24321  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
24322  const float
24323  nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
24324  nbrightness = brightness<0?0:(brightness>2?2:brightness);
24325  const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
24326  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
24327  float
24328  ntx0 = tx0/z0, nty0 = ty0/z0,
24329  ntx1 = tx1/z1, nty1 = ty1/z1,
24330  ntx2 = tx2/z2, nty2 = ty2/z2,
24331  nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
24332  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
24333  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
24334  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
24335  if (ny0>=dimy() || ny2<0) return *this;
24336  float
24337  ptxl = (ntx1 - ntx0)/(ny1 - ny0),
24338  ptxr = (ntx2 - ntx0)/(ny2 - ny0),
24339  ptxn = (ntx2 - ntx1)/(ny2 - ny1),
24340  ptyl = (nty1 - nty0)/(ny1 - ny0),
24341  ptyr = (nty2 - nty0)/(ny2 - ny0),
24342  ptyn = (nty2 - nty1)/(ny2 - ny1),
24343  pzl = (nz1 - nz0)/(ny1 - ny0),
24344  pzr = (nz2 - nz0)/(ny2 - ny0),
24345  pzn = (nz2 - nz1)/(ny2 - ny1),
24346  zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
24347  txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
24348  tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
24349  zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
24350  txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
24351  tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
24352  _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
24353  if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
24354  int xleft = xleft0, xright = xright0;
24355  float
24356  zleft = zl, zright = zr,
24357  txleft = txl, txright = txr,
24358  tyleft = tyl, tyright = tyr;
24359  if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
24360  const int dx = xright - xleft;
24361  const float
24362  pentez = (zright - zleft)/dx,
24363  pentetx = (txright - txleft)/dx,
24364  pentety = (tyright - tyleft)/dx;
24365  if (xleft<0 && dx) {
24366  zleft-=xleft*(zright - zleft)/dx;
24367  txleft-=xleft*(txright - txleft)/dx;
24368  tyleft-=xleft*(tyright - tyleft)/dx;
24369  }
24370  if (xleft<0) xleft = 0;
24371  if (xright>=dimx()-1) xright = dimx()-1;
24372  T* ptrd = ptr(xleft,y,0,0);
24373  if (opacity>=1) {
24374  if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
24375  const float invz = 1/zleft;
24376  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24377  cimg_forV(*this,k) {
24378  *ptrd = (T)*col;
24379  ptrd+=whz; col+=twhz;
24380  }
24381  ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24382  } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) {
24383  const float invz = 1/zleft;
24384  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24385  cimg_forV(*this,k) {
24386  *ptrd = (T)(nbrightness**col);
24387  ptrd+=whz; col+=twhz;
24388  }
24389  ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24390  } else for (int x = xleft; x<=xright; ++x) {
24391  const float invz = 1/zleft;
24392  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24393  cimg_forV(*this,k) {
24394  *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
24395  ptrd+=whz; col+=twhz;
24396  }
24397  ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24398  }
24399  } else {
24400  if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
24401  const float invz = 1/zleft;
24402  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24403  cimg_forV(*this,k) {
24404  *ptrd = (T)(nopacity**col + *ptrd*copacity);
24405  ptrd+=whz; col+=twhz;
24406  }
24407  ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24408  } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
24409  const float invz = 1/zleft;
24410  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24411  cimg_forV(*this,k) {
24412  *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
24413  ptrd+=whz; col+=twhz;
24414  }
24415  ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24416  } else for (int x = xleft; x<=xright; ++x) {
24417  const float invz = 1/zleft;
24418  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24419  cimg_forV(*this,k) {
24420  const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
24421  *ptrd = (T)(nopacity*val + *ptrd*copacity);
24422  ptrd+=whz; col+=twhz;
24423  }
24424  ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24425  }
24426  }
24427  zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
24428  }
24429  return *this;
24430  }
24431 
24433  template<typename tc>
24435  const int x0, const int y0, const float z0,
24436  const int x1, const int y1, const float z1,
24437  const int x2, const int y2, const float z2,
24438  const CImg<tc>& texture,
24439  const int tx0, const int ty0,
24440  const int tx1, const int ty1,
24441  const int tx2, const int ty2,
24442  const float opacity=1,
24443  const float brightness=1) {
24444  if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
24445  if (!is_sameXY(zbuffer))
24446  throw CImgArgumentException("CImg<%s>::draw_line() : Z-buffer (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) have different dimensions.",
24447  pixel_type(),zbuffer.width,zbuffer.height,zbuffer.depth,zbuffer.dim,zbuffer.data,width,height,depth,dim,data);
24448  if (!texture || texture.dim<dim)
24449  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
24450  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
24451  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);
24452  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
24453  const float
24454  nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
24455  nbrightness = brightness<0?0:(brightness>2?2:brightness);
24456  const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
24457  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
24458  float
24459  ntx0 = tx0/z0, nty0 = ty0/z0,
24460  ntx1 = tx1/z1, nty1 = ty1/z1,
24461  ntx2 = tx2/z2, nty2 = ty2/z2,
24462  nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
24463  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
24464  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
24465  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
24466  if (ny0>=dimy() || ny2<0) return *this;
24467  float
24468  ptxl = (ntx1 - ntx0)/(ny1 - ny0),
24469  ptxr = (ntx2 - ntx0)/(ny2 - ny0),
24470  ptxn = (ntx2 - ntx1)/(ny2 - ny1),
24471  ptyl = (nty1 - nty0)/(ny1 - ny0),
24472  ptyr = (nty2 - nty0)/(ny2 - ny0),
24473  ptyn = (nty2 - nty1)/(ny2 - ny1),
24474  pzl = (nz1 - nz0)/(ny1 - ny0),
24475  pzr = (nz2 - nz0)/(ny2 - ny0),
24476  pzn = (nz2 - nz1)/(ny2 - ny1),
24477  zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
24478  txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
24479  tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
24480  zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
24481  txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
24482  tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
24483  _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
24484  if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
24485  int xleft = xleft0, xright = xright0;
24486  float
24487  zleft = zl, zright = zr,
24488  txleft = txl, txright = txr,
24489  tyleft = tyl, tyright = tyr;
24490  if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
24491  const int dx = xright - xleft;
24492  const float
24493  pentez = (zright - zleft)/dx,
24494  pentetx = (txright - txleft)/dx,
24495  pentety = (tyright - tyleft)/dx;
24496  if (xleft<0 && dx) {
24497  zleft-=xleft*(zright - zleft)/dx;
24498  txleft-=xleft*(txright - txleft)/dx;
24499  tyleft-=xleft*(tyright - tyleft)/dx;
24500  }
24501  if (xleft<0) xleft = 0;
24502  if (xright>=dimx()-1) xright = dimx()-1;
24503  T *ptrd = ptr(xleft,y,0,0);
24504  float *ptrz = zbuffer.ptr(xleft,y);
24505  if (opacity>=1) {
24506  if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
24507  if (zleft>*ptrz) {
24508  *ptrz = zleft;
24509  const float invz = 1/zleft;
24510  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24511  cimg_forV(*this,k) {
24512  *ptrd = (T)*col;
24513  ptrd+=whz; col+=twhz;
24514  }
24515  ptrd-=offx;
24516  }
24517  zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24518  } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
24519  if (zleft>*ptrz) {
24520  *ptrz = zleft;
24521  const float invz = 1/zleft;
24522  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24523  cimg_forV(*this,k) {
24524  *ptrd = (T)(nbrightness**col);
24525  ptrd+=whz; col+=twhz;
24526  }
24527  ptrd-=offx;
24528  }
24529  zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24530  } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
24531  if (zleft>*ptrz) {
24532  *ptrz = zleft;
24533  const float invz = 1/zleft;
24534  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24535  cimg_forV(*this,k) {
24536  *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
24537  ptrd+=whz; col+=twhz;
24538  }
24539  ptrd-=offx;
24540  }
24541  zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24542  }
24543  } else {
24544  if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
24545  if (zleft>*ptrz) {
24546  *ptrz = zleft;
24547  const float invz = 1/zleft;
24548  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24549  cimg_forV(*this,k) {
24550  *ptrd = (T)(nopacity**col + *ptrd*copacity);
24551  ptrd+=whz; col+=twhz;
24552  }
24553  ptrd-=offx;
24554  }
24555  zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24556  } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
24557  if (zleft>*ptrz) {
24558  *ptrz = zleft;
24559  const float invz = 1/zleft;
24560  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24561  cimg_forV(*this,k) {
24562  *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
24563  ptrd+=whz; col+=twhz;
24564  }
24565  ptrd-=offx;
24566  }
24567  zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24568  } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
24569  if (zleft>*ptrz) {
24570  *ptrz = zleft;
24571  const float invz = 1/zleft;
24572  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
24573  cimg_forV(*this,k) {
24574  const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
24575  *ptrd = (T)(nopacity*val + *ptrd*copacity);
24576  ptrd+=whz; col+=twhz;
24577  }
24578  ptrd-=offx;
24579  }
24580  zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
24581  }
24582  }
24583  zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
24584  }
24585  return *this;
24586  }
24587 
24589 
24607  template<typename tc, typename tl>
24608  CImg<T>& draw_triangle(const int x0, const int y0,
24609  const int x1, const int y1,
24610  const int x2, const int y2,
24611  const tc *const color,
24612  const CImg<tl>& light,
24613  const int lx0, const int ly0,
24614  const int lx1, const int ly1,
24615  const int lx2, const int ly2,
24616  const float opacity=1) {
24617  if (is_empty()) return *this;
24618  if (!color)
24619  throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
24620  pixel_type());
24621  if (!light)
24622  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
24623  pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
24624  if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,color,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
24625  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
24626  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
24627  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
24628  nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
24629  const int whz = width*height*depth, offx = dim*whz-1;
24630  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1);
24631  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2);
24632  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2);
24633  if (ny0>=dimy() || ny2<0) return *this;
24634  _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
24635  nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
24636  int
24637  xleft = xleft0, xright = xright0,
24638  lxleft = lxleft0, lxright = lxright0,
24639  lyleft = lyleft0, lyright = lyright0;
24640  if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright);
24641  const int
24642  dx = xright - xleft,
24643  dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
24644  dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
24645  rlx = dx?(lxright - lxleft)/dx:0,
24646  rly = dx?(lyright - lyleft)/dx:0,
24647  slx = lxright>lxleft?1:-1,
24648  sly = lyright>lyleft?1:-1,
24649  ndlx = dlx - (dx?dx*(dlx/dx):0),
24650  ndly = dly - (dx?dx*(dly/dx):0);
24651  int errlx = dx>>1, errly = errlx;
24652  if (xleft<0 && dx) {
24653  lxleft-=xleft*(lxright - lxleft)/dx;
24654  lyleft-=xleft*(lyright - lyleft)/dx;
24655  }
24656  if (xleft<0) xleft = 0;
24657  if (xright>=dimx()-1) xright = dimx()-1;
24658  T* ptrd = ptr(xleft,y,0,0);
24659  if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
24660  const tl l = light(lxleft,lyleft);
24661  const tc *col = color;
24662  cimg_forV(*this,k) {
24663  *ptrd = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
24664  ptrd+=whz;
24665  }
24666  ptrd-=offx;
24667  lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
24668  lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
24669  } else for (int x = xleft; x<=xright; ++x) {
24670  const tl l = light(lxleft,lyleft);
24671  const tc *col = color;
24672  cimg_forV(*this,k) {
24673  const T val = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
24674  *ptrd = (T)(nopacity*val + *ptrd*copacity);
24675  ptrd+=whz;
24676  }
24677  ptrd-=offx;
24678  lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
24679  lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
24680  }
24681  }
24682  return *this;
24683  }
24684 
24686  template<typename tc, typename tl>
24687  CImg<T>& draw_triangle(const int x0, const int y0,
24688  const int x1, const int y1,
24689  const int x2, const int y2,
24690  const CImg<tc>& color,
24691  const CImg<tl>& light,
24692  const int lx0, const int ly0,
24693  const int lx1, const int ly1,
24694  const int lx2, const int ly2,
24695  const float opacity=1) {
24696  return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
24697  }
24698 
24700  template<typename tc, typename tl>
24702  const int x0, const int y0, const float z0,
24703  const int x1, const int y1, const float z1,
24704  const int x2, const int y2, const float z2,
24705  const tc *const color,
24706  const CImg<tl>& light,
24707  const int lx0, const int ly0,
24708  const int lx1, const int ly1,
24709  const int lx2, const int ly2,
24710  const float opacity=1) {
24711  if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
24712  if (!color)
24713  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
24714  pixel_type());
24715  if (!light)
24716  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
24717  pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
24718  if (!is_sameXY(zbuffer))
24719  throw CImgArgumentException("CImg<%s>::draw_line() : Z-buffer (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) have different dimensions.",
24720  pixel_type(),zbuffer.width,zbuffer.height,zbuffer.depth,zbuffer.dim,zbuffer.data,width,height,depth,dim,data);
24721  if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,
24722  +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
24723  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
24724  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
24725  const int whz = width*height*depth, offx = dim*whz;
24726  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
24727  nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
24728  float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
24729  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1,nz0,nz1);
24730  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2,nz0,nz2);
24731  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2,nz1,nz2);
24732  if (ny0>=dimy() || ny2<0) return *this;
24733  float
24734  pzl = (nz1 - nz0)/(ny1 - ny0),
24735  pzr = (nz2 - nz0)/(ny2 - ny0),
24736  pzn = (nz2 - nz1)/(ny2 - ny1),
24737  zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
24738  zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
24739  _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
24740  nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
24741  if (y==ny1) { zl = nz1; pzl = pzn; }
24742  int
24743  xleft = xleft0, xright = xright0,
24744  lxleft = lxleft0, lxright = lxright0,
24745  lyleft = lyleft0, lyright = lyright0;
24746  float zleft = zl, zright = zr;
24747  if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,lxleft,lxright,lyleft,lyright);
24748  const int
24749  dx = xright - xleft,
24750  dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
24751  dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
24752  rlx = dx?(lxright - lxleft)/dx:0,
24753  rly = dx?(lyright - lyleft)/dx:0,
24754  slx = lxright>lxleft?1:-1,
24755  sly = lyright>lyleft?1:-1,
24756  ndlx = dlx - (dx?dx*(dlx/dx):0),
24757  ndly = dly - (dx?dx*(dly/dx):0);
24758  const float pentez = (zright - zleft)/dx;
24759  int errlx = dx>>1, errly = errlx;
24760  if (xleft<0 && dx) {
24761  zleft-=xleft*(zright - zleft)/dx;
24762  lxleft-=xleft*(lxright - lxleft)/dx;
24763  lyleft-=xleft*(lyright - lyleft)/dx;
24764  }
24765  if (xleft<0) xleft = 0;
24766  if (xright>=dimx()-1) xright = dimx()-1;
24767  T *ptrd = ptr(xleft,y,0,0);
24768  float *ptrz = zbuffer.ptr(xleft,y);
24769  if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
24770  if (zleft>*ptrz) {
24771  *ptrz = zleft;
24772  const tl l = light(lxleft,lyleft);
24773  const tc *col = color;
24774  cimg_forV(*this,k) {
24775  const tc cval = *(col++);
24776  *ptrd = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
24777  ptrd+=whz;
24778  }
24779  ptrd-=offx;
24780  }
24781  zleft+=pentez;
24782  lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
24783  lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
24784  } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
24785  if (zleft>*ptrz) {
24786  *ptrz = zleft;
24787  const tl l = light(lxleft,lyleft);
24788  const tc *col = color;
24789  cimg_forV(*this,k) {
24790  const tc cval = *(col++);
24791  const T val = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
24792  *ptrd = (T)(nopacity*val + *ptrd*copacity);
24793  ptrd+=whz;
24794  }
24795  ptrd-=offx;
24796  }
24797  zleft+=pentez;
24798  lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
24799  lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
24800  }
24801  zr+=pzr; zl+=pzl;
24802  }
24803  return *this;
24804  }
24805 
24807  template<typename tc, typename tl>
24809  const int x0, const int y0, const float z0,
24810  const int x1, const int y1, const float z1,
24811  const int x2, const int y2, const float z2,
24812  const CImg<tc>& color,
24813  const CImg<tl>& light,
24814  const int lx0, const int ly0,
24815  const int lx1, const int ly1,
24816  const int lx2, const int ly2,
24817  const float opacity=1) {
24818  return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
24819  }
24820 
24822 
24842  template<typename tc>
24843  CImg<T>& draw_triangle(const int x0, const int y0,
24844  const int x1, const int y1,
24845  const int x2, const int y2,
24846  const CImg<tc>& texture,
24847  const int tx0, const int ty0,
24848  const int tx1, const int ty1,
24849  const int tx2, const int ty2,
24850  const float brightness0,
24851  const float brightness1,
24852  const float brightness2,
24853  const float opacity=1) {
24854  if (is_empty()) return *this;
24855  if (!texture || texture.dim<dim)
24856  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
24857  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
24858  if (is_overlapped(texture))
24859  return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,brightness0,brightness1,brightness2,opacity);
24860  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
24861  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
24862  const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
24863  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
24864  ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
24865  nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),
24866  nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),
24867  nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);
24868  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1);
24869  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2);
24870  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2);
24871  if (ny0>=dimy() || ny2<0) return *this;
24872  _cimg_for_triangle4(*this,xleft0,cleft0,txleft0,tyleft0,xright0,cright0,txright0,tyright0,y,
24873  nx0,ny0,nc0,ntx0,nty0,nx1,ny1,nc1,ntx1,nty1,nx2,ny2,nc2,ntx2,nty2) {
24874  int
24875  xleft = xleft0, xright = xright0,
24876  cleft = cleft0, cright = cright0,
24877  txleft = txleft0, txright = txright0,
24878  tyleft = tyleft0, tyright = tyright0;
24879  if (xright<xleft) cimg::swap(xleft,xright,cleft,cright,txleft,txright,tyleft,tyright);
24880  const int
24881  dx = xright - xleft,
24882  dc = cright>cleft?cright - cleft:cleft - cright,
24883  dtx = txright>txleft?txright - txleft:txleft - txright,
24884  dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
24885  rc = dx?(cright - cleft)/dx:0,
24886  rtx = dx?(txright - txleft)/dx:0,
24887  rty = dx?(tyright - tyleft)/dx:0,
24888  sc = cright>cleft?1:-1,
24889  stx = txright>txleft?1:-1,
24890  sty = tyright>tyleft?1:-1,
24891  ndc = dc - (dx?dx*(dc/dx):0),
24892  ndtx = dtx - (dx?dx*(dtx/dx):0),
24893  ndty = dty - (dx?dx*(dty/dx):0);
24894  int errc = dx>>1, errtx = errc, errty = errc;
24895  if (xleft<0 && dx) {
24896  cleft-=xleft*(cright - cleft)/dx;
24897  txleft-=xleft*(txright - txleft)/dx;
24898  tyleft-=xleft*(tyright - tyleft)/dx;
24899  }
24900  if (xleft<0) xleft = 0;
24901  if (xright>=dimx()-1) xright = dimx()-1;
24902  T* ptrd = ptr(xleft,y,0,0);
24903  if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
24904  const tc *col = texture.ptr(txleft,tyleft);
24905  cimg_forV(*this,k) {
24906  *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
24907  ptrd+=whz; col+=twhz;
24908  }
24909  ptrd-=offx;
24910  cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
24911  txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
24912  tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
24913  } else for (int x = xleft; x<=xright; ++x) {
24914  const tc *col = texture.ptr(txleft,tyleft);
24915  cimg_forV(*this,k) {
24916  const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
24917  *ptrd = (T)(nopacity*val + *ptrd*copacity);
24918  ptrd+=whz; col+=twhz;
24919  }
24920  ptrd-=offx;
24921  cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
24922  txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
24923  tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
24924  }
24925  }
24926  return *this;
24927  }
24928 
24930  template<typename tc>
24931  CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
24932  const int x1, const int y1, const float z1,
24933  const int x2, const int y2, const float z2,
24934  const CImg<tc>& texture,
24935  const int tx0, const int ty0,
24936  const int tx1, const int ty1,
24937  const int tx2, const int ty2,
24938  const float brightness0,
24939  const float brightness1,
24940  const float brightness2,
24941  const float opacity=1) {
24942  if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
24943  if (!texture || texture.dim<dim)
24944  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
24945  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
24946  if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
24947  brightness0,brightness1,brightness2,opacity);
24948  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
24949  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
24950  const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
24951  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
24952  nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),
24953  nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),
24954  nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);
24955  float
24956  ntx0 = tx0/z0, nty0 = ty0/z0,
24957  ntx1 = tx1/z1, nty1 = ty1/z1,
24958  ntx2 = tx2/z2, nty2 = ty2/z2,
24959  nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
24960  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
24961  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
24962  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
24963  if (ny0>=dimy() || ny2<0) return *this;
24964  float
24965  ptxl = (ntx1 - ntx0)/(ny1 - ny0),
24966  ptxr = (ntx2 - ntx0)/(ny2 - ny0),
24967  ptxn = (ntx2 - ntx1)/(ny2 - ny1),
24968  ptyl = (nty1 - nty0)/(ny1 - ny0),
24969  ptyr = (nty2 - nty0)/(ny2 - ny0),
24970  ptyn = (nty2 - nty1)/(ny2 - ny1),
24971  pzl = (nz1 - nz0)/(ny1 - ny0),
24972  pzr = (nz2 - nz0)/(ny2 - ny0),
24973  pzn = (nz2 - nz1)/(ny2 - ny1),
24974  zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
24975  txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
24976  tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
24977  zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
24978  txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
24979  tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
24980  _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
24981  if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
24982  int
24983  xleft = xleft0, xright = xright0,
24984  cleft = cleft0, cright = cright0;
24985  float
24986  zleft = zl, zright = zr,
24987  txleft = txl, txright = txr,
24988  tyleft = tyl, tyright = tyr;
24989  if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
24990  const int
24991  dx = xright - xleft,
24992  dc = cright>cleft?cright - cleft:cleft - cright,
24993  rc = dx?(cright - cleft)/dx:0,
24994  sc = cright>cleft?1:-1,
24995  ndc = dc - (dx?dx*(dc/dx):0);
24996  const float
24997  pentez = (zright - zleft)/dx,
24998  pentetx = (txright - txleft)/dx,
24999  pentety = (tyright - tyleft)/dx;
25000  int errc = dx>>1;
25001  if (xleft<0 && dx) {
25002  cleft-=xleft*(cright - cleft)/dx;
25003  zleft-=xleft*(zright - zleft)/dx;
25004  txleft-=xleft*(txright - txleft)/dx;
25005  tyleft-=xleft*(tyright - tyleft)/dx;
25006  }
25007  if (xleft<0) xleft = 0;
25008  if (xright>=dimx()-1) xright = dimx()-1;
25009  T* ptrd = ptr(xleft,y,0,0);
25010  if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
25011  const float invz = 1/zleft;
25012  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
25013  cimg_forV(*this,k) {
25014  *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
25015  ptrd+=whz; col+=twhz;
25016  }
25017  ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
25018  cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
25019  } else for (int x = xleft; x<=xright; ++x) {
25020  const float invz = 1/zleft;
25021  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
25022  cimg_forV(*this,k) {
25023  const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
25024  *ptrd = (T)(nopacity*val + *ptrd*copacity);
25025  ptrd+=whz; col+=twhz;
25026  }
25027  ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
25028  cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
25029  }
25030  zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
25031  }
25032  return *this;
25033  }
25034 
25036  template<typename tc>
25038  const int x0, const int y0, const float z0,
25039  const int x1, const int y1, const float z1,
25040  const int x2, const int y2, const float z2,
25041  const CImg<tc>& texture,
25042  const int tx0, const int ty0,
25043  const int tx1, const int ty1,
25044  const int tx2, const int ty2,
25045  const float brightness0,
25046  const float brightness1,
25047  const float brightness2,
25048  const float opacity=1) {
25049  if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
25050  if (!is_sameXY(zbuffer))
25051  throw CImgArgumentException("CImg<%s>::draw_line() : Z-buffer (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) have different dimensions.",
25052  pixel_type(),zbuffer.width,zbuffer.height,zbuffer.depth,zbuffer.dim,zbuffer.data,width,height,depth,dim,data);
25053  if (!texture || texture.dim<dim)
25054  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
25055  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
25056  if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
25057  brightness0,brightness1,brightness2,opacity);
25058  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
25059  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
25060  const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
25061  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
25062  nc0 = (int)((brightness0<0.0f?0.0f:(brightness0>2.0f?2.0f:brightness0))*256.0f),
25063  nc1 = (int)((brightness1<0.0f?0.0f:(brightness1>2.0f?2.0f:brightness1))*256.0f),
25064  nc2 = (int)((brightness2<0.0f?0.0f:(brightness2>2.0f?2.0f:brightness2))*256.0f);
25065  float
25066  ntx0 = tx0/z0, nty0 = ty0/z0,
25067  ntx1 = tx1/z1, nty1 = ty1/z1,
25068  ntx2 = tx2/z2, nty2 = ty2/z2,
25069  nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
25070  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
25071  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
25072  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
25073  if (ny0>=dimy() || ny2<0) return *this;
25074  float
25075  ptxl = (ntx1 - ntx0)/(ny1 - ny0),
25076  ptxr = (ntx2 - ntx0)/(ny2 - ny0),
25077  ptxn = (ntx2 - ntx1)/(ny2 - ny1),
25078  ptyl = (nty1 - nty0)/(ny1 - ny0),
25079  ptyr = (nty2 - nty0)/(ny2 - ny0),
25080  ptyn = (nty2 - nty1)/(ny2 - ny1),
25081  pzl = (nz1 - nz0)/(ny1 - ny0),
25082  pzr = (nz2 - nz0)/(ny2 - ny0),
25083  pzn = (nz2 - nz1)/(ny2 - ny1),
25084  zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
25085  txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
25086  tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
25087  zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
25088  txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
25089  tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
25090  _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
25091  if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
25092  int
25093  xleft = xleft0, xright = xright0,
25094  cleft = cleft0, cright = cright0;
25095  float
25096  zleft = zl, zright = zr,
25097  txleft = txl, txright = txr,
25098  tyleft = tyl, tyright = tyr;
25099  if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
25100  const int
25101  dx = xright - xleft,
25102  dc = cright>cleft?cright - cleft:cleft - cright,
25103  rc = dx?(cright - cleft)/dx:0,
25104  sc = cright>cleft?1:-1,
25105  ndc = dc - (dx?dx*(dc/dx):0);
25106  const float
25107  pentez = (zright - zleft)/dx,
25108  pentetx = (txright - txleft)/dx,
25109  pentety = (tyright - tyleft)/dx;
25110  int errc = dx>>1;
25111  if (xleft<0 && dx) {
25112  cleft-=xleft*(cright - cleft)/dx;
25113  zleft-=xleft*(zright - zleft)/dx;
25114  txleft-=xleft*(txright - txleft)/dx;
25115  tyleft-=xleft*(tyright - tyleft)/dx;
25116  }
25117  if (xleft<0) xleft = 0;
25118  if (xright>=dimx()-1) xright = dimx()-1;
25119  T* ptrd = ptr(xleft,y);
25120  float *ptrz = zbuffer.ptr(xleft,y);
25121  if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
25122  if (zleft>*ptrz) {
25123  *ptrz = zleft;
25124  const float invz = 1/zleft;
25125  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
25126  cimg_forV(*this,k) {
25127  *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
25128  ptrd+=whz; col+=twhz;
25129  }
25130  ptrd-=offx;
25131  }
25132  zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
25133  cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
25134  } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
25135  if (zleft>*ptrz) {
25136  *ptrz = zleft;
25137  const float invz = 1/zleft;
25138  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
25139  cimg_forV(*this,k) {
25140  const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
25141  *ptrd = (T)(nopacity*val + *ptrd*copacity);
25142  ptrd+=whz; col+=twhz;
25143  }
25144  ptrd-=offx;
25145  }
25146  zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
25147  cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
25148  }
25149  zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
25150  }
25151  return *this;
25152  }
25153 
25155 
25179  template<typename tc, typename tl>
25180  CImg<T>& draw_triangle(const int x0, const int y0,
25181  const int x1, const int y1,
25182  const int x2, const int y2,
25183  const CImg<tc>& texture,
25184  const int tx0, const int ty0,
25185  const int tx1, const int ty1,
25186  const int tx2, const int ty2,
25187  const CImg<tl>& light,
25188  const int lx0, const int ly0,
25189  const int lx1, const int ly1,
25190  const int lx2, const int ly2,
25191  const float opacity=1) {
25192  if (is_empty()) return *this;
25193  if (!texture || texture.dim<dim)
25194  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
25195  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
25196  if (!light)
25197  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
25198  pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
25199  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);
25200  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);
25201  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
25202  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
25203  const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
25204  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
25205  ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
25206  nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
25207  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1);
25208  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2);
25209  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2);
25210  if (ny0>=dimy() || ny2<0) return *this;
25211  _cimg_for_triangle5(*this,xleft0,lxleft0,lyleft0,txleft0,tyleft0,xright0,lxright0,lyright0,txright0,tyright0,y,
25212  nx0,ny0,nlx0,nly0,ntx0,nty0,nx1,ny1,nlx1,nly1,ntx1,nty1,nx2,ny2,nlx2,nly2,ntx2,nty2) {
25213  int
25214  xleft = xleft0, xright = xright0,
25215  lxleft = lxleft0, lxright = lxright0,
25216  lyleft = lyleft0, lyright = lyright0,
25217  txleft = txleft0, txright = txright0,
25218  tyleft = tyleft0, tyright = tyright0;
25219  if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright,txleft,txright,tyleft,tyright);
25220  const int
25221  dx = xright - xleft,
25222  dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
25223  dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
25224  dtx = txright>txleft?txright - txleft:txleft - txright,
25225  dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
25226  rlx = dx?(lxright - lxleft)/dx:0,
25227  rly = dx?(lyright - lyleft)/dx:0,
25228  rtx = dx?(txright - txleft)/dx:0,
25229  rty = dx?(tyright - tyleft)/dx:0,
25230  slx = lxright>lxleft?1:-1,
25231  sly = lyright>lyleft?1:-1,
25232  stx = txright>txleft?1:-1,
25233  sty = tyright>tyleft?1:-1,
25234  ndlx = dlx - (dx?dx*(dlx/dx):0),
25235  ndly = dly - (dx?dx*(dly/dx):0),
25236  ndtx = dtx - (dx?dx*(dtx/dx):0),
25237  ndty = dty - (dx?dx*(dty/dx):0);
25238  int errlx = dx>>1, errly = errlx, errtx = errlx, errty = errlx;
25239  if (xleft<0 && dx) {
25240  lxleft-=xleft*(lxright - lxleft)/dx;
25241  lyleft-=xleft*(lyright - lyleft)/dx;
25242  txleft-=xleft*(txright - txleft)/dx;
25243  tyleft-=xleft*(tyright - tyleft)/dx;
25244  }
25245  if (xleft<0) xleft = 0;
25246  if (xright>=dimx()-1) xright = dimx()-1;
25247  T* ptrd = ptr(xleft,y,0,0);
25248  if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
25249  const tl l = light(lxleft,lyleft);
25250  const tc *col = texture.ptr(txleft,tyleft);
25251  cimg_forV(*this,k) {
25252  *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
25253  ptrd+=whz; col+=twhz;
25254  }
25255  ptrd-=offx;
25256  lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
25257  lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
25258  txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
25259  tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
25260  } else for (int x = xleft; x<=xright; ++x) {
25261  const tl l = light(lxleft,lyleft);
25262  const tc *col = texture.ptr(txleft,tyleft);
25263  cimg_forV(*this,k) {
25264  const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
25265  *ptrd = (T)(nopacity*val + *ptrd*copacity);
25266  ptrd+=whz; col+=twhz;
25267  }
25268  ptrd-=offx;
25269  lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
25270  lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
25271  txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
25272  tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
25273  }
25274  }
25275  return *this;
25276  }
25277 
25279  template<typename tc, typename tl>
25280  CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
25281  const int x1, const int y1, const float z1,
25282  const int x2, const int y2, const float z2,
25283  const CImg<tc>& texture,
25284  const int tx0, const int ty0,
25285  const int tx1, const int ty1,
25286  const int tx2, const int ty2,
25287  const CImg<tl>& light,
25288  const int lx0, const int ly0,
25289  const int lx1, const int ly1,
25290  const int lx2, const int ly2,
25291  const float opacity=1) {
25292  if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
25293  if (!texture || texture.dim<dim)
25294  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
25295  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
25296  if (!light)
25297  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
25298  pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
25299  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);
25300  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);
25301  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
25302  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
25303  const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
25304  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
25305  nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
25306  float
25307  ntx0 = tx0/z0, nty0 = ty0/z0,
25308  ntx1 = tx1/z1, nty1 = ty1/z1,
25309  ntx2 = tx2/z2, nty2 = ty2/z2,
25310  nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
25311  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
25312  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
25313  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
25314  if (ny0>=dimy() || ny2<0) return *this;
25315  float
25316  ptxl = (ntx1 - ntx0)/(ny1 - ny0),
25317  ptxr = (ntx2 - ntx0)/(ny2 - ny0),
25318  ptxn = (ntx2 - ntx1)/(ny2 - ny1),
25319  ptyl = (nty1 - nty0)/(ny1 - ny0),
25320  ptyr = (nty2 - nty0)/(ny2 - ny0),
25321  ptyn = (nty2 - nty1)/(ny2 - ny1),
25322  pzl = (nz1 - nz0)/(ny1 - ny0),
25323  pzr = (nz2 - nz0)/(ny2 - ny0),
25324  pzn = (nz2 - nz1)/(ny2 - ny1),
25325  zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
25326  txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
25327  tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
25328  zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
25329  txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
25330  tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
25331  _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
25332  nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
25333  if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
25334  int
25335  xleft = xleft0, xright = xright0,
25336  lxleft = lxleft0, lxright = lxright0,
25337  lyleft = lyleft0, lyright = lyright0;
25338  float
25339  zleft = zl, zright = zr,
25340  txleft = txl, txright = txr,
25341  tyleft = tyl, tyright = tyr;
25342  if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
25343  const int
25344  dx = xright - xleft,
25345  dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
25346  dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
25347  rlx = dx?(lxright - lxleft)/dx:0,
25348  rly = dx?(lyright - lyleft)/dx:0,
25349  slx = lxright>lxleft?1:-1,
25350  sly = lyright>lyleft?1:-1,
25351  ndlx = dlx - (dx?dx*(dlx/dx):0),
25352  ndly = dly - (dx?dx*(dly/dx):0);
25353  const float
25354  pentez = (zright - zleft)/dx,
25355  pentetx = (txright - txleft)/dx,
25356  pentety = (tyright - tyleft)/dx;
25357  int errlx = dx>>1, errly = errlx;
25358  if (xleft<0 && dx) {
25359  zleft-=xleft*(zright - zleft)/dx;
25360  lxleft-=xleft*(lxright - lxleft)/dx;
25361  lyleft-=xleft*(lyright - lyleft)/dx;
25362  txleft-=xleft*(txright - txleft)/dx;
25363  tyleft-=xleft*(tyright - tyleft)/dx;
25364  }
25365  if (xleft<0) xleft = 0;
25366  if (xright>=dimx()-1) xright = dimx()-1;
25367  T* ptrd = ptr(xleft,y,0,0);
25368  if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
25369  const float invz = 1/zleft;
25370  const tl l = light(lxleft,lyleft);
25371  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
25372  cimg_forV(*this,k) {
25373  *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
25374  ptrd+=whz; col+=twhz;
25375  }
25376  ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
25377  lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
25378  lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
25379  } else for (int x = xleft; x<=xright; ++x) {
25380  const float invz = 1/zleft;
25381  const tl l = light(lxleft,lyleft);
25382  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
25383  cimg_forV(*this,k) {
25384  const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
25385  *ptrd = (T)(nopacity*val + *ptrd*copacity);
25386  ptrd+=whz; col+=twhz;
25387  }
25388  ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
25389  lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
25390  lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
25391  }
25392  zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
25393  }
25394  return *this;
25395  }
25396 
25398  template<typename tc, typename tl>
25400  const int x0, const int y0, const float z0,
25401  const int x1, const int y1, const float z1,
25402  const int x2, const int y2, const float z2,
25403  const CImg<tc>& texture,
25404  const int tx0, const int ty0,
25405  const int tx1, const int ty1,
25406  const int tx2, const int ty2,
25407  const CImg<tl>& light,
25408  const int lx0, const int ly0,
25409  const int lx1, const int ly1,
25410  const int lx2, const int ly2,
25411  const float opacity=1) {
25412  if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
25413  if (!is_sameXY(zbuffer))
25414  throw CImgArgumentException("CImg<%s>::draw_triangle() : Z-buffer (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) have different dimensions.",
25415  pixel_type(),zbuffer.width,zbuffer.height,zbuffer.depth,zbuffer.dim,zbuffer.data,width,height,depth,dim,data);
25416  if (!texture || texture.dim<dim)
25417  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
25418  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
25419  if (!light)
25420  throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
25421  pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
25422  if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
25423  +texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
25424  if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
25425  texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
25426  static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
25427  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
25428  const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
25429  int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
25430  nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
25431  float
25432  ntx0 = tx0/z0, nty0 = ty0/z0,
25433  ntx1 = tx1/z1, nty1 = ty1/z1,
25434  ntx2 = tx2/z2, nty2 = ty2/z2,
25435  nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
25436  if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
25437  if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
25438  if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
25439  if (ny0>=dimy() || ny2<0) return *this;
25440  float
25441  ptxl = (ntx1 - ntx0)/(ny1 - ny0),
25442  ptxr = (ntx2 - ntx0)/(ny2 - ny0),
25443  ptxn = (ntx2 - ntx1)/(ny2 - ny1),
25444  ptyl = (nty1 - nty0)/(ny1 - ny0),
25445  ptyr = (nty2 - nty0)/(ny2 - ny0),
25446  ptyn = (nty2 - nty1)/(ny2 - ny1),
25447  pzl = (nz1 - nz0)/(ny1 - ny0),
25448  pzr = (nz2 - nz0)/(ny2 - ny0),
25449  pzn = (nz2 - nz1)/(ny2 - ny1),
25450  zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
25451  txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
25452  tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
25453  zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
25454  txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
25455  tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
25456  _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
25457  nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
25458  if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
25459  int
25460  xleft = xleft0, xright = xright0,
25461  lxleft = lxleft0, lxright = lxright0,
25462  lyleft = lyleft0, lyright = lyright0;
25463  float
25464  zleft = zl, zright = zr,
25465  txleft = txl, txright = txr,
25466  tyleft = tyl, tyright = tyr;
25467  if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
25468  const int
25469  dx = xright - xleft,
25470  dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
25471  dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
25472  rlx = dx?(lxright - lxleft)/dx:0,
25473  rly = dx?(lyright - lyleft)/dx:0,
25474  slx = lxright>lxleft?1:-1,
25475  sly = lyright>lyleft?1:-1,
25476  ndlx = dlx - (dx?dx*(dlx/dx):0),
25477  ndly = dly - (dx?dx*(dly/dx):0);
25478  const float
25479  pentez = (zright - zleft)/dx,
25480  pentetx = (txright - txleft)/dx,
25481  pentety = (tyright - tyleft)/dx;
25482  int errlx = dx>>1, errly = errlx;
25483  if (xleft<0 && dx) {
25484  zleft-=xleft*(zright - zleft)/dx;
25485  lxleft-=xleft*(lxright - lxleft)/dx;
25486  lyleft-=xleft*(lyright - lyleft)/dx;
25487  txleft-=xleft*(txright - txleft)/dx;
25488  tyleft-=xleft*(tyright - tyleft)/dx;
25489  }
25490  if (xleft<0) xleft = 0;
25491  if (xright>=dimx()-1) xright = dimx()-1;
25492  T* ptrd = ptr(xleft,y);
25493  float *ptrz = zbuffer.ptr(xleft,y);
25494  if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
25495  if (zleft>*ptrz) {
25496  *ptrz = zleft;
25497  const float invz = 1/zleft;
25498  const tl l = light(lxleft,lyleft);
25499  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
25500  cimg_forV(*this,k) {
25501  *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
25502  ptrd+=whz; col+=twhz;
25503  }
25504  ptrd-=offx;
25505  }
25506  zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
25507  lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
25508  lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
25509  } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
25510  if (zleft>*ptrz) {
25511  *ptrz = zleft;
25512  const float invz = 1/zleft;
25513  const tl l = light(lxleft,lyleft);
25514  const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
25515  cimg_forV(*this,k) {
25516  const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
25517  *ptrd = (T)(nopacity*val + *ptrd*copacity);
25518  ptrd+=whz; col+=twhz;
25519  }
25520  ptrd-=offx;
25521  }
25522  zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
25523  lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
25524  lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
25525  }
25526  zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
25527  }
25528  return *this;
25529  }
25530 
25532 
25546  CImg<T>& draw_rectangle(const int x0, const int y0, const int z0, const int v0,
25547  const int x1, const int y1, const int z1, const int v1,
25548  const T val, const float opacity=1) {
25549  if (is_empty()) return *this;
25550  const bool bx = (x0<x1), by = (y0<y1), bz = (z0<z1), bv = (v0<v1);
25551  const int
25552  nx0 = bx?x0:x1, nx1 = bx?x1:x0,
25553  ny0 = by?y0:y1, ny1 = by?y1:y0,
25554  nz0 = bz?z0:z1, nz1 = bz?z1:z0,
25555  nv0 = bv?v0:v1, nv1 = bv?v1:v0;
25556  const int
25557  lX = (1 + nx1 - nx0) + (nx1>=dimx()?dimx() - 1 - nx1:0) + (nx0<0?nx0:0),
25558  lY = (1 + ny1 - ny0) + (ny1>=dimy()?dimy() - 1 - ny1:0) + (ny0<0?ny0:0),
25559  lZ = (1 + nz1 - nz0) + (nz1>=dimz()?dimz() - 1 - nz1:0) + (nz0<0?nz0:0),
25560  lV = (1 + nv1 - nv0) + (nv1>=dimv()?dimv() - 1 - nv1:0) + (nv0<0?nv0:0);
25561  const unsigned int offX = width - lX, offY = width*(height - lY), offZ = width*height*(depth - lZ);
25562  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
25563  T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0);
25564  if (lX>0 && lY>0 && lZ>0 && lV>0)
25565  for (int v = 0; v<lV; ++v) {
25566  for (int z = 0; z<lZ; ++z) {
25567  for (int y = 0; y<lY; ++y) {
25568  if (opacity>=1) {
25569  if (sizeof(T)!=1) { for (int x = 0; x<lX; ++x) *(ptrd++) = val; ptrd+=offX; }
25570  else { std::memset(ptrd,(int)val,lX); ptrd+=width; }
25571  } else { for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*val + *ptrd*copacity); ++ptrd; } ptrd+=offX; }
25572  }
25573  ptrd+=offY;
25574  }
25575  ptrd+=offZ;
25576  }
25577  return *this;
25578  }
25579 
25581 
25593  template<typename tc>
25594  CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
25595  const int x1, const int y1, const int z1,
25596  const tc *const color, const float opacity=1) {
25597  if (!color)
25598  throw CImgArgumentException("CImg<%s>::draw_rectangle : specified color is (null)",
25599  pixel_type());
25600  cimg_forV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity);
25601  return *this;
25602  }
25603 
25605  template<typename tc>
25606  CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
25607  const int x1, const int y1, const int z1,
25608  const CImg<tc>& color, const float opacity=1) {
25609  return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity);
25610  }
25611 
25613  template<typename tc>
25614  CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
25615  const int x1, const int y1, const int z1,
25616  const tc *const color, const float opacity,
25617  const unsigned int pattern) {
25618  return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true).
25619  draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false).
25620  draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false).
25621  draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false).
25622  draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true).
25623  draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false).
25624  draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false).
25625  draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false).
25626  draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true).
25627  draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true).
25628  draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true).
25629  draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true);
25630  }
25631 
25633  template<typename tc>
25634  CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
25635  const int x1, const int y1, const int z1,
25636  const CImg<tc>& color, const float opacity,
25637  const unsigned int pattern) {
25638  return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern);
25639  }
25640 
25642 
25652  template<typename tc>
25653  CImg<T>& draw_rectangle(const int x0, const int y0,
25654  const int x1, const int y1,
25655  const tc *const color, const float opacity=1) {
25656  return draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity);
25657  }
25658 
25660  template<typename tc>
25661  CImg<T>& draw_rectangle(const int x0, const int y0,
25662  const int x1, const int y1,
25663  const CImg<tc>& color, const float opacity=1) {
25664  return draw_rectangle(x0,y0,x1,y1,color.data,opacity);
25665  }
25666 
25668  template<typename tc>
25669  CImg<T>& draw_rectangle(const int x0, const int y0,
25670  const int x1, const int y1,
25671  const tc *const color, const float opacity,
25672  const unsigned int pattern) {
25673  if (is_empty()) return *this;
25674  if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true);
25675  if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true);
25676  const bool bx = (x0<x1), by = (y0<y1);
25677  const int
25678  nx0 = bx?x0:x1, nx1 = bx?x1:x0,
25679  ny0 = by?y0:y1, ny1 = by?y1:y0;
25680  if (ny1==ny0+1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
25681  draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false);
25682  return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
25683  draw_line(nx1,ny0+1,nx1,ny1-1,color,opacity,pattern,false).
25684  draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false).
25685  draw_line(nx0,ny1-1,nx0,ny0+1,color,opacity,pattern,false);
25686  }
25687 
25689  template<typename tc>
25690  CImg<T>& draw_rectangle(const int x0, const int y0,
25691  const int x1, const int y1,
25692  const CImg<tc>& color, const float opacity,
25693  const unsigned int pattern) {
25694  return draw_rectangle(x0,y0,x1,y1,color.data,opacity,pattern);
25695  }
25696 
25697  // Inner routine for a drawing filled polygon with generic type for coordinates.
25698  template<typename t, typename tc>
25699  CImg<T>& _draw_polygon(const t& points, const unsigned int N,
25700  const tc *const color, const float opacity) {
25701  if (is_empty() || !points || N<3) return *this;
25702  if (!color)
25703  throw CImgArgumentException("CImg<%s>::draw_polygon() : Specified color is (null).",
25704  pixel_type());
25705  _draw_scanline(color,opacity);
25706  int xmin = (int)(~0U>>1), xmax = 0, ymin = (int)(~0U>>1), ymax = 0;
25707  for (unsigned int p = 0; p<N; ++p) {
25708  const int x = (int)points(p,0), y = (int)points(p,1);
25709  if (x<xmin) xmin = x;
25710  if (x>xmax) xmax = x;
25711  if (y<ymin) ymin = y;
25712  if (y>ymax) ymax = y;
25713  }
25714  if (xmax<0 || xmin>=dimx() || ymax<0 || ymin>=dimy()) return *this;
25715  const unsigned int
25716  nymin = ymin<0?0:(unsigned int)ymin,
25717  nymax = ymax>=dimy()?height-1:(unsigned int)ymax,
25718  dy = 1 + nymax - nymin;
25719  CImg<intT> X(1+2*N,dy,1,1,0), tmp;
25720  int cx = (int)points(0,0), cy = (int)points(0,1);
25721  for (unsigned int cp = 0, p = 0; p<N; ++p) {
25722  const unsigned int np = (p!=N-1)?p+1:0, ap = (np!=N-1)?np+1:0;
25723  const int
25724  nx = (int)points(np,0), ny = (int)points(np,1), ay = (int)points(ap,1),
25725  y0 = cy - nymin, y1 = ny - nymin;
25726  if (y0!=y1) {
25727  const int countermin = ((ny<ay && cy<ny) || (ny>ay && cy>ny))?1:0;
25728  for (int x = cx, y = y0, _sx = 1, _sy = 1,
25729  _dx = nx>cx?nx-cx:((_sx=-1),cx-nx),
25730  _dy = y1>y0?y1-y0:((_sy=-1),y0-y1),
25731  _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy),
25732  _err = _dx>>1,
25733  _rx = _dy?(nx-cx)/_dy:0;
25734  _counter>=countermin;
25735  --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0))
25736  if (y>=0 && y<(int)dy) X(++X(0,y),y) = x;
25737  cp = np; cx = nx; cy = ny;
25738  } else {
25739  const int pp = (cp?cp-1:N-1), py = (int)points(pp,1);
25740  if ((cy>py && ay>cy) || (cy<py && ay<cy)) X(++X(0,y0),y0) = nx;
25741  if (cy!=ay) { cp = np; cx = nx; cy = ny; }
25742  }
25743  }
25744  for (int y = 0; y<(int)dy; ++y) {
25745  tmp.assign(X.ptr(1,y),X(0,y),1,1,1,true).sort();
25746  for (int i = 1; i<=X(0,y); ) {
25747  const int xb = X(i++,y), xe = X(i++,y);
25748  _draw_scanline(xb,xe,nymin+y,color,opacity);
25749  }
25750  }
25751  return *this;
25752  }
25753 
25755  template<typename t, typename tc>
25757  const tc *const color, const float opacity=1) {
25758  if (!points.is_sameY(2))
25759  throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
25760  pixel_type());
25761  return _draw_polygon(points,points.width,color,opacity);
25762  }
25763 
25765  template<typename t, typename tc>
25767  const CImg<tc>& color, const float opacity=1) {
25768  return draw_polygon(points,color.data,opacity);
25769  }
25770 
25772  template<typename t, typename tc>
25774  const tc *const color, const float opacity=1) {
25775  if (points.height<2)
25776  throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
25777  pixel_type());
25778  return _draw_polygon(points,points.width,color,opacity);
25779  }
25780 
25782  template<typename t, typename tc>
25784  const CImg<tc>& color, const float opacity=1) {
25785  return draw_polygon(points,color.data,opacity);
25786  }
25787 
25788  // Inner routine for drawing an outlined polygon with generic point coordinates.
25789  template<typename t, typename tc>
25790  CImg<T>& _draw_polygon(const t& points, const unsigned int W, const unsigned int H,
25791  const tc *const color, const float opacity,
25792  const unsigned int pattern) {
25793  if (is_empty() || !points || W<3) return *this;
25794  bool ninit_hatch = true;
25795  switch (H) {
25796  case 0 : case 1 :
25797  throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
25798  pixel_type());
25799  case 2 : {
25800  const int x0 = (int)points(0,0), y0 = (int)points(0,1);
25801  int ox = x0, oy = y0;
25802  for (unsigned int i = 1; i<W; ++i) {
25803  const int x = (int)points(i,0), y = (int)points(i,1);
25804  draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
25805  ninit_hatch = false;
25806  ox = x; oy = y;
25807  }
25808  draw_line(ox,oy,x0,y0,color,opacity,pattern,false);
25809  } break;
25810  default : {
25811  const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
25812  int ox = x0, oy = y0, oz = z0;
25813  for (unsigned int i = 1; i<W; ++i) {
25814  const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
25815  draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
25816  ninit_hatch = false;
25817  ox = x; oy = y; oz = z;
25818  }
25819  draw_line(ox,oy,oz,x0,y0,z0,color,opacity,pattern,false);
25820  }
25821  }
25822  return *this;
25823  }
25824 
25826  template<typename t, typename tc>
25828  const tc *const color, const float opacity,
25829  const unsigned int pattern) {
25830  unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
25831  return _draw_polygon(points,points.width,H,color,opacity,pattern);
25832  }
25833 
25835  template<typename t, typename tc>
25837  const CImg<tc>& color, const float opacity,
25838  const unsigned int pattern) {
25839  return draw_polygon(points,color.data,opacity,pattern);
25840  }
25841 
25843  template<typename t, typename tc>
25845  const tc *const color, const float opacity,
25846  const unsigned int pattern) {
25847  return _draw_polygon(points,points.width,points.height,color,opacity,pattern);
25848  }
25849 
25851  template<typename t, typename tc>
25853  const CImg<tc>& color, const float opacity,
25854  const unsigned int pattern) {
25855  return draw_polygon(points,color.data,opacity,pattern);
25856  }
25857 
25859 
25868  template<typename tc>
25869  CImg<T>& draw_circle(const int x0, const int y0, int radius,
25870  const tc *const color, const float opacity=1) {
25871  if (!is_empty()) {
25872  if (!color)
25873  throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
25874  pixel_type());
25875  _draw_scanline(color,opacity);
25876  if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
25877  if (y0>=0 && y0<dimy()) _draw_scanline(x0-radius,x0+radius,y0,color,opacity);
25878  for (int f = 1-radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x<y; ) {
25879  if (f>=0) {
25880  const int x1 = x0-x, x2 = x0+x, y1 = y0-y, y2 = y0+y;
25881  if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
25882  if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
25883  f+=(ddFy+=2); --y;
25884  }
25885  const bool no_diag = y!=(x++);
25886  ++(f+=(ddFx+=2));
25887  const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x;
25888  if (no_diag) {
25889  if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
25890  if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
25891  }
25892  }
25893  }
25894  return *this;
25895  }
25896 
25898  template<typename tc>
25899  CImg<T>& draw_circle(const int x0, const int y0, int radius,
25900  const CImg<tc>& color, const float opacity=1) {
25901  return draw_circle(x0,y0,radius,color.data,opacity);
25902  }
25903 
25905 
25912  template<typename tc>
25913  CImg<T>& draw_circle(const int x0, const int y0, int radius,
25914  const tc *const color, const float opacity,
25915  const unsigned int) {
25916  if (!is_empty()) {
25917  if (!color)
25918  throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
25919  pixel_type());
25920  if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
25921  if (!radius) return draw_point(x0,y0,color,opacity);
25922  draw_point(x0-radius,y0,color,opacity).draw_point(x0+radius,y0,color,opacity).
25923  draw_point(x0,y0-radius,color,opacity).draw_point(x0,y0+radius,color,opacity);
25924  if (radius==1) return *this;
25925  for (int f = 1-radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x<y; ) {
25926  if (f>=0) { f+=(ddFy+=2); --y; }
25927  ++x; ++(f+=(ddFx+=2));
25928  if (x!=y+1) {
25929  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;
25930  draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity).
25931  draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity);
25932  if (x!=y)
25933  draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity).
25934  draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity);
25935  }
25936  }
25937  }
25938  return *this;
25939  }
25940 
25942  template<typename tc>
25943  CImg<T>& draw_circle(const int x0, const int y0, int radius, const CImg<tc>& color,
25944  const float opacity,
25945  const unsigned int pattern) {
25946  return draw_circle(x0,y0,radius,color.data,opacity,pattern);
25947  }
25948 
25949  // Draw a 2D ellipse (inner routine).
25950  template<typename tc>
25951  CImg<T>& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle,
25952  const tc *const color, const float opacity,
25953  const unsigned int pattern) {
25954  if (is_empty()) return *this;
25955  if (!color)
25956  throw CImgArgumentException("CImg<%s>::draw_ellipse : Specified color is (null).",
25957  pixel_type());
25958  _draw_scanline(color,opacity);
25959  const float
25960  nr1 = cimg::abs(r1), nr2 = cimg::abs(r2),
25961  nangle = (float)(angle*cimg::valuePI/180),
25962  u = (float)std::cos(nangle),
25963  v = (float)std::sin(nangle),
25964  rmax = cimg::max(nr1,nr2),
25965  l1 = (float)std::pow(rmax/(nr1>0?nr1:1e-6),2),
25966  l2 = (float)std::pow(rmax/(nr2>0?nr2:1e-6),2),
25967  a = l1*u*u + l2*v*v,
25968  b = u*v*(l1-l2),
25969  c = l1*v*v + l2*u*u;
25970  const int
25971  yb = (int)std::sqrt(a*rmax*rmax/(a*c-b*b)),
25972  tymin = y0 - yb - 1,
25973  tymax = y0 + yb + 1,
25974  ymin = tymin<0?0:tymin,
25975  ymax = tymax>=dimy()?height-1:tymax;
25976  int oxmin = 0, oxmax = 0;
25977  bool first_line = true;
25978  for (int y = ymin; y<=ymax; ++y) {
25979  const float
25980  Y = y-y0 + (y<y0?0.5f:-0.5f),
25981  delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax),
25982  sdelta = delta>0?(float)std::sqrt(delta)/a:0.0f,
25983  bY = b*Y/a,
25984  fxmin = x0-0.5f-bY-sdelta,
25985  fxmax = x0+0.5f-bY+sdelta;
25986  const int xmin = (int)fxmin, xmax = (int)fxmax;
25987  if (!pattern) _draw_scanline(xmin,xmax,y,color,opacity);
25988  else {
25989  if (first_line) {
25990  if (y0-yb>=0) _draw_scanline(xmin,xmax,y,color,opacity);
25991  else draw_point(xmin,y,color,opacity).draw_point(xmax,y,color,opacity);
25992  first_line = false;
25993  } else {
25994  if (xmin<oxmin) _draw_scanline(xmin,oxmin-1,y,color,opacity);
25995  else _draw_scanline(oxmin+(oxmin==xmin?0:1),xmin,y,color,opacity);
25996  if (xmax<oxmax) _draw_scanline(xmax,oxmax-1,y,color,opacity);
25997  else _draw_scanline(oxmax+(oxmax==xmax?0:1),xmax,y,color,opacity);
25998  if (y==tymax) _draw_scanline(xmin+1,xmax-1,y,color,opacity);
25999  }
26000  }
26001  oxmin = xmin; oxmax = xmax;
26002  }
26003  return *this;
26004  }
26005 
26007 
26016  template<typename tc>
26017  CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle,
26018  const tc *const color, const float opacity=1) {
26019  return _draw_ellipse(x0,y0,r1,r2,angle,color,opacity,0U);
26020  }
26021 
26023  template<typename tc>
26024  CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle,
26025  const CImg<tc>& color, const float opacity=1) {
26026  return draw_ellipse(x0,y0,r1,r2,angle,color.data,opacity);
26027  }
26028 
26030 
26037  template<typename t, typename tc>
26038  CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
26039  const tc *const color, const float opacity=1) {
26040  CImgList<t> eig = tensor.get_symmetric_eigen();
26041  const CImg<t> &val = eig[0], &vec = eig[1];
26042  return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity);
26043  }
26044 
26046  template<typename t, typename tc>
26047  CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
26048  const CImg<tc>& color, const float opacity=1) {
26049  return draw_ellipse(x0,y0,tensor,color.data,opacity);
26050  }
26051 
26053 
26064  template<typename tc>
26065  CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle,
26066  const tc *const color, const float opacity, const unsigned int pattern) {
26067  if (pattern) _draw_ellipse(x0,y0,r1,r2,angle,color,opacity,pattern);
26068  return *this;
26069  }
26070 
26072  template<typename tc>
26073  CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle,
26074  const CImg<tc>& color, const float opacity, const unsigned int pattern) {
26075  return draw_ellipse(x0,y0,r1,r2,angle,color.data,opacity,pattern);
26076  }
26077 
26079 
26087  template<typename t, typename tc>
26088  CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
26089  const tc *const color, const float opacity,
26090  const unsigned int pattern) {
26091  CImgList<t> eig = tensor.get_symmetric_eigen();
26092  const CImg<t> &val = eig[0], &vec = eig[1];
26093  return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity,pattern);
26094  }
26095 
26097  template<typename t, typename tc>
26098  CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
26099  const CImg<tc>& color, const float opacity,
26100  const unsigned int pattern) {
26101  return draw_ellipse(x0,y0,tensor,color.data,opacity,pattern);
26102  }
26103 
26105 
26115  template<typename t>
26116  CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
26117  const CImg<t>& sprite, const float opacity=1) {
26118  if (is_empty()) return *this;
26119  if (!sprite)
26120  throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
26121  pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
26122  if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
26123  const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
26124  const int
26125  lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
26126  lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
26127  lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
26128  lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
26129  const t
26130  *ptrs = sprite.data -
26131  (bx?x0:0) -
26132  (by?y0*sprite.dimx():0) -
26133  (bz?z0*sprite.dimx()*sprite.dimy():0) -
26134  (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
26135  const unsigned int
26136  offX = width - lX, soffX = sprite.width - lX,
26137  offY = width*(height - lY), soffY = sprite.width*(sprite.height - lY),
26138  offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
26139  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
26140  if (lX>0 && lY>0 && lZ>0 && lV>0) {
26141  T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
26142  for (int v = 0; v<lV; ++v) {
26143  for (int z = 0; z<lZ; ++z) {
26144  for (int y = 0; y<lY; ++y) {
26145  if (opacity>=1) for (int x = 0; x<lX; ++x) *(ptrd++) = (T)*(ptrs++);
26146  else for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
26147  ptrd+=offX; ptrs+=soffX;
26148  }
26149  ptrd+=offY; ptrs+=soffY;
26150  }
26151  ptrd+=offZ; ptrs+=soffZ;
26152  }
26153  }
26154  return *this;
26155  }
26156 
26157  // Optimized version (internal).
26158  CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
26159  const CImg<T>& sprite, const float opacity=1) {
26160  if (is_empty()) return *this;
26161  if (!sprite)
26162  throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
26163  pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
26164  if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
26165  const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
26166  const int
26167  lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
26168  lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
26169  lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
26170  lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
26171  const T
26172  *ptrs = sprite.data -
26173  (bx?x0:0) -
26174  (by?y0*sprite.dimx():0) -
26175  (bz?z0*sprite.dimx()*sprite.dimy():0) -
26176  (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
26177  const unsigned int
26178  offX = width - lX, soffX = sprite.width - lX,
26179  offY = width*(height - lY), soffY = sprite.width*(sprite.height - lY),
26180  offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ),
26181  slX = lX*sizeof(T);
26182  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
26183  if (lX>0 && lY>0 && lZ>0 && lV>0) {
26184  T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
26185  for (int v = 0; v<lV; ++v) {
26186  for (int z = 0; z<lZ; ++z) {
26187  if (opacity>=1) for (int y = 0; y<lY; ++y) { std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; }
26188  else for (int y = 0; y<lY; ++y) {
26189  for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
26190  ptrd+=offX; ptrs+=soffX;
26191  }
26192  ptrd+=offY; ptrs+=soffY;
26193  }
26194  ptrd+=offZ; ptrs+=soffZ;
26195  }
26196  }
26197  return *this;
26198  }
26199 
26201  template<typename t>
26202  CImg<T>& draw_image(const int x0, const int y0, const int z0,
26203  const CImg<t>& sprite, const float opacity=1) {
26204  return draw_image(x0,y0,z0,0,sprite,opacity);
26205  }
26206 
26208  template<typename t>
26209  CImg<T>& draw_image(const int x0, const int y0,
26210  const CImg<t>& sprite, const float opacity=1) {
26211  return draw_image(x0,y0,0,sprite,opacity);
26212  }
26213 
26215  template<typename t>
26216  CImg<T>& draw_image(const int x0,
26217  const CImg<t>& sprite, const float opacity=1) {
26218  return draw_image(x0,0,sprite,opacity);
26219  }
26220 
26222  template<typename t>
26223  CImg<T>& draw_image(const CImg<t>& sprite, const float opacity=1) {
26224  return draw_image(0,sprite,opacity);
26225  }
26226 
26228 
26242  template<typename ti, typename tm>
26243  CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
26244  const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
26245  const float mask_valmax=1) {
26246  if (is_empty()) return *this;
26247  if (!sprite)
26248  throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
26249  pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
26250  if (!mask)
26251  throw CImgArgumentException("CImg<%s>::draw_image() : Specified mask image (%u,%u,%u,%u,%p) is empty.",
26252  pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
26253  if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,mask,opacity,mask_valmax);
26254  if (is_overlapped(mask)) return draw_image(x0,y0,z0,v0,sprite,+mask,opacity,mask_valmax);
26255  if (mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
26256  throw CImgArgumentException("CImg<%s>::draw_image() : Mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)",
26257  pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim);
26258  const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
26259  const int
26260  lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
26261  lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
26262  lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
26263  lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
26264  const int
26265  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),
26266  ssize = mask.dimx()*mask.dimy()*mask.dimz();
26267  const ti *ptrs = sprite.data + coff;
26268  const tm *ptrm = mask.data + coff;
26269  const unsigned int
26270  offX = width - lX, soffX = sprite.width - lX,
26271  offY = width*(height - lY), soffY = sprite.width*(sprite.height - lY),
26272  offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
26273  if (lX>0 && lY>0 && lZ>0 && lV>0) {
26274  T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
26275  for (int v = 0; v<lV; ++v) {
26276  ptrm = mask.data + (ptrm - mask.data)%ssize;
26277  for (int z = 0; z<lZ; ++z) {
26278  for (int y = 0; y<lY; ++y) {
26279  for (int x = 0; x<lX; ++x) {
26280  const float mopacity = (float)(*(ptrm++)*opacity),
26281  nopacity = cimg::abs(mopacity), copacity = mask_valmax - cimg::max(mopacity,0);
26282  *ptrd = (T)((nopacity*(*(ptrs++)) + *ptrd*copacity)/mask_valmax);
26283  ++ptrd;
26284  }
26285  ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
26286  }
26287  ptrd+=offY; ptrs+=soffY; ptrm+=soffY;
26288  }
26289  ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;
26290  }
26291  }
26292  return *this;
26293  }
26294 
26296  template<typename ti, typename tm>
26297  CImg<T>& draw_image(const int x0, const int y0, const int z0,
26298  const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
26299  const float mask_valmax=1) {
26300  return draw_image(x0,y0,z0,0,sprite,mask,opacity,mask_valmax);
26301  }
26302 
26304  template<typename ti, typename tm>
26305  CImg<T>& draw_image(const int x0, const int y0,
26306  const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
26307  const float mask_valmax=1) {
26308  return draw_image(x0,y0,0,sprite,mask,opacity,mask_valmax);
26309  }
26310 
26312  template<typename ti, typename tm>
26313  CImg<T>& draw_image(const int x0,
26314  const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
26315  const float mask_valmax=1) {
26316  return draw_image(x0,0,sprite,mask,opacity,mask_valmax);
26317  }
26318 
26320  template<typename ti, typename tm>
26321  CImg<T>& draw_image(const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
26322  const float mask_valmax=1) {
26323  return draw_image(0,sprite,mask,opacity,mask_valmax);
26324  }
26325 
26327 
26337  template<typename tc1, typename tc2, typename t>
26338  CImg<T>& draw_text(const int x0, const int y0, const char *const text,
26339  const tc1 *const foreground_color, const tc2 *const background_color,
26340  const float opacity, const CImgList<t>& font, ...) {
26341  char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font);
26342  std::vsprintf(tmp,text,ap); va_end(ap);
26343  return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
26344  }
26345 
26347  template<typename tc1, typename tc2, typename t>
26348  CImg<T>& draw_text(const int x0, const int y0, const char *const text,
26349  const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
26350  const float opacity, const CImgList<t>& font, ...) {
26351  char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font);
26352  std::vsprintf(tmp,text,ap); va_end(ap);
26353  return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
26354  }
26355 
26357  template<typename tc, typename t>
26358  CImg<T>& draw_text(const int x0, const int y0, const char *const text,
26359  const tc *const foreground_color, const int,
26360  const float opacity, const CImgList<t>& font, ...) {
26361  char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font);
26362  std::vsprintf(tmp,text,ap); va_end(ap);
26363  return _draw_text(x0,y0,tmp,foreground_color,(tc*)0,opacity,font);
26364  }
26365 
26367  template<typename tc, typename t>
26368  CImg<T>& draw_text(const int x0, const int y0, const char *const text,
26369  const int, const tc *const background_color,
26370  const float opacity, const CImgList<t>& font, ...) {
26371  char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font);
26372  std::vsprintf(tmp,text,ap); va_end(ap);
26373  return _draw_text(x0,y0,tmp,(tc*)0,background_color,opacity,font);
26374  }
26375 
26377 
26387  template<typename tc1, typename tc2>
26388  CImg<T>& draw_text(const int x0, const int y0, const char *const text,
26389  const tc1 *const foreground_color, const tc2 *const background_color,
26390  const float opacity=1, const unsigned int font_size=11, ...) {
26391  static CImgList<T> font;
26392  static unsigned int fsize = 0;
26393  if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
26394  char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font_size); std::vsprintf(tmp,text,ap); va_end(ap);
26395  return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
26396  }
26397 
26399  template<typename tc1, typename tc2>
26400  CImg<T>& draw_text(const int x0, const int y0, const char *const text,
26401  const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
26402  const float opacity=1, const unsigned int font_size=11, ...) {
26403  static CImgList<T> font;
26404  static unsigned int fsize = 0;
26405  if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
26406  char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font_size); std::vsprintf(tmp,text,ap); va_end(ap);
26407  return _draw_text(x0,y0,tmp,foreground_color.data,background_color.data,opacity,font);
26408  }
26409 
26411  template<typename tc>
26412  CImg<T>& draw_text(const int x0, const int y0, const char *const text,
26413  const tc *const foreground_color, const int background_color=0,
26414  const float opacity=1, const unsigned int font_size=11, ...) {
26415  static CImgList<T> font;
26416  static unsigned int fsize = 0;
26417  if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
26418  char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font_size); std::vsprintf(tmp,text,ap); va_end(ap);
26419  return _draw_text(x0,y0,tmp,foreground_color,(const tc*)background_color,opacity,font);
26420  }
26421 
26423  template<typename tc>
26424  CImg<T>& draw_text(const int x0, const int y0, const char *const text,
26425  const int, const tc *const background_color,
26426  const float opacity=1, const unsigned int font_size=11, ...) {
26427  static CImgList<T> font;
26428  static unsigned int fsize = 0;
26429  if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
26430  char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,font_size); std::vsprintf(tmp,text,ap); va_end(ap);
26431  return _draw_text(x0,y0,tmp,(tc*)0,background_color,opacity,font);
26432  }
26433 
26434  template<typename tc1, typename tc2, typename t>
26435  CImg<T>& _draw_text(const int x0, const int y0, const char *const text,
26436  const tc1 *const foreground_color, const tc2 *const background_color,
26437  const float opacity, const CImgList<t>& font) {
26438  if (!text) return *this;
26439  if (!font)
26440  throw CImgArgumentException("CImg<%s>::draw_text() : Specified font (%u,%p) is empty.",
26441  pixel_type(),font.width,font.data);
26442  const unsigned int text_length = std::strlen(text);
26443 
26444  if (is_empty()) {
26445  // If needed, pre-compute necessary size of the image
26446  int x = 0, y = 0, w = 0;
26447  unsigned char c = 0;
26448  for (unsigned int i = 0; i<text_length; ++i) {
26449  c = text[i];
26450  switch (c) {
26451  case '\n' : y+=font[' '].height; if (x>w) w = x; x = 0; break;
26452  case '\t' : x+=4*font[' '].width; break;
26453  default : if (c<font.width) x+=font[c].width;
26454  }
26455  }
26456  if (x!=0 || c=='\n') {
26457  if (x>w) w=x;
26458  y+=font[' '].height;
26459  }
26460  assign(x0+w,y0+y,1,font[' '].dim,0);
26461  if (background_color) cimg_forV(*this,k) get_shared_channel(k).fill((T)background_color[k]);
26462  }
26463 
26464  int x = x0, y = y0;
26465  CImg<T> letter;
26466  for (unsigned int i = 0; i<text_length; ++i) {
26467  const unsigned char c = text[i];
26468  switch (c) {
26469  case '\n' : y+=font[' '].height; x = x0; break;
26470  case '\t' : x+=4*font[' '].width; break;
26471  default : if (c<font.width) {
26472  letter = font[c];
26473  const CImg<T>& mask = (c+256)<(int)font.width?font[c+256]:font[c];
26474  if (foreground_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
26475  if (mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)(letter(p,0,0,k)*foreground_color[k]);
26476  if (background_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
26477  if (!mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)background_color[k];
26478  if (!background_color && font.width>=512) draw_image(x,y,letter,mask,opacity,(T)1);
26479  else draw_image(x,y,letter,opacity);
26480  x+=letter.width;
26481  }
26482  }
26483  }
26484  return *this;
26485  }
26486 
26488 
26497  template<typename t1, typename t2>
26499  const t2 *const color, const float opacity=1,
26500  const unsigned int sampling=25, const float factor=-20,
26501  const bool arrows=true, const unsigned int pattern=~0U) {
26502  return draw_quiver(flow,CImg<t2>(color,dim,1,1,1,true),opacity,sampling,factor,arrows,pattern);
26503  }
26504 
26506 
26515  template<typename t1, typename t2>
26517  const CImg<t2>& color, const float opacity=1,
26518  const unsigned int sampling=25, const float factor=-20,
26519  const bool arrows=true, const unsigned int pattern=~0U) {
26520  if (!is_empty()) {
26521  if (!flow || flow.dim!=2)
26522  throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.",
26523  pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data);
26524  if (sampling<=0)
26525  throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g",
26526  pixel_type(),sampling);
26527  const bool colorfield = (color.width==flow.width && color.height==flow.height && color.depth==1 && color.dim==dim);
26528  if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,arrows,pattern);
26529 
26530  float vmax,fact;
26531  if (factor<=0) {
26532  float m, M = (float)flow.get_norm(2).maxmin(m);
26533  vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
26534  fact = -factor;
26535  } else { fact = factor; vmax = 1; }
26536 
26537  for (unsigned int y=sampling/2; y<height; y+=sampling)
26538  for (unsigned int x=sampling/2; x<width; x+=sampling) {
26539  const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
26540  float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
26541  if (arrows) {
26542  const int xx = x+(int)u, yy = y+(int)v;
26543  if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y).data,opacity,45,sampling/5.0f,pattern);
26544  else draw_arrow(x,y,xx,yy,color,opacity,45,sampling/5.0f,pattern);
26545  } else {
26546  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);
26547  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);
26548  }
26549  }
26550  }
26551  return *this;
26552  }
26553 
26555 
26564  template<typename t, typename tc>
26565  CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
26566  const tc *const color, const float opacity=1,
26567  const unsigned int pattern=~0U) {
26568  if (!is_empty()) {
26569  int siz = (int)xvalues.size()-1;
26570  if (siz<=0) draw_line(0,y,width-1,y,color,opacity,pattern);
26571  else {
26572  if (xvalues[0]<xvalues[siz]) draw_arrow(0,y,width-1,y,color,opacity,30,5,pattern);
26573  else draw_arrow(width-1,y,0,y,color,opacity,30,5,pattern);
26574  const int yt = (y+14)<dimy()?(y+3):(y-14);
26575  char txt[32] = { 0 };
26576  cimg_foroff(xvalues,x) {
26577  std::sprintf(txt,"%g",(double)xvalues(x));
26578  const int xi = (int)(x*(width-1)/siz), xt = xi-(int)std::strlen(txt)*3;
26579  draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity).
26580  draw_text(xt<0?0:xt,yt,txt,color,(tc*)0,opacity,11);
26581  }
26582  }
26583  }
26584  return *this;
26585  }
26586 
26588  template<typename t, typename tc>
26589  CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
26590  const CImg<tc>& color, const float opacity=1,
26591  const unsigned int pattern=~0U) {
26592  return draw_axis(xvalues,y,color.data,opacity,pattern);
26593  }
26594 
26596  template<typename t, typename tc>
26597  CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
26598  const tc *const color, const float opacity=1,
26599  const unsigned int pattern=~0U) {
26600  if (!is_empty()) {
26601  int siz = (int)yvalues.size()-1;
26602  if (siz<=0) draw_line(x,0,x,height-1,color,opacity,pattern);
26603  else {
26604  if (yvalues[0]<yvalues[siz]) draw_arrow(x,0,x,height-1,color,opacity,30,5,pattern);
26605  else draw_arrow(x,height-1,x,0,color,opacity,30,5,pattern);
26606  char txt[32] = { 0 };
26607  cimg_foroff(yvalues,y) {
26608  std::sprintf(txt,"%g",(double)yvalues(y));
26609  const int
26610  yi = (int)(y*(height-1)/siz),
26611  tmp = yi-5,
26612  nyi = tmp<0?0:(tmp>=dimy()-11?dimy()-11:tmp),
26613  xt = x-(int)std::strlen(txt)*7;
26614  draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity);
26615  if (xt>0) draw_text(xt,nyi,txt,color,(tc*)0,opacity,11);
26616  else draw_text(x+3,nyi,txt,color,(tc*)0,opacity,11);
26617  }
26618  }
26619  }
26620  return *this;
26621  }
26622 
26624  template<typename t, typename tc>
26625  CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
26626  const CImg<tc>& color, const float opacity=1,
26627  const unsigned int pattern=~0U) {
26628  return draw_axis(x,yvalues,color.data,opacity,pattern);
26629  }
26630 
26632  template<typename tx, typename ty, typename tc>
26633  CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
26634  const tc *const color, const float opacity=1,
26635  const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
26636  if (!is_empty()) {
26637  const CImg<tx> nxvalues(xvalues.data,xvalues.size(),1,1,1,true);
26638  const int sizx = (int)xvalues.size()-1, wm1 = (int)(width)-1;
26639  if (sizx>0) {
26640  float ox = (float)nxvalues[0];
26641  for (unsigned int x = 1; x<width; ++x) {
26642  const float nx = (float)nxvalues._linear_atX((float)x*sizx/wm1);
26643  if (nx*ox<=0) { draw_axis(nx==0?x:x-1,yvalues,color,opacity,patterny); break; }
26644  ox = nx;
26645  }
26646  }
26647  const CImg<ty> nyvalues(yvalues.data,yvalues.size(),1,1,1,true);
26648  const int sizy = (int)yvalues.size()-1, hm1 = (int)(height)-1;
26649  if (sizy>0) {
26650  float oy = (float)nyvalues[0];
26651  for (unsigned int y = 1; y<height; ++y) {
26652  const float ny = (float)nyvalues._linear_atX((float)y*sizy/hm1);
26653  if (ny*oy<=0) { draw_axis(xvalues,ny==0?y:y-1,color,opacity,patternx); break; }
26654  oy = ny;
26655  }
26656  }
26657  }
26658  return *this;
26659  }
26660 
26662  template<typename tx, typename ty, typename tc>
26663  CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
26664  const CImg<tc>& color, const float opacity=1,
26665  const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
26666  return draw_axis(xvalues,yvalues,color.data,opacity,patternx,patterny);
26667  }
26668 
26670  template<typename tc>
26671  CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
26672  const tc *const color, const float opacity=1,
26673  const int subdivisionx=-60, const int subdivisiony=-60,
26674  const float precisionx=0, const float precisiony=0,
26675  const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
26676  if (!is_empty()) {
26677  const float
26678  dx = cimg::abs(x1-x0), dy = cimg::abs(y1-y0),
26679  px = (precisionx==0)?(float)std::pow(10.0,(int)std::log10(dx)-2.0):precisionx,
26680  py = (precisiony==0)?(float)std::pow(10.0,(int)std::log10(dy)-2.0):precisiony;
26681  draw_axis(CImg<floatT>::sequence(subdivisionx>0?subdivisionx:1-dimx()/subdivisionx,x0,x1).round(px),
26682  CImg<floatT>::sequence(subdivisiony>0?subdivisiony:1-dimy()/subdivisiony,y0,y1).round(py),
26683  color,opacity,patternx,patterny);
26684  }
26685  return *this;
26686  }
26687 
26689  template<typename tc>
26690  CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
26691  const CImg<tc>& color, const float opacity=1,
26692  const int subdivisionx=-60, const int subdivisiony=-60,
26693  const float precisionx=0, const float precisiony=0,
26694  const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
26695  return draw_axis(x0,x1,y0,y1,color.data,opacity,subdivisionx,subdivisiony,precisionx,precisiony,patternx,patterny);
26696  }
26697 
26699  template<typename tx, typename ty, typename tc>
26700  CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
26701  const tc *const color, const float opacity=1,
26702  const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
26703  if (!is_empty()) {
26704  if (xvalues) cimg_foroff(xvalues,x) {
26705  const int xi = (int)xvalues[x];
26706  if (xi>=0 && xi<dimx()) draw_line(xi,0,xi,height-1,color,opacity,patternx);
26707  }
26708  if (yvalues) cimg_foroff(yvalues,y) {
26709  const int yi = (int)yvalues[y];
26710  if (yi>=0 && yi<dimy()) draw_line(0,yi,width-1,yi,color,opacity,patterny);
26711  }
26712  }
26713  return *this;
26714  }
26715 
26717  template<typename tx, typename ty, typename tc>
26718  CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
26719  const CImg<tc>& color, const float opacity=1,
26720  const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
26721  return draw_grid(xvalues,yvalues,color.data,opacity,patternx,patterny);
26722  }
26723 
26725  template<typename tc>
26726  CImg<T>& draw_grid(const float deltax, const float deltay,
26727  const float offsetx, const float offsety,
26728  const bool invertx, const bool inverty,
26729  const tc *const color, const float opacity=1,
26730  const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
26731  CImg<uintT> seqx, seqy;
26732  if (deltax!=0) {
26733  const float dx = deltax>0?deltax:width*-deltax/100;
26734  const unsigned int nx = (unsigned int)(width/dx);
26735  seqx = CImg<uintT>::sequence(1+nx,0,(unsigned int)(dx*nx));
26736  if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x)+offsetx,(float)width);
26737  if (invertx) cimg_foroff(seqx,x) seqx(x) = width-1-seqx(x);
26738  }
26739 
26740  if (deltay!=0) {
26741  const float dy = deltay>0?deltay:height*-deltay/100;
26742  const unsigned int ny = (unsigned int)(height/dy);
26743  seqy = CImg<uintT>::sequence(1+ny,0,(unsigned int)(dy*ny));
26744  if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y)+offsety,(float)height);
26745  if (inverty) cimg_foroff(seqy,y) seqy(y) = height-1-seqy(y);
26746  }
26747  return draw_grid(seqx,seqy,color,opacity,patternx,patterny);
26748  }
26749 
26751  template<typename tc>
26752  CImg<T>& draw_grid(const float deltax, const float deltay,
26753  const float offsetx, const float offsety,
26754  const bool invertx, const bool inverty,
26755  const CImg<tc>& color, const float opacity=1,
26756  const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
26757  return draw_grid(deltax,deltay,offsetx,offsety,invertx,inverty,color.data,opacity,patternx,patterny);
26758  }
26759 
26761 
26787  template<typename t, typename tc>
26789  const tc *const color, const float opacity=1,
26790  const unsigned int plot_type=1, const int vertex_type=1,
26791  const double ymin=0, const double ymax=0, const bool expand=false,
26792  const unsigned int pattern=~0U) {
26793  if (is_empty() || height<=1) return *this;
26794  const unsigned int siz = data.size();
26795  if (!color)
26796  throw CImgArgumentException("CImg<%s>::draw_graph() : Specified color is (null)",
26797  pixel_type());
26798  tc *color1 = 0, *color2 = 0;
26799  if (plot_type==3) {
26800  color1 = new tc[dim]; color2 = new tc[dim];
26801  cimg_forV(*this,k) { color1[k] = (tc)(color[k]*0.6f); color2[k] = (tc)(color[k]*0.3f); }
26802  }
26803 
26804  double m = ymin, M = ymax;
26805  if (ymin==ymax) m = (double)data.maxmin(M);
26806  if (m==M) { --m; ++M; }
26807  const float ca = (float)(M-m)/(height-1);
26808  bool init_hatch = true;
26809  const unsigned int xp = expand?1:0;
26810 
26811  // Draw graph edges
26812  switch (plot_type%4) {
26813  case 1 : { // Segments
26814  int oX = 0, oY = (int)((data[0]-m)/ca);
26815  for (unsigned int off = 1; off<siz; ++off) {
26816  const int
26817  X = (int)(off*width/(siz-xp)),
26818  Y = (int)((data[off]-m)/ca);
26819  draw_line(oX,oY,X,Y,color,opacity,pattern,init_hatch);
26820  oX = X; oY = Y;
26821  init_hatch = false;
26822  }
26823  } break;
26824  case 2 : { // Spline
26825  const CImg<t> ndata(data.data,siz,1,1,1,true);
26826  int oY = (int)((data[0]-m)/ca);
26827  cimg_forX(*this,x) {
26828  const int Y = (int)((ndata._cubic_atX((float)x*(ndata.width-xp)/width)-m)/ca);
26829  if (x>0) draw_line(x,oY,x+1,Y,color,opacity,pattern,init_hatch);
26830  init_hatch = false;
26831  oY = Y;
26832  }
26833  } break;
26834  case 3 : { // Bars
26835  const int Y0 = (int)(-m/ca);
26836  int oX = 0;
26837  cimg_foroff(data,off) {
26838  const int
26839  X = (off+1)*width/siz-1,
26840  Y = (int)((data[off]-m)/ca);
26841  draw_rectangle(oX,Y0,X,Y,color1,opacity).
26842  draw_line(oX,Y,oX,Y0,color2,opacity).
26843  draw_line(oX,Y0,X,Y0,Y<=Y0?color2:color,opacity).
26844  draw_line(X,Y,X,Y0,color,opacity).
26845  draw_line(oX,Y,X,Y,Y<=Y0?color:color2,opacity);
26846  oX = X+1;
26847  }
26848  } break;
26849  default : break; // No edges
26850  }
26851 
26852  // Draw graph points
26853  switch (vertex_type%8) {
26854  case 1 : { // Point
26855  cimg_foroff(data,off) {
26856  const int X = off*width/(siz-xp), Y = (int)((data[off]-m)/ca);
26857  draw_point(X,Y,color,opacity);
26858  }
26859  } break;
26860  case 2 : { // Straight Cross
26861  cimg_foroff(data,off) {
26862  const int X = off*width/(siz-xp), Y = (int)((data[off]-m)/ca);
26863  draw_line(X-3,Y,X+3,Y,color,opacity).draw_line(X,Y-3,X,Y+3,color,opacity);
26864  }
26865  } break;
26866  case 3 : { // Diagonal Cross
26867  cimg_foroff(data,off) {
26868  const int X = off*width/(siz-xp), Y = (int)((data[off]-m)/ca);
26869  draw_line(X-3,Y-3,X+3,Y+3,color,opacity).draw_line(X-3,Y+3,X+3,Y-3,color,opacity);
26870  }
26871  } break;
26872  case 4 : { // Filled Circle
26873  cimg_foroff(data,off) {
26874  const int X = off*width/(siz-xp), Y = (int)((data[off]-m)/ca);
26875  draw_circle(X,Y,3,color,opacity);
26876  }
26877  } break;
26878  case 5 : { // Outlined circle
26879  cimg_foroff(data,off) {
26880  const int X = off*width/(siz-xp), Y = (int)((data[off]-m)/ca);
26881  draw_circle(X,Y,3,color,opacity,0U);
26882  }
26883  } break;
26884  case 6 : { // Square
26885  cimg_foroff(data,off) {
26886  const int X = off*width/(siz-xp), Y = (int)((data[off]-m)/ca);
26887  draw_rectangle(X-3,Y-3,X+3,Y+3,color,opacity,~0U);
26888  }
26889  } break;
26890  case 7 : { // Diamond
26891  cimg_foroff(data,off) {
26892  const int X = off*width/(siz-xp), Y = (int)((data[off]-m)/ca);
26893  draw_line(X,Y-4,X+4,Y,color,opacity).
26894  draw_line(X+4,Y,X,Y+4,color,opacity).
26895  draw_line(X,Y+4,X-4,Y,color,opacity).
26896  draw_line(X-4,Y,X,Y-4,color,opacity);
26897  }
26898  } break;
26899  default : break; // No points
26900  }
26901 
26902  if (color1) delete[] color1; if (color2) delete[] color2;
26903  return *this;
26904  }
26905 
26907  template<typename t, typename tc>
26909  const CImg<tc>& color, const float opacity=1,
26910  const unsigned int plot_type=1, const unsigned int vertex_type=1,
26911  const double ymin=0, const double ymax=0, const bool expand=false,
26912  const unsigned int pattern=~0U) {
26913  return draw_graph(data,color.data,opacity,plot_type,vertex_type,ymin,ymax,expand,pattern);
26914  }
26915 
26917 
26928  template<typename tc, typename t>
26929  CImg<T>& draw_fill(const int x, const int y, const int z,
26930  const tc *const color, const float opacity,
26931  CImg<t>& region, const float sigma=0,
26932  const bool high_connexity=false) {
26933 
26934 #define _cimg_draw_fill_test(x,y,z,res) if (region(x,y,z)) res = false; else { \
26935  res = true; \
26936  const T *reference_col = reference_color.ptr() + dim, *ptrs = ptr(x,y,z) + siz; \
26937  for (unsigned int i = dim; res && i; --i) { ptrs-=whz; res = (cimg::abs(*ptrs - *(--reference_col))<=sigma); } \
26938  region(x,y,z) = (t)(res?1:noregion); \
26939 }
26940 
26941 #define _cimg_draw_fill_set(x,y,z) { \
26942  const tc *col = color; \
26943  T *ptrd = ptr(x,y,z); \
26944  if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; } \
26945  else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; } \
26946 }
26947 
26948 #define _cimg_draw_fill_insert(x,y,z) { \
26949  if (posr1>=remaining.height) remaining.resize(3,remaining.height<<1,1,1,0); \
26950  unsigned int *ptrr = remaining.ptr(0,posr1); \
26951  *(ptrr++) = x; *(ptrr++) = y; *(ptrr++) = z; ++posr1; \
26952 }
26953 
26954 #define _cimg_draw_fill_test_neighbor(x,y,z,cond) if (cond) { \
26955  const unsigned int tx = x, ty = y, tz = z; \
26956  _cimg_draw_fill_test(tx,ty,tz,res); if (res) _cimg_draw_fill_insert(tx,ty,tz); \
26957 }
26958 
26959  if (!color)
26960  throw CImgArgumentException("CImg<%s>::draw_fill() : Specified color is (null).",
26961  pixel_type());
26962  region.assign(width,height,depth,1,(t)0);
26963  if (x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz()) {
26964  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
26965  const unsigned int whz = width*height*depth, siz = dim*whz, W1 = width-1, H1 = height-1, D1 = depth-1;
26966  const bool threed = depth>1;
26967  const CImg<T> reference_color = get_vector_at(x,y,z);
26968  CImg<uintT> remaining(3,512,1,1,0);
26969  remaining(0,0) = x; remaining(1,0) = y; remaining(2,0) = z;
26970  unsigned int posr0 = 0, posr1 = 1;
26971  region(x,y,z) = (t)1;
26972  const t noregion = ((t)1==(t)2)?(t)0:(t)(-1);
26973  if (threed) do { // 3D version of the filling algorithm
26974  const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++), zc = *(pcurr++);
26975  if (posr0>=512) { remaining.translate(0,-(int)posr0); posr1-=posr0; posr0 = 0; }
26976  bool cont, res;
26977  unsigned int nxc = xc;
26978  do { // X-backward
26979  _cimg_draw_fill_set(nxc,yc,zc);
26980  _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
26981  _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
26982  _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
26983  _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
26984  if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
26985  } while (cont);
26986  nxc = xc;
26987  do { // X-forward
26988  if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
26989  if (cont) {
26990  _cimg_draw_fill_set(nxc,yc,zc);
26991  _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
26992  _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
26993  _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
26994  _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
26995  }
26996  } while (cont);
26997  unsigned int nyc = yc;
26998  do { // Y-backward
26999  if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
27000  if (cont) {
27001  _cimg_draw_fill_set(xc,nyc,zc);
27002  _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
27003  _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
27004  _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
27005  _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
27006  }
27007  } while (cont);
27008  nyc = yc;
27009  do { // Y-forward
27010  if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
27011  if (cont) {
27012  _cimg_draw_fill_set(xc,nyc,zc);
27013  _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
27014  _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
27015  _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
27016  _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
27017  }
27018  } while (cont);
27019  unsigned int nzc = zc;
27020  do { // Z-backward
27021  if (nzc) { --nzc; _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
27022  if (cont) {
27023  _cimg_draw_fill_set(xc,yc,nzc);
27024  _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
27025  _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
27026  _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
27027  _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
27028  }
27029  } while (cont);
27030  nzc = zc;
27031  do { // Z-forward
27032  if ((++nzc)<=D1) { _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
27033  if (cont) {
27034  _cimg_draw_fill_set(xc,nyc,zc);
27035  _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
27036  _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
27037  _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
27038  _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
27039  }
27040  } while (cont);
27041  } while (posr1>posr0);
27042  else do { // 2D version of the filling algorithm
27043  const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++);
27044  if (posr0>=512) { remaining.translate(0,-(int)posr0); posr1-=posr0; posr0 = 0; }
27045  bool cont, res;
27046  unsigned int nxc = xc;
27047  do { // X-backward
27048  _cimg_draw_fill_set(nxc,yc,0);
27049  _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
27050  _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
27051  if (high_connexity) {
27052  _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
27053  _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
27054  _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
27055  _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
27056  }
27057  if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
27058  } while (cont);
27059  nxc = xc;
27060  do { // X-forward
27061  if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
27062  if (cont) {
27063  _cimg_draw_fill_set(nxc,yc,0);
27064  _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
27065  _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
27066  if (high_connexity) {
27067  _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
27068  _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
27069  _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
27070  _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
27071  }
27072  }
27073  } while (cont);
27074  unsigned int nyc = yc;
27075  do { // Y-backward
27076  if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
27077  if (cont) {
27078  _cimg_draw_fill_set(xc,nyc,0);
27079  _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
27080  _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
27081  if (high_connexity) {
27082  _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
27083  _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
27084  _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
27085  _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
27086  }
27087  }
27088  } while (cont);
27089  nyc = yc;
27090  do { // Y-forward
27091  if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
27092  if (cont) {
27093  _cimg_draw_fill_set(xc,nyc,0);
27094  _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
27095  _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
27096  if (high_connexity) {
27097  _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
27098  _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
27099  _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
27100  _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
27101  }
27102  }
27103  } while (cont);
27104  } while (posr1>posr0);
27105  if (noregion) cimg_for(region,ptr,t) if (*ptr==noregion) *ptr = (t)0;
27106  }
27107  return *this;
27108  }
27109 
27111  template<typename tc, typename t>
27112  CImg<T>& draw_fill(const int x, const int y, const int z,
27113  const CImg<tc>& color, const float opacity,
27114  CImg<t>& region, const float sigma=0, const bool high_connexity=false) {
27115  return draw_fill(x,y,z,color.data,opacity,region,sigma,high_connexity);
27116  }
27117 
27119 
27127  template<typename tc>
27128  CImg<T>& draw_fill(const int x, const int y, const int z,
27129  const tc *const color, const float opacity=1,
27130  const float sigma=0, const bool high_connexity=false) {
27131  CImg<boolT> tmp;
27132  return draw_fill(x,y,z,color,opacity,tmp,sigma,high_connexity);
27133  }
27134 
27136  template<typename tc>
27137  CImg<T>& draw_fill(const int x, const int y, const int z,
27138  const CImg<tc>& color, const float opacity=1,
27139  const float sigma=0, const bool high_connexity=false) {
27140  return draw_fill(x,y,z,color.data,opacity,sigma,high_connexity);
27141  }
27142 
27144 
27151  template<typename tc>
27152  CImg<T>& draw_fill(const int x, const int y,
27153  const tc *const color, const float opacity=1,
27154  const float sigma=0, const bool high_connexity=false) {
27155  CImg<boolT> tmp;
27156  return draw_fill(x,y,0,color,opacity,tmp,sigma,high_connexity);
27157  }
27158 
27160  template<typename tc>
27161  CImg<T>& draw_fill(const int x, const int y,
27162  const CImg<tc>& color, const float opacity=1,
27163  const float sigma=0, const bool high_connexity=false) {
27164  return draw_fill(x,y,color.data,opacity,sigma,high_connexity);
27165  }
27166 
27168 
27177  CImg<T>& draw_plasma(const int x0, const int y0, const int x1, const int y1,
27178  const float alpha=1, const float beta=1,
27179  const float opacity=1) {
27180  if (!is_empty()) {
27181  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
27182  int nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1;
27183  if (nx1<nx0) cimg::swap(nx0,nx1);
27184  if (ny1<ny0) cimg::swap(ny0,ny1);
27185  if (nx0<0) nx0 = 0;
27186  if (nx1>=dimx()) nx1 = width-1;
27187  if (ny0<0) ny0 = 0;
27188  if (ny1>=dimy()) ny1 = height-1;
27189  const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx = (xc-nx0), dy = (yc-ny0);
27190  const Tfloat dc = (Tfloat)(std::sqrt((float)(dx*dx+dy*dy))*alpha + beta);
27191  Tfloat val = 0;
27192  cimg_forV(*this,k) {
27193  if (opacity>=1) {
27194  const Tfloat
27195  val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
27196  val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
27197  (*this)(xc,ny0,0,k) = (T)((val0+val1)/2);
27198  (*this)(xc,ny1,0,k) = (T)((val2+val3)/2);
27199  (*this)(nx0,yc,0,k) = (T)((val0+val2)/2);
27200  (*this)(nx1,yc,0,k) = (T)((val1+val3)/2);
27201  do {
27202  val = (Tfloat)(0.25f*((Tfloat)((*this)(nx0,ny0,0,k)) +
27203  (Tfloat)((*this)(nx1,ny0,0,k)) +
27204  (Tfloat)((*this)(nx1,ny1,0,k)) +
27205  (Tfloat)((*this)(nx0,ny1,0,k))) +
27206  dc*cimg::grand());
27207  } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
27208  (*this)(xc,yc,0,k) = (T)val;
27209  } else {
27210  const Tfloat
27211  val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
27212  val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
27213  (*this)(xc,ny0,0,k) = (T)(((val0+val1)*nopacity + copacity*(*this)(xc,ny0,0,k))/2);
27214  (*this)(xc,ny1,0,k) = (T)(((val2+val3)*nopacity + copacity*(*this)(xc,ny1,0,k))/2);
27215  (*this)(nx0,yc,0,k) = (T)(((val0+val2)*nopacity + copacity*(*this)(nx0,yc,0,k))/2);
27216  (*this)(nx1,yc,0,k) = (T)(((val1+val3)*nopacity + copacity*(*this)(nx1,yc,0,k))/2);
27217  do {
27218  val = (Tfloat)(0.25f*(((Tfloat)((*this)(nx0,ny0,0,k)) +
27219  (Tfloat)((*this)(nx1,ny0,0,k)) +
27220  (Tfloat)((*this)(nx1,ny1,0,k)) +
27221  (Tfloat)((*this)(nx0,ny1,0,k))) +
27222  dc*cimg::grand())*nopacity + copacity*(*this)(xc,yc,0,k));
27223  } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
27224  (*this)(xc,yc,0,k) = (T)val;
27225  }
27226  }
27227  if (xc!=nx0 || yc!=ny0) {
27228  draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity);
27229  draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity);
27230  draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity);
27231  draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity);
27232  }
27233  }
27234  return *this;
27235  }
27236 
27238 
27243  CImg<T>& draw_plasma(const float alpha=1, const float beta=1,
27244  const float opacity=1) {
27245  return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity);
27246  }
27247 
27249  template<typename tc>
27250  CImg<T>& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1,
27251  const CImg<tc>& color_palette, const float opacity=1,
27252  const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
27253  const unsigned int itermax=255,
27254  const bool normalized_iteration=false,
27255  const bool julia_set=false,
27256  const double paramr=0, const double parami=0) {
27257  if (is_empty()) return *this;
27258  CImg<tc> palette;
27259  if (color_palette) palette.assign(color_palette.data,color_palette.size()/color_palette.dim,1,1,color_palette.dim,true);
27260  if (palette && palette.dim!=dim)
27261  throw CImgArgumentException("CImg<%s>::draw_mandelbrot() : Specified color palette (%u,%u,%u,%u,%p) is not \n"
27262  "compatible with instance image (%u,%u,%u,%u,%p).",
27263  pixel_type(),color_palette.width,color_palette.height,color_palette.depth,color_palette.dim,
27264  color_palette.data,width,height,depth,dim,data);
27265  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), ln2 = (float)std::log(2.0);
27266  unsigned int iter = 0;
27267  cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
27268  const double x = z0r + p*(z1r-z0r)/width, y = z0i + q*(z1i-z0i)/height;
27269  double zr, zi, cr, ci;
27270  if (julia_set) { zr = x; zi = y; cr = paramr; ci = parami; }
27271  else { zr = paramr; zi = parami; cr = x; ci = y; }
27272  for (iter=1; zr*zr + zi*zi<=4 && iter<=itermax; ++iter) {
27273  const double temp = zr*zr - zi*zi + cr;
27274  zi = 2*zr*zi + ci;
27275  zr = temp;
27276  }
27277  if (iter>itermax) {
27278  if (palette) {
27279  if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette(0,k);
27280  else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(0,k)*nopacity + (*this)(p,q,0,k)*copacity);
27281  } else {
27282  if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)0;
27283  else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)((*this)(p,q,0,k)*copacity);
27284  }
27285  } else if (normalized_iteration) {
27286  const float
27287  normz = (float)cimg::abs(zr*zr+zi*zi),
27288  niter = (float)(iter + 1 - std::log(std::log(normz))/ln2);
27289  if (palette) {
27290  if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._linear_atX(niter,k);
27291  else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette._linear_atX(niter,k)*nopacity + (*this)(p,q,0,k)*copacity);
27292  } else {
27293  if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)niter;
27294  else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(niter*nopacity + (*this)(p,q,0,k)*copacity);
27295  }
27296  } else {
27297  if (palette) {
27298  if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._atX(iter,k);
27299  else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(iter,k)*nopacity + (*this)(p,q,0,k)*copacity);
27300  } else {
27301  if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)iter;
27302  else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(iter*nopacity + (*this)(p,q,0,k)*copacity);
27303  }
27304  }
27305  }
27306  return *this;
27307  }
27308 
27310  template<typename tc>
27311  CImg<T>& draw_mandelbrot(const CImg<tc>& color_palette, const float opacity=1,
27312  const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
27313  const unsigned int itermax=255,
27314  const bool normalized_iteration=false,
27315  const bool julia_set=false,
27316  const double paramr=0, const double parami=0) {
27317  return draw_mandelbrot(0,0,width-1,height-1,color_palette,opacity,z0r,z0i,z1r,z1i,itermax,normalized_iteration,julia_set,paramr,parami);
27318  }
27319 
27321 
27327  template<typename tc>
27328  CImg<T>& draw_gaussian(const float xc, const float sigma,
27329  const tc *const color, const float opacity=1) {
27330  if (is_empty()) return *this;
27331  if (!color)
27332  throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
27333  pixel_type());
27334  const float sigma2 = 2*sigma*sigma, nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
27335  const unsigned int whz = width*height*depth;
27336  const tc *col = color;
27337  cimg_forX(*this,x) {
27338  const float dx = (x - xc), val = (float)std::exp(-dx*dx/sigma2);
27339  T *ptrd = ptr(x,0,0,0);
27340  if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
27341  else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
27342  col-=dim;
27343  }
27344  return *this;
27345  }
27346 
27348  template<typename tc>
27349  CImg<T>& draw_gaussian(const float xc, const float sigma,
27350  const CImg<tc>& color, const float opacity=1) {
27351  return draw_gaussian(xc,sigma,color.data,opacity);
27352  }
27353 
27355 
27362  template<typename t, typename tc>
27363  CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
27364  const tc *const color, const float opacity=1) {
27365  if (is_empty()) return *this;
27366  typedef typename cimg::superset<t,float>::type tfloat;
27367  if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1)
27368  throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 2x2 matrix.",
27369  pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
27370  if (!color)
27371  throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
27372  pixel_type());
27373  const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
27374  const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1);
27375  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
27376  const unsigned int whz = width*height*depth;
27377  const tc *col = color;
27378  float dy = -yc;
27379  cimg_forY(*this,y) {
27380  float dx = -xc;
27381  cimg_forX(*this,x) {
27382  const float val = (float)std::exp(a*dx*dx + b*dx*dy + c*dy*dy);
27383  T *ptrd = ptr(x,y,0,0);
27384  if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
27385  else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
27386  col-=dim;
27387  ++dx;
27388  }
27389  ++dy;
27390  }
27391  return *this;
27392  }
27393 
27395  template<typename t, typename tc>
27396  CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
27397  const CImg<tc>& color, const float opacity=1) {
27398  return draw_gaussian(xc,yc,tensor,color.data,opacity);
27399  }
27400 
27402  template<typename tc>
27403  CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
27404  const tc *const color, const float opacity=1) {
27405  const double
27406  a = r1*ru*ru + r2*rv*rv,
27407  b = (r1-r2)*ru*rv,
27408  c = r1*rv*rv + r2*ru*ru;
27409  const CImg<Tfloat> tensor(2,2,1,1, a,b,b,c);
27410  return draw_gaussian(xc,yc,tensor,color,opacity);
27411  }
27412 
27414  template<typename tc>
27415  CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
27416  const CImg<tc>& color, const float opacity=1) {
27417  return draw_gaussian(xc,yc,r1,r2,ru,rv,color.data,opacity);
27418  }
27419 
27421 
27428  template<typename tc>
27429  CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
27430  const tc *const color, const float opacity=1) {
27431  return draw_gaussian(xc,yc,CImg<floatT>::diagonal(sigma,sigma),color,opacity);
27432  }
27433 
27435  template<typename tc>
27436  CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
27437  const CImg<tc>& color, const float opacity=1) {
27438  return draw_gaussian(xc,yc,sigma,color.data,opacity);
27439  }
27440 
27442 
27450  template<typename t, typename tc>
27451  CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
27452  const tc *const color, const float opacity=1) {
27453  if (is_empty()) return *this;
27454  typedef typename cimg::superset<t,float>::type tfloat;
27455  if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1)
27456  throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 3x3 matrix.",
27457  pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
27458  const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
27459  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);
27460  const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
27461  const unsigned int whz = width*height*depth;
27462  const tc *col = color;
27463  cimg_forXYZ(*this,x,y,z) {
27464  const float
27465  dx = (x - xc), dy = (y - yc), dz = (z - zc),
27466  val = (float)std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz);
27467  T *ptrd = ptr(x,y,z,0);
27468  if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
27469  else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
27470  col-=dim;
27471  }
27472  return *this;
27473  }
27474 
27476  template<typename t, typename tc>
27477  CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
27478  const CImg<tc>& color, const float opacity=1) {
27479  return draw_gaussian(xc,yc,zc,tensor,color.data,opacity);
27480  }
27481 
27483 
27491  template<typename tc>
27492  CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
27493  const tc *const color, const float opacity=1) {
27494  return draw_gaussian(xc,yc,zc,CImg<floatT>::diagonal(sigma,sigma,sigma),color,opacity);
27495  }
27496 
27498  template<typename tc>
27499  CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
27500  const CImg<tc>& color, const float opacity=1) {
27501  return draw_gaussian(xc,yc,zc,sigma,color.data,opacity);
27502  }
27503 
27505 
27521  template<typename tp, typename tf, typename tc, typename to>
27522  CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
27523  const CImg<tp>& vertices, const CImgList<tf>& primitives,
27524  const CImgList<tc>& colors, const CImgList<to>& opacities,
27525  const unsigned int render_type=4,
27526  const bool double_sided=false, const float focale=500,
27527  const float lightx=0, const float lighty=0, const float lightz=-5000,
27528  const float specular_light=0.2f, const float specular_shine=0.1f,
27530  return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,opacities.width,
27531  render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
27532  }
27533 
27534 #ifdef cimg_use_board
27535  template<typename tp, typename tf, typename tc, typename to>
27536  CImg<T>& draw_object3d(LibBoard::Board& board,
27537  const float x0, const float y0, const float z0,
27538  const CImg<tp>& vertices, const CImgList<tf>& primitives,
27539  const CImgList<tc>& colors, const CImgList<to>& opacities,
27540  const unsigned int render_type=4,
27541  const bool double_sided=false, const float focale=500,
27542  const float lightx=0, const float lighty=0, const float lightz=-5000,
27543  const float specular_light=0.2f, const float specular_shine=0.1f,
27545  return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,opacities.width,
27546  render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
27547  }
27548 #endif
27549  template<typename tp, typename tf, typename tc, typename to>
27550  CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
27551  const CImg<tp>& vertices, const CImgList<tf>& primitives,
27552  const CImgList<tc>& colors, const CImg<to>& opacities,
27553  const unsigned int render_type=4,
27554  const bool double_sided=false, const float focale=500,
27555  const float lightx=0, const float lighty=0, const float lightz=-5000,
27556  const float specular_light=0.2f, const float specular_shine=0.1f,
27558  return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,opacities.size(),
27559  render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
27560  }
27561 
27562 #ifdef cimg_use_board
27563  template<typename tp, typename tf, typename tc, typename to>
27564  CImg<T>& draw_object3d(LibBoard::Board& board,
27565  const float x0, const float y0, const float z0,
27566  const CImg<tp>& vertices, const CImgList<tf>& primitives,
27567  const CImgList<tc>& colors, const CImg<to>& opacities,
27568  const unsigned int render_type=4,
27569  const bool double_sided=false, const float focale=500,
27570  const float lightx=0, const float lighty=0, const float lightz=-5000,
27571  const float specular_light=0.2f, const float specular_shine=0.1f,
27573  return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities,opacities.size(),
27574  render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
27575  }
27576 #endif
27577 
27579  template<typename tp, typename tf, typename tc>
27580  CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
27581  const CImg<tp>& vertices, const CImgList<tf>& primitives,
27582  const CImgList<tc>& colors,
27583  const unsigned int render_type=4,
27584  const bool double_sided=false, const float focale=500,
27585  const float lightx=0, const float lighty=0, const float lightz=-5000,
27586  const float specular_light=0.2f, const float specular_shine=0.1f,
27588  static const CImg<floatT> opacities;
27589  return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities,
27590  render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
27591  }
27592 
27593 #ifdef cimg_use_board
27594  template<typename tp, typename tf, typename tc, typename to>
27595  CImg<T>& draw_object3d(LibBoard::Board& board,
27596  const float x0, const float y0, const float z0,
27597  const CImg<tp>& vertices, const CImgList<tf>& primitives,
27598  const CImgList<tc>& colors,
27599  const unsigned int render_type=4,
27600  const bool double_sided=false, const float focale=500,
27601  const float lightx=0, const float lighty=0, const float lightz=-5000,
27602  const float specular_light=0.2f, const float specular_shine=0.1f,
27604  static const CImg<floatT> opacities;
27605  return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities,
27606  render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
27607  }
27608 #endif
27609 
27610  template<typename tc, typename to>
27611  void __draw_object3d(const unsigned int n_primitive, const unsigned int nb_opacities, const CImgList<to>& opacities, const CImg<tc>& color,
27612  const int nx0, const int ny0, const CImg<T>& sprite, const float opac) {
27613  if (n_primitive<nb_opacities && opacities[n_primitive].is_sameXY(color))
27614  draw_image(nx0,ny0,sprite,opacities[n_primitive].get_resize(sprite.width,sprite.height,1,sprite.dim,1));
27615  else draw_image(nx0,ny0,sprite,opac);
27616  }
27617 
27618  template<typename tc, typename to>
27619  void __draw_object3d(const unsigned int, const unsigned int, const CImg<to>&, const CImg<tc>&,
27620  const int nx0, const int ny0, const CImg<T>& sprite, const float opac) {
27621  draw_image(nx0,ny0,sprite,opac);
27622  }
27623 
27624  template<typename tp, typename tf, typename tc, typename to>
27625  CImg<T>& _draw_object3d(void *const pboard, CImg<floatT>& zbuffer,
27626  const float X, const float Y, const float Z,
27627  const CImg<tp>& vertices,
27628  const CImgList<tf>& primitives,
27629  const CImgList<tc>& colors,
27630  const to& opacities, const unsigned int nb_opacities,
27631  const unsigned int render_type,
27632  const bool double_sided, const float focale,
27633  const float lightx, const float lighty, const float lightz,
27634  const float specular_light, const float specular_shine) {
27635  if (is_empty() || !vertices || !primitives) return *this;
27636  vertices.is_object3d(primitives,false,true);
27637 #ifndef cimg_use_board
27638  if (pboard) return *this;
27639 #endif
27640  const float
27641  nspec = 1.0f-(specular_light<0.0f?0.0f:(specular_light>1.0f?1.0f:specular_light)),
27642  nspec2 = 1.0f+(specular_shine<0.0f?0.0f:specular_shine),
27643  nsl1 = (nspec2-1)/cimg::sqr(nspec-1),
27644  nsl2 = (1-2*nsl1*nspec),
27645  nsl3 = nspec2-nsl1-nsl2;
27646 
27647  // Create light texture for phong-like rendering
27648  static CImg<floatT> light_texture;
27649  if (render_type==5) {
27650  if (colors.width>primitives.width) light_texture.assign(colors[primitives.width])/=255;
27651  else {
27652  static float olightx = 0, olighty = 0, olightz = 0, ospecular_shine = 0;
27653  if (!light_texture || lightx!=olightx || lighty!=olighty || lightz!=olightz || specular_shine!=ospecular_shine) {
27654  light_texture.assign(512,512);
27655  const float white[] = { 1 },
27656  dlx = lightx-X, dly = lighty-Y, dlz = lightz-Z,
27657  nl = (float)std::sqrt(dlx*dlx+dly*dly+dlz*dlz),
27658  nlx = light_texture.width/2*(1+dlx/nl),
27659  nly = light_texture.height/2*(1+dly/nl);
27660  light_texture.draw_gaussian(nlx,nly,light_texture.width/3.0f,white);
27661  cimg_forXY(light_texture,x,y) {
27662  const float factor = light_texture(x,y);
27663  if (factor>nspec) light_texture(x,y) = cimg::min(2,nsl1*factor*factor+nsl2*factor+nsl3);
27664  }
27665  olightx = lightx; olighty = lighty; olightz = lightz; ospecular_shine = specular_shine;
27666  }
27667  }
27668  }
27669 
27670  // Compute 3D to 2D projection
27671  CImg<floatT> projections(vertices.width,2);
27672  cimg_forX(projections,l) {
27673  const float
27674  x = (float)vertices(l,0),
27675  y = (float)vertices(l,1),
27676  z = (float)vertices(l,2);
27677  const float projectedz = z + Z + focale;
27678  projections(l,1) = Y + focale*y/projectedz;
27679  projections(l,0) = X + focale*x/projectedz;
27680  }
27681 
27682  // Compute and sort visible primitives
27683  CImg<uintT> visibles(primitives.width);
27684  CImg<floatT> zrange(primitives.width);
27685  unsigned int nb_visibles = 0;
27686  const float zmin = -focale+1.5f;
27687  { cimglist_for(primitives,l) {
27688  const CImg<tf>& primitive = primitives[l];
27689  switch (primitive.size()) {
27690 
27691  case 1 : { // Point
27692  const unsigned int i0 = (unsigned int)primitive(0);
27693  const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z + vertices(i0,2));
27694  if (z0>zmin && x0>=0 && x0<width && y0>=0 && y0<height) {
27695  visibles(nb_visibles) = (unsigned int)l;
27696  zrange(nb_visibles++) = z0;
27697  }
27698  } break;
27699  case 5 : { // Sphere
27700  const unsigned int
27701  i0 = (unsigned int)primitive(0),
27702  i1 = (unsigned int)primitive(1),
27703  i2 = (unsigned int)primitive(2);
27704  const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z + vertices(i0,2));
27705  int radius;
27706  if (i2) radius = (int)(i2*focale/(z0+focale));
27707  else {
27708  const float x1 = projections(i1,0), y1 = projections(i1,1);
27709  const int deltax = (int)(x1-x0), deltay = (int)(y1-y0);
27710  radius = (int)std::sqrt((float)(deltax*deltax + deltay*deltay));
27711  }
27712  if (z0>zmin && x0+radius>=0 && x0-radius<width && y0+radius>=0 && y0-radius<height) {
27713  visibles(nb_visibles) = (unsigned int)l;
27714  zrange(nb_visibles++) = z0;
27715  }
27716  } break;
27717  case 2 : // Segment
27718  case 6 : {
27719  const unsigned int
27720  i0 = (unsigned int)primitive(0),
27721  i1 = (unsigned int)primitive(1);
27722  const float
27723  x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z + vertices(i0,2)),
27724  x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z + vertices(i1,2));
27725  float xm, xM, ym, yM;
27726  if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
27727  if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
27728  if (z0>zmin && z1>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
27729  visibles(nb_visibles) = (unsigned int)l;
27730  zrange(nb_visibles++) = 0.5f*(z0+z1);
27731  }
27732  } break;
27733  case 3 : // Triangle
27734  case 9 : {
27735  const unsigned int
27736  i0 = (unsigned int)primitive(0),
27737  i1 = (unsigned int)primitive(1),
27738  i2 = (unsigned int)primitive(2);
27739  const float
27740  x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z + vertices(i0,2)),
27741  x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z + vertices(i1,2)),
27742  x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z + vertices(i2,2));
27743  float xm, xM, ym, yM;
27744  if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
27745  if (x2<xm) xm = x2;
27746  if (x2>xM) xM = x2;
27747  if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
27748  if (y2<ym) ym = y2;
27749  if (y2>yM) yM = y2;
27750  if (z0>zmin && z1>zmin && z2>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
27751  const float d = (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);
27752  if (double_sided || d<0) {
27753  visibles(nb_visibles) = (unsigned int)l;
27754  zrange(nb_visibles++) = (z0+z1+z2)/3;
27755  }
27756  }
27757  } break;
27758  case 4 : // Rectangle
27759  case 12 : {
27760  const unsigned int
27761  i0 = (unsigned int)primitive(0),
27762  i1 = (unsigned int)primitive(1),
27763  i2 = (unsigned int)primitive(2),
27764  i3 = (unsigned int)primitive(3);
27765  const float
27766  x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z + vertices(i0,2)),
27767  x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z + vertices(i1,2)),
27768  x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z + vertices(i2,2)),
27769  x3 = projections(i3,0), y3 = projections(i3,1), z3 = (float)(Z + vertices(i3,2));
27770  float xm, xM, ym, yM;
27771  if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
27772  if (x2<xm) xm = x2;
27773  if (x2>xM) xM = x2;
27774  if (x3<xm) xm = x3;
27775  if (x3>xM) xM = x3;
27776  if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
27777  if (y2<ym) ym = y2;
27778  if (y2>yM) yM = y2;
27779  if (y3<ym) ym = y3;
27780  if (y3>yM) yM = y3;
27781  if (z0>zmin && z1>zmin && z2>zmin && z3>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
27782  const float d = (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0);
27783  if (double_sided || d<0) {
27784  visibles(nb_visibles) = (unsigned int)l;
27785  zrange(nb_visibles++) = (z0 + z1 + z2 + z3)/4;
27786  }
27787  }
27788  } break;
27789  default :
27790  throw CImgArgumentException("CImg<%s>::draw_object3d() : Primitive %u is invalid (size = %u, can be 1,2,3,4,5,6,9 or 12)",
27791  pixel_type(),l,primitive.size());
27792  }
27793  }
27794  }
27795  if (nb_visibles<=0) return *this;
27796  CImg<uintT> permutations;
27797  CImg<floatT>(zrange.data,nb_visibles,1,1,1,true).sort(permutations,false);
27798 
27799  // Compute light properties
27800  CImg<floatT> lightprops;
27801  switch (render_type) {
27802  case 3 : { // Flat Shading
27803  lightprops.assign(nb_visibles);
27804  cimg_forX(lightprops,l) {
27805  const CImg<tf>& primitive = primitives(visibles(permutations(l)));
27806  const unsigned int psize = primitive.size();
27807  if (psize==3 || psize==4 || psize==9 || psize==12) {
27808  const unsigned int
27809  i0 = (unsigned int)primitive(0),
27810  i1 = (unsigned int)primitive(1),
27811  i2 = (unsigned int)primitive(2);
27812  const float
27813  x0 = (float)vertices(i0,0), y0 = (float)vertices(i0,1), z0 = (float)vertices(i0,2),
27814  x1 = (float)vertices(i1,0), y1 = (float)vertices(i1,1), z1 = (float)vertices(i1,2),
27815  x2 = (float)vertices(i2,0), y2 = (float)vertices(i2,1), z2 = (float)vertices(i2,2),
27816  dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
27817  dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
27818  nx = dy1*dz2 - dz1*dy2,
27819  ny = dz1*dx2 - dx1*dz2,
27820  nz = dx1*dy2 - dy1*dx2,
27821  norm = (float)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
27822  lx = X + (x0 + x1 + x2)/3 - lightx,
27823  ly = Y + (y0 + y1 + y2)/3 - lighty,
27824  lz = Z + (z0 + z1 + z2)/3 - lightz,
27825  nl = (float)std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
27826  factor = cimg::max(cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
27827  lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
27828  } else lightprops[l] = 1;
27829  }
27830  } break;
27831 
27832  case 4 : // Gouraud Shading
27833  case 5 : { // Phong-Shading
27834  CImg<floatT> vertices_normals(vertices.width,3,1,1,0);
27835  for (unsigned int l = 0; l<nb_visibles; ++l) {
27836  const CImg<tf>& primitive = primitives[visibles(l)];
27837  const unsigned int psize = primitive.size();
27838  const bool
27839  triangle_flag = (psize==3) || (psize==9),
27840  rectangle_flag = (psize==4) || (psize==12);
27841  if (triangle_flag || rectangle_flag) {
27842  const unsigned int
27843  i0 = (unsigned int)primitive(0),
27844  i1 = (unsigned int)primitive(1),
27845  i2 = (unsigned int)primitive(2),
27846  i3 = rectangle_flag?(unsigned int)primitive(3):0;
27847  const float
27848  x0 = (float)vertices(i0,0), y0 = (float)vertices(i0,1), z0 = (float)vertices(i0,2),
27849  x1 = (float)vertices(i1,0), y1 = (float)vertices(i1,1), z1 = (float)vertices(i1,2),
27850  x2 = (float)vertices(i2,0), y2 = (float)vertices(i2,1), z2 = (float)vertices(i2,2),
27851  dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
27852  dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
27853  nnx = dy1*dz2 - dz1*dy2,
27854  nny = dz1*dx2 - dx1*dz2,
27855  nnz = dx1*dy2 - dy1*dx2,
27856  norm = 1e-5f + (float)std::sqrt(nnx*nnx + nny*nny + nnz*nnz),
27857  nx = nnx/norm,
27858  ny = nny/norm,
27859  nz = nnz/norm;
27860  vertices_normals(i0,0)+=nx; vertices_normals(i0,1)+=ny; vertices_normals(i0,2)+=nz;
27861  vertices_normals(i1,0)+=nx; vertices_normals(i1,1)+=ny; vertices_normals(i1,2)+=nz;
27862  vertices_normals(i2,0)+=nx; vertices_normals(i2,1)+=ny; vertices_normals(i2,2)+=nz;
27863  if (rectangle_flag) { vertices_normals(i3,0)+=nx; vertices_normals(i3,1)+=ny; vertices_normals(i3,2)+=nz; }
27864  }
27865  }
27866 
27867  if (double_sided) cimg_forX(vertices_normals,p) if (vertices_normals(p,2)>0) {
27868  vertices_normals(p,0) = -vertices_normals(p,0);
27869  vertices_normals(p,1) = -vertices_normals(p,1);
27870  vertices_normals(p,2) = -vertices_normals(p,2);
27871  }
27872 
27873  if (render_type==4) {
27874  lightprops.assign(vertices.width);
27875  cimg_forX(lightprops,ll) {
27876  const float
27877  nx = vertices_normals(ll,0),
27878  ny = vertices_normals(ll,1),
27879  nz = vertices_normals(ll,2),
27880  norm = (float)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
27881  lx = (float)(X + vertices(ll,0) - lightx),
27882  ly = (float)(Y + vertices(ll,1) - lighty),
27883  lz = (float)(Z + vertices(ll,2) - lightz),
27884  nl = (float)std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
27885  factor = cimg::max((-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
27886  lightprops[ll] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
27887  }
27888  } else {
27889  const unsigned int
27890  lw2 = light_texture.width/2 - 1,
27891  lh2 = light_texture.height/2 - 1;
27892  lightprops.assign(vertices.width,2);
27893  cimg_forX(lightprops,ll) {
27894  const float
27895  nx = vertices_normals(ll,0),
27896  ny = vertices_normals(ll,1),
27897  nz = vertices_normals(ll,2),
27898  norm = (float)std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
27899  nnx = nx/norm,
27900  nny = ny/norm;
27901  lightprops(ll,0) = lw2*(1 + nnx);
27902  lightprops(ll,1) = lh2*(1 + nny);
27903  }
27904  }
27905  } break;
27906  }
27907 
27908  // Draw visible primitives
27909  const CImg<tc> default_color(1,dim,1,1,(tc)200);
27910  for (unsigned int l = 0; l<nb_visibles; ++l) {
27911  const unsigned int n_primitive = visibles(permutations(l));
27912  const CImg<tf>& primitive = primitives[n_primitive];
27913  const CImg<tc>& color = n_primitive<colors.width?colors[n_primitive]:default_color;
27914  const float opac = n_primitive<nb_opacities?opacities(n_primitive,0):1.0f;
27915 #ifdef cimg_use_board
27916  LibBoard::Board &board = *(LibBoard::Board*)pboard;
27917 #endif
27918 
27919  switch (primitive.size()) {
27920  case 1 : { // Colored point or sprite
27921  const unsigned int n0 = (unsigned int)primitive[0];
27922  const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
27923  if (color.size()==dim) { // Colored point.
27924  draw_point(x0,y0,color,opac);
27925 #ifdef cimg_use_board
27926  if (pboard) {
27927  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
27928  board.fillCircle((float)x0,dimy()-(float)y0,0);
27929  }
27930 #endif
27931  } else { // Colored sprite.
27932  const float z = Z + vertices(n0,2);
27933  const int
27934  factor = (int)(focale*100/(z+focale)),
27935  sw = color.width*factor/200,
27936  sh = color.height*factor/200,
27937  nx0 = x0 - sw, ny0 = y0 - sh;
27938  if (x0+sw>=0 && nx0<dimx() && y0+sh>=0 && ny0<dimy()) {
27939  const CImg<T> sprite = color.get_resize(-factor,-factor,1,-100,render_type<=3?1:3);
27940  __draw_object3d(n_primitive,nb_opacities,opacities,color,nx0,ny0,sprite,opac);
27941 #ifdef cimg_use_board
27942  if (pboard) {
27943  board.setPenColorRGBi(128,128,128);
27944  board.setFillColor(LibBoard::Color::None);
27945  board.drawRectangle((float)nx0,dimy()-(float)ny0,sw,sh);
27946  }
27947 #endif
27948  }
27949  }
27950  } break;
27951  case 2 : { // Colored line
27952  const unsigned int
27953  n0 = (unsigned int)primitive[0],
27954  n1 = (unsigned int)primitive[1];
27955  const int
27956  x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
27957  x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
27958  const float
27959  z0 = vertices(n0,2) + Z + focale,
27960  z1 = vertices(n1,2) + Z + focale;
27961  if (render_type) {
27962  if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac);
27963  else draw_line(x0,y0,x1,y1,color,opac);
27964 #ifdef cimg_use_board
27965  if (pboard) {
27966  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
27967  board.drawLine((float)x0,dimy()-(float)y0,x1,dimy()-(float)y1);
27968  }
27969 #endif
27970  } else {
27971  draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac);
27972 #ifdef cimg_use_board
27973  if (pboard) {
27974  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
27975  board.drawCircle((float)x0,dimy()-(float)y0,0);
27976  board.drawCircle((float)x1,dimy()-(float)y1,0);
27977  }
27978 #endif
27979  }
27980  } break;
27981  case 5 : { // Colored sphere
27982  const unsigned int
27983  n0 = (unsigned int)primitive[0],
27984  n1 = (unsigned int)primitive[1],
27985  n2 = (unsigned int)primitive[2];
27986  const int
27987  x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
27988  int radius;
27989  if (n2) radius = (int)(n2*focale/(Z + vertices(n0,2) + focale));
27990  else {
27991  const int
27992  x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
27993  deltax = x1-x0, deltay = y1-y0;
27994  radius = (int)std::sqrt((float)(deltax*deltax + deltay*deltay));
27995  }
27996  switch (render_type) {
27997  case 0 :
27998  draw_point(x0,y0,color,opac);
27999 #ifdef cimg_use_board
28000  if (pboard) {
28001  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
28002  board.fillCircle((float)x0,dimy()-(float)y0,0);
28003  }
28004 #endif
28005  break;
28006  case 1 :
28007  draw_circle(x0,y0,radius,color,opac,~0U);
28008 #ifdef cimg_use_board
28009  if (pboard) {
28010  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
28011  board.setFillColor(LibBoard::Color::None);
28012  board.drawCircle((float)x0,dimy()-(float)y0,(float)radius);
28013  }
28014 #endif
28015  break;
28016  default :
28017  draw_circle(x0,y0,radius,color,opac);
28018 #ifdef cimg_use_board
28019  if (pboard) {
28020  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
28021  board.fillCircle((float)x0,dimy()-(float)y0,(float)radius);
28022  }
28023 #endif
28024  break;
28025  }
28026  } break;
28027  case 6 : { // Textured line
28028  const unsigned int
28029  n0 = (unsigned int)primitive[0],
28030  n1 = (unsigned int)primitive[1],
28031  tx0 = (unsigned int)primitive[2],
28032  ty0 = (unsigned int)primitive[3],
28033  tx1 = (unsigned int)primitive[4],
28034  ty1 = (unsigned int)primitive[5];
28035  const int
28036  x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
28037  x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
28038  const float
28039  z0 = vertices(n0,2) + Z + focale,
28040  z1 = vertices(n1,2) + Z + focale;
28041  if (render_type) {
28042  if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac);
28043  else draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opac);
28044 #ifdef cimg_use_board
28045  if (pboard) {
28046  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28047  board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
28048  }
28049 #endif
28050  } else {
28051  draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
28052  draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac);
28053 #ifdef cimg_use_board
28054  if (pboard) {
28055  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28056  board.drawCircle((float)x0,dimy()-(float)y0,0);
28057  board.drawCircle((float)x1,dimy()-(float)y1,0);
28058  }
28059 #endif
28060  }
28061  } break;
28062  case 3 : { // Colored triangle
28063  const unsigned int
28064  n0 = (unsigned int)primitive[0],
28065  n1 = (unsigned int)primitive[1],
28066  n2 = (unsigned int)primitive[2];
28067  const int
28068  x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
28069  x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
28070  x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
28071  const float
28072  z0 = vertices(n0,2) + Z + focale,
28073  z1 = vertices(n1,2) + Z + focale,
28074  z2 = vertices(n2,2) + Z + focale;
28075  switch (render_type) {
28076  case 0 :
28077  draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).draw_point(x2,y2,color,opac);
28078 #ifdef cimg_use_board
28079  if (pboard) {
28080  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
28081  board.drawCircle((float)x0,dimy()-(float)y0,0);
28082  board.drawCircle((float)x1,dimy()-(float)y1,0);
28083  board.drawCircle((float)x2,dimy()-(float)y2,0);
28084  }
28085 #endif
28086  break;
28087  case 1 :
28088  if (zbuffer)
28089  draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,opac).
28090  draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac);
28091  else
28092  draw_line(x0,y0,x1,y1,color,opac).draw_line(x0,y0,x2,y2,color,opac).
28093  draw_line(x1,y1,x2,y2,color,opac);
28094 #ifdef cimg_use_board
28095  if (pboard) {
28096  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
28097  board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
28098  board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
28099  board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28100  }
28101 #endif
28102  break;
28103  case 2 :
28104  if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,opac);
28105  else draw_triangle(x0,y0,x1,y1,x2,y2,color,opac);
28106 #ifdef cimg_use_board
28107  if (pboard) {
28108  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
28109  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28110  }
28111 #endif
28112  break;
28113  case 3 :
28114  if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l));
28115  else _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l));
28116 #ifdef cimg_use_board
28117  if (pboard) {
28118  const float lp = cimg::min(lightprops(l),1);
28119  board.setPenColorRGBi((unsigned char)(color[0]*lp),
28120  (unsigned char)(color[1]*lp),
28121  (unsigned char)(color[2]*lp),
28122  (unsigned char)(opac*255));
28123  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28124  }
28125 #endif
28126  break;
28127  case 4 :
28128  if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
28129  else draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
28130 #ifdef cimg_use_board
28131  if (pboard) {
28132  board.setPenColorRGBi((unsigned char)(color[0]),
28133  (unsigned char)(color[1]),
28134  (unsigned char)(color[2]),
28135  (unsigned char)(opac*255));
28136  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
28137  (float)x1,dimy()-(float)y1,lightprops(n1),
28138  (float)x2,dimy()-(float)y2,lightprops(n2));
28139  }
28140 #endif
28141  break;
28142  case 5 : {
28143  const unsigned int
28144  lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
28145  lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
28146  lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1);
28147  if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
28148  else draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
28149 #ifdef cimg_use_board
28150  if (pboard) {
28151  const float
28152  l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
28153  l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
28154  l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
28155  board.setPenColorRGBi((unsigned char)(color[0]),
28156  (unsigned char)(color[1]),
28157  (unsigned char)(color[2]),
28158  (unsigned char)(opac*255));
28159  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
28160  (float)x1,dimy()-(float)y1,l1,
28161  (float)x2,dimy()-(float)y2,l2);
28162  }
28163 #endif
28164  } break;
28165  }
28166  } break;
28167  case 4 : { // Colored rectangle
28168  const unsigned int
28169  n0 = (unsigned int)primitive[0],
28170  n1 = (unsigned int)primitive[1],
28171  n2 = (unsigned int)primitive[2],
28172  n3 = (unsigned int)primitive[3];
28173  const int
28174  x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
28175  x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
28176  x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
28177  x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
28178  const float
28179  z0 = vertices(n0,2) + Z + focale,
28180  z1 = vertices(n1,2) + Z + focale,
28181  z2 = vertices(n2,2) + Z + focale,
28182  z3 = vertices(n3,2) + Z + focale;
28183  switch (render_type) {
28184  case 0 :
28185  draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).
28186  draw_point(x2,y2,color,opac).draw_point(x3,y3,color,opac);
28187 #ifdef cimg_use_board
28188  if (pboard) {
28189  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
28190  board.drawCircle((float)x0,dimy()-(float)y0,0);
28191  board.drawCircle((float)x1,dimy()-(float)y1,0);
28192  board.drawCircle((float)x2,dimy()-(float)y2,0);
28193  board.drawCircle((float)x3,dimy()-(float)y3,0);
28194  }
28195 #endif
28196  break;
28197  case 1 :
28198  if (zbuffer)
28199  draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac).
28200  draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,opac).draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,opac);
28201  else
28202  draw_line(x0,y0,x1,y1,color,opac).draw_line(x1,y1,x2,y2,color,opac).
28203  draw_line(x2,y2,x3,y3,color,opac).draw_line(x3,y3,x0,y0,color,opac);
28204 #ifdef cimg_use_board
28205  if (pboard) {
28206  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
28207  board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
28208  board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28209  board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
28210  board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
28211  }
28212 #endif
28213  break;
28214  case 2 :
28215  if (zbuffer)
28216  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);
28217  else
28218  draw_triangle(x0,y0,x1,y1,x2,y2,color,opac).draw_triangle(x0,y0,x2,y2,x3,y3,color,opac);
28219 #ifdef cimg_use_board
28220  if (pboard) {
28221  board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
28222  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28223  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
28224  }
28225 #endif
28226  break;
28227  case 3 :
28228  if (zbuffer)
28229  draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l)).
28230  draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color.data,opac,lightprops(l));
28231  else
28232  _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l)).
28233  _draw_triangle(x0,y0,x2,y2,x3,y3,color.data,opac,lightprops(l));
28234 #ifdef cimg_use_board
28235  if (pboard) {
28236  const float lp = cimg::min(lightprops(l),1);
28237  board.setPenColorRGBi((unsigned char)(color[0]*lp),
28238  (unsigned char)(color[1]*lp),
28239  (unsigned char)(color[2]*lp),(unsigned char)(opac*255));
28240  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28241  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
28242  }
28243 #endif
28244  break;
28245  case 4 : {
28246  const float
28247  lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
28248  lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
28249  if (zbuffer)
28250  draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprop0,lightprop1,lightprop2,opac).
28251  draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,lightprop0,lightprop2,lightprop3,opac);
28252  else
28253  draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprop0,lightprop1,lightprop2,opac).
28254  draw_triangle(x0,y0,x2,y2,x3,y3,color,lightprop0,lightprop2,lightprop3,opac);
28255 #ifdef cimg_use_board
28256  if (pboard) {
28257  board.setPenColorRGBi((unsigned char)(color[0]),
28258  (unsigned char)(color[1]),
28259  (unsigned char)(color[2]),
28260  (unsigned char)(opac*255));
28261  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
28262  (float)x1,dimy()-(float)y1,lightprop1,
28263  (float)x2,dimy()-(float)y2,lightprop2);
28264  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
28265  (float)x2,dimy()-(float)y2,lightprop2,
28266  (float)x3,dimy()-(float)y3,lightprop3);
28267  }
28268 #endif
28269  } break;
28270  case 5 : {
28271  const unsigned int
28272  lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
28273  lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
28274  lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
28275  lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
28276  if (zbuffer)
28277  draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
28278  draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
28279  else
28280  draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
28281  draw_triangle(x0,y0,x2,y2,x3,y3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
28282 #ifdef cimg_use_board
28283  if (pboard) {
28284  const float
28285  l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
28286  l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
28287  l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
28288  l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
28289  board.setPenColorRGBi((unsigned char)(color[0]),
28290  (unsigned char)(color[1]),
28291  (unsigned char)(color[2]),
28292  (unsigned char)(opac*255));
28293  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
28294  (float)x1,dimy()-(float)y1,l1,
28295  (float)x2,dimy()-(float)y2,l2);
28296  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
28297  (float)x2,dimy()-(float)y2,l2,
28298  (float)x3,dimy()-(float)y3,l3);
28299  }
28300 #endif
28301  } break;
28302  }
28303  } break;
28304  case 9 : { // Textured triangle
28305  const unsigned int
28306  n0 = (unsigned int)primitive[0],
28307  n1 = (unsigned int)primitive[1],
28308  n2 = (unsigned int)primitive[2],
28309  tx0 = (unsigned int)primitive[3],
28310  ty0 = (unsigned int)primitive[4],
28311  tx1 = (unsigned int)primitive[5],
28312  ty1 = (unsigned int)primitive[6],
28313  tx2 = (unsigned int)primitive[7],
28314  ty2 = (unsigned int)primitive[8];
28315  const int
28316  x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
28317  x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
28318  x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
28319  const float
28320  z0 = vertices(n0,2) + Z + focale,
28321  z1 = vertices(n1,2) + Z + focale,
28322  z2 = vertices(n2,2) + Z + focale;
28323  switch (render_type) {
28324  case 0 :
28325  draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
28326  draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
28327  draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac);
28328 #ifdef cimg_use_board
28329  if (pboard) {
28330  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28331  board.drawCircle((float)x0,dimy()-(float)y0,0);
28332  board.drawCircle((float)x1,dimy()-(float)y1,0);
28333  board.drawCircle((float)x2,dimy()-(float)y2,0);
28334  }
28335 #endif
28336  break;
28337  case 1 :
28338  if (zbuffer)
28339  draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
28340  draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
28341  draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
28342  else
28343  draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
28344  draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
28345  draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
28346 #ifdef cimg_use_board
28347  if (pboard) {
28348  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28349  board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
28350  board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
28351  board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28352  }
28353 #endif
28354  break;
28355  case 2 :
28356  if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
28357  else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
28358 #ifdef cimg_use_board
28359  if (pboard) {
28360  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28361  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28362  }
28363 #endif
28364  break;
28365  case 3 :
28366  if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
28367  else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
28368 #ifdef cimg_use_board
28369  if (pboard) {
28370  const float lp = cimg::min(lightprops(l),1);
28371  board.setPenColorRGBi((unsigned char)(128*lp),
28372  (unsigned char)(128*lp),
28373  (unsigned char)(128*lp),
28374  (unsigned char)(opac*255));
28375  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28376  }
28377 #endif
28378  break;
28379  case 4 :
28380  if (zbuffer)
28381  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);
28382  else
28383  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);
28384 #ifdef cimg_use_board
28385  if (pboard) {
28386  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28387  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
28388  (float)x1,dimy()-(float)y1,lightprops(n1),
28389  (float)x2,dimy()-(float)y2,lightprops(n2));
28390  }
28391 #endif
28392  break;
28393  case 5 :
28394  if (zbuffer)
28395  draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
28396  (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
28397  (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
28398  (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
28399  opac);
28400  else
28401  draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
28402  (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
28403  (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
28404  (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
28405  opac);
28406 #ifdef cimg_use_board
28407  if (pboard) {
28408  const float
28409  l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
28410  l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
28411  l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
28412  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28413  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,(float)x1,dimy()-(float)y1,l1,(float)x2,dimy()-(float)y2,l2);
28414  }
28415 #endif
28416  break;
28417  }
28418  } break;
28419  case 12 : { // Textured rectangle
28420  const unsigned int
28421  n0 = (unsigned int)primitive[0],
28422  n1 = (unsigned int)primitive[1],
28423  n2 = (unsigned int)primitive[2],
28424  n3 = (unsigned int)primitive[3],
28425  tx0 = (unsigned int)primitive[4],
28426  ty0 = (unsigned int)primitive[5],
28427  tx1 = (unsigned int)primitive[6],
28428  ty1 = (unsigned int)primitive[7],
28429  tx2 = (unsigned int)primitive[8],
28430  ty2 = (unsigned int)primitive[9],
28431  tx3 = (unsigned int)primitive[10],
28432  ty3 = (unsigned int)primitive[11];
28433  const int
28434  x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
28435  x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
28436  x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
28437  x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
28438  const float
28439  z0 = vertices(n0,2) + Z + focale,
28440  z1 = vertices(n1,2) + Z + focale,
28441  z2 = vertices(n2,2) + Z + focale,
28442  z3 = vertices(n3,2) + Z + focale;
28443 
28444  switch (render_type) {
28445  case 0 :
28446  draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
28447  draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
28448  draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac).
28449  draw_point(x3,y3,color.get_vector_at(tx3,ty3),opac);
28450 #ifdef cimg_use_board
28451  if (pboard) {
28452  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28453  board.drawCircle((float)x0,dimy()-(float)y0,0);
28454  board.drawCircle((float)x1,dimy()-(float)y1,0);
28455  board.drawCircle((float)x2,dimy()-(float)y2,0);
28456  board.drawCircle((float)x3,dimy()-(float)y3,0);
28457  }
28458 #endif
28459  break;
28460  case 1 :
28461  if (zbuffer)
28462  draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
28463  draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
28464  draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
28465  draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
28466  else
28467  draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
28468  draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
28469  draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
28470  draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
28471 #ifdef cimg_use_board
28472  if (pboard) {
28473  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28474  board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
28475  board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28476  board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
28477  board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
28478  }
28479 #endif
28480  break;
28481  case 2 :
28482  if (zbuffer)
28483  draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
28484  draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
28485  else
28486  draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
28487  draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
28488 #ifdef cimg_use_board
28489  if (pboard) {
28490  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28491  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28492  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
28493  }
28494 #endif
28495  break;
28496  case 3 :
28497  if (zbuffer)
28498  draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
28499  draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
28500  else
28501  draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
28502  draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
28503 #ifdef cimg_use_board
28504  if (pboard) {
28505  const float lp = cimg::min(lightprops(l),1);
28506  board.setPenColorRGBi((unsigned char)(128*lp),
28507  (unsigned char)(128*lp),
28508  (unsigned char)(128*lp),
28509  (unsigned char)(opac*255));
28510  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
28511  board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
28512  }
28513 #endif
28514  break;
28515  case 4 : {
28516  const float
28517  lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
28518  lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
28519  if (zbuffer)
28520  draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
28521  draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
28522  else
28523  draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
28524  draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
28525 #ifdef cimg_use_board
28526  if (pboard) {
28527  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28528  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
28529  (float)x1,dimy()-(float)y1,lightprop1,
28530  (float)x2,dimy()-(float)y2,lightprop2);
28531  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
28532  (float)x2,dimy()-(float)y2,lightprop2,
28533  (float)x3,dimy()-(float)y3,lightprop3);
28534  }
28535 #endif
28536  } break;
28537  case 5 : {
28538  const unsigned int
28539  lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
28540  lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
28541  lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
28542  lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
28543  if (zbuffer)
28544  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).
28545  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);
28546  else
28547  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).
28548  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);
28549 #ifdef cimg_use_board
28550  if (pboard) {
28551  const float
28552  l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
28553  l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
28554  l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
28555  l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
28556  board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
28557  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
28558  (float)x1,dimy()-(float)y1,l1,
28559  (float)x2,dimy()-(float)y2,l2);
28560  board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
28561  (float)x2,dimy()-(float)y2,l2,
28562  (float)x3,dimy()-(float)y3,l3);
28563  }
28564 #endif
28565  } break;
28566  }
28567  } break;
28568  }
28569  }
28570  return *this;
28571  }
28572 
28574  //---------------------------
28575  //
28577 
28578  //---------------------------
28579 
28581 
28589  const int select_type=2, unsigned int *const XYZ=0,
28590  const unsigned char *const color=0) {
28591  return get_select(disp,select_type,XYZ,color).transfer_to(*this);
28592  }
28593 
28595  CImg<T>& select(const char *const title,
28596  const int select_type=2, unsigned int *const XYZ=0,
28597  const unsigned char *const color=0) {
28598  return get_select(title,select_type,XYZ,color).transfer_to(*this);
28599  }
28600 
28603  const int select_type=2, unsigned int *const XYZ=0,
28604  const unsigned char *const color=0) const {
28605  return _get_select(disp,0,select_type,XYZ,color,0,0,0);
28606  }
28607 
28609  CImg<intT> get_select(const char *const title,
28610  const int select_type=2, unsigned int *const XYZ=0,
28611  const unsigned char *const color=0) const {
28612  CImgDisplay disp;
28613  return _get_select(disp,title,select_type,XYZ,color,0,0,0);
28614  }
28615 
28616  CImg<intT> _get_select(CImgDisplay &disp, const char *const title,
28617  const int coords_type, unsigned int *const XYZ,
28618  const unsigned char *const color,
28619  const int origX, const int origY, const int origZ) const {
28620  if (is_empty())
28621  throw CImgInstanceException("CImg<%s>::select() : Instance image (%u,%u,%u,%u,%p) is empty.",
28622  pixel_type(),width,height,depth,dim,data);
28623  if (!disp) {
28624  char ntitle[64] = { 0 }; if (!title) { std::sprintf(ntitle,"CImg<%s>",pixel_type()); }
28625  disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
28626  }
28627 
28628  const unsigned int
28629  old_normalization = disp.normalization,
28630  hatch = 0x55555555;
28631 
28632  bool old_is_resized = disp.is_resized;
28633  disp.normalization = 0;
28634  disp.show().key = 0;
28635 
28636  unsigned char foreground_color[] = { 255,255,105 }, background_color[] = { 0,0,0 };
28637  if (color) std::memcpy(foreground_color,color,sizeof(unsigned char)*cimg::min(3,dimv()));
28638 
28639  int area = 0, clicked_area = 0, phase = 0,
28640  X0 = (int)((XYZ?XYZ[0]:width/2)%width), Y0 = (int)((XYZ?XYZ[1]:height/2)%height), Z0 = (int)((XYZ?XYZ[2]:depth/2)%depth),
28641  X1 =-1, Y1 = -1, Z1 = -1,
28642  X = -1, Y = -1, Z = -1,
28643  oX = X, oY = Y, oZ = Z;
28644  unsigned int old_button = 0, key = 0;
28645 
28646  bool shape_selected = false, text_down = false;
28647  CImg<ucharT> visu, visu0;
28648  char text[1024] = { 0 };
28649 
28650  while (!key && !disp.is_closed && !shape_selected) {
28651 
28652  // Handle mouse motion and selection
28653  oX = X; oY = Y; oZ = Z;
28654  int mx = disp.mouse_x, my = disp.mouse_y;
28655  const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height;
28656 
28657  area = 0;
28658  if (mX<dimx() && mY<dimy()) { area = 1; X = mX; Y = mY; Z = phase?Z1:Z0; }
28659  if (mX<dimx() && mY>=dimy()) { area = 2; X = mX; Z = mY-height; Y = phase?Y1:Y0; }
28660  if (mX>=dimx() && mY<dimy()) { area = 3; Y = mY; Z = mX-width; X = phase?X1:X0; }
28661 
28662  switch (key = disp.key) {
28663  case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
28664  case cimg::keyPAGEUP : if (disp.is_keyCTRLLEFT) { ++disp.wheel; key = 0; } break;
28665  case cimg::keyPAGEDOWN : if (disp.is_keyCTRLLEFT) { --disp.wheel; key = 0; } break;
28666  case cimg::keyD : if (disp.is_keyCTRLLEFT) {
28667  disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
28668  CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
28669  disp.key = key = 0;
28670  } break;
28671  case cimg::keyC : if (disp.is_keyCTRLLEFT) {
28672  disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
28673  disp.key = key = 0; visu0.assign();
28674  } break;
28675  case cimg::keyR : if (disp.is_keyCTRLLEFT) {
28677  disp.key = key = 0; visu0.assign();
28678  } break;
28679  case cimg::keyF : if (disp.is_keyCTRLLEFT) {
28680  disp.resize(disp.screen_dimx(),disp.screen_dimy(),false).toggle_fullscreen().is_resized = true;
28681  disp.key = key = 0; visu0.assign();
28682  } break;
28683  case cimg::keyS : if (disp.is_keyCTRLLEFT) {
28684  static unsigned int snap_number = 0;
28685  char filename[32] = { 0 };
28686  std::FILE *file;
28687  do {
28688  std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
28689  if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
28690  } while (file);
28691  if (visu0) {
28692  visu.draw_text(2,2,"Saving snapshot...",foreground_color,background_color,0.8f,11).display(disp);
28693  visu0.save(filename);
28694  visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
28695  }
28696  disp.key = key = 0;
28697  } break;
28698  case cimg::keyO : if (disp.is_keyCTRLLEFT) {
28699  static unsigned int snap_number = 0;
28700  char filename[32] = { 0 };
28701  std::FILE *file;
28702  do {
28703  std::sprintf(filename,"CImg_%.4u.cimg",snap_number++);
28704  if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
28705  } while (file);
28706  visu.draw_text(2,2,"Saving instance...",foreground_color,background_color,0.8f,11).display(disp);
28707  save(filename);
28708  visu.draw_text(2,2,"Instance '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
28709  disp.key = key = 0;
28710  } break;
28711  }
28712 
28713  if (!area) mx = my = X = Y = Z = -1;
28714  else {
28715  if (disp.button&1 && phase<2) { X1 = X; Y1 = Y; Z1 = Z; }
28716  if (!(disp.button&1) && phase>=2) {
28717  switch (clicked_area) {
28718  case 1 : Z1 = Z; break;
28719  case 2 : Y1 = Y; break;
28720  case 3 : X1 = X; break;
28721  }
28722  }
28723  if (disp.button&2) { if (phase) { X1 = X; Y1 = Y; Z1 = Z; } else { X0 = X; Y0 = Y; Z0 = Z; } }
28724  if (disp.button&4) { oX = X = X0; oY = Y = Y0; oZ = Z = Z0; phase = 0; visu.assign(); }
28725  if (disp.wheel) {
28726  if (depth>1 && !disp.is_keyCTRLLEFT && !disp.is_keySHIFTLEFT && !disp.is_keyALT) {
28727  switch (area) {
28728  case 1 : if (phase) Z = (Z1+=disp.wheel); else Z = (Z0+=disp.wheel); break;
28729  case 2 : if (phase) Y = (Y1+=disp.wheel); else Y = (Y0+=disp.wheel); break;
28730  case 3 : if (phase) X = (X1+=disp.wheel); else X = (X0+=disp.wheel); break;
28731  }
28732  disp.wheel = 0;
28733  } else key = ~0U;
28734  }
28735  if ((disp.button&1)!=old_button) {
28736  switch (phase++) {
28737  case 0 : X0 = X1 = X; Y0 = Y1 = Y; Z0 = Z1 = Z; clicked_area = area; break;
28738  case 1 : X1 = X; Y1 = Y; Z1 = Z; break;
28739  }
28740  old_button = disp.button&1;
28741  }
28742  if (depth>1 && (X!=oX || Y!=oY || Z!=oZ)) visu0.assign();
28743  }
28744 
28745  if (phase) {
28746  if (!coords_type) shape_selected = phase?true:false;
28747  else {
28748  if (depth>1) shape_selected = (phase==3)?true:false;
28749  else shape_selected = (phase==2)?true:false;
28750  }
28751  }
28752 
28753  if (X0<0) X0 = 0; if (X0>=dimx()) X0 = dimx()-1; if (Y0<0) Y0 = 0; if (Y0>=dimy()) Y0 = dimy()-1;
28754  if (Z0<0) Z0 = 0; if (Z0>=dimz()) Z0 = dimz()-1;
28755  if (X1<1) X1 = 0; if (X1>=dimx()) X1 = dimx()-1; if (Y1<0) Y1 = 0; if (Y1>=dimy()) Y1 = dimy()-1;
28756  if (Z1<0) Z1 = 0; if (Z1>=dimz()) Z1 = dimz()-1;
28757 
28758  // Draw visualization image on the display
28759  if (oX!=X || oY!=Y || oZ!=Z || !visu0) {
28760  if (!visu0) {
28761  CImg<Tuchar> tmp, tmp0;
28762  if (depth!=1) {
28763  tmp0 = (!phase)?get_projections2d(X0,Y0,Z0):get_projections2d(X1,Y1,Z1);
28764  tmp = tmp0.get_channels(0,cimg::min(2U,dim-1));
28765  } else tmp = get_channels(0,cimg::min(2U,dim-1));
28766  switch (old_normalization) {
28767  case 0 : visu0 = tmp; break;
28768  case 3 :
28769  if (cimg::type<T>::is_float()) visu0 = tmp.normalize(0,(T)255);
28770  else {
28771  const float m = (float)cimg::type<T>::min(), M = (float)cimg::type<T>::max();
28772  visu0.assign(tmp.width,tmp.height,1,tmp.dim);
28773  unsigned char *ptrd = visu0.end();
28774  cimg_for(tmp,ptrs,Tuchar) *(--ptrd) = (unsigned char)((*ptrs-m)*255.0f/(M-m));
28775  } break;
28776  default : visu0 = tmp.normalize(0,255);
28777  }
28778  visu0.resize(disp);
28779  }
28780  visu = visu0;
28781  if (!color) {
28782  if (visu.mean()<200) {
28783  foreground_color[0] = foreground_color[1] = foreground_color[2] = 255;
28784  background_color[0] = background_color[1] = background_color[2] = 0;
28785  } else {
28786  foreground_color[0] = foreground_color[1] = foreground_color[2] = 0;
28787  background_color[0] = background_color[1] = background_color[2] = 255;
28788  }
28789  }
28790 
28791  const int d = (depth>1)?depth:0;
28792  if (phase) switch (coords_type) {
28793  case 1 : {
28794  const int
28795  x0 = (int)((X0+0.5f)*disp.width/(width+d)),
28796  y0 = (int)((Y0+0.5f)*disp.height/(height+d)),
28797  x1 = (int)((X1+0.5f)*disp.width/(width+d)),
28798  y1 = (int)((Y1+0.5f)*disp.height/(height+d));
28799  visu.draw_arrow(x0,y0,x1,y1,foreground_color,0.6f,30,5,hatch);
28800  if (d) {
28801  const int
28802  zx0 = (int)((width+Z0+0.5f)*disp.width/(width+d)),
28803  zx1 = (int)((width+Z1+0.5f)*disp.width/(width+d)),
28804  zy0 = (int)((height+Z0+0.5f)*disp.height/(height+d)),
28805  zy1 = (int)((height+Z1+0.5f)*disp.height/(height+d));
28806  visu.draw_arrow(zx0,y0,zx1,y1,foreground_color,0.6f,30,5,hatch).
28807  draw_arrow(x0,zy0,x1,zy1,foreground_color,0.6f,30,5,hatch);
28808  }
28809  } break;
28810  case 2 : {
28811  const int
28812  x0 = (X0<X1?X0:X1)*disp.width/(width+d), y0 = (Y0<Y1?Y0:Y1)*disp.height/(height+d),
28813  x1 = ((X0<X1?X1:X0)+1)*disp.width/(width+d)-1, y1 = ((Y0<Y1?Y1:Y0)+1)*disp.height/(height+d)-1;
28814  visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.2f).draw_rectangle(x0,y0,x1,y1,foreground_color,0.6f,hatch);
28815  if (d) {
28816  const int
28817  zx0 = (int)((width+(Z0<Z1?Z0:Z1))*disp.width/(width+d)),
28818  zy0 = (int)((height+(Z0<Z1?Z0:Z1))*disp.height/(height+d)),
28819  zx1 = (int)((width+(Z0<Z1?Z1:Z0)+1)*disp.width/(width+d))-1,
28820  zy1 = (int)((height+(Z0<Z1?Z1:Z0)+1)*disp.height/(height+d))-1;
28821  visu.draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.2f).draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.6f,hatch);
28822  visu.draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.2f).draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.6f,hatch);
28823  }
28824  } break;
28825  case 3 : {
28826  const int
28827  x0 = X0*disp.width/(width+d),
28828  y0 = Y0*disp.height/(height+d),
28829  x1 = X1*disp.width/(width+d)-1,
28830  y1 = Y1*disp.height/(height+d)-1;
28831  visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),0,foreground_color,0.2f).
28832  draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),0,foreground_color,0.6f,hatch);
28833  if (d) {
28834  const int
28835  zx0 = (int)((width+Z0)*disp.width/(width+d)),
28836  zy0 = (int)((height+Z0)*disp.height/(height+d)),
28837  zx1 = (int)((width+Z1+1)*disp.width/(width+d))-1,
28838  zy1 = (int)((height+Z1+1)*disp.height/(height+d))-1;
28839  visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),0,foreground_color,0.2f).
28840  draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),0,foreground_color,0.6f,hatch).
28841  draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),0,foreground_color,0.2f).
28842  draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),0,foreground_color,0.6f,hatch);
28843  }
28844  } break;
28845  } else {
28846  const int
28847  x0 = X*disp.width/(width+d),
28848  y0 = Y*disp.height/(height+d),
28849  x1 = (X+1)*disp.width/(width+d)-1,
28850  y1 = (Y+1)*disp.height/(height+d)-1;
28851  if (x1-x0>=4 && y1-y0>=4) visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.4f,~0U);
28852  }
28853 
28854  if (my<12) text_down = true;
28855  if (my>=visu.dimy()-11) text_down = false;
28856  if (!coords_type || !phase) {
28857  if (X>=0 && Y>=0 && Z>=0 && X<dimx() && Y<dimy() && Z<dimz()) {
28858  if (depth>1) std::sprintf(text,"Point (%d,%d,%d) = [ ",origX+X,origY+Y,origZ+Z);
28859  else std::sprintf(text,"Point (%d,%d) = [ ",origX+X,origY+Y);
28860  char *ctext = text + std::strlen(text), *const ltext = text + 512;
28861  for (unsigned int k = 0; k<dim && ctext<ltext; ++k) {
28862  std::sprintf(ctext,cimg::type<T>::format(),cimg::type<T>::format((*this)(X,Y,Z,k)));
28863  ctext = text + std::strlen(text);
28864  *(ctext++) = ' '; *ctext = 0;
28865  }
28866  std::sprintf(text + std::strlen(text),"]");
28867  }
28868  } else switch (coords_type) {
28869  case 1 : {
28870  const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), norm = std::sqrt(dX*dX+dY*dY+dZ*dZ);
28871  if (depth>1) std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), Norm = %g",
28872  origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,norm);
28873  else std::sprintf(text,"Vect (%d,%d)-(%d,%d), Norm = %g",
28874  origX+X0,origY+Y0,origX+X1,origY+Y1,norm);
28875  } break;
28876  case 2 :
28877  if (depth>1) std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size = (%d,%d,%d)",
28878  origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origZ+(Z0<Z1?Z0:Z1),
28879  origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),origZ+(Z0<Z1?Z1:Z0),
28880  1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
28881  else std::sprintf(text,"Box (%d,%d)-(%d,%d), Size = (%d,%d)",
28882  origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),
28883  1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
28884  break;
28885  default :
28886  if (depth>1) std::sprintf(text,"Ellipse (%d,%d,%d)-(%d,%d,%d), Radii = (%d,%d,%d)",
28887  origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,
28888  1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
28889  else std::sprintf(text,"Ellipse (%d,%d)-(%d,%d), Radii = (%d,%d)",
28890  origX+X0,origY+Y0,origX+X1,origY+Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
28891 
28892  }
28893  if (phase || (mx>=0 && my>=0)) visu.draw_text(0,text_down?visu.dimy()-11:0,text,foreground_color,background_color,0.7f,11);
28894  disp.display(visu).wait(25);
28895  } else if (!shape_selected) disp.wait();
28896  if (disp.is_resized) { disp.resize(false).is_resized = false; old_is_resized = true; visu0.assign(); }
28897  }
28898 
28899  // Return result
28900  CImg<intT> res(1,6,1,1,-1);
28901  if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; }
28902  if (shape_selected) {
28903  if (coords_type==2) {
28904  if (X0>X1) cimg::swap(X0,X1);
28905  if (Y0>Y1) cimg::swap(Y0,Y1);
28906  if (Z0>Z1) cimg::swap(Z0,Z1);
28907  }
28908  if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1;
28909  switch (coords_type) {
28910  case 1 :
28911  case 2 : res[3] = X1; res[4] = Y1; res[5] = Z1;
28912  default : res[0] = X0; res[1] = Y0; res[2] = Z0;
28913  }
28914  }
28915  disp.button = 0;
28916  disp.normalization = old_normalization;
28917  disp.is_resized = old_is_resized;
28918  if (key!=~0U) disp.key = key;
28919  return res;
28920  }
28921 
28924  const unsigned int plot_type=1, const unsigned int vertex_type=1,
28925  const char *const labelx=0, const double xmin=0, const double xmax=0,
28926  const char *const labely=0, const double ymin=0, const double ymax=0) const {
28927  if (is_empty())
28928  throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
28929  pixel_type(),width,height,depth,dim,data);
28930  const unsigned int siz = width*height*depth, onormalization = disp.normalization;
28931  if (!disp) { char ntitle[64] = { 0 }; std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
28932  disp.show().key = disp.normalization = disp.button = disp.wheel = 0; // Must keep 'key' field unchanged.
28933  double nymin = ymin, nymax = ymax, nxmin = xmin, nxmax = xmax;
28934  if (nymin==nymax) nymin = (Tfloat)minmax(nymax);
28935  if (nymin==nymax) { --nymin; ++nymax; }
28936  if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; }
28937 
28938  const unsigned char black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 220,220,220 };
28939  const unsigned char gray2[] = { 110,110,110 }, ngray[] = { 35,35,35 };
28940  static unsigned int odimv = 0;
28941  static CImg<ucharT> palette;
28942  if (odimv!=dim) {
28943  odimv = dim;
28944  palette = CImg<ucharT>(3,dim,1,1,120).noise(70,1);
28945  if (dim==1) { palette[0] = palette[1] = 120; palette[2] = 200; }
28946  else {
28947  palette(0,0) = 220; palette(1,0) = 10; palette(2,0) = 10;
28948  if (dim>1) { palette(0,1) = 10; palette(1,1) = 220; palette(2,1) = 10; }
28949  if (dim>2) { palette(0,2) = 10; palette(1,2) = 10; palette(2,2) = 220; }
28950  }
28951  }
28952 
28953  CImg<ucharT> visu0, visu, graph, text, axes;
28954  const unsigned int whz = width*height*depth;
28955  int x0 = -1, x1 = -1, y0 = -1, y1 = -1, omouse_x = -2, omouse_y = -2;
28956  char message[1024] = { 0 };
28957  unsigned int okey = 0, obutton = 0;
28958  CImg_3x3(I,unsigned char);
28959 
28960  for (bool selected = false; !selected && !disp.is_closed && !okey && !disp.wheel; ) {
28961  const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
28962  const unsigned int key = disp.key, button = disp.button;
28963 
28964  // Generate graph representation.
28965  if (!visu0) {
28966  visu0.assign(disp.dimx(),disp.dimy(),1,3,220);
28967  const int gdimx = disp.dimx() - 32, gdimy = disp.dimy() - 32;
28968  if (gdimx>0 && gdimy>0) {
28969  graph.assign(gdimx,gdimy,1,3,255);
28970  graph.draw_grid(-10,-10,0,0,false,true,black,0.2f,0x33333333,0x33333333);
28971  cimg_forV(*this,k) graph.draw_graph(get_shared_channel(k),&palette(0,k),(plot_type!=3 || dim==1)?1:0.6f,
28972  plot_type,vertex_type,nymax,nymin,false);
28973 
28974  axes.assign(gdimx,gdimy,1,1,0);
28975  const float
28976  dx = (float)cimg::abs(nxmax-nxmin), dy = (float)cimg::abs(nymax-nymin),
28977  px = (float)std::pow(10.0,(int)std::log10(dx)-2.0),
28978  py = (float)std::pow(10.0,(int)std::log10(dy)-2.0);
28979  const CImg<Tdouble>
28980  seqx = CImg<Tdouble>::sequence(1 + gdimx/60,nxmin,nxmax).round(px),
28981  seqy = CImg<Tdouble>::sequence(1 + gdimy/60,nymax,nymin).round(py);
28982  axes.draw_axis(seqx,seqy,white);
28983  if (nymin>0) axes.draw_axis(seqx,gdimy-1,gray);
28984  if (nymax<0) axes.draw_axis(seqx,0,gray);
28985  if (nxmin>0) axes.draw_axis(0,seqy,gray);
28986  if (nxmax<0) axes.draw_axis(gdimx-1,seqy,gray);
28987 
28988  cimg_for3x3(axes,x,y,0,0,I)
28989  if (Icc) {
28990  if (Icc==255) cimg_forV(graph,k) graph(x,y,k) = 0;
28991  else cimg_forV(graph,k) graph(x,y,k) = (unsigned char)(2*graph(x,y,k)/3);
28992  }
28993  else if (Ipc || Inc || Icp || Icn || Ipp || Inn || Ipn || Inp) cimg_forV(graph,k) graph(x,y,k) = (graph(x,y,k)+255)/2;
28994 
28995  visu0.draw_image(16,16,graph);
28996  visu0.draw_line(15,15,16+gdimx,15,gray2).draw_line(16+gdimx,15,16+gdimx,16+gdimy,gray2).
28997  draw_line(16+gdimx,16+gdimy,15,16+gdimy,white).draw_line(15,16+gdimy,15,15,white);
28998  } else graph.assign();
28999  text.assign().draw_text(0,0,labelx?labelx:"X-axis",white,ngray,1);
29000  visu0.draw_image((visu0.dimx()-text.dimx())/2,visu0.dimy()-14,~text);
29001  text.assign().draw_text(0,0,labely?labely:"Y-axis",white,ngray,1).rotate(-90);
29002  visu0.draw_image(2,(visu0.dimy()-text.dimy())/2,~text);
29003  visu.assign();
29004  }
29005 
29006  // Generate and display current view.
29007  if (!visu) {
29008  visu.assign(visu0);
29009  if (graph && x0>=0 && x1>=0) {
29010  const int
29011  nx0 = x0<=x1?x0:x1,
29012  nx1 = x0<=x1?x1:x0,
29013  ny0 = y0<=y1?y0:y1,
29014  ny1 = y0<=y1?y1:y0,
29015  sx0 = 16 + nx0*(visu.dimx()-32)/whz,
29016  sx1 = 15 + (nx1+1)*(visu.dimx()-32)/whz,
29017  sy0 = 16 + ny0,
29018  sy1 = 16 + ny1;
29019 
29020  if (y0>=0 && y1>=0)
29021  visu.draw_rectangle(sx0,sy0,sx1,sy1,gray,0.5f).draw_rectangle(sx0,sy0,sx1,sy1,black,0.5f,0xCCCCCCCCU);
29022  else visu.draw_rectangle(sx0,0,sx1,visu.dimy()-17,gray,0.5f).
29023  draw_line(sx0,16,sx0,visu.dimy()-17,black,0.5f,0xCCCCCCCCU).
29024  draw_line(sx1,16,sx1,visu.dimy()-17,black,0.5f,0xCCCCCCCCU);
29025  }
29026  if (mouse_x>=16 && mouse_y>=16 && mouse_x<visu.dimx()-16 && mouse_y<visu.dimy()-16) {
29027  if (graph) visu.draw_line(mouse_x,16,mouse_x,visu.dimy()-17,black,0.5f,0x55555555U);
29028  const unsigned x = (mouse_x-16)*whz/(disp.dimx()-32);
29029  const double cx = nxmin + x*(nxmax-nxmin)/whz;
29030  if (dim>=7)
29031  std::sprintf(message,"Value[%g] = ( %g %g %g ... %g %g %g )",cx,
29032  (double)(*this)(x,0,0,0),(double)(*this)(x,0,0,1),(double)(*this)(x,0,0,2),
29033  (double)(*this)(x,0,0,dim-4),(double)(*this)(x,0,0,dim-3),(double)(*this)(x,0,0,dim-1));
29034  else {
29035  std::sprintf(message,"Value[%g] = ( ",cx);
29036  cimg_forV(*this,k) std::sprintf(message+std::strlen(message),"%g ",(double)(*this)(x,0,0,k));
29037  std::sprintf(message+std::strlen(message),")");
29038  }
29039  if (x0>=0 && x1>=0) {
29040  const int
29041  nx0 = x0<=x1?x0:x1,
29042  nx1 = x0<=x1?x1:x0,
29043  ny0 = y0<=y1?y0:y1,
29044  ny1 = y0<=y1?y1:y0;
29045  const double
29046  cx0 = nxmin + nx0*(nxmax-nxmin)/(visu.dimx()-32),
29047  cx1 = nxmin + nx1*(nxmax-nxmin)/(visu.dimx()-32),
29048  cy0 = nymax - ny0*(nymax-nymin)/(visu.dimy()-32),
29049  cy1 = nymax - ny1*(nymax-nymin)/(visu.dimy()-32);
29050  if (y0>=0 && y1>=0)
29051  std::sprintf(message+std::strlen(message)," - Range ( %g, %g ) - ( %g, %g )",cx0,cy0,cx1,cy1);
29052  else
29053  std::sprintf(message+std::strlen(message)," - Range [ %g - %g ]",cx0,cx1);
29054  }
29055  text.assign().draw_text(0,0,message,white,ngray,1);
29056  visu.draw_image((visu.dimx()-text.dimx())/2,2,~text);
29057  }
29058  visu.display(disp);
29059  }
29060 
29061  // Test keys.
29062  switch (okey = key) {
29063  case cimg::keyCTRLLEFT : okey = 0; break;
29064  case cimg::keyD : if (disp.is_keyCTRLLEFT) {
29065  disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
29066  CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
29067  disp.key = okey = 0;
29068  } break;
29069  case cimg::keyC : if (disp.is_keyCTRLLEFT) {
29070  disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
29071  disp.key = okey = 0;
29072  } break;
29073  case cimg::keyR : if (disp.is_keyCTRLLEFT) {
29074  disp.normalscreen().resize(cimg_fitscreen(640,480,1),false).is_resized = true;
29075  disp.key = okey = 0;
29076  } break;
29077  case cimg::keyF : if (disp.is_keyCTRLLEFT) {
29078  disp.resize(disp.screen_dimx(),disp.screen_dimy(),false).toggle_fullscreen().is_resized = true;
29079  disp.key = okey = 0;
29080  } break;
29081  case cimg::keyS : if (disp.is_keyCTRLLEFT) {
29082  static unsigned int snap_number = 0;
29083  if (visu || visu0) {
29084  CImg<ucharT> &screen = visu?visu:visu0;
29085  char filename[32] = { 0 };
29086  std::FILE *file;
29087  do {
29088  std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
29089  if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
29090  } while (file);
29091  (+screen).draw_text(2,2,"Saving BMP snapshot...",black,gray,1,11).display(disp);
29092  screen.save(filename);
29093  screen.draw_text(2,2,"Snapshot '%s' saved.",black,gray,1,11,filename).display(disp);
29094  }
29095  disp.key = okey = 0;
29096  } break;
29097  }
29098 
29099  // Handle mouse motion and mouse buttons
29100  if (obutton!=button || omouse_x!=mouse_x || omouse_y!=mouse_y) {
29101  visu.assign();
29102  if (disp.mouse_x>=0 && disp.mouse_y>=0) {
29103  const int
29104  mx = (mouse_x-16)*(int)whz/(disp.dimx()-32),
29105  cx = mx<0?0:(mx>=(int)whz?whz-1:mx),
29106  my = mouse_y-16,
29107  cy = my<=0?0:(my>=(disp.dimy()-32)?(disp.dimy()-32):my);
29108  if (button&1) { if (!obutton) { x0 = cx; y0 = -1; } else { x1 = cx; y1 = -1; }}
29109  else if (button&2) { if (!obutton) { x0 = cx; y0 = cy; } else { x1 = cx; y1 = cy; }}
29110  else if (obutton) { x1 = cx; y1 = y1>=0?cy:-1; selected = true; }
29111  } else if (!button && obutton) selected = true;
29112  obutton = button; omouse_x = mouse_x; omouse_y = mouse_y;
29113  }
29114  if (disp.is_resized) { disp.resize(false); visu0.assign(); }
29115  if (visu && visu0) disp.wait();
29116  }
29117  disp.normalization = onormalization;
29118  if (x1<x0) cimg::swap(x0,x1);
29119  if (y1<y0) cimg::swap(y0,y1);
29120  disp.key = okey;
29121  return CImg<intT>(4,1,1,1,x0,y0,x1,y1);
29122  }
29123 
29125 
29130  CImg<T>& load(const char *const filename) {
29131  if (!filename)
29132  throw CImgArgumentException("CImg<%s>::load() : Cannot load (null) filename.",
29133  pixel_type());
29134  const char *ext = cimg::split_filename(filename);
29135  const unsigned int omode = cimg::exception_mode();
29136  cimg::exception_mode() = 0;
29137  assign();
29138  try {
29139 #ifdef cimg_load_plugin
29140  cimg_load_plugin(filename);
29141 #endif
29142 #ifdef cimg_load_plugin1
29143  cimg_load_plugin1(filename);
29144 #endif
29145 #ifdef cimg_load_plugin2
29146  cimg_load_plugin2(filename);
29147 #endif
29148 #ifdef cimg_load_plugin3
29149  cimg_load_plugin3(filename);
29150 #endif
29151 #ifdef cimg_load_plugin4
29152  cimg_load_plugin4(filename);
29153 #endif
29154 #ifdef cimg_load_plugin5
29155  cimg_load_plugin5(filename);
29156 #endif
29157 #ifdef cimg_load_plugin6
29158  cimg_load_plugin6(filename);
29159 #endif
29160 #ifdef cimg_load_plugin7
29161  cimg_load_plugin7(filename);
29162 #endif
29163 #ifdef cimg_load_plugin8
29164  cimg_load_plugin8(filename);
29165 #endif
29166  // ASCII formats
29167  if (!cimg::strcasecmp(ext,"asc")) load_ascii(filename);
29168  if (!cimg::strcasecmp(ext,"dlm") ||
29169  !cimg::strcasecmp(ext,"txt")) load_dlm(filename);
29170 
29171  // 2D binary formats
29172  if (!cimg::strcasecmp(ext,"bmp")) load_bmp(filename);
29173  if (!cimg::strcasecmp(ext,"jpg") ||
29174  !cimg::strcasecmp(ext,"jpeg") ||
29175  !cimg::strcasecmp(ext,"jpe") ||
29176  !cimg::strcasecmp(ext,"jfif") ||
29177  !cimg::strcasecmp(ext,"jif")) load_jpeg(filename);
29178  if (!cimg::strcasecmp(ext,"png")) load_png(filename);
29179  if (!cimg::strcasecmp(ext,"ppm") ||
29180  !cimg::strcasecmp(ext,"pgm") ||
29181  !cimg::strcasecmp(ext,"pnm")) load_pnm(filename);
29182  if (!cimg::strcasecmp(ext,"tif") ||
29183  !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
29184  if (!cimg::strcasecmp(ext,"cr2") ||
29185  !cimg::strcasecmp(ext,"crw") ||
29186  !cimg::strcasecmp(ext,"dcr") ||
29187  !cimg::strcasecmp(ext,"mrw") ||
29188  !cimg::strcasecmp(ext,"nef") ||
29189  !cimg::strcasecmp(ext,"orf") ||
29190  !cimg::strcasecmp(ext,"pix") ||
29191  !cimg::strcasecmp(ext,"ptx") ||
29192  !cimg::strcasecmp(ext,"raf") ||
29193  !cimg::strcasecmp(ext,"srf")) load_dcraw_external(filename);
29194 
29195  // 3D binary formats
29196  if (!cimg::strcasecmp(ext,"dcm") ||
29197  !cimg::strcasecmp(ext,"dicom")) load_medcon_external(filename);
29198  if (!cimg::strcasecmp(ext,"hdr") ||
29199  !cimg::strcasecmp(ext,"nii")) load_analyze(filename);
29200  if (!cimg::strcasecmp(ext,"par") ||
29201  !cimg::strcasecmp(ext,"rec")) load_parrec(filename);
29202  if (!cimg::strcasecmp(ext,"inr")) load_inr(filename);
29203  if (!cimg::strcasecmp(ext,"pan")) load_pandore(filename);
29204  if (!cimg::strcasecmp(ext,"cimg") ||
29205  !cimg::strcasecmp(ext,"cimgz") ||
29206  !*ext) return load_cimg(filename);
29207 
29208  // Archive files
29209  if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
29210 
29211  // Image sequences
29212  if (!cimg::strcasecmp(ext,"avi") ||
29213  !cimg::strcasecmp(ext,"mov") ||
29214  !cimg::strcasecmp(ext,"asf") ||
29215  !cimg::strcasecmp(ext,"divx") ||
29216  !cimg::strcasecmp(ext,"flv") ||
29217  !cimg::strcasecmp(ext,"mpg") ||
29218  !cimg::strcasecmp(ext,"m1v") ||
29219  !cimg::strcasecmp(ext,"m2v") ||
29220  !cimg::strcasecmp(ext,"m4v") ||
29221  !cimg::strcasecmp(ext,"mjp") ||
29222  !cimg::strcasecmp(ext,"mkv") ||
29223  !cimg::strcasecmp(ext,"mpe") ||
29224  !cimg::strcasecmp(ext,"movie") ||
29225  !cimg::strcasecmp(ext,"ogm") ||
29226  !cimg::strcasecmp(ext,"qt") ||
29227  !cimg::strcasecmp(ext,"rm") ||
29228  !cimg::strcasecmp(ext,"vob") ||
29229  !cimg::strcasecmp(ext,"wmv") ||
29230  !cimg::strcasecmp(ext,"xvid") ||
29231  !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
29232  if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
29233  } catch (CImgException& e) {
29234  if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
29235  cimg::exception_mode() = omode;
29236  throw CImgIOException("CImg<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
29237  } else try {
29238  const char *const ftype = cimg::file_type(0,filename);
29239  assign();
29240  if (!cimg::strcasecmp(ftype,"pnm")) load_pnm(filename);
29241  if (!cimg::strcasecmp(ftype,"bmp")) load_bmp(filename);
29242  if (!cimg::strcasecmp(ftype,"jpeg")) load_jpeg(filename);
29243  if (!cimg::strcasecmp(ftype,"pan")) load_pandore(filename);
29244  if (!cimg::strcasecmp(ftype,"png")) load_png(filename);
29245  if (!cimg::strcasecmp(ftype,"tiff")) load_tiff(filename);
29246  if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
29247  } catch (CImgException&) {
29248  try {
29249  load_other(filename);
29250  } catch (CImgException&) {
29251  assign();
29252  }
29253  }
29254  }
29255  cimg::exception_mode() = omode;
29256  if (is_empty())
29257  throw CImgIOException("CImg<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
29258  return *this;
29259  }
29260 
29261  static CImg<T> get_load(const char *const filename) {
29262  return CImg<T>().load(filename);
29263  }
29264 
29266  CImg<T>& load_ascii(const char *const filename) {
29267  return _load_ascii(0,filename);
29268  }
29269 
29270  static CImg<T> get_load_ascii(const char *const filename) {
29271  return CImg<T>().load_ascii(filename);
29272  }
29273 
29275  CImg<T>& load_ascii(std::FILE *const file) {
29276  return _load_ascii(file,0);
29277  }
29278 
29279  static CImg<T> get_load_ascii(std::FILE *const file) {
29280  return CImg<T>().load_ascii(file);
29281  }
29282 
29283  CImg<T>& _load_ascii(std::FILE *const file, const char *const filename) {
29284  if (!filename && !file)
29285  throw CImgArgumentException("CImg<%s>::load_ascii() : Cannot load (null) filename.",
29286  pixel_type());
29287  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29288  char line[256] = { 0 };
29289  int err = std::fscanf(nfile,"%255[^\n]",line);
29290  unsigned int off, dx = 0, dy = 1, dz = 1, dv = 1;
29291  std::sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dv);
29292  err = std::fscanf(nfile,"%*[^0-9.eE+-]");
29293  if (!dx || !dy || !dz || !dv) {
29294  if (!file) cimg::fclose(nfile);
29295  throw CImgIOException("CImg<%s>::load_ascii() : File '%s', invalid .ASC header, specified image dimensions are (%u,%u,%u,%u).",
29296  pixel_type(),filename?filename:"(FILE*)",dx,dy,dz,dv);
29297  }
29298  assign(dx,dy,dz,dv);
29299  const unsigned int siz = size();
29300  double val;
29301  T *ptr = data;
29302  for (err = 1, off = 0; off<siz && err==1; ++off) {
29303  err = std::fscanf(nfile,"%lf%*[^0-9.eE+-]",&val);
29304  *(ptr++) = (T)val;
29305  }
29306  if (err!=1)
29307  cimg::warn("CImg<%s>::load_ascii() : File '%s', only %u/%u values read.",
29308  pixel_type(),filename?filename:"(FILE*)",off-1,siz);
29309  if (!file) cimg::fclose(nfile);
29310  return *this;
29311  }
29312 
29314  CImg<T>& load_dlm(const char *const filename) {
29315  return _load_dlm(0,filename);
29316  }
29317 
29318  static CImg<T> get_load_dlm(const char *const filename) {
29319  return CImg<T>().load_dlm(filename);
29320  }
29321 
29323  CImg<T>& load_dlm(std::FILE *const file) {
29324  return _load_dlm(file,0);
29325  }
29326 
29327  static CImg<T> get_load_dlm(std::FILE *const file) {
29328  return CImg<T>().load_dlm(file);
29329  }
29330 
29331  CImg<T>& _load_dlm(std::FILE *const file, const char *const filename) {
29332  if (!filename && !file)
29333  throw CImgArgumentException("CImg<%s>::load_dlm() : Cannot load (null) filename.",
29334  pixel_type());
29335  std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
29336  char delimiter[256] = { 0 }, tmp[256] = { 0 };
29337  unsigned int cdx = 0, dx = 0, dy = 0;
29338  int err = 0;
29339  double val;
29340  assign(256,256);
29341  while ((err = std::fscanf(nfile,"%lf%255[^0-9.+-]",&val,delimiter))>0) {
29342  if (err>0) (*this)(cdx++,dy) = (T)val;
29343  if (cdx>=width) resize(3*width/2,1,1,1,0);
29344  char c = 0;
29345  if (!std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') {
29346  dx = cimg::max(cdx,dx);
29347  if (++dy>=height) resize(width,3*height/2,1,1,0);
29348  cdx = 0;
29349  }
29350  }
29351  if (cdx && err==1) { dx = cdx; ++dy; }
29352  if (!dx || !dy) {
29353  if (!file) cimg::fclose(nfile);
29354  throw CImgIOException("CImg<%s>::load_dlm() : File '%s', invalid DLM file.",pixel_type(),filename?filename:"(FILE*)");
29355  }
29356  resize(dx,dy,1,1,0);
29357  if (!file) cimg::fclose(nfile);
29358  return *this;
29359  }
29360 
29362  CImg<T>& load_bmp(const char *const filename) {
29363  return _load_bmp(0,filename);
29364  }
29365 
29366  static CImg<T> get_load_bmp(const char *const filename) {
29367  return CImg<T>().load_bmp(filename);
29368  }
29369 
29371  CImg<T>& load_bmp(std::FILE *const file) {
29372  return _load_bmp(file,0);
29373  }
29374 
29375  static CImg<T> get_load_bmp(std::FILE *const file) {
29376  return CImg<T>().load_bmp(file);
29377  }
29378 
29379  CImg<T>& _load_bmp(std::FILE *const file, const char *const filename) {
29380  if (!filename && !file)
29381  throw CImgArgumentException("CImg<%s>::load_bmp() : Cannot load (null) filename.",
29382  pixel_type());
29383  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29384  unsigned char header[64] = { 0 };
29385  cimg::fread(header,54,nfile);
29386  if (header[0]!='B' || header[1]!='M') {
29387  if (!file) cimg::fclose(nfile);
29388  throw CImgIOException("CImg<%s>::load_bmp() : Invalid valid BMP file (filename '%s').",
29389  pixel_type(),filename?filename:"(FILE*)");
29390  }
29391  assign();
29392 
29393  // Read header and pixel buffer
29394  int
29395  file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24),
29396  offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24),
29397  dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24),
29398  dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24),
29399  compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24),
29400  nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24),
29401  bpp = header[0x1C] + (header[0x1D]<<8),
29402  *palette = 0;
29403  const int
29404  dx_bytes = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)),
29405  align = (4-dx_bytes%4)%4,
29406  buf_size = cimg::min(cimg::abs(dy)*(dx_bytes+align),file_size-offset);
29407 
29408  if (bpp<16) { if (!nb_colors) nb_colors=1<<bpp; } else nb_colors = 0;
29409  if (nb_colors) { palette = new int[nb_colors]; cimg::fread(palette,nb_colors,nfile); }
29410  const int xoffset = offset-54-4*nb_colors;
29411  if (xoffset>0) std::fseek(nfile,xoffset,SEEK_CUR);
29412  unsigned char *buffer = new unsigned char[buf_size], *ptrs = buffer;
29413  cimg::fread(buffer,buf_size,nfile);
29414  if (!file) cimg::fclose(nfile);
29415 
29416  // Decompress buffer (if necessary)
29417  if (compression) {
29418  delete[] buffer;
29419  if (file) {
29420  throw CImgIOException("CImg<%s>::load_bmp() : Not able to read a compressed BMP file using a *FILE input",
29421  pixel_type());
29422  } else return load_other(filename);
29423  }
29424 
29425  // Read pixel data
29426  assign(dx,cimg::abs(dy),1,3);
29427  switch (bpp) {
29428  case 1 : { // Monochrome
29429  for (int y = dimy()-1; y>=0; --y) {
29430  unsigned char mask = 0x80, val = 0;
29431  cimg_forX(*this,x) {
29432  if (mask==0x80) val = *(ptrs++);
29433  const unsigned char *col = (unsigned char*)(palette+(val&mask?1:0));
29434  (*this)(x,y,2) = (T)*(col++);
29435  (*this)(x,y,1) = (T)*(col++);
29436  (*this)(x,y,0) = (T)*(col++);
29437  mask = cimg::ror(mask);
29438  } ptrs+=align; }
29439  } break;
29440  case 4 : { // 16 colors
29441  for (int y = dimy()-1; y>=0; --y) {
29442  unsigned char mask = 0xF0, val = 0;
29443  cimg_forX(*this,x) {
29444  if (mask==0xF0) val = *(ptrs++);
29445  const unsigned char color = (unsigned char)((mask<16)?(val&mask):((val&mask)>>4));
29446  unsigned char *col = (unsigned char*)(palette+color);
29447  (*this)(x,y,2) = (T)*(col++);
29448  (*this)(x,y,1) = (T)*(col++);
29449  (*this)(x,y,0) = (T)*(col++);
29450  mask = cimg::ror(mask,4);
29451  } ptrs+=align; }
29452  } break;
29453  case 8 : { // 256 colors
29454  for (int y = dimy()-1; y>=0; --y) { cimg_forX(*this,x) {
29455  const unsigned char *col = (unsigned char*)(palette+*(ptrs++));
29456  (*this)(x,y,2) = (T)*(col++);
29457  (*this)(x,y,1) = (T)*(col++);
29458  (*this)(x,y,0) = (T)*(col++);
29459  } ptrs+=align; }
29460  } break;
29461  case 16 : { // 16 bits colors
29462  for (int y = dimy()-1; y>=0; --y) { cimg_forX(*this,x) {
29463  const unsigned char c1 = *(ptrs++), c2 = *(ptrs++);
29464  const unsigned short col = (unsigned short)(c1|(c2<<8));
29465  (*this)(x,y,2) = (T)(col&0x1F);
29466  (*this)(x,y,1) = (T)((col>>5)&0x1F);
29467  (*this)(x,y,0) = (T)((col>>10)&0x1F);
29468  } ptrs+=align; }
29469  } break;
29470  case 24 : { // 24 bits colors
29471  for (int y = dimy()-1; y>=0; --y) { cimg_forX(*this,x) {
29472  (*this)(x,y,2) = (T)*(ptrs++);
29473  (*this)(x,y,1) = (T)*(ptrs++);
29474  (*this)(x,y,0) = (T)*(ptrs++);
29475  } ptrs+=align; }
29476  } break;
29477  case 32 : { // 32 bits colors
29478  for (int y = dimy()-1; y>=0; --y) { cimg_forX(*this,x) {
29479  (*this)(x,y,2) = (T)*(ptrs++);
29480  (*this)(x,y,1) = (T)*(ptrs++);
29481  (*this)(x,y,0) = (T)*(ptrs++);
29482  ++ptrs;
29483  } ptrs+=align; }
29484  } break;
29485  }
29486  if (palette) delete[] palette;
29487  delete[] buffer;
29488  if (dy<0) mirror('y');
29489  return *this;
29490  }
29491 
29493  CImg<T>& load_jpeg(const char *const filename) {
29494  return _load_jpeg(0,filename);
29495  }
29496 
29497  static CImg<T> get_load_jpeg(const char *const filename) {
29498  return CImg<T>().load_jpeg(filename);
29499  }
29500 
29502  CImg<T>& load_jpeg(std::FILE *const file) {
29503  return _load_jpeg(file,0);
29504  }
29505 
29506  static CImg<T> get_load_jpeg(std::FILE *const file) {
29507  return CImg<T>().load_jpeg(file);
29508  }
29509 
29510  CImg<T>& _load_jpeg(std::FILE *const file, const char *const filename) {
29511  if (!filename && !file)
29512  throw CImgArgumentException("CImg<%s>::load_jpeg() : Cannot load (null) filename.",
29513  pixel_type());
29514 #ifndef cimg_use_jpeg
29515  if (file)
29516  throw CImgIOException("CImg<%s>::load_jpeg() : File '(FILE*)' cannot be read without using libjpeg.",
29517  pixel_type());
29518  else return load_other(filename);
29519 #else
29520  struct jpeg_decompress_struct cinfo;
29521  struct jpeg_error_mgr jerr;
29522  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29523 
29524  cinfo.err = jpeg_std_error(&jerr);
29525  jpeg_create_decompress(&cinfo);
29526  jpeg_stdio_src(&cinfo,nfile);
29527  jpeg_read_header(&cinfo,TRUE);
29528  jpeg_start_decompress(&cinfo);
29529 
29530  if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) {
29531  cimg::warn("CImg<%s>::load_jpeg() : Don't know how to read image '%s' with libpeg, trying ImageMagick's convert",
29532  pixel_type(),filename?filename:"(FILE*)");
29533  if (!file) return load_other(filename);
29534  else {
29535  if (!file) cimg::fclose(nfile);
29536  throw CImgIOException("CImg<%s>::load_jpeg() : Cannot read JPEG image '%s' using a *FILE input.",
29537  pixel_type(),filename?filename:"(FILE*)");
29538  }
29539  }
29540 
29541  const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
29542  unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components], *buf2 = buf;
29543  JSAMPROW row_pointer[1];
29544  while (cinfo.output_scanline < cinfo.output_height) {
29545  row_pointer[0] = &buf[cinfo.output_scanline*row_stride];
29546  jpeg_read_scanlines(&cinfo,row_pointer,1);
29547  }
29548  jpeg_finish_decompress(&cinfo);
29549  jpeg_destroy_decompress(&cinfo);
29550  if (!file) cimg::fclose(nfile);
29551 
29552  assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components);
29553  switch (dim) {
29554  case 1 : {
29555  T *ptr_g = data;
29556  cimg_forXY(*this,x,y) *(ptr_g++) = (T)*(buf2++);
29557  } break;
29558  case 3 : {
29559  T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
29560  cimg_forXY(*this,x,y) {
29561  *(ptr_r++) = (T)*(buf2++);
29562  *(ptr_g++) = (T)*(buf2++);
29563  *(ptr_b++) = (T)*(buf2++);
29564  }
29565  } break;
29566  case 4 : {
29567  T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1),
29568  *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3);
29569  cimg_forXY(*this,x,y) {
29570  *(ptr_r++) = (T)*(buf2++);
29571  *(ptr_g++) = (T)*(buf2++);
29572  *(ptr_b++) = (T)*(buf2++);
29573  *(ptr_a++) = (T)*(buf2++);
29574  }
29575  } break;
29576  }
29577  delete[] buf;
29578  return *this;
29579 #endif
29580  }
29581 
29583  // Added April/may 2006 by Christoph Hormann <chris_hormann@gmx.de>
29584  // This is experimental code, not much tested, use with care.
29585  CImg<T>& load_magick(const char *const filename) {
29586  if (!filename)
29587  throw CImgArgumentException("CImg<%s>::load_magick() : Cannot load (null) filename.",
29588  pixel_type());
29589 #ifdef cimg_use_magick
29590  Magick::Image image(filename);
29591  const unsigned int W = image.size().width(), H = image.size().height();
29592  switch (image.type()) {
29593  case Magick::PaletteMatteType :
29594  case Magick::TrueColorMatteType :
29595  case Magick::ColorSeparationType : {
29596  assign(W,H,1,4);
29597  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);
29598  Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29599  for (unsigned int off = W*H; off; --off) {
29600  *(rdata++) = (T)(pixels->red);
29601  *(gdata++) = (T)(pixels->green);
29602  *(bdata++) = (T)(pixels->blue);
29603  *(adata++) = (T)(pixels->opacity);
29604  ++pixels;
29605  }
29606  } break;
29607  case Magick::PaletteType :
29608  case Magick::TrueColorType : {
29609  assign(W,H,1,3);
29610  T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
29611  Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29612  for (unsigned int off = W*H; off; --off) {
29613  *(rdata++) = (T)(pixels->red);
29614  *(gdata++) = (T)(pixels->green);
29615  *(bdata++) = (T)(pixels->blue);
29616  ++pixels;
29617  }
29618  } break;
29619  case Magick::GrayscaleMatteType : {
29620  assign(W,H,1,2);
29621  T *data = ptr(0,0,0,0), *adata = ptr(0,0,0,1);
29622  Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29623  for (unsigned int off = W*H; off; --off) {
29624  *(data++) = (T)(pixels->red);
29625  *(adata++) = (T)(pixels->opacity);
29626  ++pixels;
29627  }
29628  } break;
29629  default : {
29630  assign(W,H,1,1);
29631  T *data = ptr(0,0,0,0);
29632  Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29633  for (unsigned int off = W*H; off; --off) {
29634  *(data++) = (T)(pixels->red);
29635  ++pixels;
29636  }
29637  }
29638  }
29639 #else
29640  throw CImgIOException("CImg<%s>::load_magick() : File '%s', Magick++ library has not been linked.",
29641  pixel_type(),filename);
29642 #endif
29643  return *this;
29644  }
29645 
29646  static CImg<T> get_load_magick(const char *const filename) {
29647  return CImg<T>().load_magick(filename);
29648  }
29649 
29651  CImg<T>& load_png(const char *const filename) {
29652  return _load_png(0,filename);
29653  }
29654 
29655  static CImg<T> get_load_png(const char *const filename) {
29656  return CImg<T>().load_png(filename);
29657  }
29658 
29660  CImg<T>& load_png(std::FILE *const file) {
29661  return _load_png(file,0);
29662  }
29663 
29664  static CImg<T> get_load_png(std::FILE *const file) {
29665  return CImg<T>().load_png(file);
29666  }
29667 
29668  // (Note : Most of this function has been written by Eric Fausett)
29669  CImg<T>& _load_png(std::FILE *const file, const char *const filename) {
29670  if (!filename && !file)
29671  throw CImgArgumentException("CImg<%s>::load_png() : Cannot load (null) filename.",
29672  pixel_type());
29673 #ifndef cimg_use_png
29674  if (file)
29675  throw CImgIOException("CImg<%s>::load_png() : File '(FILE*)' cannot be read without using libpng.",
29676  pixel_type());
29677  else return load_other(filename);
29678 #else
29679  // Open file and check for PNG validity
29680  const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
29681  std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb");
29682 
29683  unsigned char pngCheck[8] = { 0 };
29684  cimg::fread(pngCheck,8,(std::FILE*)nfile);
29685  if (png_sig_cmp(pngCheck,0,8)) {
29686  if (!file) cimg::fclose(nfile);
29687  throw CImgIOException("CImg<%s>::load_png() : File '%s' is not a valid PNG file.",
29688  pixel_type(),nfilename?nfilename:"(FILE*)");
29689  }
29690 
29691  // Setup PNG structures for read
29692  png_voidp user_error_ptr = 0;
29693  png_error_ptr user_error_fn = 0, user_warning_fn = 0;
29694  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn);
29695  if (!png_ptr) {
29696  if (!file) cimg::fclose(nfile);
29697  throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'png_ptr' data structure.",
29698  pixel_type(),nfilename?nfilename:"(FILE*)");
29699  }
29700  png_infop info_ptr = png_create_info_struct(png_ptr);
29701  if (!info_ptr) {
29702  if (!file) cimg::fclose(nfile);
29703  png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0);
29704  throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'info_ptr' data structure.",
29705  pixel_type(),nfilename?nfilename:"(FILE*)");
29706  }
29707  png_infop end_info = png_create_info_struct(png_ptr);
29708  if (!end_info) {
29709  if (!file) cimg::fclose(nfile);
29710  png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0);
29711  throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'end_info' data structure.",
29712  pixel_type(),nfilename?nfilename:"(FILE*)");
29713  }
29714 
29715  // Error handling callback for png file reading
29716  if (setjmp(png_jmpbuf(png_ptr))) {
29717  if (!file) cimg::fclose((std::FILE*)nfile);
29718  png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
29719  throw CImgIOException("CImg<%s>::load_png() : File '%s', unknown fatal error.",
29720  pixel_type(),nfilename?nfilename:"(FILE*)");
29721  }
29722  png_init_io(png_ptr, nfile);
29723  png_set_sig_bytes(png_ptr, 8);
29724 
29725  // Get PNG Header Info up to data block
29726  png_read_info(png_ptr,info_ptr);
29727  png_uint_32 W, H;
29728  int bit_depth, color_type, interlace_type;
29729  png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,int_p_NULL,int_p_NULL);
29730  int new_bit_depth = bit_depth;
29731  int new_color_type = color_type;
29732 
29733  // Transforms to unify image data
29734  if (new_color_type == PNG_COLOR_TYPE_PALETTE){
29735  png_set_palette_to_rgb(png_ptr);
29736  new_color_type -= PNG_COLOR_MASK_PALETTE;
29737  new_bit_depth = 8;
29738  }
29739  if (new_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){
29740  png_set_gray_1_2_4_to_8(png_ptr);
29741  new_bit_depth = 8;
29742  }
29743  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
29744  png_set_tRNS_to_alpha(png_ptr);
29745  if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){
29746  png_set_gray_to_rgb(png_ptr);
29747  new_color_type |= PNG_COLOR_MASK_COLOR;
29748  }
29749  if (new_color_type == PNG_COLOR_TYPE_RGB)
29750  png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);
29751  png_read_update_info(png_ptr,info_ptr);
29752  if (!(new_bit_depth==8 || new_bit_depth==16)) {
29753  if (!file) cimg::fclose(nfile);
29754  png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
29755  throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong bit coding (bit_depth=%u)",
29756  pixel_type(),nfilename?nfilename:"(FILE*)",new_bit_depth);
29757  }
29758  const int byte_depth = new_bit_depth>>3;
29759 
29760  // Allocate Memory for Image Read
29761  png_bytep *imgData = new png_bytep[H];
29762  for (unsigned int row = 0; row<H; ++row) imgData[row] = new png_byte[byte_depth*4*W];
29763  png_read_image(png_ptr,imgData);
29764  png_read_end(png_ptr,end_info);
29765 
29766  // Read pixel data
29767  if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA)) {
29768  if (!file) cimg::fclose(nfile);
29769  png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);
29770  throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong color coding (new_color_type=%u)",
29771  pixel_type(),nfilename?nfilename:"(FILE*)",new_color_type);
29772  }
29773  const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB);
29774  assign(W,H,1,no_alpha_channel?3:4);
29775  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);
29776  switch (new_bit_depth) {
29777  case 8 : {
29778  cimg_forY(*this,y){
29779  const unsigned char *ptrs = (unsigned char*)imgData[y];
29780  cimg_forX(*this,x){
29781  *(ptr1++) = (T)*(ptrs++);
29782  *(ptr2++) = (T)*(ptrs++);
29783  *(ptr3++) = (T)*(ptrs++);
29784  if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
29785  }
29786  }
29787  } break;
29788  case 16 : {
29789  cimg_forY(*this,y){
29790  const unsigned short *ptrs = (unsigned short*)(imgData[y]);
29792  cimg_forX(*this,x){
29793  *(ptr1++) = (T)*(ptrs++);
29794  *(ptr2++) = (T)*(ptrs++);
29795  *(ptr3++) = (T)*(ptrs++);
29796  if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
29797  }
29798  }
29799  } break;
29800  }
29801  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
29802 
29803  // Deallocate Image Read Memory
29804  cimg_forY(*this,n) delete[] imgData[n];
29805  delete[] imgData;
29806  if (!file) cimg::fclose(nfile);
29807  return *this;
29808 #endif
29809  }
29810 
29812  CImg<T>& load_pnm(const char *const filename) {
29813  return _load_pnm(0,filename);
29814  }
29815 
29816  static CImg<T> get_load_pnm(const char *const filename) {
29817  return CImg<T>().load_pnm(filename);
29818  }
29819 
29821  CImg<T>& load_pnm(std::FILE *const file) {
29822  return _load_pnm(file,0);
29823  }
29824 
29825  static CImg<T> get_load_pnm(std::FILE *const file) {
29826  return CImg<T>().load_pnm(file);
29827  }
29828 
29829  CImg<T>& _load_pnm(std::FILE *const file, const char *const filename) {
29830  if (!filename && !file)
29831  throw CImgArgumentException("CImg<%s>::load_pnm() : Cannot load (null) filename.",
29832  pixel_type());
29833  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29834  unsigned int ppm_type, W, H, colormax = 255;
29835  char item[1024] = { 0 };
29836  int err, rval, gval, bval;
29837  const int cimg_iobuffer = 12*1024*1024;
29838  while ((err=std::fscanf(nfile,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile);
29839  if (std::sscanf(item," P%u",&ppm_type)!=1) {
29840  if (!file) cimg::fclose(nfile);
29841  throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PNM header 'P?' not found.",
29842  pixel_type(),filename?filename:"(FILE*)");
29843  }
29844  while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile);
29845  if ((err=std::sscanf(item," %u %u %u",&W,&H,&colormax))<2) {
29846  if (!file) cimg::fclose(nfile);
29847  throw CImgIOException("CImg<%s>::load_pnm() : File '%s', WIDTH and HEIGHT fields are not defined in PNM header.",
29848  pixel_type(),filename?filename:"(FILE*)");
29849  }
29850  if (err==2) {
29851  while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile);
29852  if (std::sscanf(item,"%u",&colormax)!=1)
29853  cimg::warn("CImg<%s>::load_pnm() : File '%s', COLORMAX field is not defined in PNM header.",
29854  pixel_type(),filename?filename:"(FILE*)");
29855  }
29856  std::fgetc(nfile);
29857  assign();
29858 
29859  switch (ppm_type) {
29860  case 2 : { // Grey Ascii
29861  assign(W,H,1,1);
29862  T* rdata = data;
29863  cimg_foroff(*this,off) { if (std::fscanf(nfile,"%d",&rval)>0) *(rdata++) = (T)rval; else break; }
29864  } break;
29865  case 3 : { // Color Ascii
29866  assign(W,H,1,3);
29867  T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
29868  cimg_forXY(*this,x,y) {
29869  if (std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval)==3) { *(rdata++) = (T)rval; *(gdata++) = (T)gval; *(bdata++) = (T)bval; }
29870  else break;
29871  }
29872  } break;
29873  case 5 : { // Grey Binary
29874  if (colormax<256) { // 8 bits
29875  CImg<ucharT> raw;
29876  assign(W,H,1,1);
29877  T *ptrd = ptr(0,0,0,0);
29878  for (int toread = (int)size(); toread>0; ) {
29879  raw.assign(cimg::min(toread,cimg_iobuffer));
29880  cimg::fread(raw.data,raw.width,nfile);
29881  toread-=raw.width;
29882  const unsigned char *ptrs = raw.data;
29883  for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
29884  }
29885  } else { // 16 bits
29886  CImg<ushortT> raw;
29887  assign(W,H,1,1);
29888  T *ptrd = ptr(0,0,0,0);
29889  for (int toread = (int)size(); toread>0; ) {
29890  raw.assign(cimg::min(toread,cimg_iobuffer/2));
29891  cimg::fread(raw.data,raw.width,nfile);
29892  if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
29893  toread-=raw.width;
29894  const unsigned short *ptrs = raw.data;
29895  for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
29896  }
29897  }
29898  } break;
29899  case 6 : { // Color Binary
29900  if (colormax<256) { // 8 bits
29901  CImg<ucharT> raw;
29902  assign(W,H,1,3);
29903  T
29904  *ptr_r = ptr(0,0,0,0),
29905  *ptr_g = ptr(0,0,0,1),
29906  *ptr_b = ptr(0,0,0,2);
29907  for (int toread = (int)size(); toread>0; ) {
29908  raw.assign(cimg::min(toread,cimg_iobuffer));
29909  cimg::fread(raw.data,raw.width,nfile);
29910  toread-=raw.width;
29911  const unsigned char *ptrs = raw.data;
29912  for (unsigned int off = raw.width/3; off; --off) {
29913  *(ptr_r++) = (T)*(ptrs++);
29914  *(ptr_g++) = (T)*(ptrs++);
29915  *(ptr_b++) = (T)*(ptrs++);
29916  }
29917  }
29918  } else { // 16 bits
29919  CImg<ushortT> raw;
29920  assign(W,H,1,3);
29921  T
29922  *ptr_r = ptr(0,0,0,0),
29923  *ptr_g = ptr(0,0,0,1),
29924  *ptr_b = ptr(0,0,0,2);
29925  for (int toread = (int)size(); toread>0; ) {
29926  raw.assign(cimg::min(toread,cimg_iobuffer/2));
29927  cimg::fread(raw.data,raw.width,nfile);
29928  if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
29929  toread-=raw.width;
29930  const unsigned short *ptrs = raw.data;
29931  for (unsigned int off = raw.width/3; off; --off) {
29932  *(ptr_r++) = (T)*(ptrs++);
29933  *(ptr_g++) = (T)*(ptrs++);
29934  *(ptr_b++) = (T)*(ptrs++);
29935  }
29936  }
29937  }
29938  } break;
29939  default :
29940  if (!file) cimg::fclose(nfile);
29941  throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PPM type 'P%d' not supported.",
29942  pixel_type(),filename?filename:"(FILE*)",ppm_type);
29943  }
29944  if (!file) cimg::fclose(nfile);
29945  return *this;
29946  }
29947 
29949  CImg<T>& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
29950  return _load_rgb(0,filename,dimw,dimh);
29951  }
29952 
29953  static CImg<T> get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
29954  return CImg<T>().load_rgb(filename,dimw,dimh);
29955  }
29956 
29958  CImg<T>& load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
29959  return _load_rgb(file,0,dimw,dimh);
29960  }
29961 
29962  static CImg<T> get_load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
29963  return CImg<T>().load_rgb(file,dimw,dimh);
29964  }
29965 
29966  CImg<T>& _load_rgb(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
29967  if (!filename && !file)
29968  throw CImgArgumentException("CImg<%s>::load_rgb() : Cannot load (null) filename.",
29969  pixel_type());
29970  if (!dimw || !dimh) return assign();
29971  const int cimg_iobuffer = 12*1024*1024;
29972  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29973  CImg<ucharT> raw;
29974  assign(dimw,dimh,1,3);
29975  T
29976  *ptr_r = ptr(0,0,0,0),
29977  *ptr_g = ptr(0,0,0,1),
29978  *ptr_b = ptr(0,0,0,2);
29979  for (int toread = (int)size(); toread>0; ) {
29980  raw.assign(cimg::min(toread,cimg_iobuffer));
29981  cimg::fread(raw.data,raw.width,nfile);
29982  toread-=raw.width;
29983  const unsigned char *ptrs = raw.data;
29984  for (unsigned int off = raw.width/3; off; --off) {
29985  *(ptr_r++) = (T)*(ptrs++);
29986  *(ptr_g++) = (T)*(ptrs++);
29987  *(ptr_b++) = (T)*(ptrs++);
29988  }
29989  }
29990  if (!file) cimg::fclose(nfile);
29991  return *this;
29992  }
29993 
29995  CImg<T>& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
29996  return _load_rgba(0,filename,dimw,dimh);
29997  }
29998 
29999  static CImg<T> get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
30000  return CImg<T>().load_rgba(filename,dimw,dimh);
30001  }
30002 
30004  CImg<T>& load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
30005  return _load_rgba(file,0,dimw,dimh);
30006  }
30007 
30008  static CImg<T> get_load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
30009  return CImg<T>().load_rgba(file,dimw,dimh);
30010  }
30011 
30012  CImg<T>& _load_rgba(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
30013  if (!filename && !file)
30014  throw CImgArgumentException("CImg<%s>::load_rgba() : Cannot load (null) filename.",
30015  pixel_type());
30016  if (!dimw || !dimh) return assign();
30017  const int cimg_iobuffer = 12*1024*1024;
30018  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
30019  CImg<ucharT> raw;
30020  assign(dimw,dimh,1,4);
30021  T
30022  *ptr_r = ptr(0,0,0,0),
30023  *ptr_g = ptr(0,0,0,1),
30024  *ptr_b = ptr(0,0,0,2),
30025  *ptr_a = ptr(0,0,0,3);
30026  for (int toread = (int)size(); toread>0; ) {
30027  raw.assign(cimg::min(toread,cimg_iobuffer));
30028  cimg::fread(raw.data,raw.width,nfile);
30029  toread-=raw.width;
30030  const unsigned char *ptrs = raw.data;
30031  for (unsigned int off = raw.width/4; off; --off) {
30032  *(ptr_r++) = (T)*(ptrs++);
30033  *(ptr_g++) = (T)*(ptrs++);
30034  *(ptr_b++) = (T)*(ptrs++);
30035  *(ptr_a++) = (T)*(ptrs++);
30036  }
30037  }
30038  if (!file) cimg::fclose(nfile);
30039  return *this;
30040  }
30041 
30043  CImg<T>& load_tiff(const char *const filename,
30044  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30045  const unsigned int step_frame=1) {
30046  if (!filename)
30047  throw CImgArgumentException("CImg<%s>::load_tiff() : Cannot load (null) filename.",
30048  pixel_type());
30049  const unsigned int
30050  nfirst_frame = first_frame<last_frame?first_frame:last_frame,
30051  nstep_frame = step_frame?step_frame:1;
30052  unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
30053 
30054 #ifndef cimg_use_tiff
30055  if (nfirst_frame || nlast_frame!=~0U || nstep_frame>1)
30056  throw CImgArgumentException("CImg<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
30057  "('cimg_use_tiff' must be defined).",
30058  pixel_type(),filename);
30059  return load_other(filename);
30060 #else
30061  TIFF *tif = TIFFOpen(filename,"r");
30062  if (tif) {
30063  unsigned int nb_images = 0;
30064  do ++nb_images; while (TIFFReadDirectory(tif));
30065  if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
30066  cimg::warn("CImg<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
30067  pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
30068  if (nfirst_frame>=nb_images) return assign();
30069  if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
30070  TIFFSetDirectory(tif,0);
30071  CImg<T> frame;
30072  for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) {
30073  frame._load_tiff(tif,l);
30074  if (l==nfirst_frame) assign(frame.width,frame.height,1+(nlast_frame-nfirst_frame)/nstep_frame,frame.dim);
30075  if (frame.width>width || frame.height>height || frame.dim>dim)
30076  resize(cimg::max(frame.width,width),cimg::max(frame.height,height),-100,cimg::max(frame.dim,dim),0);
30077  draw_image(0,0,(l-nfirst_frame)/nstep_frame,frame);
30078  }
30079  TIFFClose(tif);
30080  } else throw CImgException("CImg<%s>::load_tiff() : File '%s' cannot be opened.",
30081  pixel_type(),filename);
30082  return *this;
30083 #endif
30084  }
30085 
30086  static CImg<T> get_load_tiff(const char *const filename,
30087  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30088  const unsigned int step_frame=1) {
30089  return CImg<T>().load_tiff(filename,first_frame,last_frame,step_frame);
30090  }
30091 
30092  // (Original contribution by Jerome Boulanger).
30093 #ifdef cimg_use_tiff
30094  CImg<T>& _load_tiff(TIFF *tif, const unsigned int directory) {
30095  if (!TIFFSetDirectory(tif,directory)) return assign();
30096  uint16 samplesperpixel, bitspersample;
30097  uint32 nx,ny;
30098  const char *const filename = TIFFFileName(tif);
30099  TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx);
30100  TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny);
30101  TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel);
30102  if (samplesperpixel!=1 && samplesperpixel!=3 && samplesperpixel!=4) {
30103  cimg::warn("CImg<%s>::load_tiff() : File '%s', unknow value for tag : TIFFTAG_SAMPLESPERPIXEL, will force it to 1.",
30104  pixel_type(),filename);
30105  samplesperpixel = 1;
30106  }
30107  TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample);
30108  assign(nx,ny,1,samplesperpixel);
30109  if (bitspersample!=8 || !(samplesperpixel==3 || samplesperpixel==4)) {
30110  uint16 photo, config;
30111  TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config);
30112  TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo);
30113  if (TIFFIsTiled(tif)) {
30114  uint32 tw, th;
30115  TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw);
30116  TIFFGetField(tif,TIFFTAG_TILELENGTH,&th);
30117  if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
30118  case 8 : {
30119  unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
30120  if (buf) {
30121  for (unsigned int row = 0; row<ny; row+=th)
30122  for (unsigned int col = 0; col<nx; col+=tw) {
30123  if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
30124  _TIFFfree(buf); TIFFClose(tif);
30125  throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
30126  pixel_type(),filename);
30127  } else {
30128  unsigned char *ptr = buf;
30129  for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
30130  for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
30131  for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30132  (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
30133  }
30134  }
30135  _TIFFfree(buf);
30136  }
30137  } break;
30138  case 16 : {
30139  unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
30140  if (buf) {
30141  for (unsigned int row = 0; row<ny; row+=th)
30142  for (unsigned int col = 0; col<nx; col+=tw) {
30143  if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
30144  _TIFFfree(buf); TIFFClose(tif);
30145  throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
30146  pixel_type(),filename);
30147  } else {
30148  unsigned short *ptr = buf;
30149  for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
30150  for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
30151  for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30152  (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
30153  }
30154  }
30155  _TIFFfree(buf);
30156  }
30157  } break;
30158  case 32 : {
30159  float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
30160  if (buf) {
30161  for (unsigned int row = 0; row<ny; row+=th)
30162  for (unsigned int col = 0; col<nx; col+=tw) {
30163  if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
30164  _TIFFfree(buf); TIFFClose(tif);
30165  throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
30166  pixel_type(),filename);
30167  } else {
30168  float *ptr = buf;
30169  for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
30170  for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
30171  for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30172  (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
30173  }
30174  }
30175  _TIFFfree(buf);
30176  }
30177  } break;
30178  } else switch (bitspersample) {
30179  case 8 : {
30180  unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
30181  if (buf) {
30182  for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30183  for (unsigned int row = 0; row<ny; row+=th)
30184  for (unsigned int col = 0; col<nx; col+=tw) {
30185  if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
30186  _TIFFfree(buf); TIFFClose(tif);
30187  throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
30188  pixel_type(),filename);
30189  } else {
30190  unsigned char *ptr = buf;
30191  for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
30192  for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
30193  (*this)(cc,rr,vv) = (T)(float)*(ptr++);
30194  }
30195  }
30196  _TIFFfree(buf);
30197  }
30198  } break;
30199  case 16 : {
30200  unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
30201  if (buf) {
30202  for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30203  for (unsigned int row = 0; row<ny; row+=th)
30204  for (unsigned int col = 0; col<nx; col+=tw) {
30205  if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
30206  _TIFFfree(buf); TIFFClose(tif);
30207  throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
30208  pixel_type(),filename);
30209  } else {
30210  unsigned short *ptr = buf;
30211  for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
30212  for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
30213  (*this)(cc,rr,vv) = (T)(float)*(ptr++);
30214  }
30215  }
30216  _TIFFfree(buf);
30217  }
30218  } break;
30219  case 32 : {
30220  float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
30221  if (buf) {
30222  for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30223  for (unsigned int row = 0; row<ny; row+=th)
30224  for (unsigned int col = 0; col<nx; col+=tw) {
30225  if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
30226  _TIFFfree(buf); TIFFClose(tif);
30227  throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
30228  pixel_type(),filename);
30229  } else {
30230  float *ptr = buf;
30231  for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
30232  for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
30233  (*this)(cc,rr,vv) = (T)(float)*(ptr++);
30234  }
30235  }
30236  _TIFFfree(buf);
30237  }
30238  } break;
30239  }
30240  } else {
30241  if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
30242  case 8 : {
30243  unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
30244  if (buf) {
30245  uint32 row, rowsperstrip = (uint32)-1;
30246  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30247  for (row = 0; row<ny; row+= rowsperstrip) {
30248  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30249  tstrip_t strip = TIFFComputeStrip(tif, row, 0);
30250  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30251  _TIFFfree(buf); TIFFClose(tif);
30252  throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
30253  pixel_type(),filename);
30254  }
30255  unsigned char *ptr = buf;
30256  for (unsigned int rr = 0; rr<nrow; ++rr)
30257  for (unsigned int cc = 0; cc<nx; ++cc)
30258  for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30259  }
30260  _TIFFfree(buf);
30261  }
30262  } break;
30263  case 16 : {
30264  unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
30265  if (buf) {
30266  uint32 row, rowsperstrip = (uint32)-1;
30267  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30268  for (row = 0; row<ny; row+= rowsperstrip) {
30269  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30270  tstrip_t strip = TIFFComputeStrip(tif, row, 0);
30271  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30272  _TIFFfree(buf); TIFFClose(tif);
30273  throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
30274  pixel_type(),filename);
30275  }
30276  unsigned short *ptr = buf;
30277  for (unsigned int rr = 0; rr<nrow; ++rr)
30278  for (unsigned int cc = 0; cc<nx; ++cc)
30279  for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30280  }
30281  _TIFFfree(buf);
30282  }
30283  } break;
30284  case 32 : {
30285  float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
30286  if (buf) {
30287  uint32 row, rowsperstrip = (uint32)-1;
30288  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30289  for (row = 0; row<ny; row+= rowsperstrip) {
30290  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30291  tstrip_t strip = TIFFComputeStrip(tif, row, 0);
30292  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30293  _TIFFfree(buf); TIFFClose(tif);
30294  throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
30295  pixel_type(),filename);
30296  }
30297  float *ptr = buf;
30298  for (unsigned int rr = 0; rr<nrow; ++rr)
30299  for (unsigned int cc = 0; cc<nx; ++cc)
30300  for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30301  }
30302  _TIFFfree(buf);
30303  }
30304  } break;
30305  } else switch (bitspersample){
30306  case 8 : {
30307  unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
30308  if (buf) {
30309  uint32 row, rowsperstrip = (uint32)-1;
30310  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30311  for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30312  for (row = 0; row<ny; row+= rowsperstrip) {
30313  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30314  tstrip_t strip = TIFFComputeStrip(tif, row, vv);
30315  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30316  _TIFFfree(buf); TIFFClose(tif);
30317  throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
30318  pixel_type(),filename);
30319  }
30320  unsigned char *ptr = buf;
30321  for (unsigned int rr = 0;rr<nrow; ++rr)
30322  for (unsigned int cc = 0; cc<nx; ++cc)
30323  (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30324  }
30325  _TIFFfree(buf);
30326  }
30327  } break;
30328  case 16 : {
30329  unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
30330  if (buf) {
30331  uint32 row, rowsperstrip = (uint32)-1;
30332  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30333  for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30334  for (row = 0; row<ny; row+= rowsperstrip) {
30335  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30336  tstrip_t strip = TIFFComputeStrip(tif, row, vv);
30337  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30338  _TIFFfree(buf); TIFFClose(tif);
30339  throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
30340  pixel_type(),filename);
30341  }
30342  unsigned short *ptr = buf;
30343  for (unsigned int rr = 0; rr<nrow; ++rr)
30344  for (unsigned int cc = 0; cc<nx; ++cc)
30345  (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30346  }
30347  _TIFFfree(buf);
30348  }
30349  } break;
30350  case 32 : {
30351  float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
30352  if (buf) {
30353  uint32 row, rowsperstrip = (uint32)-1;
30354  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30355  for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30356  for (row = 0; row<ny; row+= rowsperstrip) {
30357  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30358  tstrip_t strip = TIFFComputeStrip(tif, row, vv);
30359  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30360  _TIFFfree(buf); TIFFClose(tif);
30361  throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
30362  pixel_type(),filename);
30363  }
30364  float *ptr = buf;
30365  for (unsigned int rr = 0; rr<nrow; ++rr) for (unsigned int cc = 0; cc<nx; ++cc)
30366  (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30367  }
30368  _TIFFfree(buf);
30369  }
30370  } break;
30371  }
30372  }
30373  } else {
30374  uint32* raster = (uint32*)_TIFFmalloc(nx * ny * sizeof (uint32));
30375  if (!raster) {
30376  _TIFFfree(raster); TIFFClose(tif);
30377  throw CImgException("CImg<%s>::load_tiff() : File '%s', not enough memory for buffer allocation.",
30378  pixel_type(),filename);
30379  }
30380  TIFFReadRGBAImage(tif,nx,ny,raster,0);
30381  switch (samplesperpixel) {
30382  case 1 : {
30383  cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny-1-y)+x]+ 128) / 257);
30384  } break;
30385  case 3 : {
30386  cimg_forXY(*this,x,y) {
30387  (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
30388  (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
30389  (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
30390  }
30391  } break;
30392  case 4 : {
30393  cimg_forXY(*this,x,y) {
30394  (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
30395  (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
30396  (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
30397  (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny-1-y)+x]);
30398  }
30399  } break;
30400  }
30401  _TIFFfree(raster);
30402  }
30403  return *this;
30404  }
30405 #endif
30406 
30408  CImg<T>& load_analyze(const char *const filename, float *const voxsize=0) {
30409  return _load_analyze(0,filename,voxsize);
30410  }
30411 
30412  static CImg<T> get_load_analyze(const char *const filename, float *const voxsize=0) {
30413  return CImg<T>().load_analyze(filename,voxsize);
30414  }
30415 
30417  CImg<T>& load_analyze(std::FILE *const file, float *const voxsize=0) {
30418  return _load_analyze(file,0,voxsize);
30419  }
30420 
30421  static CImg<T> get_load_analyze(std::FILE *const file, float *const voxsize=0) {
30422  return CImg<T>().load_analyze(file,voxsize);
30423  }
30424 
30425  CImg<T>& _load_analyze(std::FILE *const file, const char *const filename, float *const voxsize=0) {
30426  if (!filename && !file)
30427  throw CImgArgumentException("CImg<%s>::load_analyze() : Cannot load (null) filename.",
30428  pixel_type());
30429  std::FILE *nfile_header = 0, *nfile = 0;
30430  if (!file) {
30431  char body[1024] = { 0 };
30432  const char *ext = cimg::split_filename(filename,body);
30433  if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file.
30434  nfile_header = cimg::fopen(filename,"rb");
30435  std::sprintf(body+std::strlen(body),".img");
30436  nfile = cimg::fopen(body,"rb");
30437  } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file.
30438  nfile = cimg::fopen(filename,"rb");
30439  std::sprintf(body+std::strlen(body),".hdr");
30440  nfile_header = cimg::fopen(body,"rb");
30441  } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file.
30442  } else nfile_header = nfile = file; // File is a Niftii file.
30443  if (!nfile || !nfile_header)
30444  throw CImgIOException("CImg<%s>::load_analyze() : File '%s', not recognized as an Analyze7.5 or NIFTI file.",
30445  pixel_type(),filename?filename:"(FILE*)");
30446 
30447  // Read header.
30448  bool endian = false;
30449  unsigned int header_size;
30450  cimg::fread(&header_size,1,nfile_header);
30451  if (!header_size)
30452  throw CImgIOException("CImg<%s>::load_analyze() : File '%s', zero-sized header found.",
30453  pixel_type(),filename?filename:"(FILE*)");
30454  if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); }
30455  unsigned char *header = new unsigned char[header_size];
30456  cimg::fread(header+4,header_size-4,nfile_header);
30457  if (!file && nfile_header!=nfile) cimg::fclose(nfile_header);
30458  if (endian) {
30459  cimg::invert_endianness((short*)(header+40),5);
30460  cimg::invert_endianness((short*)(header+70),1);
30461  cimg::invert_endianness((short*)(header+72),1);
30462  cimg::invert_endianness((float*)(header+76),4);
30463  cimg::invert_endianness((float*)(header+112),1);
30464  }
30465  unsigned short *dim = (unsigned short*)(header+40), dimx = 1, dimy = 1, dimz = 1, dimv = 1;
30466  if (!dim[0])
30467  cimg::warn("CImg<%s>::load_analyze() : File '%s', tells that image has zero dimensions.",
30468  pixel_type(),filename?filename:"(FILE*)");
30469  if (dim[0]>4)
30470  cimg::warn("CImg<%s>::load_analyze() : File '%s', number of image dimension is %u, reading only the 4 first dimensions",
30471  pixel_type(),filename?filename:"(FILE*)",dim[0]);
30472  if (dim[0]>=1) dimx = dim[1];
30473  if (dim[0]>=2) dimy = dim[2];
30474  if (dim[0]>=3) dimz = dim[3];
30475  if (dim[0]>=4) dimv = dim[4];
30476  float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
30477  const unsigned short datatype = *(short*)(header+70);
30478  if (voxsize) {
30479  const float *vsize = (float*)(header+76);
30480  voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3];
30481  }
30482  delete[] header;
30483 
30484  // Read pixel data.
30486  switch (datatype) {
30487  case 2 : {
30488  unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
30489  cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30490  cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30491  delete[] buffer;
30492  } break;
30493  case 4 : {
30494  short *buffer = new short[dimx*dimy*dimz*dimv];
30495  cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30496  if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30497  cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30498  delete[] buffer;
30499  } break;
30500  case 8 : {
30501  int *buffer = new int[dimx*dimy*dimz*dimv];
30502  cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30503  if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30504  cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30505  delete[] buffer;
30506  } break;
30507  case 16 : {
30508  float *buffer = new float[dimx*dimy*dimz*dimv];
30509  cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30510  if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30511  cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30512  delete[] buffer;
30513  } break;
30514  case 64 : {
30515  double *buffer = new double[dimx*dimy*dimz*dimv];
30516  cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30517  if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30518  cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30519  delete[] buffer;
30520  } break;
30521  default :
30522  if (!file) cimg::fclose(nfile);
30523  throw CImgIOException("CImg<%s>::load_analyze() : File '%s', cannot read images with 'datatype = %d'",
30524  pixel_type(),filename?filename:"(FILE*)",datatype);
30525  }
30526  if (!file) cimg::fclose(nfile);
30527  return *this;
30528  }
30529 
30531  CImg<T>& load_cimg(const char *const filename, const char axis='z', const char align='p') {
30532  CImgList<T> list;
30533  list.load_cimg(filename);
30534  if (list.width==1) return list[0].transfer_to(*this);
30535  return assign(list.get_append(axis,align));
30536  }
30537 
30538  static CImg<T> get_load_cimg(const char *const filename, const char axis='z', const char align='p') {
30539  return CImg<T>().load_cimg(filename,axis,align);
30540  }
30541 
30543  CImg<T>& load_cimg(std::FILE *const file, const char axis='z', const char align='p') {
30544  CImgList<T> list;
30545  list.load_cimg(file);
30546  if (list.width==1) return list[0].transfer_to(*this);
30547  return assign(list.get_append(axis,align));
30548  }
30549 
30550  static CImg<T> get_load_cimg(std::FILE *const file, const char axis='z', const char align='p') {
30551  return CImg<T>().load_cimg(file,axis,align);
30552  }
30553 
30555  CImg<T>& load_cimg(const char *const filename,
30556  const unsigned int n0, const unsigned int n1,
30557  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30558  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30559  const char axis='z', const char align='p') {
30560  CImgList<T> list;
30561  list.load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
30562  if (list.width==1) return list[0].transfer_to(*this);
30563  return assign(list.get_append(axis,align));
30564  }
30565 
30566  static CImg<T> get_load_cimg(const char *const filename,
30567  const unsigned int n0, const unsigned int n1,
30568  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30569  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30570  const char axis='z', const char align='p') {
30571  return CImg<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
30572  }
30573 
30575  CImg<T>& load_cimg(std::FILE *const file,
30576  const unsigned int n0, const unsigned int n1,
30577  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30578  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30579  const char axis='z', const char align='p') {
30580  CImgList<T> list;
30581  list.load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
30582  if (list.width==1) return list[0].transfer_to(*this);
30583  return assign(list.get_append(axis,align));
30584  }
30585 
30586  static CImg<T> get_load_cimg(std::FILE *const file,
30587  const unsigned int n0, const unsigned int n1,
30588  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30589  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30590  const char axis='z', const char align='p') {
30591  return CImg<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
30592  }
30593 
30595  CImg<T>& load_inr(const char *const filename, float *const voxsize=0) {
30596  return _load_inr(0,filename,voxsize);
30597  }
30598 
30599  static CImg<T> get_load_inr(const char *const filename, float *const voxsize=0) {
30600  return CImg<T>().load_inr(filename,voxsize);
30601  }
30602 
30604  CImg<T>& load_inr(std::FILE *const file, float *const voxsize=0) {
30605  return _load_inr(file,0,voxsize);
30606  }
30607 
30608  static CImg<T> get_load_inr(std::FILE *const file, float *voxsize=0) {
30609  return CImg<T>().load_inr(file,voxsize);
30610  }
30611 
30612  // Load an image from an INRIMAGE-4 file (internal).
30613  static void _load_inr_header(std::FILE *file, int out[8], float *const voxsize) {
30614  char item[1024] = { 0 }, tmp1[64] = { 0 }, tmp2[64] = { 0 };
30615  out[0] = std::fscanf(file,"%63s",item);
30616  out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1;
30617  if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0)
30618  throw CImgIOException("CImg<%s>::load_inr() : File does not appear to be a valid INR file.\n"
30619  "(INRIMAGE-4 identifier not found)",
30620  pixel_type());
30621  while (std::fscanf(file," %63[^\n]%*c",item)!=EOF && std::strncmp(item,"##}",3)) {
30622  std::sscanf(item," XDIM%*[^0-9]%d",out);
30623  std::sscanf(item," YDIM%*[^0-9]%d",out+1);
30624  std::sscanf(item," ZDIM%*[^0-9]%d",out+2);
30625  std::sscanf(item," VDIM%*[^0-9]%d",out+3);
30626  std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6);
30627  if (voxsize) {
30628  std::sscanf(item," VX%*[^0-9.+-]%f",voxsize);
30629  std::sscanf(item," VY%*[^0-9.+-]%f",voxsize+1);
30630  std::sscanf(item," VZ%*[^0-9.+-]%f",voxsize+2);
30631  }
30632  if (std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1;
30633  switch (std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
30634  case 0 : break;
30635  case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strcpy(tmp1,tmp2);
30636  case 1 :
30637  if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4] = 0;
30638  if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1;
30639  if (!cimg::strncasecmp(tmp1,"packed",6)) out[4] = 2;
30640  if (out[4]>=0) break;
30641  default :
30642  throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2);
30643  }
30644  }
30645  if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
30646  throw CImgIOException("CImg<%s>::load_inr() : Bad dimensions in .inr file = ( %d , %d , %d , %d )",
30647  pixel_type(),out[0],out[1],out[2],out[3]);
30648  if(out[4]<0 || out[5]<0)
30649  throw CImgIOException("CImg<%s>::load_inr() : TYPE is not fully defined",
30650  pixel_type());
30651  if(out[6]<0)
30652  throw CImgIOException("CImg<%s>::load_inr() : PIXSIZE is not fully defined",
30653  pixel_type());
30654  if(out[7]<0)
30655  throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type is not defined",
30656  pixel_type());
30657  }
30658 
30659  CImg<T>& _load_inr(std::FILE *const file, const char *const filename, float *const voxsize) {
30660 #define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \
30661  if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \
30662  Ts *xval, *val = new Ts[fopt[0]*fopt[3]]; \
30663  cimg_forYZ(*this,y,z) { \
30664  cimg::fread(val,fopt[0]*fopt[3],nfile); \
30665  if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \
30666  xval = val; cimg_forX(*this,x) cimg_forV(*this,k) (*this)(x,y,z,k) = (T)*(xval++); \
30667  } \
30668  delete[] val; \
30669  loaded = true; \
30670  }
30671 
30672  if (!filename && !file)
30673  throw CImgArgumentException("CImg<%s>::load_inr() : Cannot load (null) filename.",
30674  pixel_type());
30675  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
30676  int fopt[8], endian=cimg::endianness()?1:0;
30677  bool loaded = false;
30678  if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1;
30679  _load_inr_header(nfile,fopt,voxsize);
30680  assign(fopt[0],fopt[1],fopt[2],fopt[3]);
30681  _cimg_load_inr_case(0,0,8, unsigned char);
30682  _cimg_load_inr_case(0,1,8, char);
30683  _cimg_load_inr_case(0,0,16,unsigned short);
30684  _cimg_load_inr_case(0,1,16,short);
30685  _cimg_load_inr_case(0,0,32,unsigned int);
30686  _cimg_load_inr_case(0,1,32,int);
30687  _cimg_load_inr_case(1,0,32,float);
30688  _cimg_load_inr_case(1,1,32,float);
30689  _cimg_load_inr_case(1,0,64,double);
30690  _cimg_load_inr_case(1,1,64,double);
30691  if (!loaded) {
30692  if (!file) cimg::fclose(nfile);
30693  throw CImgIOException("CImg<%s>::load_inr() : File '%s', cannot read images of the type specified in the file",
30694  pixel_type(),filename?filename:"(FILE*)");
30695  }
30696  if (!file) cimg::fclose(nfile);
30697  return *this;
30698  }
30699 
30701  CImg<T>& load_pandore(const char *const filename) {
30702  return _load_pandore(0,filename);
30703  }
30704 
30705  static CImg<T> get_load_pandore(const char *const filename) {
30706  return CImg<T>().load_pandore(filename);
30707  }
30708 
30710  CImg<T>& load_pandore(std::FILE *const file) {
30711  return _load_pandore(file,0);
30712  }
30713 
30714  static CImg<T> get_load_pandore(std::FILE *const file) {
30715  return CImg<T>().load_pandore(file);
30716  }
30717 
30718  CImg<T>& _load_pandore(std::FILE *const file, const char *const filename) {
30719 #define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \
30720  cimg::fread(dims,nbdim,nfile); \
30721  if (endian) cimg::invert_endianness(dims,nbdim); \
30722  assign(nwidth,nheight,ndepth,ndim); \
30723  const unsigned int siz = size(); \
30724  stype *buffer = new stype[siz]; \
30725  cimg::fread(buffer,siz,nfile); \
30726  if (endian) cimg::invert_endianness(buffer,siz); \
30727  T *ptrd = data; \
30728  cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \
30729  buffer-=siz; \
30730  delete[] buffer
30731 
30732 #define _cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1,stype2,stype3,ltype) { \
30733  if (sizeof(stype1)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1); } \
30734  else if (sizeof(stype2)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype2); } \
30735  else if (sizeof(stype3)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype3); } \
30736  else throw CImgIOException("CImg<%s>::load_pandore() : File '%s' cannot be read, datatype not supported on this architecture.", \
30737  pixel_type(),filename?filename:"(FILE*)"); }
30738 
30739  if (!filename && !file)
30740  throw CImgArgumentException("CImg<%s>::load_pandore() : Cannot load (null) filename.",
30741  pixel_type());
30742  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
30743  typedef unsigned char uchar;
30744  typedef unsigned short ushort;
30745  typedef unsigned int uint;
30746  typedef unsigned long ulong;
30747  char header[32] = { 0 };
30748  cimg::fread(header,12,nfile);
30749  if (cimg::strncasecmp("PANDORE",header,7)) {
30750  if (!file) cimg::fclose(nfile);
30751  throw CImgIOException("CImg<%s>::load_pandore() : File '%s' is not a valid PANDORE file, "
30752  "(PANDORE identifier not found).",
30753  pixel_type(),filename?filename:"(FILE*)");
30754  }
30755  unsigned int imageid, dims[8] = { 0 };
30756  cimg::fread(&imageid,1,nfile);
30757  const bool endian = (imageid>255);
30758  if (endian) cimg::invert_endianness(imageid);
30759  cimg::fread(header,20,nfile);
30760 
30761  switch (imageid) {
30762  case 2: _cimg_load_pandore_case(2,dims[1],1,1,1,uchar,uchar,uchar,1); break;
30763  case 3: _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break;
30764  case 4: _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break;
30765  case 5: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,uchar,uchar,uchar,1); break;
30766  case 6: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break;
30767  case 7: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break;
30768  case 8: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,uchar,uchar,uchar,1); break;
30769  case 9: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break;
30770  case 10: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break;
30771  case 11 : { // Region 1D
30772  cimg::fread(dims,3,nfile);
30773  if (endian) cimg::invert_endianness(dims,3);
30774  assign(dims[1],1,1,1);
30775  const unsigned siz = size();
30776  if (dims[2]<256) {
30777  unsigned char *buffer = new unsigned char[siz];
30778  cimg::fread(buffer,siz,nfile);
30779  T *ptrd = data;
30780  cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30781  buffer-=siz;
30782  delete[] buffer;
30783  } else {
30784  if (dims[2]<65536) {
30785  unsigned short *buffer = new unsigned short[siz];
30786  cimg::fread(buffer,siz,nfile);
30787  if (endian) cimg::invert_endianness(buffer,siz);
30788  T *ptrd = data;
30789  cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30790  buffer-=siz;
30791  delete[] buffer;
30792  } else {
30793  unsigned int *buffer = new unsigned int[siz];
30794  cimg::fread(buffer,siz,nfile);
30795  if (endian) cimg::invert_endianness(buffer,siz);
30796  T *ptrd = data;
30797  cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30798  buffer-=siz;
30799  delete[] buffer;
30800  }
30801  }
30802  }
30803  break;
30804  case 12 : { // Region 2D
30805  cimg::fread(dims,4,nfile);
30806  if (endian) cimg::invert_endianness(dims,4);
30807  assign(dims[2],dims[1],1,1);
30808  const unsigned int siz = size();
30809  if (dims[3]<256) {
30810  unsigned char *buffer = new unsigned char[siz];
30811  cimg::fread(buffer,siz,nfile);
30812  T *ptrd = data;
30813  cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30814  buffer-=siz;
30815  delete[] buffer;
30816  } else {
30817  if (dims[3]<65536) {
30818  unsigned short *buffer = new unsigned short[siz];
30819  cimg::fread(buffer,siz,nfile);
30820  if (endian) cimg::invert_endianness(buffer,siz);
30821  T *ptrd = data;
30822  cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30823  buffer-=siz;
30824  delete[] buffer;
30825  } else {
30826  unsigned long *buffer = new unsigned long[siz];
30827  cimg::fread(buffer,siz,nfile);
30828  if (endian) cimg::invert_endianness(buffer,siz);
30829  T *ptrd = data;
30830  cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30831  buffer-=siz;
30832  delete[] buffer;
30833  }
30834  }
30835  }
30836  break;
30837  case 13 : { // Region 3D
30838  cimg::fread(dims,5,nfile);
30839  if (endian) cimg::invert_endianness(dims,5);
30840  assign(dims[3],dims[2],dims[1],1);
30841  const unsigned int siz = size();
30842  if (dims[4]<256) {
30843  unsigned char *buffer = new unsigned char[siz];
30844  cimg::fread(buffer,siz,nfile);
30845  T *ptrd = data;
30846  cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30847  buffer-=siz;
30848  delete[] buffer;
30849  } else {
30850  if (dims[4]<65536) {
30851  unsigned short *buffer = new unsigned short[siz];
30852  cimg::fread(buffer,siz,nfile);
30853  if (endian) cimg::invert_endianness(buffer,siz);
30854  T *ptrd = data;
30855  cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30856  buffer-=siz;
30857  delete[] buffer;
30858  } else {
30859  unsigned int *buffer = new unsigned int[siz];
30860  cimg::fread(buffer,siz,nfile);
30861  if (endian) cimg::invert_endianness(buffer,siz);
30862  T *ptrd = data;
30863  cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30864  buffer-=siz;
30865  delete[] buffer;
30866  }
30867  }
30868  }
30869  break;
30870  case 16: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,uchar,uchar,uchar,1); break;
30871  case 17: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break;
30872  case 18: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break;
30873  case 19: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,uchar,uchar,uchar,1); break;
30874  case 20: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break;
30875  case 21: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break;
30876  case 22: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],uchar,uchar,uchar,1); break;
30877  case 23: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4);
30878  case 24: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],ulong,uint,ushort,4); break;
30879  case 25: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break;
30880  case 26: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],uchar,uchar,uchar,1); break;
30881  case 27: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break;
30882  case 28: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],ulong,uint,ushort,4); break;
30883  case 29: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break;
30884  case 30: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],uchar,uchar,uchar,1); break;
30885  case 31: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break;
30886  case 32: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],ulong,uint,ushort,4); break;
30887  case 33: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break;
30888  case 34 : { // Points 1D
30889  int ptbuf[4] = { 0 };
30890  cimg::fread(ptbuf,1,nfile);
30891  if (endian) cimg::invert_endianness(ptbuf,1);
30892  assign(1); (*this)(0) = (T)ptbuf[0];
30893  } break;
30894  case 35 : { // Points 2D
30895  int ptbuf[4] = { 0 };
30896  cimg::fread(ptbuf,2,nfile);
30897  if (endian) cimg::invert_endianness(ptbuf,2);
30898  assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0];
30899  } break;
30900  case 36 : { // Points 3D
30901  int ptbuf[4] = { 0 };
30902  cimg::fread(ptbuf,3,nfile);
30903  if (endian) cimg::invert_endianness(ptbuf,3);
30904  assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0];
30905  } break;
30906  default :
30907  if (!file) cimg::fclose(nfile);
30908  throw CImgIOException("CImg<%s>::load_pandore() : File '%s', cannot read images with ID_type = %u",
30909  pixel_type(),filename?filename:"(FILE*)",imageid);
30910  }
30911  if (!file) cimg::fclose(nfile);
30912  return *this;
30913  }
30914 
30916  CImg<T>& load_parrec(const char *const filename, const char axis='v', const char align='p') {
30917  CImgList<T> list;
30918  list.load_parrec(filename);
30919  if (list.width==1) return list[0].transfer_to(*this);
30920  return assign(list.get_append(axis,align));
30921  }
30922 
30923  static CImg<T> get_load_parrec(const char *const filename, const char axis='v', const char align='p') {
30924  return CImg<T>().load_parrec(filename,axis,align);
30925  }
30926 
30928  CImg<T>& load_raw(const char *const filename,
30929  const unsigned int sizex, const unsigned int sizey=1,
30930  const unsigned int sizez=1, const unsigned int sizev=1,
30931  const bool multiplexed=false, const bool invert_endianness=false) {
30932  return _load_raw(0,filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30933  }
30934 
30935  static CImg<T> get_load_raw(const char *const filename,
30936  const unsigned int sizex, const unsigned int sizey=1,
30937  const unsigned int sizez=1, const unsigned int sizev=1,
30938  const bool multiplexed=false, const bool invert_endianness=false) {
30939  return CImg<T>().load_raw(filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30940  }
30941 
30943  CImg<T>& load_raw(std::FILE *const file,
30944  const unsigned int sizex, const unsigned int sizey=1,
30945  const unsigned int sizez=1, const unsigned int sizev=1,
30946  const bool multiplexed=false, const bool invert_endianness=false) {
30947  return _load_raw(file,0,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30948  }
30949 
30950  static CImg<T> get_load_raw(std::FILE *const file,
30951  const unsigned int sizex, const unsigned int sizey=1,
30952  const unsigned int sizez=1, const unsigned int sizev=1,
30953  const bool multiplexed=false, const bool invert_endianness=false) {
30954  return CImg<T>().load_raw(file,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30955  }
30956 
30957  CImg<T>& _load_raw(std::FILE *const file, const char *const filename,
30958  const unsigned int sizex, const unsigned int sizey,
30959  const unsigned int sizez, const unsigned int sizev,
30960  const bool multiplexed, const bool invert_endianness) {
30961  if (!filename && !file)
30962  throw CImgArgumentException("CImg<%s>::load_raw() : Cannot load (null) filename.",
30963  pixel_type());
30964  assign(sizex,sizey,sizez,sizev,0);
30965  const unsigned int siz = size();
30966  if (siz) {
30967  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
30968  if (!multiplexed) {
30969  cimg::fread(data,siz,nfile);
30970  if (invert_endianness) cimg::invert_endianness(data,siz);
30971  }
30972  else {
30973  CImg<T> buf(1,1,1,sizev);
30974  cimg_forXYZ(*this,x,y,z) {
30975  cimg::fread(buf.data,sizev,nfile);
30976  if (invert_endianness) cimg::invert_endianness(buf.data,sizev);
30977  set_vector_at(buf,x,y,z); }
30978  }
30979  if (!file) cimg::fclose(nfile);
30980  }
30981  return *this;
30982  }
30983 
30985  CImg<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30986  const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
30987  const char axis='z', const char align='p') {
30988  return get_load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume,axis,align).transfer_to(*this);
30989  }
30990 
30991  static CImg<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30992  const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
30993  const char axis='z', const char align='p') {
30994  return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume).get_append(axis,align);
30995  }
30996 
30998  CImg<T>& load_yuv(const char *const filename,
30999  const unsigned int sizex, const unsigned int sizey=1,
31000  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
31001  const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
31002  return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
31003  }
31004 
31005  static CImg<T> get_load_yuv(const char *const filename,
31006  const unsigned int sizex, const unsigned int sizey=1,
31007  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
31008  const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
31009  return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
31010  }
31011 
31013  CImg<T>& load_yuv(std::FILE *const file,
31014  const unsigned int sizex, const unsigned int sizey=1,
31015  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
31016  const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
31017  return get_load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
31018  }
31019 
31020  static CImg<T> get_load_yuv(std::FILE *const file,
31021  const unsigned int sizex, const unsigned int sizey=1,
31022  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
31023  const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
31024  return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
31025  }
31026 
31028  template<typename tf, typename tc>
31029  CImg<T>& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors) {
31030  return _load_off(0,filename,primitives,colors);
31031  }
31032 
31033  template<typename tf, typename tc>
31034  static CImg<T> get_load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors) {
31035  return CImg<T>().load_off(filename,primitives,colors);
31036  }
31037 
31039  template<typename tf, typename tc>
31040  CImg<T>& load_off(std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors) {
31041  return _load_off(file,0,primitives,colors);
31042  }
31043 
31044  template<typename tf, typename tc>
31045  static CImg<T> get_load_off(std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors) {
31046  return CImg<T>().load_off(file,primitives,colors);
31047  }
31048 
31049  template<typename tf, typename tc>
31050  CImg<T>& _load_off(std::FILE *const file, const char *const filename,
31051  CImgList<tf>& primitives, CImgList<tc>& colors) {
31052  if (!filename && !file)
31053  throw CImgArgumentException("CImg<%s>::load_off() : Cannot load (null) filename.",
31054  pixel_type());
31055  std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
31056  unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0;
31057  char line[256] = { 0 };
31058  int err;
31059 
31060  // Skip comments, and read magic string OFF
31061  do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
31062  if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) {
31063  if (!file) cimg::fclose(nfile);
31064  throw CImgIOException("CImg<%s>::load_off() : File '%s', keyword 'OFF' not found.",
31065  pixel_type(),filename?filename:"(FILE*)");
31066  }
31067  do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
31068  if ((err = std::sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) {
31069  if (!file) cimg::fclose(nfile);
31070  throw CImgIOException("CImg<%s>::load_off() : File '%s', invalid vertices/primitives numbers.",
31071  pixel_type(),filename?filename:"(FILE*)");
31072  }
31073 
31074  // Read points data
31075  assign(nb_points,3);
31076  float X = 0, Y = 0, Z = 0;
31077  cimg_forX(*this,l) {
31078  do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
31079  if ((err = std::sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) {
31080  if (!file) cimg::fclose(nfile);
31081  throw CImgIOException("CImg<%s>::load_off() : File '%s', cannot read point %u/%u.\n",
31082  pixel_type(),filename?filename:"(FILE*)",l+1,nb_points);
31083  }
31084  (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z;
31085  }
31086 
31087  // Read primitive data
31088  primitives.assign();
31089  colors.assign();
31090  bool stopflag = false;
31091  while (!stopflag) {
31092  float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f;
31093  unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
31094  line[0] = 0;
31095  if ((err = std::fscanf(nfile,"%u",&prim))!=1) stopflag=true;
31096  else {
31097  ++nb_read;
31098  switch (prim) {
31099  case 1 : {
31100  if ((err = std::fscanf(nfile,"%u%255[^\n] ",&i0,line))<2) {
31101  cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
31102  pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
31103  err = std::fscanf(nfile,"%*[^\n] ");
31104  } else {
31105  err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
31106  CImg<tf>::vector(i0).transfer_to(primitives);
31107  CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).transfer_to(colors);
31108  }
31109  } break;
31110  case 2 : {
31111  if ((err = std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line))<2) {
31112  cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
31113  pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
31114  err = std::fscanf(nfile,"%*[^\n] ");
31115  } else {
31116  err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
31117  CImg<tf>::vector(i0,i1).transfer_to(primitives);
31118  CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).transfer_to(colors);
31119  }
31120  } break;
31121  case 3 : {
31122  if ((err = std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line))<3) {
31123  cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
31124  pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
31125  err = std::fscanf(nfile,"%*[^\n] ");
31126  } else {
31127  err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
31128  CImg<tf>::vector(i0,i2,i1).transfer_to(primitives);
31129  CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).transfer_to(colors);
31130  }
31131  } break;
31132  case 4 : {
31133  if ((err = std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line))<4) {
31134  cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
31135  pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
31136  err = std::fscanf(nfile,"%*[^\n] ");
31137  } else {
31138  err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
31139  CImg<tf>::vector(i0,i3,i2,i1).transfer_to(primitives);
31140  CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)).transfer_to(colors);
31141  }
31142  } break;
31143  case 5 : {
31144  if ((err = std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line))<5) {
31145  cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
31146  pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
31147  err = std::fscanf(nfile,"%*[^\n] ");
31148  } else {
31149  err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
31150  CImg<tf>::vector(i0,i3,i2,i1).transfer_to(primitives);
31151  CImg<tf>::vector(i0,i4,i3).transfer_to(primitives);
31152  colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
31153  ++nb_primitives;
31154  }
31155  } break;
31156  case 6 : {
31157  if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line))<6) {
31158  cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
31159  pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
31160  err = std::fscanf(nfile,"%*[^\n] ");
31161  } else {
31162  err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
31163  CImg<tf>::vector(i0,i3,i2,i1).transfer_to(primitives);
31164  CImg<tf>::vector(i0,i5,i4,i3).transfer_to(primitives);
31165  colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
31166  ++nb_primitives;
31167  }
31168  } break;
31169  case 7 : {
31170  if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line))<7) {
31171  cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
31172  pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
31173  err = std::fscanf(nfile,"%*[^\n] ");
31174  } else {
31175  err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
31176  CImg<tf>::vector(i0,i4,i3,i1).transfer_to(primitives);
31177  CImg<tf>::vector(i0,i6,i5,i4).transfer_to(primitives);
31178  CImg<tf>::vector(i3,i2,i1).transfer_to(primitives);
31179  colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
31180  ++(++nb_primitives);
31181  }
31182  } break;
31183  case 8 : {
31184  if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line))<7) {
31185  cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
31186  pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
31187  err = std::fscanf(nfile,"%*[^\n] ");
31188  } else {
31189  err = std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
31190  CImg<tf>::vector(i0,i3,i2,i1).transfer_to(primitives);
31191  CImg<tf>::vector(i0,i5,i4,i3).transfer_to(primitives);
31192  CImg<tf>::vector(i0,i7,i6,i5).transfer_to(primitives);
31193  colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
31194  ++(++nb_primitives);
31195  }
31196  } break;
31197  default :
31198  cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u (%u vertices).",
31199  pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives,prim);
31200  err = std::fscanf(nfile,"%*[^\n] ");
31201  }
31202  }
31203  }
31204  if (!file) cimg::fclose(nfile);
31205  if (primitives.width!=nb_primitives)
31206  cimg::warn("CImg<%s>::load_off() : File '%s', read only %u primitives instead of %u as claimed in the header.",
31207  pixel_type(),filename?filename:"(FILE*)",primitives.width,nb_primitives);
31208  return *this;
31209  }
31210 
31212  CImg<T>& load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
31213  return get_load_ffmpeg_external(filename,axis,align).transfer_to(*this);
31214  }
31215 
31216  static CImg<T> get_load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
31217  return CImgList<T>().load_ffmpeg_external(filename).get_append(axis,align);
31218  }
31219 
31221  CImg<T>& load_graphicsmagick_external(const char *const filename) {
31222  if (!filename)
31223  throw CImgArgumentException("CImg<%s>::load_graphicsmagick_external() : Cannot load (null) filename.",
31224  pixel_type());
31225  char command[1024] = { 0 }, filetmp[512] = { 0 };
31226  std::FILE *file = 0;
31227 #if cimg_OS==1
31228  std::sprintf(command,"%s convert \"%s\" ppm:-",cimg::graphicsmagick_path(),filename);
31229  file = popen(command,"r");
31230  if (file) { load_pnm(file); pclose(file); return *this; }
31231 #endif
31232  do {
31233  std::sprintf(filetmp,"%s%c%s.ppm",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
31234  if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
31235  } while (file);
31236  std::sprintf(command,"%s convert \"%s\" %s",cimg::graphicsmagick_path(),filename,filetmp);
31238  if (!(file = std::fopen(filetmp,"rb"))) {
31239  cimg::fclose(cimg::fopen(filename,"r"));
31240  throw CImgIOException("CImg<%s>::load_graphicsmagick_external() : Failed to open image '%s'.\n\n"
31241  "Path of 'GraphicsMagick's gm' : \"%s\"\n"
31242  "Path of temporary filename : \"%s\"",
31243  pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
31244  } else cimg::fclose(file);
31245  load_pnm(filetmp);
31246  std::remove(filetmp);
31247  return *this;
31248  }
31249 
31250  static CImg<T> get_load_graphicsmagick_external(const char *const filename) {
31251  return CImg<T>().load_graphicsmagick_external(filename);
31252  }
31253 
31255  CImg<T>& load_gzip_external(const char *const filename) {
31256  if (!filename)
31257  throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
31258  pixel_type());
31259  char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 };
31260  const char
31261  *ext = cimg::split_filename(filename,body),
31262  *ext2 = cimg::split_filename(body,0);
31263  std::FILE *file = 0;
31264  do {
31265  if (!cimg::strcasecmp(ext,"gz")) {
31266  if (*ext2) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);
31267  else std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
31268  } else {
31269  if (*ext) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);
31270  else std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
31271  }
31272  if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
31273  } while (file);
31274  std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
31275  cimg::system(command);
31276  if (!(file = std::fopen(filetmp,"rb"))) {
31277  cimg::fclose(cimg::fopen(filename,"r"));
31278  throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
31279  pixel_type(),filename);
31280  } else cimg::fclose(file);
31281  load(filetmp);
31282  std::remove(filetmp);
31283  return *this;
31284  }
31285 
31286  static CImg<T> get_load_gzip_external(const char *const filename) {
31287  return CImg<T>().load_gzip_external(filename);
31288  }
31289 
31291  CImg<T>& load_imagemagick_external(const char *const filename) {
31292  if (!filename)
31293  throw CImgArgumentException("CImg<%s>::load_imagemagick_external() : Cannot load (null) filename.",
31294  pixel_type());
31295  char command[1024] = { 0 }, filetmp[512] = { 0 };
31296  std::FILE *file = 0;
31297 #if cimg_OS==1
31298  std::sprintf(command,"%s \"%s\" ppm:-",cimg::imagemagick_path(),filename);
31299  file = popen(command,"r");
31300  if (file) { load_pnm(file); pclose(file); return *this; }
31301 #endif
31302  do {
31303  std::sprintf(filetmp,"%s%c%s.ppm",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
31304  if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
31305  } while (file);
31306  std::sprintf(command,"%s \"%s\" %s",cimg::imagemagick_path(),filename,filetmp);
31308  if (!(file = std::fopen(filetmp,"rb"))) {
31309  cimg::fclose(cimg::fopen(filename,"r"));
31310  throw CImgIOException("CImg<%s>::load_imagemagick_external() : Failed to open image '%s'.\n\n"
31311  "Path of 'ImageMagick's convert' : \"%s\"\n"
31312  "Path of temporary filename : \"%s\"",
31313  pixel_type(),filename,cimg::imagemagick_path(),filetmp);
31314  } else cimg::fclose(file);
31315  load_pnm(filetmp);
31316  std::remove(filetmp);
31317  return *this;
31318  }
31319 
31320  static CImg<T> get_load_imagemagick_external(const char *const filename) {
31321  return CImg<T>().load_imagemagick_external(filename);
31322  }
31323 
31325  CImg<T>& load_medcon_external(const char *const filename) {
31326  if (!filename)
31327  throw CImgArgumentException("CImg<%s>::load_medcon_external() : Cannot load (null) filename.",
31328  pixel_type());
31329  char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 };
31330  cimg::fclose(cimg::fopen(filename,"r"));
31331  std::FILE *file = 0;
31332  do {
31333  std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
31334  if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
31335  } while (file);
31336  std::sprintf(command,"%s -w -c anlz -o %s -f %s",cimg::medcon_path(),filetmp,filename);
31337  cimg::system(command);
31338  cimg::split_filename(filetmp,body);
31339  std::sprintf(command,"m000-%s.hdr",body);
31340  file = std::fopen(command,"rb");
31341  if (!file) {
31342  throw CImgIOException("CImg<%s>::load_medcon_external() : Failed to open image '%s'.\n\n"
31343  "Path of 'medcon' : \"%s\"\n"
31344  "Path of temporary filename : \"%s\"",
31345  pixel_type(),filename,cimg::medcon_path(),filetmp);
31346  } else cimg::fclose(file);
31347  load_analyze(command);
31348  std::remove(command);
31349  std::sprintf(command,"m000-%s.img",body);
31350  std::remove(command);
31351  return *this;
31352  }
31353 
31354  static CImg<T> get_load_medcon_external(const char *const filename) {
31355  return CImg<T>().load_medcon_external(filename);
31356  }
31357 
31359  CImg<T>& load_dcraw_external(const char *const filename) {
31360  if (!filename)
31361  throw CImgArgumentException("CImg<%s>::load_dcraw_external() : Cannot load (null) filename.",
31362  pixel_type());
31363  char command[1024] = { 0 }, filetmp[512] = { 0 };
31364  std::FILE *file = 0;
31365 #if cimg_OS==1
31366  std::sprintf(command,"%s -4 -c \"%s\"",cimg::dcraw_path(),filename);
31367  file = popen(command,"r");
31368  if (file) { load_pnm(file); pclose(file); return *this; }
31369 #endif
31370  do {
31371  std::sprintf(filetmp,"%s%c%s.ppm",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
31372  if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
31373  } while (file);
31374  std::sprintf(command,"%s -4 -c \"%s\" > %s",cimg::dcraw_path(),filename,filetmp);
31375  cimg::system(command,cimg::dcraw_path());
31376  if (!(file = std::fopen(filetmp,"rb"))) {
31377  cimg::fclose(cimg::fopen(filename,"r"));
31378  throw CImgIOException("CImg<%s>::load_dcraw_external() : Failed to open image '%s'.\n\n"
31379  "Path of 'dcraw' : \"%s\"\n"
31380  "Path of temporary filename : \"%s\"",
31381  pixel_type(),filename,cimg::dcraw_path(),filetmp);
31382  } else cimg::fclose(file);
31383  load_pnm(filetmp);
31384  std::remove(filetmp);
31385  return *this;
31386  }
31387 
31388  static CImg<T> get_load_dcraw_external(const char *const filename) {
31389  return CImg<T>().load_dcraw_external(filename);
31390  }
31391 
31393  CImg<T>& load_other(const char *const filename) {
31394  if (!filename)
31395  throw CImgArgumentException("CImg<%s>::load_other() : Cannot load (null) filename.",
31396  pixel_type());
31397  const unsigned int omode = cimg::exception_mode();
31398  cimg::exception_mode() = 0;
31399  try { load_magick(filename); }
31400  catch (CImgException&) {
31401  try { load_imagemagick_external(filename); }
31402  catch (CImgException&) {
31403  try { load_graphicsmagick_external(filename); }
31404  catch (CImgException&) {
31405  assign();
31406  }
31407  }
31408  }
31409  cimg::exception_mode() = omode;
31410  if (is_empty())
31411  throw CImgIOException("CImg<%s>::load_other() : File '%s' cannot be opened.",
31412  pixel_type(),filename);
31413  return *this;
31414  }
31415 
31416  static CImg<T> get_load_other(const char *const filename) {
31417  return CImg<T>().load_other(filename);
31418  }
31419 
31421  //---------------------------
31422  //
31424 
31425  //---------------------------
31426 
31428 
31432  const CImg<T>& print(const char *title=0, const bool display_stats=true) const {
31433  int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0;
31434  static CImg<doubleT> st;
31435  if (!is_empty() && display_stats) {
31436  st = get_stats();
31437  xm = (int)st[4]; ym = (int)st[5], zm = (int)st[6], vm = (int)st[7];
31438  xM = (int)st[8]; yM = (int)st[9], zM = (int)st[10], vM = (int)st[11];
31439  }
31440  const unsigned int siz = size(), msiz = siz*sizeof(T), siz1 = siz-1;
31441  const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2), width1 = width-1;
31442  char ntitle[64] = { 0 };
31443  if (!title) std::sprintf(ntitle,"CImg<%s>",pixel_type());
31444  std::fprintf(cimg_stdout,"%s: this = %p, size = (%u,%u,%u,%u) [%u %s], data = (%s*)%p..%p (%s) = [ ",
31445  title?title:ntitle,(void*)this,width,height,depth,dim,
31446  mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
31447  mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
31448  pixel_type(),(void*)begin(),(void*)((char*)end()-1),
31449  is_shared?"shared":"not shared");
31450  if (!is_empty()) cimg_foroff(*this,off) {
31452  if (off!=siz1) std::fprintf(cimg_stdout,"%s",off%width==width1?" ; ":" ");
31453  if (off==7 && siz>16) { off = siz1-8; if (off!=7) std::fprintf(cimg_stdout,"... "); }
31454  }
31455  if (!is_empty() && display_stats)
31456  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",
31457  st[0],st[1],st[2],std::sqrt(st[3]),xm,ym,zm,vm,xM,yM,zM,vM);
31458  else std::fprintf(cimg_stdout,"%s].\n",is_empty()?"":" ");
31459  return *this;
31460  }
31461 
31463  const CImg<T>& display(CImgDisplay& disp) const {
31464  disp.display(*this);
31465  return *this;
31466  }
31467 
31469  const CImg<T>& display(CImgDisplay &disp, const bool display_info) const {
31470  return _display(disp,0,display_info);
31471  }
31472 
31474  const CImg<T>& display(const char *const title=0, const bool display_info=true) const {
31475  CImgDisplay disp;
31476  return _display(disp,title,display_info);
31477  }
31478 
31479  const CImg<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info) const {
31480  if (is_empty())
31481  throw CImgInstanceException("CImg<%s>::display() : Instance image (%u,%u,%u,%u,%p) is empty.",
31482  pixel_type(),width,height,depth,dim,data);
31483  unsigned int oldw = 0, oldh = 0, XYZ[3], key = 0, mkey = 0;
31484  int x0 = 0, y0 = 0, z0 = 0, x1 = dimx()-1, y1 = dimy()-1, z1 = dimz()-1;
31485  float frametiming = 5;
31486 
31487  char ntitle[256] = { 0 };
31488  if (!disp) {
31489  if (!title) std::sprintf(ntitle,"CImg<%s> (%ux%ux%ux%u)",pixel_type(),width,height,depth,dim);
31490  disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
31491  }
31492  std::strncpy(ntitle,disp.title,255);
31493  if (display_info) print(ntitle);
31494 
31495  CImg<T> zoom;
31496  for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
31497  if (reset_view) {
31498  XYZ[0] = (x0 + x1)/2; XYZ[1] = (y0 + y1)/2; XYZ[2] = (z0 + z1)/2;
31499  x0 = 0; y0 = 0; z0 = 0; x1 = width-1; y1 = height-1; z1 = depth-1;
31500  oldw = disp.width; oldh = disp.height;
31501  reset_view = false;
31502  }
31503  if (!x0 && !y0 && !z0 && x1==dimx()-1 && y1==dimy()-1 && z1==dimz()-1) zoom.assign();
31504  else zoom = get_crop(x0,y0,z0,x1,y1,z1);
31505 
31506  const unsigned int
31507  dx = 1 + x1 - x0, dy = 1 + y1 - y0, dz = 1 + z1 - z0,
31508  tw = dx + (dz>1?dz:0), th = dy + (dz>1?dz:0);
31509  if (resize_disp) {
31510  const unsigned int
31511  ttw = tw*disp.width/oldw, tth = th*disp.height/oldh,
31512  dM = cimg::max(ttw,tth), diM = cimg::max(disp.width,disp.height),
31513  imgw = cimg::max(16U,ttw*diM/dM), imgh = cimg::max(16U,tth*diM/dM);
31514  disp.normalscreen().resize(cimg_fitscreen(imgw,imgh,1),false);
31515  resize_disp = false;
31516  }
31517  oldw = tw; oldh = th;
31518 
31519  bool
31520  go_up = false, go_down = false, go_left = false, go_right = false,
31521  go_inc = false, go_dec = false, go_in = false, go_out = false,
31522  go_in_center = false;
31523  const CImg<T>& visu = zoom?zoom:*this;
31524  const CImg<intT> selection = visu._get_select(disp,0,2,XYZ,0,x0,y0,z0);
31525  if (disp.wheel) {
31526  if (disp.is_keyCTRLLEFT) { if (!mkey || mkey==1) go_out = !(go_in = disp.wheel>0); go_in_center = false; mkey = 1; }
31527  else if (disp.is_keySHIFTLEFT) { if (!mkey || mkey==2) go_right = !(go_left = disp.wheel>0); mkey = 2; }
31528  else if (disp.is_keyALT || depth==1) { if (!mkey || mkey==3) go_down = !(go_up = disp.wheel>0); mkey = 3; }
31529  else mkey = 0;
31530  disp.wheel = 0;
31531  } else mkey = 0;
31532  const int
31533  sx0 = selection(0), sy0 = selection(1), sz0 = selection(2),
31534  sx1 = selection(3), sy1 = selection(4), sz1 = selection(5);
31535  if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) {
31536  x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1; x0+=sx0; y0+=sy0; z0+=sz0;
31537  if (sx0==sx1 && sy0==sy1 && sz0==sz1) reset_view = true;
31538  resize_disp = true;
31539  } else switch (key = disp.key) {
31540  case 0 : case cimg::keyCTRLLEFT : case cimg::keyPAD5 : case cimg::keySHIFTLEFT : case cimg::keyALT : disp.key = key = 0; break;
31541  case cimg::keyP : if (visu.depth>1 && disp.is_keyCTRLLEFT) { // Special mode : play stack of frames
31542  const unsigned int
31543  w1 = visu.width*disp.width/(visu.width+(visu.depth>1?visu.depth:0)),
31544  h1 = visu.height*disp.height/(visu.height+(visu.depth>1?visu.depth:0));
31545  disp.resize(cimg_fitscreen(w1,h1,1),false).key = disp.wheel = key = 0;
31546  for (unsigned int timer = 0; !key && !disp.is_closed && !disp.button; ) {
31547  if (disp.is_resized) disp.resize(false);
31548  if (!timer) {
31549  visu.get_slice(XYZ[2]).display(disp.set_title("%s | z=%d",ntitle,XYZ[2]));
31550  if (++XYZ[2]>=visu.depth) XYZ[2] = 0;
31551  }
31552  if (++timer>(unsigned int)frametiming) timer = 0;
31553  if (disp.wheel) { frametiming-=disp.wheel/3.0f; disp.wheel = 0; }
31554  switch (key = disp.key) {
31555  case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
31556  case cimg::keyPAGEUP : frametiming-=0.3f; key = 0; break;
31557  case cimg::keyPAGEDOWN : frametiming+=0.3f; key = 0; break;
31558  case cimg::keyD : if (disp.is_keyCTRLLEFT) {
31559  disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
31560  CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false);
31561  disp.key = key = 0;
31562  } break;
31563  case cimg::keyC : if (disp.is_keyCTRLLEFT) {
31564  disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false);
31565  disp.key = key = 0;
31566  } break;
31567  case cimg::keyR : if (disp.is_keyCTRLLEFT) {
31569  disp.key = key = 0;
31570  } break;
31571  case cimg::keyF : if (disp.is_keyCTRLLEFT)
31572  disp.resize(disp.screen_dimx(),disp.screen_dimy(),false).toggle_fullscreen().key = key = 0;
31573  break;
31574  }
31575  frametiming = frametiming<1?1:(frametiming>39?39:frametiming);
31576  disp.wait(20);
31577  }
31578  const unsigned int
31579  w2 = (visu.width + (visu.depth>1?visu.depth:0))*disp.width/visu.width,
31580  h2 = (visu.height + (visu.depth>1?visu.depth:0))*disp.height/visu.height;
31581  disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(ntitle);
31582  key = disp.key = disp.button = disp.wheel = 0;
31583  } break;
31584  case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
31585  case cimg::keyPADADD : go_in = true; go_in_center = true; key = 0; break;
31586  case cimg::keyPADSUB : go_out = true; key = 0; break;
31587  case cimg::keyARROWLEFT : case cimg::keyPAD4: go_left = true; key = 0; break;
31588  case cimg::keyARROWRIGHT : case cimg::keyPAD6: go_right = true; key = 0; break;
31589  case cimg::keyARROWUP : case cimg::keyPAD8: go_up = true; key = 0; break;
31590  case cimg::keyARROWDOWN : case cimg::keyPAD2: go_down = true; key = 0; break;
31591  case cimg::keyPAD7 : go_up = go_left = true; key = 0; break;
31592  case cimg::keyPAD9 : go_up = go_right = true; key = 0; break;
31593  case cimg::keyPAD1 : go_down = go_left = true; key = 0; break;
31594  case cimg::keyPAD3 : go_down = go_right = true; key = 0; break;
31595  case cimg::keyPAGEUP : go_inc = true; key = 0; break;
31596  case cimg::keyPAGEDOWN : go_dec = true; key = 0; break;
31597  }
31598  if (go_in) {
31599  const int
31600  mx = go_in_center?disp.dimx()/2:disp.mouse_x,
31601  my = go_in_center?disp.dimy()/2:disp.mouse_y,
31602  mX = mx*(width+(depth>1?depth:0))/disp.width,
31603  mY = my*(height+(depth>1?depth:0))/disp.height;
31604  int X = XYZ[0], Y = XYZ[1], Z = XYZ[2];
31605  if (mX<dimx() && mY<dimy()) { X = x0 + mX*(1+x1-x0)/width; Y = y0 + mY*(1+y1-y0)/height; Z = XYZ[2]; }
31606  if (mX<dimx() && mY>=dimy()) { X = x0 + mX*(1+x1-x0)/width; Z = z0 + (mY-height)*(1+z1-z0)/depth; Y = XYZ[1]; }
31607  if (mX>=dimx() && mY<dimy()) { Y = y0 + mY*(1+y1-y0)/height; Z = z0 + (mX-width)*(1+z1-z0)/depth; X = XYZ[0]; }
31608  if (x1-x0>4) { x0 = X - 7*(X-x0)/8; x1 = X + 7*(x1-X)/8; }
31609  if (y1-y0>4) { y0 = Y - 7*(Y-y0)/8; y1 = Y + 7*(y1-Y)/8; }
31610  if (z1-z0>4) { z0 = Z - 7*(Z-z0)/8; z1 = Z + 7*(z1-Z)/8; }
31611  }
31612  if (go_out) {
31613  const int
31614  deltax = (x1-x0)/8, deltay = (y1-y0)/8, deltaz = (z1-z0)/8,
31615  ndeltax = deltax?deltax:(width>1?1:0),
31616  ndeltay = deltay?deltay:(height>1?1:0),
31617  ndeltaz = deltaz?deltaz:(depth>1?1:0);
31618  x0-=ndeltax; y0-=ndeltay; z0-=ndeltaz;
31619  x1+=ndeltax; y1+=ndeltay; z1+=ndeltaz;
31620  if (x0<0) { x1-=x0; x0 = 0; if (x1>=dimx()) x1 = dimx()-1; }
31621  if (y0<0) { y1-=y0; y0 = 0; if (y1>=dimy()) y1 = dimy()-1; }
31622  if (z0<0) { z1-=z0; z0 = 0; if (z1>=dimz()) z1 = dimz()-1; }
31623  if (x1>=dimx()) { x0-=(x1-dimx()+1); x1 = dimx()-1; if (x0<0) x0 = 0; }
31624  if (y1>=dimy()) { y0-=(y1-dimy()+1); y1 = dimy()-1; if (y0<0) y0 = 0; }
31625  if (z1>=dimz()) { z0-=(z1-dimz()+1); z1 = dimz()-1; if (z0<0) z0 = 0; }
31626  }
31627  if (go_left) {
31628  const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
31629  if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
31630  else { x1-=x0; x0 = 0; }
31631  }
31632  if (go_right) {
31633  const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
31634  if (x1+ndelta<dimx()) { x0+=ndelta; x1+=ndelta; }
31635  else { x0+=(dimx()-1-x1); x1 = dimx()-1; }
31636  }
31637  if (go_up) {
31638  const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
31639  if (y0-ndelta>=0) { y0-=ndelta; y1-=ndelta; }
31640  else { y1-=y0; y0 = 0; }
31641  }
31642  if (go_down) {
31643  const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
31644  if (y1+ndelta<dimy()) { y0+=ndelta; y1+=ndelta; }
31645  else { y0+=(dimy()-1-y1); y1 = dimy()-1; }
31646  }
31647  if (go_inc) {
31648  const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
31649  if (z0-ndelta>=0) { z0-=ndelta; z1-=ndelta; }
31650  else { z1-=z0; z0 = 0; }
31651  }
31652  if (go_dec) {
31653  const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
31654  if (z1+ndelta<dimz()) { z0+=ndelta; z1+=ndelta; }
31655  else { z0+=(depth-1-z1); z1 = depth-1; }
31656  }
31657  }
31658  disp.key = key;
31659  return *this;
31660  }
31661 
31663  template<typename tp, typename tf, typename tc, typename to>
31665  const CImg<tp>& vertices,
31666  const CImgList<tf>& primitives,
31667  const CImgList<tc>& colors,
31668  const to& opacities,
31669  const bool centering=true,
31670  const int render_static=4, const int render_motion=1,
31671  const bool double_sided=true, const float focale=500,
31672  const float specular_light=0.2f, const float specular_shine=0.1f,
31673  const bool display_axes=true, float *const pose_matrix=0) const {
31674  return _display_object3d(disp,0,vertices,primitives,colors,opacities,centering,render_static,
31675  render_motion,double_sided,focale,specular_light,specular_shine,
31676  display_axes,pose_matrix);
31677  }
31678 
31680  template<typename tp, typename tf, typename tc, typename to>
31681  const CImg<T>& display_object3d(const char *const title,
31682  const CImg<tp>& vertices,
31683  const CImgList<tf>& primitives,
31684  const CImgList<tc>& colors,
31685  const to& opacities,
31686  const bool centering=true,
31687  const int render_static=4, const int render_motion=1,
31688  const bool double_sided=true, const float focale=500,
31689  const float specular_light=0.2f, const float specular_shine=0.1f,
31690  const bool display_axes=true, float *const pose_matrix=0) const {
31691  CImgDisplay disp;
31692  return _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,render_static,
31693  render_motion,double_sided,focale,specular_light,specular_shine,
31694  display_axes,pose_matrix);
31695  }
31696 
31698  template<typename tp, typename tf, typename tc>
31700  const CImg<tp>& vertices,
31701  const CImgList<tf>& primitives,
31702  const CImgList<tc>& colors,
31703  const bool centering=true,
31704  const int render_static=4, const int render_motion=1,
31705  const bool double_sided=true, const float focale=500,
31706  const float specular_light=0.2f, const float specular_shine=0.1f,
31707  const bool display_axes=true, float *const pose_matrix=0) const {
31708  return display_object3d(disp,vertices,primitives,colors,CImgList<floatT>(),centering,
31709  render_static,render_motion,double_sided,focale,specular_light,specular_shine,
31710  display_axes,pose_matrix);
31711  }
31712 
31714  template<typename tp, typename tf, typename tc>
31715  const CImg<T>& display_object3d(const char *const title,
31716  const CImg<tp>& vertices,
31717  const CImgList<tf>& primitives,
31718  const CImgList<tc>& colors,
31719  const bool centering=true,
31720  const int render_static=4, const int render_motion=1,
31721  const bool double_sided=true, const float focale=500,
31722  const float specular_light=0.2f, const float specular_shine=0.1f,
31723  const bool display_axes=true, float *const pose_matrix=0) const {
31724  return display_object3d(title,vertices,primitives,colors,CImgList<floatT>(),centering,
31725  render_static,render_motion,double_sided,focale,specular_light,specular_shine,
31726  display_axes,pose_matrix);
31727  }
31728 
31730  template<typename tp, typename tf>
31732  const CImg<tp>& vertices,
31733  const CImgList<tf>& primitives,
31734  const bool centering=true,
31735  const int render_static=4, const int render_motion=1,
31736  const bool double_sided=true, const float focale=500,
31737  const float specular_light=0.2f, const float specular_shine=0.1f,
31738  const bool display_axes=true, float *const pose_matrix=0) const {
31739  return display_object3d(disp,vertices,primitives,CImgList<T>(),centering,
31740  render_static,render_motion,double_sided,focale,specular_light,specular_shine,
31741  display_axes,pose_matrix);
31742  }
31743 
31745  template<typename tp, typename tf>
31746  const CImg<T>& display_object3d(const char *const title,
31747  const CImg<tp>& vertices,
31748  const CImgList<tf>& primitives,
31749  const bool centering=true,
31750  const int render_static=4, const int render_motion=1,
31751  const bool double_sided=true, const float focale=500,
31752  const float specular_light=0.2f, const float specular_shine=0.1f,
31753  const bool display_axes=true, float *const pose_matrix=0) const {
31754  return display_object3d(title,vertices,primitives,CImgList<T>(),centering,
31755  render_static,render_motion,double_sided,focale,specular_light,specular_shine,
31756  display_axes,pose_matrix);
31757  }
31758 
31760  template<typename tp>
31762  const CImg<tp>& vertices,
31763  const bool centering=true,
31764  const int render_static=4, const int render_motion=1,
31765  const bool double_sided=true, const float focale=500,
31766  const float specular_light=0.2f, const float specular_shine=0.1f,
31767  const bool display_axes=true, float *const pose_matrix=0) const {
31768  return display_object3d(disp,vertices,CImgList<uintT>(),centering,
31769  render_static,render_motion,double_sided,focale,specular_light,specular_shine,
31770  display_axes,pose_matrix);
31771  }
31772 
31774  template<typename tp>
31775  const CImg<T>& display_object3d(const char *const title,
31776  const CImg<tp>& vertices,
31777  const bool centering=true,
31778  const int render_static=4, const int render_motion=1,
31779  const bool double_sided=true, const float focale=500,
31780  const float specular_light=0.2f, const float specular_shine=0.1f,
31781  const bool display_axes=true, float *const pose_matrix=0) const {
31782  return display_object3d(title,vertices,CImgList<uintT>(),centering,
31783  render_static,render_motion,double_sided,focale,specular_light,specular_shine,
31784  display_axes,pose_matrix);
31785  }
31786 
31787  template<typename tp, typename tf, typename tc, typename to>
31788  const CImg<T>& _display_object3d(CImgDisplay& disp, const char *const title,
31789  const CImg<tp>& vertices,
31790  const CImgList<tf>& primitives,
31791  const CImgList<tc>& colors,
31792  const to& opacities,
31793  const bool centering,
31794  const int render_static, const int render_motion,
31795  const bool double_sided, const float focale,
31796  const float specular_light, const float specular_shine,
31797  const bool display_axes, float *const pose_matrix) const {
31798 
31799  // Check input arguments
31800  if (is_empty()) {
31801  if (disp) return CImg<T>(disp.width,disp.height,1,colors[0].size(),0).
31802  _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,
31803  render_static,render_motion,double_sided,focale,specular_light,specular_shine,
31804  display_axes,pose_matrix);
31805  else return CImg<T>(cimg_fitscreen(640,480,1),1,colors?colors[0].size():3,0).
31806  _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,
31807  render_static,render_motion,double_sided,focale,specular_light,specular_shine,
31808  display_axes,pose_matrix);
31809  }
31810  vertices.is_object3d(primitives,true,true);
31811  if (vertices.width && !primitives) {
31812  CImgList<tf> nprimitives(vertices.width,1,1,1,1);
31813  cimglist_for(nprimitives,l) nprimitives(l,0) = l;
31814  return _display_object3d(disp,title,vertices,nprimitives,colors,opacities,centering,
31815  render_static,render_motion,double_sided,focale,specular_light,specular_shine,
31816  display_axes,pose_matrix);
31817  }
31818  if (!disp) {
31819  char ntitle[256] = { 0 };
31820  if (!title) { std::sprintf(ntitle,"CImg<%s> (%u vertices, %u primitives)",pixel_type(),vertices.width,primitives.width); }
31821  disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
31822  }
31823 
31824  CImgList<tc> _colors;
31825  if (!colors) _colors.insert(primitives.width,CImg<tc>::vector(200,200,200));
31826  const CImgList<tc> &ncolors = colors?colors:_colors;
31827 
31828  // Init 3D objects and compute object statistics
31829  CImg<floatT>
31830  pose, rot_mat, zbuffer(disp.width,disp.height,1,1,0),
31831  centered_vertices = centering?CImg<floatT>(vertices.width,3):CImg<floatT>(),
31832  rotated_vertices(vertices.width,3),
31833  bbox_vertices, rotated_bbox_vertices,
31834  axes_vertices, rotated_axes_vertices,
31835  bbox_opacities, axes_opacities;
31836  CImgList<uintT> bbox_primitives, axes_primitives;
31837  CImgList<T> bbox_colors, bbox_colors2, axes_colors;
31838  float dx = 0, dy = 0, dz = 0, ratio = 1;
31839 
31840  T minval = (T)0, maxval = (T)255;
31841  if (disp.normalization && colors) {
31842  minval = colors.minmax(maxval);
31843  if (minval==maxval) { minval = (T)0; maxval = (T)255; }
31844  }
31845  unsigned int ns_width = 0, ns_height = 0;
31846  const float meanval = (float)mean();
31847  bool color_model = true;
31848  if (cimg::abs(meanval-minval)>cimg::abs(meanval-maxval)) color_model = false;
31849  const CImg<T>
31850  background_color(1,1,1,dim,color_model?minval:maxval),
31851  foreground_color(1,1,1,dim,color_model?maxval:minval);
31852 
31853  float xm = cimg::type<float>::max(), xM = 0, ym = xm, yM = 0, zm = xm, zM = 0;
31854  cimg_forX(vertices,i) {
31855  const float x = (float)vertices(i,0), y = (float)vertices(i,1), z = (float)vertices(i,2);
31856  if (x<xm) xm = x;
31857  if (x>xM) xM = x;
31858  if (y<ym) ym = y;
31859  if (y>yM) yM = y;
31860  if (z<zm) zm = z;
31861  if (z>zM) zM = z;
31862  }
31863  const float delta = cimg::max(xM-xm,yM-ym,zM-zm);
31864 
31865  if (display_axes) {
31866  rotated_axes_vertices = axes_vertices.assign(7,3,1,1,
31867  0,20,0,0,22,-6,-6,
31868  0,0,20,0,-6,22,-6,
31869  0,0,0,20,0,0,22);
31870  axes_opacities.assign(3,1,1,1,1);
31871  axes_colors.assign(3,dim,1,1,1,foreground_color[0]);
31872  axes_primitives.assign(3,1,2,1,1, 0,1, 0,2, 0,3);
31873  }
31874 
31875  // Begin user interaction loop
31876  CImg<T> visu0(*this), visu;
31877  bool init = true, clicked = false, redraw = true;
31878  unsigned int key = 0;
31879  int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
31880  disp.show().flush();
31881 
31882  while (!disp.is_closed && !key) {
31883 
31884  // Init object position and scale if necessary
31885  if (init) {
31886  ratio = delta>0?(2.0f*cimg::min(disp.width,disp.height)/(3.0f*delta)):0;
31887  dx = 0.5f*(xM + xm); dy = 0.5f*(yM + ym); dz = 0.5f*(zM + zm);
31888  if (centering) {
31889  cimg_forX(centered_vertices,l) {
31890  centered_vertices(l,0) = (float)((vertices(l,0) - dx)*ratio);
31891  centered_vertices(l,1) = (float)((vertices(l,1) - dy)*ratio);
31892  centered_vertices(l,2) = (float)((vertices(l,2) - dz)*ratio);
31893  }
31894  }
31895 
31896  if (render_static<0 || render_motion<0) {
31897  rotated_bbox_vertices = bbox_vertices.assign(8,3,1,1,
31898  xm,xM,xM,xm,xm,xM,xM,xm,
31899  ym,ym,yM,yM,ym,ym,yM,yM,
31900  zm,zm,zm,zm,zM,zM,zM,zM);
31901  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);
31902  bbox_colors.assign(6,dim,1,1,1,background_color[0]);
31903  bbox_colors2.assign(6,dim,1,1,1,foreground_color[0]);
31904  bbox_opacities.assign(bbox_colors.width,1,1,1,0.3f);
31905  }
31906 
31907  if (!pose) {
31908  if (pose_matrix) pose = CImg<floatT>(pose_matrix,4,4,1,1,false);
31909  else pose = CImg<floatT>::identity_matrix(4);
31910  }
31911  init = false;
31912  redraw = true;
31913  }
31914 
31915  // Rotate and Draw 3D object
31916  if (redraw) {
31917  const float
31918  r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0),
31919  r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1),
31920  r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2);
31921  if ((clicked && render_motion>=0) || (!clicked && render_static>=0)) {
31922  if (centering) cimg_forX(centered_vertices,l) {
31923  const float x = centered_vertices(l,0), y = centered_vertices(l,1), z = centered_vertices(l,2);
31924  rotated_vertices(l,0) = r00*x + r10*y + r20*z + r30;
31925  rotated_vertices(l,1) = r01*x + r11*y + r21*z + r31;
31926  rotated_vertices(l,2) = r02*x + r12*y + r22*z + r32;
31927  } else cimg_forX(vertices,l) {
31928  const float
31929  x = (float)vertices(l,0),
31930  y = (float)vertices(l,1),
31931  z = (float)vertices(l,2);
31932  rotated_vertices(l,0) = r00*x + r10*y + r20*z + r30;
31933  rotated_vertices(l,1) = r01*x + r11*y + r21*z + r31;
31934  rotated_vertices(l,2) = r02*x + r12*y + r22*z + r32;
31935  }
31936  } else {
31937  if (!centering) cimg_forX(bbox_vertices,l) {
31938  const float x = bbox_vertices(l,0), y = bbox_vertices(l,1), z = bbox_vertices(l,2);
31939  rotated_bbox_vertices(l,0) = r00*x + r10*y + r20*z + r30;
31940  rotated_bbox_vertices(l,1) = r01*x + r11*y + r21*z + r31;
31941  rotated_bbox_vertices(l,2) = r02*x + r12*y + r22*z + r32;
31942  } else cimg_forX(bbox_vertices,l) {
31943  const float x = (bbox_vertices(l,0) - dx)*ratio, y = (bbox_vertices(l,1) - dy)*ratio, z = (bbox_vertices(l,2) - dz)*ratio;
31944  rotated_bbox_vertices(l,0) = r00*x + r10*y + r20*z + r30;
31945  rotated_bbox_vertices(l,1) = r01*x + r11*y + r21*z + r31;
31946  rotated_bbox_vertices(l,2) = r02*x + r12*y + r22*z + r32;
31947  }
31948  }
31949 
31950  // Draw object
31951  visu = visu0;
31952  if ((clicked && render_motion<0) || (!clicked && render_static<0))
31953  visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_vertices,bbox_primitives,bbox_colors,bbox_opacities,2,false,focale).
31954  draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_vertices,bbox_primitives,bbox_colors2,1,false,focale);
31955  else visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,
31956  rotated_vertices,primitives,ncolors,opacities,clicked?render_motion:render_static,
31957  double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
31958  (!clicked && render_static>0)?zbuffer.fill(0):CImg<floatT>::empty());
31959 
31960  // Draw axes
31961  if (display_axes) {
31962  const float Xaxes = 25, Yaxes = visu.height - 35.0f;
31963  cimg_forX(axes_vertices,l) {
31964  const float x = axes_vertices(l,0), y = axes_vertices(l,1), z = axes_vertices(l,2);
31965  rotated_axes_vertices(l,0) = r00*x + r10*y + r20*z;
31966  rotated_axes_vertices(l,1) = r01*x + r11*y + r21*z;
31967  rotated_axes_vertices(l,2) = r02*x + r12*y + r22*z;
31968  }
31969  axes_opacities(0,0) = (rotated_axes_vertices(1,2)>0)?0.5f:1.0f;
31970  axes_opacities(1,0) = (rotated_axes_vertices(2,2)>0)?0.5f:1.0f;
31971  axes_opacities(2,0) = (rotated_axes_vertices(3,2)>0)?0.5f:1.0f;
31972  visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_vertices,axes_primitives,axes_colors,axes_opacities,1,false,focale).
31973  draw_text((int)(Xaxes+rotated_axes_vertices(4,0)),
31974  (int)(Yaxes+rotated_axes_vertices(4,1)),
31975  "X",axes_colors[0].data,0,axes_opacities(0,0),11).
31976  draw_text((int)(Xaxes+rotated_axes_vertices(5,0)),
31977  (int)(Yaxes+rotated_axes_vertices(5,1)),
31978  "Y",axes_colors[1].data,0,axes_opacities(1,0),11).
31979  draw_text((int)(Xaxes+rotated_axes_vertices(6,0)),
31980  (int)(Yaxes+rotated_axes_vertices(6,1)),
31981  "Z",axes_colors[2].data,0,axes_opacities(2,0),11);
31982  }
31983  visu.display(disp);
31984  if (!clicked || render_motion==render_static) redraw = false;
31985  }
31986 
31987  // Handle user interaction
31988  disp.wait();
31989  if ((disp.button || disp.wheel) && disp.mouse_x>=0 && disp.mouse_y>=0) {
31990  redraw = true;
31991  if (!clicked) { x0 = x1 = disp.mouse_x; y0 = y1 = disp.mouse_y; if (!disp.wheel) clicked = true; }
31992  else { x1 = disp.mouse_x; y1 = disp.mouse_y; }
31993  if (disp.button&1) {
31994  const float
31995  R = 0.45f*cimg::min(disp.width,disp.height),
31996  R2 = R*R,
31997  u0 = (float)(x0-disp.dimx()/2),
31998  v0 = (float)(y0-disp.dimy()/2),
31999  u1 = (float)(x1-disp.dimx()/2),
32000  v1 = (float)(y1-disp.dimy()/2),
32001  n0 = (float)std::sqrt(u0*u0+v0*v0),
32002  n1 = (float)std::sqrt(u1*u1+v1*v1),
32003  nu0 = n0>R?(u0*R/n0):u0,
32004  nv0 = n0>R?(v0*R/n0):v0,
32005  nw0 = (float)std::sqrt(cimg::max(0,R2-nu0*nu0-nv0*nv0)),
32006  nu1 = n1>R?(u1*R/n1):u1,
32007  nv1 = n1>R?(v1*R/n1):v1,
32008  nw1 = (float)std::sqrt(cimg::max(0,R2-nu1*nu1-nv1*nv1)),
32009  u = nv0*nw1-nw0*nv1,
32010  v = nw0*nu1-nu0*nw1,
32011  w = nv0*nu1-nu0*nv1,
32012  n = (float)std::sqrt(u*u+v*v+w*w),
32013  alpha = (float)std::asin(n/R2);
32014  rot_mat = CImg<floatT>::rotation_matrix(u,v,w,alpha);
32015  rot_mat *= pose.get_crop(0,0,2,2);
32016  pose.draw_image(rot_mat);
32017  x0=x1; y0=y1;
32018  }
32019  if (disp.button&2) { pose(3,2)+=(y1-y0); x0 = x1; y0 = y1; }
32020  if (disp.wheel) { pose(3,2)-=focale*disp.wheel/10; disp.wheel = 0; }
32021  if (disp.button&4) { pose(3,0)+=(x1-x0); pose(3,1)+=(y1-y0); x0 = x1; y0 = y1; }
32022  if ((disp.button&1) && (disp.button&2)) { init = true; disp.button = 0; x0 = x1; y0 = y1; pose = CImg<floatT>::identity_matrix(4); }
32023  } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; }
32024 
32025  switch (key = disp.key) {
32026  case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
32027  case cimg::keyD: if (disp.is_keyCTRLLEFT) {
32028  disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
32029  CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
32030  disp.key = key = 0;
32031  } break;
32032  case cimg::keyC : if (disp.is_keyCTRLLEFT) {
32033  disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
32034  disp.key = key = 0;
32035  } break;
32036  case cimg::keyR : if (disp.is_keyCTRLLEFT) {
32038  disp.key = key = 0;
32039  } break;
32040  case cimg::keyF : if (disp.is_keyCTRLLEFT) {
32041  if (!ns_width || !ns_height ||
32042  ns_width>(unsigned int)disp.screen_dimx() || ns_height>(unsigned int)disp.screen_dimy()) {
32043  ns_width = disp.screen_dimx()*3U/4;
32044  ns_height = disp.screen_dimy()*3U/4;
32045  }
32046  if (disp.is_fullscreen) disp.resize(ns_width,ns_height,false);
32047  else {
32048  ns_width = (unsigned int)disp.width; ns_height = disp.height;
32049  disp.resize(disp.screen_dimx(),disp.screen_dimy(),false);
32050  }
32051  disp.toggle_fullscreen().is_resized = true;
32052  disp.key = key = 0;
32053  } break;
32054  case cimg::keyZ : if (disp.is_keyCTRLLEFT) { // Enable/Disable Z-buffer
32055  if (zbuffer) zbuffer.assign();
32056  else zbuffer.assign(disp.width,disp.height,1,1,0);
32057  disp.key = key = 0; redraw = true;
32058  } break;
32059  case cimg::keyS : if (disp.is_keyCTRLLEFT) { // Save snapshot
32060  static unsigned int snap_number = 0;
32061  char filename[32] = { 0 };
32062  std::FILE *file;
32063  do {
32064  std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
32065  if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
32066  } while (file);
32067  (+visu).draw_text(2,2,"Saving BMP snapshot...",foreground_color,background_color,1,11).display(disp);
32068  visu.save(filename);
32069  visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
32070  disp.key = key = 0;
32071  } break;
32072  case cimg::keyO : if (disp.is_keyCTRLLEFT) { // Save object as an .OFF file
32073  static unsigned int snap_number = 0;
32074  char filename[32] = { 0 };
32075  std::FILE *file;
32076  do {
32077  std::sprintf(filename,"CImg_%.4u.off",snap_number++);
32078  if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
32079  } while (file);
32080  visu.draw_text(2,2,"Saving object...",foreground_color,background_color,1,11).display(disp);
32081  vertices.save_off(filename,primitives,ncolors);
32082  visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
32083  disp.key = key = 0;
32084  } break;
32085 #ifdef cimg_use_board
32086  case cimg::keyP : if (disp.is_keyCTRLLEFT) { // Save object as a .EPS file
32087  static unsigned int snap_number = 0;
32088  char filename[32] = { 0 };
32089  std::FILE *file;
32090  do {
32091  std::sprintf(filename,"CImg_%.4u.eps",snap_number++);
32092  if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
32093  } while (file);
32094  visu.draw_text(2,2,"Saving EPS snapshot...",foreground_color,background_color,1,11).display(disp);
32095  LibBoard::Board board;
32096  (+visu).draw_object3d(board,visu.width/2.0f,visu.height/2.0f,0,
32097  rotated_vertices,primitives,ncolors,opacities,clicked?render_motion:render_static,
32098  double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
32099  zbuffer.fill(0));
32100  board.saveEPS(filename);
32101  visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
32102  disp.key = key = 0;
32103  } break;
32104  case cimg::keyV : if (disp.is_keyCTRLLEFT) { // Save object as a .SVG file
32105  static unsigned int snap_number = 0;
32106  char filename[32] = { 0 };
32107  std::FILE *file;
32108  do {
32109  std::sprintf(filename,"CImg_%.4u.svg",snap_number++);
32110  if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
32111  } while (file);
32112  visu.draw_text(2,2,"Saving SVG snapshot...",foreground_color,background_color,1,11).display(disp);
32113  LibBoard::Board board;
32114  (+visu).draw_object3d(board,visu.width/2.0f,visu.height/2.0f,0,
32115  rotated_vertices,primitives,ncolors,opacities,clicked?render_motion:render_static,
32116  double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
32117  zbuffer.fill(0));
32118  board.saveSVG(filename);
32119  visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
32120  disp.key = key = 0;
32121  } break;
32122 #endif
32123  }
32124  if (disp.is_resized) { disp.resize(false); visu0 = get_resize(disp,1); if (zbuffer) zbuffer.assign(disp.width,disp.height); redraw = true; }
32125  }
32126  if (pose_matrix) std::memcpy(pose_matrix,pose.data,16*sizeof(float));
32127  disp.button = 0;
32128  disp.key = key;
32129  return *this;
32130  }
32131 
32134  const unsigned int plot_type=1, const unsigned int vertex_type=1,
32135  const char *const labelx=0, const double xmin=0, const double xmax=0,
32136  const char *const labely=0, const double ymin=0, const double ymax=0) const {
32137  if (is_empty())
32138  throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
32139  pixel_type(),width,height,depth,dim,data);
32140  const unsigned int siz = width*height*depth, onormalization = disp.normalization;
32141  if (!disp) { char ntitle[64] = { 0 }; std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
32142  disp.show().flush().normalization = 0;
32143  double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax;
32144  if (nxmin==nxmax) { nxmin = 0; nxmax = siz; }
32145  int x0 = 0, x1 = dimx()*dimy()*dimz()-1, key = 0;
32146 
32147  for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
32148  if (reset_view) { x0 = 0; x1 = dimx()*dimy()*dimz()-1; y0 = ymin; y1 = ymax; reset_view = false; }
32149  CImg<T> zoom(x1-x0+1,1,1,dimv());
32150  cimg_forV(*this,k) zoom.get_shared_channel(k) = CImg<T>(ptr(x0,0,0,k),x1-x0+1,1,1,1,true);
32151 
32152  if (y0==y1) y0 = zoom.minmax(y1);
32153  if (y0==y1) { --y0; ++y1; }
32154  const CImg<intT> selection = zoom.get_select_graph(disp,plot_type,vertex_type,
32155  labelx,nxmin + x0*(nxmax-nxmin)/siz,nxmin + (x1+1)*(nxmax-nxmin)/siz,
32156  labely,y0,y1);
32157 
32158  const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
32159  if (selection[0]>=0 && selection[2]>=0) {
32160  x1 = x0 + selection[2];
32161  x0 += selection[0];
32162  if (x0==x1) reset_view = true;
32163  if (selection[1]>=0 && selection[3]>=0) {
32164  y0 = y1 - selection[3]*(y1-y0)/(disp.dimy()-32);
32165  y1 -= selection[1]*(y1-y0)/(disp.dimy()-32);
32166  }
32167  } else {
32168  bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false;
32169  switch (key = disp.key) {
32170  case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
32171  case cimg::keyPADADD : go_in = true; key = 0; break;
32172  case cimg::keyPADSUB : go_out = true; key = 0; break;
32173  case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; key = 0; break;
32174  case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; key = 0; break;
32175  case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; key = 0; break;
32176  case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; key = 0; break;
32177  case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; break;
32178  case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; break;
32179  case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; break;
32180  case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; break;
32181  }
32182  if (disp.wheel) go_out = !(go_in = disp.wheel>0);
32183 
32184  if (go_in) {
32185  const int
32186  xsiz = x1 - x0,
32187  mx = (mouse_x-16)*xsiz/(disp.dimx()-32),
32188  cx = x0 + (mx<0?0:(mx>=xsiz?xsiz:mx));
32189  if (x1-x0>4) {
32190  x0 = cx - 7*(cx-x0)/8; x1 = cx + 7*(x1-cx)/8;
32191  if (disp.is_keyCTRLLEFT) {
32192  const double
32193  ysiz = y1 - y0,
32194  my = (mouse_y-16)*ysiz/(disp.dimy()-32),
32195  cy = y1 - (my<0?0:(my>=ysiz?ysiz:my));
32196  y0 = cy - 7*(cy-y0)/8; y1 = cy + 7*(y1-cy)/8;
32197  } else y0 = y1 = 0;
32198  }
32199  }
32200  if (go_out) {
32201  const int deltax = (x1-x0)/8, ndeltax = deltax?deltax:(siz>1?1:0);
32202  x0-=ndeltax; x1+=ndeltax;
32203  if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz-1; }
32204  if (x1>=(int)siz) { x0-=(x1-siz+1); x1 = (int)siz-1; if (x0<0) x0 = 0; }
32205  if (disp.is_keyCTRLLEFT) {
32206  const double deltay = (y1-y0)/8, ndeltay = deltay?deltay:0.01;
32207  y0-=ndeltay; y1+=ndeltay;
32208  }
32209  }
32210  if (go_left) {
32211  const int delta = (x1-x0)/5, ndelta = delta?delta:1;
32212  if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
32213  else { x1-=x0; x0 = 0; }
32214  go_left = false;
32215  }
32216  if (go_right) {
32217  const int delta = (x1-x0)/5, ndelta = delta?delta:1;
32218  if (x1+ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; }
32219  else { x0+=(siz-1-x1); x1 = siz-1; }
32220  go_right = false;
32221  }
32222  if (go_up) {
32223  const double delta = (y1-y0)/10, ndelta = delta?delta:1;
32224  y0+=ndelta; y1+=ndelta;
32225  go_up = false;
32226  }
32227  if (go_down) {
32228  const double delta = (y1-y0)/10, ndelta = delta?delta:1;
32229  y0-=ndelta; y1-=ndelta;
32230  go_down = false;
32231  }
32232  }
32233  }
32234  disp.normalization = onormalization;
32235  return *this;
32236  }
32237 
32239  const CImg<T>& display_graph(const char *const title=0,
32240  const unsigned int plot_type=1, const unsigned int vertex_type=1,
32241  const char *const labelx=0, const double xmin=0, const double xmax=0,
32242  const char *const labely=0, const double ymin=0, const double ymax=0) const {
32243  if (is_empty())
32244  throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
32245  pixel_type(),width,height,depth,dim,data);
32246  char ntitle[64] = { 0 }; if (!title) std::sprintf(ntitle,"CImg<%s>",pixel_type());
32247  CImgDisplay disp(cimg_fitscreen(640,480,1),title?title:ntitle,0);
32248  return display_graph(disp,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax);
32249  }
32250 
32252 
32256  const CImg<T>& save(const char *const filename, const int number=-1) const {
32257  if (is_empty())
32258  throw CImgInstanceException("CImg<%s>::save() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32259  pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32260  if (!filename)
32261  throw CImgArgumentException("CImg<%s>::save() : Instance image (%u,%u,%u,%u,%p) cannot be saved as a (null) filename.",
32262  pixel_type(),width,height,depth,dim,data);
32263  const char *ext = cimg::split_filename(filename);
32264  char nfilename[1024] = { 0 };
32265  const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
32266 #ifdef cimg_save_plugin
32267  cimg_save_plugin(fn);
32268 #endif
32269 #ifdef cimg_save_plugin1
32270  cimg_save_plugin1(fn);
32271 #endif
32272 #ifdef cimg_save_plugin2
32273  cimg_save_plugin2(fn);
32274 #endif
32275 #ifdef cimg_save_plugin3
32276  cimg_save_plugin3(fn);
32277 #endif
32278 #ifdef cimg_save_plugin4
32279  cimg_save_plugin4(fn);
32280 #endif
32281 #ifdef cimg_save_plugin5
32282  cimg_save_plugin5(fn);
32283 #endif
32284 #ifdef cimg_save_plugin6
32285  cimg_save_plugin6(fn);
32286 #endif
32287 #ifdef cimg_save_plugin7
32288  cimg_save_plugin7(fn);
32289 #endif
32290 #ifdef cimg_save_plugin8
32291  cimg_save_plugin8(fn);
32292 #endif
32293  // ASCII formats
32294  if (!cimg::strcasecmp(ext,"asc")) return save_ascii(fn);
32295  if (!cimg::strcasecmp(ext,"dlm") ||
32296  !cimg::strcasecmp(ext,"txt")) return save_dlm(fn);
32297  if (!cimg::strcasecmp(ext,"cpp") ||
32298  !cimg::strcasecmp(ext,"hpp") ||
32299  !cimg::strcasecmp(ext,"h") ||
32300  !cimg::strcasecmp(ext,"c")) return save_cpp(fn);
32301 
32302  // 2D binary formats
32303  if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(fn);
32304  if (!cimg::strcasecmp(ext,"jpg") ||
32305  !cimg::strcasecmp(ext,"jpeg") ||
32306  !cimg::strcasecmp(ext,"jpe") ||
32307  !cimg::strcasecmp(ext,"jfif") ||
32308  !cimg::strcasecmp(ext,"jif")) return save_jpeg(fn);
32309  if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(fn);
32310  if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(fn);
32311  if (!cimg::strcasecmp(ext,"png")) return save_png(fn);
32312  if (!cimg::strcasecmp(ext,"pgm") ||
32313  !cimg::strcasecmp(ext,"ppm") ||
32314  !cimg::strcasecmp(ext,"pnm")) return save_pnm(fn);
32315  if (!cimg::strcasecmp(ext,"tif") ||
32316  !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
32317 
32318  // 3D binary formats
32319  if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
32320  if (!cimg::strcasecmp(ext,"cimg") || !*ext) return save_cimg(fn,false);
32321  if (!cimg::strcasecmp(ext,"dcm")) return save_medcon_external(fn);
32322  if (!cimg::strcasecmp(ext,"hdr") ||
32323  !cimg::strcasecmp(ext,"nii")) return save_analyze(fn);
32324  if (!cimg::strcasecmp(ext,"inr")) return save_inr(fn);
32325  if (!cimg::strcasecmp(ext,"pan")) return save_pandore(fn);
32326  if (!cimg::strcasecmp(ext,"raw")) return save_raw(fn);
32327 
32328  // Archive files
32329  if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
32330 
32331  // Image sequences
32332  if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
32333  if (!cimg::strcasecmp(ext,"avi") ||
32334  !cimg::strcasecmp(ext,"mov") ||
32335  !cimg::strcasecmp(ext,"asf") ||
32336  !cimg::strcasecmp(ext,"divx") ||
32337  !cimg::strcasecmp(ext,"flv") ||
32338  !cimg::strcasecmp(ext,"mpg") ||
32339  !cimg::strcasecmp(ext,"m1v") ||
32340  !cimg::strcasecmp(ext,"m2v") ||
32341  !cimg::strcasecmp(ext,"m4v") ||
32342  !cimg::strcasecmp(ext,"mjp") ||
32343  !cimg::strcasecmp(ext,"mkv") ||
32344  !cimg::strcasecmp(ext,"mpe") ||
32345  !cimg::strcasecmp(ext,"movie") ||
32346  !cimg::strcasecmp(ext,"ogm") ||
32347  !cimg::strcasecmp(ext,"qt") ||
32348  !cimg::strcasecmp(ext,"rm") ||
32349  !cimg::strcasecmp(ext,"vob") ||
32350  !cimg::strcasecmp(ext,"wmv") ||
32351  !cimg::strcasecmp(ext,"xvid") ||
32352  !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
32353  return save_other(fn);
32354  }
32355 
32356  // Save the image as an ASCII file (ASCII Raw + simple header) (internal).
32357  const CImg<T>& _save_ascii(std::FILE *const file, const char *const filename) const {
32358  if (is_empty())
32359  throw CImgInstanceException("CImg<%s>::save_ascii() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32360  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32361  if (!file && !filename)
32362  throw CImgArgumentException("CImg<%s>::save_ascii() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32363  pixel_type(),width,height,depth,dim,data);
32364  std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
32365  std::fprintf(nfile,"%u %u %u %u\n",width,height,depth,dim);
32366  const T* ptrs = data;
32367  cimg_forYZV(*this,y,z,v) {
32368  cimg_forX(*this,x) std::fprintf(nfile,"%g ",(double)*(ptrs++));
32369  std::fputc('\n',nfile);
32370  }
32371  if (!file) cimg::fclose(nfile);
32372  return *this;
32373  }
32374 
32376  const CImg<T>& save_ascii(const char *const filename) const {
32377  return _save_ascii(0,filename);
32378  }
32379 
32381  const CImg<T>& save_ascii(std::FILE *const file) const {
32382  return _save_ascii(file,0);
32383  }
32384 
32385  // Save the image as a C or CPP source file (internal).
32386  const CImg<T>& _save_cpp(std::FILE *const file, const char *const filename) const {
32387  if (!file && !filename)
32388  throw CImgArgumentException("CImg<%s>::save_cpp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32389  pixel_type(),width,height,depth,dim,data);
32390  if (is_empty())
32391  throw CImgInstanceException("CImg<%s>::save_cpp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32392  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32393  std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
32394  char varname[1024] = { 0 };
32395  if (filename) std::sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname);
32396  if (!*varname) std::sprintf(varname,"unnamed");
32397  std::fprintf(nfile,
32398  "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n"
32399  "%s data_%s[] = { \n ",
32400  varname,width,height,depth,dim,pixel_type(),pixel_type(),varname);
32401  for (unsigned int off = 0, siz = size()-1; off<=siz; ++off) {
32402  std::fprintf(nfile,cimg::type<T>::format(),cimg::type<T>::format((*this)[off]));
32403  if (off==siz) std::fprintf(nfile," };\n");
32404  else if (!((off+1)%16)) std::fprintf(nfile,",\n ");
32405  else std::fprintf(nfile,", ");
32406  }
32407  if (!file) cimg::fclose(nfile);
32408  return *this;
32409  }
32410 
32412  const CImg<T>& save_cpp(const char *const filename) const {
32413  return _save_cpp(0,filename);
32414  }
32415 
32417  const CImg<T>& save_cpp(std::FILE *const file) const {
32418  return _save_cpp(file,0);
32419  }
32420 
32421  // Save the image as a DLM file (internal).
32422  const CImg<T>& _save_dlm(std::FILE *const file, const char *const filename) const {
32423  if (is_empty())
32424  throw CImgInstanceException("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32425  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32426  if (!file && !filename)
32427  throw CImgArgumentException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32428  pixel_type(),width,height,depth,dim,data);
32429  if (depth>1)
32430  cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Pixel values along Z will be unrolled.",
32431  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32432  if (dim>1)
32433  cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. "
32434  "Pixel values along V will be unrolled.",
32435  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32436 
32437  std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
32438  const T* ptrs = data;
32439  cimg_forYZV(*this,y,z,v) {
32440  cimg_forX(*this,x) std::fprintf(nfile,"%g%s",(double)*(ptrs++),(x==dimx()-1)?"":",");
32441  std::fputc('\n',nfile);
32442  }
32443  if (!file) cimg::fclose(nfile);
32444  return *this;
32445  }
32446 
32448  const CImg<T>& save_dlm(const char *const filename) const {
32449  return _save_dlm(0,filename);
32450  }
32451 
32453  const CImg<T>& save_dlm(std::FILE *const file) const {
32454  return _save_dlm(file,0);
32455  }
32456 
32457  // Save the image as a BMP file (internal).
32458  const CImg<T>& _save_bmp(std::FILE *const file, const char *const filename) const {
32459  if (is_empty())
32460  throw CImgInstanceException("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32461  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32462  if (!file && !filename)
32463  throw CImgArgumentException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32464  pixel_type(),width,height,depth,dim,data);
32465  if (depth>1)
32466  cimg::warn("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
32467  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32468  if (dim>3)
32469  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.",
32470  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32471 
32472  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
32473  unsigned char header[54] = { 0 }, align_buf[4] = { 0 };
32474  const unsigned int
32475  align = (4 - (3*width)%4)%4,
32476  buf_size = (3*width+align)*dimy(),
32477  file_size = 54 + buf_size;
32478  header[0] = 'B'; header[1] = 'M';
32479  header[0x02] = file_size&0xFF;
32480  header[0x03] = (file_size>>8)&0xFF;
32481  header[0x04] = (file_size>>16)&0xFF;
32482  header[0x05] = (file_size>>24)&0xFF;
32483  header[0x0A] = 0x36;
32484  header[0x0E] = 0x28;
32485  header[0x12] = width&0xFF;
32486  header[0x13] = (width>>8)&0xFF;
32487  header[0x14] = (width>>16)&0xFF;
32488  header[0x15] = (width>>24)&0xFF;
32489  header[0x16] = height&0xFF;
32490  header[0x17] = (height>>8)&0xFF;
32491  header[0x18] = (height>>16)&0xFF;
32492  header[0x19] = (height>>24)&0xFF;
32493  header[0x1A] = 1;
32494  header[0x1B] = 0;
32495  header[0x1C] = 24;
32496  header[0x1D] = 0;
32497  header[0x22] = buf_size&0xFF;
32498  header[0x23] = (buf_size>>8)&0xFF;
32499  header[0x24] = (buf_size>>16)&0xFF;
32500  header[0x25] = (buf_size>>24)&0xFF;
32501  header[0x27] = 0x1;
32502  header[0x2B] = 0x1;
32503  cimg::fwrite(header,54,nfile);
32504 
32505  const T
32506  *pR = ptr(0,height-1,0,0),
32507  *pG = (dim>=2)?ptr(0,height-1,0,1):0,
32508  *pB = (dim>=3)?ptr(0,height-1,0,2):0;
32509 
32510  switch (dim) {
32511  case 1 : {
32512  cimg_forY(*this,y) { cimg_forX(*this,x) {
32513  const unsigned char val = (unsigned char)*(pR++);
32514  std::fputc(val,nfile); std::fputc(val,nfile); std::fputc(val,nfile);
32515  }
32516  cimg::fwrite(align_buf,align,nfile);
32517  pR-=2*width;
32518  }} break;
32519  case 2 : {
32520  cimg_forY(*this,y) { cimg_forX(*this,x) {
32521  std::fputc(0,nfile);
32522  std::fputc((unsigned char)(*(pG++)),nfile);
32523  std::fputc((unsigned char)(*(pR++)),nfile);
32524  }
32525  cimg::fwrite(align_buf,align,nfile);
32526  pR-=2*width; pG-=2*width;
32527  }} break;
32528  default : {
32529  cimg_forY(*this,y) { cimg_forX(*this,x) {
32530  std::fputc((unsigned char)(*(pB++)),nfile);
32531  std::fputc((unsigned char)(*(pG++)),nfile);
32532  std::fputc((unsigned char)(*(pR++)),nfile);
32533  }
32534  cimg::fwrite(align_buf,align,nfile);
32535  pR-=2*width; pG-=2*width; pB-=2*width;
32536  }
32537  }
32538  }
32539  if (!file) cimg::fclose(nfile);
32540  return *this;
32541  }
32542 
32544  const CImg<T>& save_bmp(const char *const filename) const {
32545  return _save_bmp(0,filename);
32546  }
32547 
32549  const CImg<T>& save_bmp(std::FILE *const file) const {
32550  return _save_bmp(file,0);
32551  }
32552 
32553  // Save a file in JPEG format (internal).
32554  const CImg<T>& _save_jpeg(std::FILE *const file, const char *const filename, const unsigned int quality) const {
32555  if (is_empty())
32556  throw CImgInstanceException("CImg<%s>::save_jpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32557  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32558  if (!file && !filename)
32559  throw CImgArgumentException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32560  pixel_type(),width,height,depth,dim,data);
32561  if (depth>1)
32562  cimg::warn("CImg<%s>::save_jpeg() : File '%s, instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
32563  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32564 #ifndef cimg_use_jpeg
32565  if (!file) return save_other(filename,quality);
32566  else throw CImgIOException("CImg<%s>::save_jpeg() : Cannot save a JPEG image in a *FILE output. Use libjpeg instead.",
32567  pixel_type());
32568 #else
32569  // Fill pixel buffer
32570  unsigned char *buf;
32571  unsigned int dimbuf = 0;
32572  J_COLOR_SPACE colortype = JCS_RGB;
32573  switch (dim) {
32574  case 1 : { // Greyscale images
32575  unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=1)];
32576  colortype = JCS_GRAYSCALE;
32577  const T *ptr_g = data;
32578  cimg_forXY(*this,x,y) *(buf2++) = (unsigned char)*(ptr_g++);
32579  } break;
32580  case 2 : { // RG images
32581  unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
32582  const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1);
32583  colortype = JCS_RGB;
32584  cimg_forXY(*this,x,y) {
32585  *(buf2++) = (unsigned char)*(ptr_r++);
32586  *(buf2++) = (unsigned char)*(ptr_g++);
32587  *(buf2++) = 0;
32588  }
32589  } break;
32590  case 3 : { // RGB images
32591  unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
32592  const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
32593  colortype = JCS_RGB;
32594  cimg_forXY(*this,x,y) {
32595  *(buf2++) = (unsigned char)*(ptr_r++);
32596  *(buf2++) = (unsigned char)*(ptr_g++);
32597  *(buf2++) = (unsigned char)*(ptr_b++);
32598  }
32599  } break;
32600  default : { // CMYK images
32601  unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=4)];
32602  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);
32603  colortype = JCS_CMYK;
32604  cimg_forXY(*this,x,y) {
32605  *(buf2++) = (unsigned char)*(ptr_r++);
32606  *(buf2++) = (unsigned char)*(ptr_g++);
32607  *(buf2++) = (unsigned char)*(ptr_b++);
32608  *(buf2++) = (unsigned char)*(ptr_a++);
32609  }
32610  }
32611  }
32612 
32613  // Call libjpeg functions
32614  struct jpeg_compress_struct cinfo;
32615  struct jpeg_error_mgr jerr;
32616  cinfo.err = jpeg_std_error(&jerr);
32617  jpeg_create_compress(&cinfo);
32618  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
32619  jpeg_stdio_dest(&cinfo,nfile);
32620  cinfo.image_width = width;
32621  cinfo.image_height = height;
32622  cinfo.input_components = dimbuf;
32623  cinfo.in_color_space = colortype;
32624  jpeg_set_defaults(&cinfo);
32625  jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
32626  jpeg_start_compress(&cinfo,TRUE);
32627 
32628  const unsigned int row_stride = width*dimbuf;
32629  JSAMPROW row_pointer[1];
32630  while (cinfo.next_scanline < cinfo.image_height) {
32631  row_pointer[0] = &buf[cinfo.next_scanline*row_stride];
32632  jpeg_write_scanlines(&cinfo,row_pointer,1);
32633  }
32634  jpeg_finish_compress(&cinfo);
32635 
32636  delete[] buf;
32637  if (!file) cimg::fclose(nfile);
32638  jpeg_destroy_compress(&cinfo);
32639  return *this;
32640 #endif
32641  }
32642 
32644  const CImg<T>& save_jpeg(const char *const filename, const unsigned int quality=100) const {
32645  return _save_jpeg(0,filename,quality);
32646  }
32647 
32649  const CImg<T>& save_jpeg(std::FILE *const file, const unsigned int quality=100) const {
32650  return _save_jpeg(file,0,quality);
32651  }
32652 
32654  const CImg<T>& save_magick(const char *const filename, const unsigned int bytes_per_pixel=0) const {
32655  if (is_empty())
32656  throw CImgInstanceException("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32657  pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32658  if (!filename)
32659  throw CImgArgumentException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32660  pixel_type(),width,height,depth,dim,data);
32661  unsigned int foo = bytes_per_pixel; foo = 0;
32662 #ifdef cimg_use_magick
32663  double stmin, stmax = (double)maxmin(stmin);
32664  if (depth>1)
32665  cimg::warn("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
32666  pixel_type(),filename,width,height,depth,dim,data);
32667  if (dim>3)
32668  cimg::warn("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved.",
32669  pixel_type(),filename,width,height,depth,dim,data);
32670  if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536)
32671  cimg::warn("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) has pixel values in [%g,%g]. Probable type overflow.",
32672  pixel_type(),filename,width,height,depth,dim,data,stmin,stmax);
32673  Magick::Image image(Magick::Geometry(width,height),"black");
32674  image.type(Magick::TrueColorType);
32675  image.depth(bytes_per_pixel?(8*bytes_per_pixel):(stmax>=256?16:8));
32676  const T
32677  *rdata = ptr(0,0,0,0),
32678  *gdata = dim>1?ptr(0,0,0,1):0,
32679  *bdata = dim>2?ptr(0,0,0,2):0;
32680  Magick::PixelPacket *pixels = image.getPixels(0,0,width,height);
32681  switch (dim) {
32682  case 1 : // Scalar images
32683  for (unsigned int off = width*height; off; --off) {
32684  pixels->red = pixels->green = pixels->blue = (Magick::Quantum)*(rdata++);
32685  ++pixels;
32686  }
32687  break;
32688  case 2 : // RG images
32689  for (unsigned int off = width*height; off; --off) {
32690  pixels->red = (Magick::Quantum)*(rdata++);
32691  pixels->green = (Magick::Quantum)*(gdata++);
32692  pixels->blue = 0; ++pixels;
32693  }
32694  break;
32695  default : // RGB images
32696  for (unsigned int off = width*height; off; --off) {
32697  pixels->red = (Magick::Quantum)*(rdata++);
32698  pixels->green = (Magick::Quantum)*(gdata++);
32699  pixels->blue = (Magick::Quantum)*(bdata++);
32700  ++pixels;
32701  }
32702  }
32703  image.syncPixels();
32704  image.write(filename);
32705 #else
32706  throw CImgIOException("CImg<%s>::save_magick() : File '%s', Magick++ library has not been linked.",
32707  pixel_type(),filename);
32708 #endif
32709  return *this;
32710  }
32711 
32712  // Save an image to a PNG file (internal).
32713  // Most of this function has been written by Eric Fausett
32714  const CImg<T>& _save_png(std::FILE *const file, const char *const filename, const unsigned int bytes_per_pixel=0) const {
32715  if (is_empty())
32716  throw CImgInstanceException("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32717  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32718  if (!filename)
32719  throw CImgArgumentException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32720  pixel_type(),width,height,depth,dim,data);
32721  if (depth>1)
32722  cimg::warn("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
32723  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32724  unsigned int foo = bytes_per_pixel; foo = 0;
32725 #ifndef cimg_use_png
32726  if (!file) return save_other(filename);
32727  else throw CImgIOException("CImg<%s>::save_png() : Cannot save a PNG image in a *FILE output. You must use 'libpng' to do this instead.",
32728  pixel_type());
32729 #else
32730  const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
32731  std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb");
32732 
32733  double stmin, stmax = (double)maxmin(stmin);
32734  if (depth>1)
32735  cimg::warn("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
32736  pixel_type(),filename,width,height,depth,dim,data);
32737  if (dim>3)
32738  cimg::warn("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved.",
32739  pixel_type(),filename,width,height,depth,dim,data);
32740  if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536)
32741  cimg::warn("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) has pixel values in [%g,%g]. Probable type overflow.",
32742  pixel_type(),filename,width,height,depth,dim,data,stmin,stmax);
32743 
32744  // Setup PNG structures for write
32745  png_voidp user_error_ptr = 0;
32746  png_error_ptr user_error_fn = 0, user_warning_fn = 0;
32747  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn, user_warning_fn);
32748  if(!png_ptr){
32749  if (!file) cimg::fclose(nfile);
32750  throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'png_ptr' data structure.",
32751  pixel_type(),nfilename?nfilename:"(FILE*)");
32752  }
32753  png_infop info_ptr = png_create_info_struct(png_ptr);
32754  if (!info_ptr) {
32755  png_destroy_write_struct(&png_ptr,(png_infopp)0);
32756  if (!file) cimg::fclose(nfile);
32757  throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'info_ptr' data structure.",
32758  pixel_type(),nfilename?nfilename:"(FILE*)");
32759  }
32760  if (setjmp(png_jmpbuf(png_ptr))) {
32761  png_destroy_write_struct(&png_ptr, &info_ptr);
32762  if (!file) cimg::fclose(nfile);
32763  throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
32764  pixel_type(),nfilename?nfilename:"(FILE*)");
32765  }
32766  png_init_io(png_ptr, nfile);
32767  png_uint_32 width = dimx(), height = dimy();
32768  const int bit_depth = bytes_per_pixel?(bytes_per_pixel*8):(stmax>=256?16:8);
32769  int color_type;
32770  switch (dimv()) {
32771  case 1 : color_type = PNG_COLOR_TYPE_GRAY; break;
32772  case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
32773  case 3 : color_type = PNG_COLOR_TYPE_RGB; break;
32774  default : color_type = PNG_COLOR_TYPE_RGB_ALPHA;
32775  }
32776  const int interlace_type = PNG_INTERLACE_NONE;
32777  const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
32778  const int filter_method = PNG_FILTER_TYPE_DEFAULT;
32779  png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type,compression_type, filter_method);
32780  png_write_info(png_ptr, info_ptr);
32781  const int byte_depth = bit_depth>>3;
32782  const int numChan = dimv()>4?4:dimv();
32783  const int pixel_bit_depth_flag = numChan * (bit_depth-1);
32784 
32785  // Allocate Memory for Image Save and Fill pixel data
32786  png_bytep *imgData = new png_byte*[height];
32787  for (unsigned int row = 0; row<height; ++row) imgData[row] = new png_byte[byte_depth*numChan*width];
32788  const T *pC0 = ptr(0,0,0,0);
32789  switch (pixel_bit_depth_flag) {
32790  case 7 : { // Gray 8-bit
32791  cimg_forY(*this,y) {
32792  unsigned char *ptrd = imgData[y];
32793  cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++);
32794  }
32795  } break;
32796  case 14 : { // Gray w/ Alpha 8-bit
32797  const T *pC1 = ptr(0,0,0,1);
32798  cimg_forY(*this,y) {
32799  unsigned char *ptrd = imgData[y];
32800  cimg_forX(*this,x) {
32801  *(ptrd++) = (unsigned char)*(pC0++);
32802  *(ptrd++) = (unsigned char)*(pC1++);
32803  }
32804  }
32805  } break;
32806  case 21 : { // RGB 8-bit
32807  const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
32808  cimg_forY(*this,y) {
32809  unsigned char *ptrd = imgData[y];
32810  cimg_forX(*this,x) {
32811  *(ptrd++) = (unsigned char)*(pC0++);
32812  *(ptrd++) = (unsigned char)*(pC1++);
32813  *(ptrd++) = (unsigned char)*(pC2++);
32814  }
32815  }
32816  } break;
32817  case 28 : { // RGB x/ Alpha 8-bit
32818  const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
32819  cimg_forY(*this,y){
32820  unsigned char *ptrd = imgData[y];
32821  cimg_forX(*this,x){
32822  *(ptrd++) = (unsigned char)*(pC0++);
32823  *(ptrd++) = (unsigned char)*(pC1++);
32824  *(ptrd++) = (unsigned char)*(pC2++);
32825  *(ptrd++) = (unsigned char)*(pC3++);
32826  }
32827  }
32828  } break;
32829  case 15 : { // Gray 16-bit
32830  cimg_forY(*this,y){
32831  unsigned short *ptrd = (unsigned short*)(imgData[y]);
32832  cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++);
32833  if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],width);
32834  }
32835  } break;
32836  case 30 : { // Gray w/ Alpha 16-bit
32837  const T *pC1 = ptr(0,0,0,1);
32838  cimg_forY(*this,y){
32839  unsigned short *ptrd = (unsigned short*)(imgData[y]);
32840  cimg_forX(*this,x) {
32841  *(ptrd++) = (unsigned short)*(pC0++);
32842  *(ptrd++) = (unsigned short)*(pC1++);
32843  }
32844  if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*width);
32845  }
32846  } break;
32847  case 45 : { // RGB 16-bit
32848  const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
32849  cimg_forY(*this,y) {
32850  unsigned short *ptrd = (unsigned short*)(imgData[y]);
32851  cimg_forX(*this,x) {
32852  *(ptrd++) = (unsigned short)*(pC0++);
32853  *(ptrd++) = (unsigned short)*(pC1++);
32854  *(ptrd++) = (unsigned short)*(pC2++);
32855  }
32856  if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*width);
32857  }
32858  } break;
32859  case 60 : { // RGB w/ Alpha 16-bit
32860  const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
32861  cimg_forY(*this,y) {
32862  unsigned short *ptrd = (unsigned short*)(imgData[y]);
32863  cimg_forX(*this,x) {
32864  *(ptrd++) = (unsigned short)*(pC0++);
32865  *(ptrd++) = (unsigned short)*(pC1++);
32866  *(ptrd++) = (unsigned short)*(pC2++);
32867  *(ptrd++) = (unsigned short)*(pC3++);
32868  }
32869  if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*width);
32870  }
32871  } break;
32872  default :
32873  if (!file) cimg::fclose(nfile);
32874  throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
32875  pixel_type(),nfilename?nfilename:"(FILE*)");
32876  }
32877  png_write_image(png_ptr, imgData);
32878  png_write_end(png_ptr, info_ptr);
32879  png_destroy_write_struct(&png_ptr, &info_ptr);
32880 
32881  // Deallocate Image Write Memory
32882  cimg_forY(*this,n) delete[] imgData[n];
32883  delete[] imgData;
32884  if (!file) cimg::fclose(nfile);
32885  return *this;
32886 #endif
32887  }
32888 
32890  const CImg<T>& save_png(const char *const filename, const unsigned int bytes_per_pixel=0) const {
32891  return _save_png(0,filename,bytes_per_pixel);
32892  }
32893 
32895  const CImg<T>& save_png(std::FILE *const file, const unsigned int bytes_per_pixel=0) const {
32896  return _save_png(file,0,bytes_per_pixel);
32897  }
32898 
32899  // Save the image as a PNM file (internal function).
32900  const CImg<T>& _save_pnm(std::FILE *const file, const char *const filename, const unsigned int bytes_per_pixel=0) const {
32901  if (!file && !filename)
32902  throw CImgArgumentException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32903  pixel_type(),width,height,depth,dim,data);
32904  if (is_empty())
32905  throw CImgInstanceException("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32906  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32907  double stmin, stmax = (double)maxmin(stmin);
32908  if (depth>1)
32909  cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
32910  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32911  if (dim>3)
32912  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.",
32913  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32914  if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536)
32915  cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) has pixel values in [%g,%g]. Probable type overflow.",
32916  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data,stmin,stmax);
32917  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
32918  const T
32919  *ptrR = ptr(0,0,0,0),
32920  *ptrG = (dim>=2)?ptr(0,0,0,1):0,
32921  *ptrB = (dim>=3)?ptr(0,0,0,2):0;
32922  const unsigned int buf_size = width*height*(dim==1?1:3);
32923 
32924  std::fprintf(nfile,"P%c\n# CREATOR: CImg Library (original size = %ux%ux%ux%u)\n%u %u\n%u\n",
32925  (dim==1?'5':'6'),width,height,depth,dim,width,height,stmax<256?255:(stmax<4096?4095:65535));
32926 
32927  switch (dim) {
32928  case 1 : { // Scalar image
32929  if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PGM 8 bits
32930  unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
32931  cimg_forXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++);
32932  cimg::fwrite(ptrd,buf_size,nfile);
32933  delete[] ptrd;
32934  } else { // Binary PGM 16 bits
32935  unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
32936  cimg_forXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++);
32937  if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
32938  cimg::fwrite(ptrd,buf_size,nfile);
32939  delete[] ptrd;
32940  }
32941  } break;
32942  case 2 : { // RG image
32943  if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits
32944  unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
32945  cimg_forXY(*this,x,y) {
32946  *(xptrd++) = (unsigned char)*(ptrR++);
32947  *(xptrd++) = (unsigned char)*(ptrG++);
32948  *(xptrd++) = 0;
32949  }
32950  cimg::fwrite(ptrd,buf_size,nfile);
32951  delete[] ptrd;
32952  } else { // Binary PPM 16 bits
32953  unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
32954  cimg_forXY(*this,x,y) {
32955  *(xptrd++) = (unsigned short)*(ptrR++);
32956  *(xptrd++) = (unsigned short)*(ptrG++);
32957  *(xptrd++) = 0;
32958  }
32959  if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
32960  cimg::fwrite(ptrd,buf_size,nfile);
32961  delete[] ptrd;
32962  }
32963  } break;
32964  default : { // RGB image
32965  if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits
32966  unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
32967  cimg_forXY(*this,x,y) {
32968  *(xptrd++) = (unsigned char)*(ptrR++);
32969  *(xptrd++) = (unsigned char)*(ptrG++);
32970  *(xptrd++) = (unsigned char)*(ptrB++);
32971  }
32972  cimg::fwrite(ptrd,buf_size,nfile);
32973  delete[] ptrd;
32974  } else { // Binary PPM 16 bits
32975  unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
32976  cimg_forXY(*this,x,y) {
32977  *(xptrd++) = (unsigned short)*(ptrR++);
32978  *(xptrd++) = (unsigned short)*(ptrG++);
32979  *(xptrd++) = (unsigned short)*(ptrB++);
32980  }
32981  if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
32982  cimg::fwrite(ptrd,buf_size,nfile);
32983  delete[] ptrd;
32984  }
32985  }
32986  }
32987  if (!file) cimg::fclose(nfile);
32988  return *this;
32989  }
32990 
32992  const CImg<T>& save_pnm(const char *const filename, const unsigned int bytes_per_pixel=0) const {
32993  return _save_pnm(0,filename,bytes_per_pixel);
32994  }
32995 
32997  const CImg<T>& save_pnm(std::FILE *const file, const unsigned int bytes_per_pixel=0) const {
32998  return _save_pnm(file,0,bytes_per_pixel);
32999  }
33000 
33001  // Save the image as a RGB file (internal).
33002  const CImg<T>& _save_rgb(std::FILE *const file, const char *const filename) const {
33003  if (is_empty())
33004  throw CImgInstanceException("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33005  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
33006  if (!file && !filename)
33007  throw CImgArgumentException("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
33008  pixel_type(),width,height,depth,dim,data);
33009  if (dim!=3)
33010  cimg::warn("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) has not exactly 3 channels.",
33011  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
33012  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
33013  const unsigned int wh = width*height;
33014  unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer;
33015  const T
33016  *ptr1 = ptr(0,0,0,0),
33017  *ptr2 = dim>1?ptr(0,0,0,1):0,
33018  *ptr3 = dim>2?ptr(0,0,0,2):0;
33019  switch (dim) {
33020  case 1 : { // Scalar image
33021  for (unsigned int k = 0; k<wh; ++k) {
33022  const unsigned char val = (unsigned char)*(ptr1++);
33023  *(nbuffer++) = val;
33024  *(nbuffer++) = val;
33025  *(nbuffer++) = val;
33026  }} break;
33027  case 2 : { // RG image
33028  for (unsigned int k = 0; k<wh; ++k) {
33029  *(nbuffer++) = (unsigned char)(*(ptr1++));
33030  *(nbuffer++) = (unsigned char)(*(ptr2++));
33031  *(nbuffer++) = 0;
33032  }} break;
33033  default : { // RGB image
33034  for (unsigned int k = 0; k<wh; ++k) {
33035  *(nbuffer++) = (unsigned char)(*(ptr1++));
33036  *(nbuffer++) = (unsigned char)(*(ptr2++));
33037  *(nbuffer++) = (unsigned char)(*(ptr3++));
33038  }
33039  }
33040  }
33041  cimg::fwrite(buffer,3*wh,nfile);
33042  if (!file) cimg::fclose(nfile);
33043  delete[] buffer;
33044  return *this;
33045  }
33046 
33048  const CImg<T>& save_rgb(const char *const filename) const {
33049  return _save_rgb(0,filename);
33050  }
33051 
33053  const CImg<T>& save_rgb(std::FILE *const file) const {
33054  return _save_rgb(file,0);
33055  }
33056 
33057  // Save the image as a RGBA file (internal).
33058  const CImg<T>& _save_rgba(std::FILE *const file, const char *const filename) const {
33059  if (is_empty())
33060  throw CImgInstanceException("CImg<%s>::save_rgba() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33061  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
33062  if (!file && !filename)
33063  throw CImgArgumentException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
33064  pixel_type(),width,height,depth,dim,data);
33065  if (dim!=4)
33066  cimg::warn("CImg<%s>::save_rgba() : File '%s, instance image (%u,%u,%u,%u,%p) has not exactly 4 channels.",
33067  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
33068  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
33069  const unsigned int wh = width*height;
33070  unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer;
33071  const T
33072  *ptr1 = ptr(0,0,0,0),
33073  *ptr2 = dim>1?ptr(0,0,0,1):0,
33074  *ptr3 = dim>2?ptr(0,0,0,2):0,
33075  *ptr4 = dim>3?ptr(0,0,0,3):0;
33076  switch (dim) {
33077  case 1 : { // Scalar images
33078  for (unsigned int k = 0; k<wh; ++k) {
33079  const unsigned char val = (unsigned char)*(ptr1++);
33080  *(nbuffer++) = val;
33081  *(nbuffer++) = val;
33082  *(nbuffer++) = val;
33083  *(nbuffer++) = 255;
33084  }} break;
33085  case 2 : { // RG images
33086  for (unsigned int k = 0; k<wh; ++k) {
33087  *(nbuffer++) = (unsigned char)(*(ptr1++));
33088  *(nbuffer++) = (unsigned char)(*(ptr2++));
33089  *(nbuffer++) = 0;
33090  *(nbuffer++) = 255;
33091  }} break;
33092  case 3 : { // RGB images
33093  for (unsigned int k = 0; k<wh; ++k) {
33094  *(nbuffer++) = (unsigned char)(*(ptr1++));
33095  *(nbuffer++) = (unsigned char)(*(ptr2++));
33096  *(nbuffer++) = (unsigned char)(*(ptr3++));
33097  *(nbuffer++) = 255;
33098  }} break;
33099  default : { // RGBA images
33100  for (unsigned int k = 0; k<wh; ++k) {
33101  *(nbuffer++) = (unsigned char)(*(ptr1++));
33102  *(nbuffer++) = (unsigned char)(*(ptr2++));
33103  *(nbuffer++) = (unsigned char)(*(ptr3++));
33104  *(nbuffer++) = (unsigned char)(*(ptr4++));
33105  }
33106  }
33107  }
33108  cimg::fwrite(buffer,4*wh,nfile);
33109  if (!file) cimg::fclose(nfile);
33110  delete[] buffer;
33111  return *this;
33112  }
33113 
33115  const CImg<T>& save_rgba(const char *const filename) const {
33116  return _save_rgba(0,filename);
33117  }
33118 
33120  const CImg<T>& save_rgba(std::FILE *const file) const {
33121  return _save_rgba(file,0);
33122  }
33123 
33124  // Save a plane into a tiff file
33125 #ifdef cimg_use_tiff
33126 
33127 #define _cimg_save_tif(types,typed) \
33128  if (!std::strcmp(types,pixel_type())) { const typed foo = (typed)0; return _save_tiff(tif,directory,foo); }
33129 
33130  template<typename t>
33131  const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const t& pixel_t) const {
33132  if (is_empty() || !tif || pixel_t) return *this;
33133  const char *const filename = TIFFFileName(tif);
33134  uint32 rowsperstrip = (uint32)-1;
33135  uint16 spp = dim, bpp = sizeof(t)*8, photometric, compression = COMPRESSION_NONE;
33136  if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB;
33137  else photometric = PHOTOMETRIC_MINISBLACK;
33138  TIFFSetDirectory(tif,directory);
33139  TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,width);
33140  TIFFSetField(tif,TIFFTAG_IMAGELENGTH,height);
33141  TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
33142  TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp);
33143  if (cimg::type<t>::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3);
33144  else if (cimg::type<t>::min()==0) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,1);
33145  else TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,2);
33146  TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp);
33147  TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
33148  TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric);
33149  TIFFSetField(tif,TIFFTAG_COMPRESSION,compression);
33150  rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip);
33151  TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip);
33152  TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB);
33153  TIFFSetField(tif,TIFFTAG_SOFTWARE,"CImg");
33154  t *const buf = (t*)_TIFFmalloc(TIFFStripSize(tif));
33155  if (buf) {
33156  for (unsigned int row = 0; row<height; row+=rowsperstrip) {
33157  uint32 nrow = (row + rowsperstrip>height?height-row:rowsperstrip);
33158  tstrip_t strip = TIFFComputeStrip(tif,row,0);
33159  tsize_t i = 0;
33160  for (unsigned int rr = 0; rr<nrow; ++rr)
33161  for (unsigned int cc = 0; cc<width; ++cc)
33162  for (unsigned int vv = 0; vv<spp; ++vv)
33163  buf[i++] = (t)(*this)(cc,row + rr,0,vv);
33164  if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(t))<0)
33165  throw CImgException("CImg<%s>::save_tiff() : File '%s', an error has occured while writing a strip.",
33166  pixel_type(),filename?filename:"(FILE*)");
33167  }
33168  _TIFFfree(buf);
33169  }
33170  TIFFWriteDirectory(tif);
33171  return (*this);
33172  }
33173 
33174  const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory) const {
33175  typedef unsigned char uchar;
33176  typedef unsigned short ushort;
33177  typedef unsigned int uint;
33178  typedef unsigned long ulong;
33179  _cimg_save_tif("bool",uchar);
33180  _cimg_save_tif("char",char);
33181  _cimg_save_tif("unsigned char",uchar);
33182  _cimg_save_tif("short",short);
33183  _cimg_save_tif("unsigned short",ushort);
33184  _cimg_save_tif("int",int);
33185  _cimg_save_tif("unsigned int",uint);
33186  _cimg_save_tif("long",int);
33187  _cimg_save_tif("unsigned long",uint);
33188  _cimg_save_tif("float",float);
33189  _cimg_save_tif("double",float);
33190  const char *const filename = TIFFFileName(tif);
33191  throw CImgException("CImg<%s>::save_tiff() : File '%s', pixel type is not supported.",
33192  pixel_type(),filename?filename:"(FILE*)");
33193  return *this;
33194  }
33195 #endif
33196 
33198  const CImg<T>& save_tiff(const char *const filename) const {
33199  if (is_empty())
33200  throw CImgInstanceException("CImg<%s>::save_tiff() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33201  pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
33202  if (!filename)
33203  throw CImgArgumentException("CImg<%s>::save_tiff() : Specified filename is (null) for instance image (%u,%u,%u,%u,%p).",
33204  pixel_type(),width,height,depth,dim,data);
33205 #ifdef cimg_use_tiff
33206  TIFF *tif = TIFFOpen(filename,"w");
33207  if (tif) {
33208  cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z);
33209  TIFFClose(tif);
33210  } else throw CImgException("CImg<%s>::save_tiff() : File '%s', error while opening file stream for writing.",
33211  pixel_type(),filename);
33212 #else
33213  return save_other(filename);
33214 #endif
33215  return *this;
33216  }
33217 
33219  const CImg<T>& save_analyze(const char *const filename, const float *const voxsize=0) const {
33220  if (is_empty())
33221  throw CImgInstanceException("CImg<%s>::save_analyze() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33222  pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
33223  if (!filename)
33224  throw CImgArgumentException("CImg<%s>::save_analyze() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
33225  pixel_type(),width,height,depth,dim,data);
33226  std::FILE *file;
33227  char header[348] = { 0 }, hname[1024] = { 0 }, iname[1024] = { 0 };
33228  const char *ext = cimg::split_filename(filename);
33229  short datatype=-1;
33230  std::memset(header,0,348);
33231  if (!ext[0]) { std::sprintf(hname,"%s.hdr",filename); std::sprintf(iname,"%s.img",filename); }
33232  if (!cimg::strncasecmp(ext,"hdr",3)) {
33233  std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(iname+std::strlen(iname)-3,"img");
33234  }
33235  if (!cimg::strncasecmp(ext,"img",3)) {
33236  std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(hname+std::strlen(iname)-3,"hdr");
33237  }
33238  if (!cimg::strncasecmp(ext,"nii",3)) {
33239  std::strcpy(hname,filename); iname[0] = 0;
33240  }
33241  ((int*)(header))[0] = 348;
33242  std::sprintf(header+4,"CImg");
33243  std::sprintf(header+14," ");
33244  ((short*)(header+36))[0] = 4096;
33245  ((char*)(header+38))[0] = 114;
33246  ((short*)(header+40))[0] = 4;
33247  ((short*)(header+40))[1] = width;
33248  ((short*)(header+40))[2] = height;
33249  ((short*)(header+40))[3] = depth;
33250  ((short*)(header+40))[4] = dim;
33251  if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2;
33252  if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2;
33253  if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2;
33254  if (!cimg::strcasecmp(pixel_type(),"unsigned short")) datatype = 4;
33255  if (!cimg::strcasecmp(pixel_type(),"short")) datatype = 4;
33256  if (!cimg::strcasecmp(pixel_type(),"unsigned int")) datatype = 8;
33257  if (!cimg::strcasecmp(pixel_type(),"int")) datatype = 8;
33258  if (!cimg::strcasecmp(pixel_type(),"unsigned long")) datatype = 8;
33259  if (!cimg::strcasecmp(pixel_type(),"long")) datatype = 8;
33260  if (!cimg::strcasecmp(pixel_type(),"float")) datatype = 16;
33261  if (!cimg::strcasecmp(pixel_type(),"double")) datatype = 64;
33262  if (datatype<0)
33263  throw CImgIOException("CImg<%s>::save_analyze() : Cannot save image '%s' since pixel type (%s)"
33264  "is not handled in Analyze7.5 specifications.\n",
33265  pixel_type(),filename,pixel_type());
33266  ((short*)(header+70))[0] = datatype;
33267  ((short*)(header+72))[0] = sizeof(T);
33268  ((float*)(header+112))[0] = 1;
33269  ((float*)(header+76))[0] = 0;
33270  if (voxsize) {
33271  ((float*)(header+76))[1] = voxsize[0];
33272  ((float*)(header+76))[2] = voxsize[1];
33273  ((float*)(header+76))[3] = voxsize[2];
33274  } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1;
33275  file = cimg::fopen(hname,"wb");
33276  cimg::fwrite(header,348,file);
33277  if (iname[0]) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); }
33278  cimg::fwrite(data,size(),file);
33279  cimg::fclose(file);
33280  return *this;
33281  }
33282 
33284  const CImg<T>& save_cimg(const char *const filename, const bool compress=false) const {
33285  CImgList<T>(*this,true).save_cimg(filename,compress);
33286  return *this;
33287  }
33288 
33289  // Save the image as a .cimg file.
33290  const CImg<T>& save_cimg(std::FILE *const file, const bool compress=false) const {
33291  CImgList<T>(*this,true).save_cimg(file,compress);
33292  return *this;
33293  }
33294 
33296  const CImg<T>& save_cimg(const char *const filename,
33297  const unsigned int n0,
33298  const unsigned int x0, const unsigned int y0,
33299  const unsigned int z0, const unsigned int v0) const {
33300  CImgList<T>(*this,true).save_cimg(filename,n0,x0,y0,z0,v0);
33301  return *this;
33302  }
33303 
33305  const CImg<T>& save_cimg(std::FILE *const file,
33306  const unsigned int n0,
33307  const unsigned int x0, const unsigned int y0,
33308  const unsigned int z0, const unsigned int v0) const {
33309  CImgList<T>(*this,true).save_cimg(file,n0,x0,y0,z0,v0);
33310  return *this;
33311  }
33312 
33314  static void save_empty_cimg(const char *const filename,
33315  const unsigned int dx, const unsigned int dy=1,
33316  const unsigned int dz=1, const unsigned int dv=1) {
33317  return CImgList<T>::save_empty_cimg(filename,1,dx,dy,dz,dv);
33318  }
33319 
33321  static void save_empty_cimg(std::FILE *const file,
33322  const unsigned int dx, const unsigned int dy=1,
33323  const unsigned int dz=1, const unsigned int dv=1) {
33324  return CImgList<T>::save_empty_cimg(file,1,dx,dy,dz,dv);
33325  }
33326 
33327  // Save the image as an INRIMAGE-4 file (internal).
33328  const CImg<T>& _save_inr(std::FILE *const file, const char *const filename, const float *const voxsize) const {
33329  if (is_empty())
33330  throw CImgInstanceException("CImg<%s>::save_inr() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33331  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
33332  if (!filename)
33333  throw CImgArgumentException("CImg<%s>::save_inr() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
33334  pixel_type(),width,height,depth,dim,data);
33335  int inrpixsize=-1;
33336  const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0";
33337  if (!cimg::strcasecmp(pixel_type(),"unsigned char")) { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
33338  if (!cimg::strcasecmp(pixel_type(),"char")) { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
33339  if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; }
33340  if (!cimg::strcasecmp(pixel_type(),"short")) { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; }
33341  if (!cimg::strcasecmp(pixel_type(),"unsigned int")) { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; }
33342  if (!cimg::strcasecmp(pixel_type(),"int")) { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; }
33343  if (!cimg::strcasecmp(pixel_type(),"float")) { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; }
33344  if (!cimg::strcasecmp(pixel_type(),"double")) { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; }
33345  if (inrpixsize<=0)
33346  throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of '%s'",
33347  pixel_type(),pixel_type());
33348  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
33349  char header[257] = { 0 };
33350  int err = std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim);
33351  if (voxsize) err += std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]);
33352  err += std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm");
33353  std::memset(header+err,'\n',252-err);
33354  std::memcpy(header+252,"##}\n",4);
33355  cimg::fwrite(header,256,nfile);
33356  cimg_forXYZ(*this,x,y,z) cimg_forV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),1,nfile);
33357  if (!file) cimg::fclose(nfile);
33358  return *this;
33359  }
33360 
33362  const CImg<T>& save_inr(const char *const filename, const float *const voxsize=0) const {
33363  return _save_inr(0,filename,voxsize);
33364  }
33365 
33367  const CImg<T>& save_inr(std::FILE *const file, const float *const voxsize=0) const {
33368  return _save_inr(file,0,voxsize);
33369  }
33370 
33371  // Save the image as a PANDORE-5 file (internal).
33372  unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const {
33373  unsigned int nbdims = 0;
33374  if (id==2 || id==3 || id==4) { dims[0] = 1; dims[1] = width; nbdims = 2; }
33375  if (id==5 || id==6 || id==7) { dims[0] = 1; dims[1] = height; dims[2] = width; nbdims=3; }
33376  if (id==8 || id==9 || id==10) { dims[0] = dim; dims[1] = depth; dims[2] = height; dims[3] = width; nbdims = 4; }
33377  if (id==16 || id==17 || id==18) { dims[0] = 3; dims[1] = height; dims[2] = width; dims[3] = colorspace; nbdims = 4; }
33378  if (id==19 || id==20 || id==21) { dims[0] = 3; dims[1] = depth; dims[2] = height; dims[3] = width; dims[4] = colorspace; nbdims = 5; }
33379  if (id==22 || id==23 || id==25) { dims[0] = dim; dims[1] = width; nbdims = 2; }
33380  if (id==26 || id==27 || id==29) { dims[0] = dim; dims[1] = height; dims[2] = width; nbdims=3; }
33381  if (id==30 || id==31 || id==33) { dims[0] = dim; dims[1] = depth; dims[2] = height; dims[3] = width; nbdims = 4; }
33382  return nbdims;
33383  }
33384 
33385  const CImg<T>& _save_pandore(std::FILE *const file, const char *const filename, const unsigned int colorspace) const {
33386  typedef unsigned char uchar;
33387  typedef unsigned short ushort;
33388  typedef unsigned int uint;
33389  typedef unsigned long ulong;
33390 
33391 #define __cimg_save_pandore_case(dtype) \
33392  dtype *buffer = new dtype[size()]; \
33393  const T *ptrs = data; \
33394  cimg_foroff(*this,off) *(buffer++) = (dtype)(*(ptrs++)); \
33395  buffer-=size(); \
33396  cimg::fwrite(buffer,size(),nfile); \
33397  delete[] buffer
33398 
33399 #define _cimg_save_pandore_case(sy,sz,sv,stype,id) \
33400  if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !std::strcmp(stype,pixel_type())) { \
33401  unsigned int *iheader = (unsigned int*)(header+12); \
33402  nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \
33403  cimg::fwrite(header,36,nfile); \
33404  if (sizeof(ulong)==4) { ulong ndims[5] = { 0 }; for (int d = 0; d<5; ++d) ndims[d] = (ulong)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
33405  else if (sizeof(uint)==4) { uint ndims[5] = { 0 }; for (int d = 0; d<5; ++d) ndims[d] = (uint)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
33406  else if (sizeof(ushort)==4) { ushort ndims[5] = { 0 }; for (int d = 0; d<5; ++d) ndims[d] = (ushort)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
33407  else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
33408  "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
33409  depth,dim,data); \
33410  if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
33411  __cimg_save_pandore_case(uchar); \
33412  } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
33413  if (sizeof(ulong)==4) { __cimg_save_pandore_case(ulong); } \
33414  else if (sizeof(uint)==4) { __cimg_save_pandore_case(uint); } \
33415  else if (sizeof(ushort)==4) { __cimg_save_pandore_case(ushort); } \
33416  else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
33417  "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
33418  depth,dim,data); \
33419  } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
33420  if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \
33421  else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \
33422  else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
33423  "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
33424  depth,dim,data); \
33425  } \
33426  saved = true; \
33427  }
33428 
33429  if (is_empty())
33430  throw CImgInstanceException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33431  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
33432  if (!file && !filename)
33433  throw CImgArgumentException("CImg<%s>::save_pandore() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
33434  pixel_type(),width,height,depth,dim,data);
33435  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
33436  unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
33437  0,0,0,0,'C','I','m','g',0,0,0,0,0,'N','o',' ','d','a','t','e',0,0,0,0 };
33438  unsigned int nbdims, dims[5] = { 0 };
33439  bool saved = false;
33440  _cimg_save_pandore_case(1,1,1,"unsigned char",2);
33441  _cimg_save_pandore_case(1,1,1,"char",3);
33442  _cimg_save_pandore_case(1,1,1,"short",3);
33443  _cimg_save_pandore_case(1,1,1,"unsigned short",3);
33444  _cimg_save_pandore_case(1,1,1,"unsigned int",3);
33445  _cimg_save_pandore_case(1,1,1,"int",3);
33446  _cimg_save_pandore_case(1,1,1,"unsigned long",4);
33447  _cimg_save_pandore_case(1,1,1,"long",3);
33448  _cimg_save_pandore_case(1,1,1,"float",4);
33449  _cimg_save_pandore_case(1,1,1,"double",4);
33450 
33451  _cimg_save_pandore_case(0,1,1,"unsigned char",5);
33452  _cimg_save_pandore_case(0,1,1,"char",6);
33453  _cimg_save_pandore_case(0,1,1,"short",6);
33454  _cimg_save_pandore_case(0,1,1,"unsigned short",6);
33455  _cimg_save_pandore_case(0,1,1,"unsigned int",6);
33456  _cimg_save_pandore_case(0,1,1,"int",6);
33457  _cimg_save_pandore_case(0,1,1,"unsigned long",7);
33458  _cimg_save_pandore_case(0,1,1,"long",6);
33459  _cimg_save_pandore_case(0,1,1,"float",7);
33460  _cimg_save_pandore_case(0,1,1,"double",7);
33461 
33462  _cimg_save_pandore_case(0,0,1,"unsigned char",8);
33463  _cimg_save_pandore_case(0,0,1,"char",9);
33464  _cimg_save_pandore_case(0,0,1,"short",9);
33465  _cimg_save_pandore_case(0,0,1,"unsigned short",9);
33466  _cimg_save_pandore_case(0,0,1,"unsigned int",9);
33467  _cimg_save_pandore_case(0,0,1,"int",9);
33468  _cimg_save_pandore_case(0,0,1,"unsigned long",10);
33469  _cimg_save_pandore_case(0,0,1,"long",9);
33470  _cimg_save_pandore_case(0,0,1,"float",10);
33471  _cimg_save_pandore_case(0,0,1,"double",10);
33472 
33473  _cimg_save_pandore_case(0,1,3,"unsigned char",16);
33474  _cimg_save_pandore_case(0,1,3,"char",17);
33475  _cimg_save_pandore_case(0,1,3,"short",17);
33476  _cimg_save_pandore_case(0,1,3,"unsigned short",17);
33477  _cimg_save_pandore_case(0,1,3,"unsigned int",17);
33478  _cimg_save_pandore_case(0,1,3,"int",17);
33479  _cimg_save_pandore_case(0,1,3,"unsigned long",18);
33480  _cimg_save_pandore_case(0,1,3,"long",17);
33481  _cimg_save_pandore_case(0,1,3,"float",18);
33482  _cimg_save_pandore_case(0,1,3,"double",18);
33483 
33484  _cimg_save_pandore_case(0,0,3,"unsigned char",19);
33485  _cimg_save_pandore_case(0,0,3,"char",20);
33486  _cimg_save_pandore_case(0,0,3,"short",20);
33487  _cimg_save_pandore_case(0,0,3,"unsigned short",20);
33488  _cimg_save_pandore_case(0,0,3,"unsigned int",20);
33489  _cimg_save_pandore_case(0,0,3,"int",20);
33490  _cimg_save_pandore_case(0,0,3,"unsigned long",21);
33491  _cimg_save_pandore_case(0,0,3,"long",20);
33492  _cimg_save_pandore_case(0,0,3,"float",21);
33493  _cimg_save_pandore_case(0,0,3,"double",21);
33494 
33495  _cimg_save_pandore_case(1,1,0,"unsigned char",22);
33496  _cimg_save_pandore_case(1,1,0,"char",23);
33497  _cimg_save_pandore_case(1,1,0,"short",23);
33498  _cimg_save_pandore_case(1,1,0,"unsigned short",23);
33499  _cimg_save_pandore_case(1,1,0,"unsigned int",23);
33500  _cimg_save_pandore_case(1,1,0,"int",23);
33501  _cimg_save_pandore_case(1,1,0,"unsigned long",25);
33502  _cimg_save_pandore_case(1,1,0,"long",23);
33503  _cimg_save_pandore_case(1,1,0,"float",25);
33504  _cimg_save_pandore_case(1,1,0,"double",25);
33505 
33506  _cimg_save_pandore_case(0,1,0,"unsigned char",26);
33507  _cimg_save_pandore_case(0,1,0,"char",27);
33508  _cimg_save_pandore_case(0,1,0,"short",27);
33509  _cimg_save_pandore_case(0,1,0,"unsigned short",27);
33510  _cimg_save_pandore_case(0,1,0,"unsigned int",27);
33511  _cimg_save_pandore_case(0,1,0,"int",27);
33512  _cimg_save_pandore_case(0,1,0,"unsigned long",29);
33513  _cimg_save_pandore_case(0,1,0,"long",27);
33514  _cimg_save_pandore_case(0,1,0,"float",29);
33515  _cimg_save_pandore_case(0,1,0,"double",29);
33516 
33517  _cimg_save_pandore_case(0,0,0,"unsigned char",30);
33518  _cimg_save_pandore_case(0,0,0,"char",31);
33519  _cimg_save_pandore_case(0,0,0,"short",31);
33520  _cimg_save_pandore_case(0,0,0,"unsigned short",31);
33521  _cimg_save_pandore_case(0,0,0,"unsigned int",31);
33522  _cimg_save_pandore_case(0,0,0,"int",31);
33523  _cimg_save_pandore_case(0,0,0,"unsigned long",33);
33524  _cimg_save_pandore_case(0,0,0,"long",31);
33525  _cimg_save_pandore_case(0,0,0,"float",33);
33526  _cimg_save_pandore_case(0,0,0,"double",33);
33527 
33528  if (!file) cimg::fclose(nfile);
33529  return *this;
33530  }
33531 
33533  const CImg<T>& save_pandore(const char *const filename, const unsigned int colorspace=0) const {
33534  return _save_pandore(0,filename,colorspace);
33535  }
33536 
33538  const CImg<T>& save_pandore(std::FILE *const file, const unsigned int colorspace=0) const {
33539  return _save_pandore(file,0,colorspace);
33540  }
33541 
33542  // Save the image as a RAW file (internal).
33543  const CImg<T>& _save_raw(std::FILE *const file, const char *const filename, const bool multiplexed) const {
33544  if (is_empty())
33545  throw CImgInstanceException("CImg<%s>::save_raw() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33546  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
33547  if (!file && !filename)
33548  throw CImgArgumentException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
33549  pixel_type(),width,height,depth,dim,data);
33550  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
33551  if (!multiplexed) cimg::fwrite(data,size(),nfile);
33552  else {
33553  CImg<T> buf(dim);
33554  cimg_forXYZ(*this,x,y,z) {
33555  cimg_forV(*this,k) buf[k] = (*this)(x,y,z,k);
33556  cimg::fwrite(buf.data,dim,nfile);
33557  }
33558  }
33559  if (!file) cimg::fclose(nfile);
33560  return *this;
33561  }
33562 
33564  const CImg<T>& save_raw(const char *const filename, const bool multiplexed=false) const {
33565  return _save_raw(0,filename,multiplexed);
33566  }
33567 
33569  const CImg<T>& save_raw(std::FILE *const file, const bool multiplexed=false) const {
33570  return _save_raw(file,0,multiplexed);
33571  }
33572 
33574  const CImg<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
33575  const unsigned int fps=25) const {
33576  if (is_empty())
33577  throw CImgInstanceException("CImg<%s>::save_ffmpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33578  pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
33579  if (!filename)
33580  throw CImgArgumentException("CImg<%s>::save_ffmpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
33581  pixel_type(),width,height,depth,dim,data);
33582  if (!fps)
33583  throw CImgArgumentException("CImg<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
33584  pixel_type(),filename);
33585 #ifndef cimg_use_ffmpeg
33586  return save_ffmpeg_external(filename,first_frame,last_frame);
33587 #else
33588  get_split('z').save_ffmpeg(filename,first_frame,last_frame,fps);
33589 #endif
33590  return *this;
33591  }
33592 
33594  const CImg<T>& save_yuv(const char *const filename, const bool rgb2yuv=true) const {
33595  get_split('z').save_yuv(filename,rgb2yuv);
33596  return *this;
33597  }
33598 
33600  const CImg<T>& save_yuv(std::FILE *const file, const bool rgb2yuv=true) const {
33601  get_split('z').save_yuv(file,rgb2yuv);
33602  return *this;
33603  }
33604 
33605  // Save OFF files (internal).
33606  template<typename tf, typename tc>
33607  const CImg<T>& _save_off(std::FILE *const file, const char *const filename,
33608  const CImgList<tf>& primitives, const CImgList<tc>& colors) const {
33609  if (is_empty())
33610  throw CImgInstanceException("CImg<%s>::save_off() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33611  pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
33612  if (!file && !filename)
33613  throw CImgArgumentException("CImg<%s>::save_off() : Specified filename is (null).",
33614  pixel_type());
33615  if (height<3) return get_resize(-100,3,1,1,0)._save_off(file,filename,primitives,colors);
33616  CImgList<tc> _colors;
33617  if (!colors) _colors.insert(primitives.width,CImg<tc>::vector(200,200,200));
33618  const CImgList<tc>& ncolors = colors?colors:_colors;
33619 
33620  std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
33621  std::fprintf(nfile,"OFF\n%u %u %u\n",width,primitives.width,3*primitives.width);
33622  cimg_forX(*this,i) std::fprintf(nfile,"%f %f %f\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2)));
33623  cimglist_for(primitives,l) {
33624  const unsigned int prim = primitives[l].size();
33625  const bool textured = (prim>4);
33626  const CImg<tc>& color = ncolors[l];
33627  const unsigned int s = textured?color.dimv():color.size();
33628  const float
33629  r = textured?(s>0?(float)(color.get_shared_channel(0).mean()/255.0f):1.0f):(s>0?(float)(color(0)/255.0f):1.0f),
33630  g = textured?(s>1?(float)(color.get_shared_channel(1).mean()/255.0f):r) :(s>1?(float)(color(1)/255.0f):r),
33631  b = textured?(s>2?(float)(color.get_shared_channel(2).mean()/255.0f):r) :(s>2?(float)(color(2)/255.0f):r);
33632 
33633  switch (prim) {
33634  case 1 :
33635  std::fprintf(nfile,"1 %u %f %f %f\n",(unsigned int)primitives(l,0),r,g,b);
33636  break;
33637  case 2 : case 6 :
33638  std::fprintf(nfile,"2 %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b);
33639  break;
33640  case 3 : case 9 :
33641  std::fprintf(nfile,"3 %u %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,2),
33642  (unsigned int)primitives(l,1),r,g,b);
33643  break;
33644  case 4 : case 12 :
33645  std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
33646  (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),(unsigned int)primitives(l,2),
33647  (unsigned int)primitives(l,1),r,g,b);
33648  break;
33649  }
33650  }
33651  if (!file) cimg::fclose(nfile);
33652  return *this;
33653  }
33654 
33656  template<typename tf, typename tc>
33657  const CImg<T>& save_off(const char *const filename,
33658  const CImgList<tf>& primitives, const CImgList<tc>& colors) const {
33659  return _save_off(0,filename,primitives,colors);
33660  }
33661 
33663  template<typename tf, typename tc>
33664  const CImg<T>& save_off(std::FILE *const file,
33665  const CImgList<tf>& primitives, const CImgList<tc>& colors) const {
33666  return _save_off(file,0,primitives,colors);
33667  }
33668 
33670  const CImg<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
33671  const char *const codec="mpeg2video") const {
33672  if (is_empty())
33673  throw CImgInstanceException("CImg<%s>::save_ffmpeg_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33674  pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
33675  if (!filename)
33676  throw CImgArgumentException("CImg<%s>::save_ffmpeg_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
33677  pixel_type(),width,height,depth,dim,data);
33678  get_split('z').save_ffmpeg_external(filename,first_frame,last_frame,codec);
33679  return *this;
33680  }
33681 
33683 
33689  const CImg<T>& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const {
33690  if (is_empty())
33691  throw CImgInstanceException("CImg<%s>::save_graphicsmagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33692  pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
33693  if (!filename)
33694  throw CImgArgumentException("CImg<%s>::save_graphicsmagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
33695  pixel_type(),width,height,depth,dim,data);
33696  char command[1024] = { 0 }, filetmp[512] = { 0 };
33697  std::FILE *file;
33698  do {
33699  if (dim==1) std::sprintf(filetmp,"%s%c%s.pgm",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
33700  else std::sprintf(filetmp,"%s%c%s.ppm",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
33701  if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
33702  } while (file);
33703  save_pnm(filetmp);
33704  std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::graphicsmagick_path(),quality,filetmp,filename);
33705  cimg::system(command);
33706  file = std::fopen(filename,"rb");
33707  if (!file)
33708  throw CImgIOException("CImg<%s>::save_graphicsmagick_external() : Failed to save image '%s'.\n\n"
33709  "Path of 'gm' : \"%s\"\n"
33710  "Path of temporary filename : \"%s\"\n",
33711  pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
33712  if (file) cimg::fclose(file);
33713  std::remove(filetmp);
33714  return *this;
33715  }
33716 
33718  const CImg<T>& save_gzip_external(const char *const filename) const {
33719  if (!filename)
33720  throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
33721  pixel_type());
33722  char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 };
33723  const char
33724  *ext = cimg::split_filename(filename,body),
33725  *ext2 = cimg::split_filename(body,0);
33726  std::FILE *file;
33727  do {
33728  if (!cimg::strcasecmp(ext,"gz")) {
33729  if (*ext2) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);
33730  else std::sprintf(filetmp,"%s%c%s.cimg",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
33731  } else {
33732  if (*ext) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);
33733  else std::sprintf(filetmp,"%s%c%s.cimg",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
33734  }
33735  if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
33736  } while (file);
33737  save(filetmp);
33738  std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
33739  cimg::system(command);
33740  file = std::fopen(filename,"rb");
33741  if (!file)
33742  throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
33743  pixel_type(),filename);
33744  else cimg::fclose(file);
33745  std::remove(filetmp);
33746  return *this;
33747  }
33748 
33750 
33756  const CImg<T>& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const {
33757  if (is_empty())
33758  throw CImgInstanceException("CImg<%s>::save_imagemagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33759  pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
33760  if (!filename)
33761  throw CImgArgumentException("CImg<%s>::save_imagemagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
33762  pixel_type(),width,height,depth,dim,data);
33763  char command[1024] = { 0 }, filetmp[512] = { 0 };
33764  std::FILE *file;
33765  do {
33766  std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),dim==1?"pgm":"ppm");
33767  if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
33768  } while (file);
33769  save_pnm(filetmp);
33770  std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::imagemagick_path(),quality,filetmp,filename);
33771  cimg::system(command);
33772  file = std::fopen(filename,"rb");
33773  if (!file)
33774  throw CImgIOException("CImg<%s>::save_imagemagick_external() : Failed to save image '%s'.\n\n"
33775  "Path of 'convert' : \"%s\"\n"
33776  "Path of temporary filename : \"%s\"\n",
33777  pixel_type(),filename,cimg::imagemagick_path(),filetmp);
33778  if (file) cimg::fclose(file);
33779  std::remove(filetmp);
33780  return *this;
33781  }
33782 
33784  const CImg<T>& save_medcon_external(const char *const filename) const {
33785  if (is_empty())
33786  throw CImgInstanceException("CImg<%s>::save_medcon_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33787  pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
33788  if (!filename)
33789  throw CImgArgumentException("CImg<%s>::save_medcon_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
33790  pixel_type(),width,height,depth,dim,data);
33791 
33792  char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 };
33793  std::FILE *file;
33794  do {
33795  std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
33796  if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
33797  } while (file);
33798  save_analyze(filetmp);
33799  std::sprintf(command,"%s -w -c dicom -o %s -f %s",cimg::medcon_path(),filename,filetmp);
33800  cimg::system(command);
33801  std::remove(filetmp);
33802  cimg::split_filename(filetmp,body);
33803  std::sprintf(filetmp,"%s.img",body);
33804  std::remove(filetmp);
33805  std::sprintf(command,"m000-%s",filename);
33806  file = std::fopen(command,"rb");
33807  if (!file) {
33808  cimg::fclose(cimg::fopen(filename,"r"));
33809  throw CImgIOException("CImg<%s>::save_medcon_external() : Failed to save image '%s'.\n\n"
33810  "Path of 'medcon' : \"%s\"\n"
33811  "Path of temporary filename : \"%s\"",
33812  pixel_type(),filename,cimg::medcon_path(),filetmp);
33813  } else cimg::fclose(file);
33814  std::rename(command,filename);
33815  return *this;
33816  }
33817 
33818  // Try to save the image if other extension is provided.
33819  const CImg<T>& save_other(const char *const filename, const unsigned int quality=100) const {
33820  if (is_empty())
33821  throw CImgInstanceException("CImg<%s>::save_other() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
33822  pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
33823  if (!filename)
33824  throw CImgIOException("CImg<%s>::save_other() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
33825  pixel_type());
33826  const unsigned int omode = cimg::exception_mode();
33827  bool is_saved = true;
33828  cimg::exception_mode() = 0;
33829  try { save_magick(filename); }
33830  catch (CImgException&) {
33831  try { save_imagemagick_external(filename,quality); }
33832  catch (CImgException&) {
33833  try { save_graphicsmagick_external(filename,quality); }
33834  catch (CImgException&) {
33835  is_saved = false;
33836  }
33837  }
33838  }
33839  cimg::exception_mode() = omode;
33840  if (!is_saved)
33841  throw CImgIOException("CImg<%s>::save_other() : File '%s' cannot be saved.\n"
33842  "Check you have either the ImageMagick or GraphicsMagick package installed.",
33843  pixel_type(),filename);
33844  return *this;
33845  }
33846 
33847  // Get a 40x38 color logo of a 'danger' item (internal).
33848  static CImg<T> logo40x38() {
33849  static bool first_time = true;
33850  static CImg<T> res(40,38,1,3);
33851  if (first_time) {
33852  const unsigned char *ptrs = cimg::logo40x38;
33853  T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2);
33854  for (unsigned int off = 0; off<res.width*res.height;) {
33855  const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++);
33856  for (unsigned int l = 0; l<n; ++off, ++l) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; }
33857  }
33858  first_time = false;
33859  }
33860  return res;
33861  }
33862 
33864  };
33865 
33866  /*
33867  #-----------------------------------------
33868  #
33869  #
33870  #
33871  # Definition of the CImgList<T> structure
33872  #
33873  #
33874  #
33875  #------------------------------------------
33876  */
33877 
33879  template<typename T>
33880  struct CImgList {
33881 
33883  unsigned int width;
33884 
33886  unsigned int allocated_width;
33887 
33890 
33892  typedef CImg<T>* iterator;
33893 
33895  typedef const CImg<T>* const_iterator;
33896 
33898  typedef T value_type;
33899 
33900  // Define common T-dependant types.
33918  typedef typename cimg::last<T,int>::type intT;
33923 
33925  //---------------------------
33926  //
33928 
33929  //---------------------------
33930 #ifdef cimglist_plugin
33931 #include cimglist_plugin
33932 #endif
33933 #ifdef cimglist_plugin1
33934 #include cimglist_plugin1
33935 #endif
33936 #ifdef cimglist_plugin2
33937 #include cimglist_plugin2
33938 #endif
33939 #ifdef cimglist_plugin3
33940 #include cimglist_plugin3
33941 #endif
33942 #ifdef cimglist_plugin4
33943 #include cimglist_plugin4
33944 #endif
33945 #ifdef cimglist_plugin5
33946 #include cimglist_plugin5
33947 #endif
33948 #ifdef cimglist_plugin6
33949 #include cimglist_plugin6
33950 #endif
33951 #ifdef cimglist_plugin7
33952 #include cimglist_plugin7
33953 #endif
33954 #ifdef cimglist_plugin8
33955 #include cimglist_plugin8
33956 #endif
33957 
33959  //--------------------------------------------------------
33960  //
33962 
33963  //--------------------------------------------------------
33964 
33967  if (data) delete[] data;
33968  }
33969 
33972  width(0),allocated_width(0),data(0) {}
33973 
33975  explicit CImgList(const unsigned int n):width(n) {
33977  }
33978 
33980  CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1,
33981  const unsigned int depth=1, const unsigned int dim=1):
33982  width(0),allocated_width(0),data(0) {
33983  assign(n);
33984  cimglist_apply(*this,assign)(width,height,depth,dim);
33985  }
33986 
33988  CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
33989  const unsigned int depth, const unsigned int dim, const T val):
33990  width(0),allocated_width(0),data(0) {
33991  assign(n);
33992  cimglist_apply(*this,assign)(width,height,depth,dim,val);
33993  }
33994 
33996  CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
33997  const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...):
33998  width(0),allocated_width(0),data(0) {
33999 #define _CImgList_stdarg(t) { \
34000  assign(n,width,height,depth,dim); \
34001  const unsigned int siz = width*height*depth*dim, nsiz = siz*n; \
34002  T *ptrd = data->data; \
34003  va_list ap; \
34004  va_start(ap,val1); \
34005  for (unsigned int l = 0, s = 0, i = 0; i<nsiz; ++i) { \
34006  *(ptrd++) = (T)(i==0?val0:(i==1?val1:va_arg(ap,t))); \
34007  if ((++s)==siz) { ptrd = data[++l].data; s = 0; } \
34008  } \
34009  va_end(ap); \
34010  }
34011  _CImgList_stdarg(int);
34012  }
34013 
34015  CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
34016  const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...):
34017  width(0),allocated_width(0),data(0) {
34018  _CImgList_stdarg(double);
34019  }
34020 
34022  template<typename t>
34023  CImgList(const unsigned int n, const CImg<t>& img, const bool shared=false):width(0),allocated_width(0),data(0) {
34024  assign(n);
34025  cimglist_apply(*this,assign)(img,shared);
34026  }
34027 
34029  template<typename t>
34030  explicit CImgList(const CImg<t>& img, const bool shared=false):width(0),allocated_width(0),data(0) {
34031  assign(1);
34032  data[0].assign(img,shared);
34033  }
34034 
34036  template<typename t1, typename t2>
34037  CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false):width(0),allocated_width(0),data(0) {
34038  assign(2);
34039  data[0].assign(img1,shared); data[1].assign(img2,shared);
34040  }
34041 
34043  template<typename t1, typename t2, typename t3>
34044  CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false):
34045  width(0),allocated_width(0),data(0) {
34046  assign(3);
34047  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
34048  }
34049 
34051  template<typename t1, typename t2, typename t3, typename t4>
34052  CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const bool shared=false):
34053  width(0),allocated_width(0),data(0) {
34054  assign(4);
34055  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
34056  }
34057 
34059  template<typename t1, typename t2, typename t3, typename t4, typename t5>
34060  CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
34061  const CImg<t5>& img5, const bool shared=false):
34062  width(0),allocated_width(0),data(0) {
34063  assign(5);
34064  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
34065  data[4].assign(img5,shared);
34066  }
34067 
34069  template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
34070  CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
34071  const CImg<t5>& img5, const CImg<t6>& img6, const bool shared=false):
34072  width(0),allocated_width(0),data(0) {
34073  assign(6);
34074  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
34075  data[4].assign(img5,shared); data[5].assign(img6,shared);
34076  }
34077 
34079  template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
34080  CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
34081  const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false):
34082  width(0),allocated_width(0),data(0) {
34083  assign(7);
34084  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
34085  data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
34086  }
34087 
34089  template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
34090  CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
34091  const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false):
34092  width(0),allocated_width(0),data(0) {
34093  assign(8);
34094  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
34095  data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
34096  }
34097 
34099  template<typename t>
34100  CImgList(const CImgList<t>& list):width(0),allocated_width(0),data(0) {
34101  assign(list.width);
34102  cimglist_for(*this,l) data[l].assign(list[l],false);
34103  }
34104 
34105  CImgList(const CImgList<T>& list):width(0),allocated_width(0),data(0) {
34106  assign(list.width);
34107  cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
34108  }
34109 
34111  template<typename t>
34112  CImgList(const CImgList<t>& list, const bool shared):width(0),allocated_width(0),data(0) {
34113  assign(list.width);
34114  cimglist_for(*this,l) data[l].assign(list[l],shared);
34115  }
34116 
34118  explicit CImgList(const char *const filename):width(0),allocated_width(0),data(0) {
34119  assign(filename);
34120  }
34121 
34123  explicit CImgList(const CImgDisplay &disp):width(0),allocated_width(0),data(0) {
34124  assign(disp);
34125  }
34126 
34129  CImgList<T> res(width);
34130  cimglist_for(*this,l) res[l].assign(data[l],true);
34131  return res;
34132  }
34133 
34135  const CImgList<T> get_shared() const {
34136  CImgList<T> res(width);
34137  cimglist_for(*this,l) res[l].assign(data[l],true);
34138  return res;
34139  }
34140 
34142 
34147  return assign();
34148  }
34149 
34152  if (data) delete[] data;
34153  width = allocated_width = 0;
34154  data = 0;
34155  return *this;
34156  }
34157 
34159  CImgList<T>& assign(const unsigned int n) {
34160  if (n) {
34161  if (allocated_width<n || allocated_width>(n<<2)) {
34162  if (data) delete[] data;
34164  }
34165  width = n;
34166  } else assign();
34167  return *this;
34168  }
34169 
34171  CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height=1,
34172  const unsigned int depth=1, const unsigned int dim=1) {
34173  assign(n);
34174  cimglist_apply(*this,assign)(width,height,depth,dim);
34175  return *this;
34176  }
34177 
34179  CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
34180  const unsigned int depth, const unsigned int dim, const T val) {
34181  assign(n);
34182  cimglist_apply(*this,assign)(width,height,depth,dim,val);
34183  return *this;
34184  }
34185 
34187  CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
34188  const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...) {
34189  _CImgList_stdarg(int);
34190  return *this;
34191  }
34192 
34194  CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
34195  const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...) {
34196  _CImgList_stdarg(double);
34197  return *this;
34198  }
34199 
34201  template<typename t>
34202  CImgList<T>& assign(const CImgList<t>& list, const bool shared=false) {
34203  assign(list.width);
34204  cimglist_for(*this,l) data[l].assign(list[l],shared);
34205  return *this;
34206  }
34207 
34209  template<typename t>
34210  CImgList<T>& assign(const unsigned int n, const CImg<t>& img, const bool shared=false) {
34211  assign(n);
34212  cimglist_apply(*this,assign)(img,shared);
34213  return *this;
34214  }
34215 
34217  template<typename t>
34218  CImgList<T>& assign(const CImg<t>& img, const bool shared=false) {
34219  assign(1);
34220  data[0].assign(img,shared);
34221  return *this;
34222  }
34223 
34225  template<typename t1, typename t2>
34226  CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false) {
34227  assign(2);
34228  data[0].assign(img1,shared); data[1].assign(img2,shared);
34229  return *this;
34230  }
34231 
34233  template<typename t1, typename t2, typename t3>
34234  CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false) {
34235  assign(3);
34236  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
34237  return *this;
34238  }
34239 
34241  template<typename t1, typename t2, typename t3, typename t4>
34242  CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
34243  const bool shared=false) {
34244  assign(4);
34245  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
34246  return *this;
34247  }
34248 
34250  template<typename t1, typename t2, typename t3, typename t4, typename t5>
34251  CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
34252  const CImg<t5>& img5, const bool shared=false) {
34253  assign(5);
34254  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
34255  data[4].assign(img5,shared);
34256  return *this;
34257  }
34258 
34260  template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
34261  CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
34262  const CImg<t5>& img5, const CImg<t6>& img6, const bool shared=false) {
34263  assign(6);
34264  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
34265  data[4].assign(img5,shared); data[5].assign(img6,shared);
34266  return *this;
34267  }
34268 
34270  template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
34271  CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
34272  const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false) {
34273  assign(7);
34274  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
34275  data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
34276  return *this;
34277  }
34278 
34280  template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
34281  CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
34282  const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8,
34283  const bool shared=false) {
34284  assign(8);
34285  data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
34286  data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
34287  return *this;
34288  }
34289 
34291  CImgList<T>& assign(const char *const filename) {
34292  return load(filename);
34293  }
34294 
34297  return assign(CImg<T>(disp));
34298  }
34299 
34301  template<typename t>
34303  list.assign(size());
34304  cimglist_for(*this,l) data[l].transfer_to(list[l]);
34305  assign();
34306  return list;
34307  }
34308 
34310  list.assign();
34311  return swap(list);
34312  }
34313 
34314  template<typename t>
34315  CImgList<t>& transfer_to(CImgList<t>& list, const unsigned int pos) {
34316  if (is_empty()) return list;
34317  const unsigned int npos = pos>list.width?list.width:pos;
34318  list.insert(width,npos);
34319  cimglist_for(*this,l) (*this)[l].transfer_to(list.at(npos+l));
34320  assign();
34321  return list;
34322  }
34323 
34326  cimg::swap(width,list.width);
34327  cimg::swap(allocated_width,list.allocated_width);
34328  cimg::swap(data,list.data);
34329  return list;
34330  }
34331 
34333  static CImgList<T>& empty() {
34334  static CImgList<T> _empty;
34335  return _empty.assign();
34336  }
34337 
34339  //------------------------------------------
34340  //
34342 
34343  //------------------------------------------
34344 
34346  CImg<T>& operator[](const unsigned int pos) {
34347 #if cimg_debug>=3
34348  if (pos>=width) {
34349  cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
34350  pixel_type(),pos,width);
34351  return *data;
34352  }
34353 #endif
34354  return data[pos];
34355  }
34356 
34357  const CImg<T>& operator[](const unsigned int pos) const {
34358 #if cimg_debug>=3
34359  if (pos>=width) {
34360  cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
34361  pixel_type(),pos,width);
34362  return *data;
34363  }
34364 #endif
34365  return data[pos];
34366  }
34367 
34369  CImg<T>& operator()(const unsigned int pos) {
34370  return (*this)[pos];
34371  }
34372 
34373  const CImg<T>& operator()(const unsigned int pos) const {
34374  return (*this)[pos];
34375  }
34376 
34378  T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
34379  const unsigned int z=0, const unsigned int v=0) {
34380  return (*this)[pos](x,y,z,v);
34381  }
34382  const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
34383  const unsigned int z=0, const unsigned int v=0) const {
34384  return (*this)[pos](x,y,z,v);
34385  }
34386 
34388  operator bool() const {
34389  return !is_empty();
34390  }
34391 
34393  template<typename t>
34395  return assign(img);
34396  }
34397 
34400  return assign(disp);
34401  }
34402 
34404  template<typename t>
34406  return assign(list);
34407  }
34408 
34410  return assign(list);
34411  }
34412 
34414  CImgList<T>& operator=(const char *const filename) {
34415  return assign(filename);
34416  }
34417 
34419 
34424  return CImgList<T>(*this,false);
34425  }
34426 
34428  template<typename t>
34430  return insert(img);
34431  }
34432 
34434  template<typename t>
34436  return insert(list);
34437  }
34438 
34440  CImg<T> operator>(const char axis) const {
34441  return get_append(axis,'p');
34442  }
34443 
34445  CImgList<T> operator<(const char axis) const {
34446  return get_split(axis);
34447  }
34448 
34450  //-------------------------------------
34451  //
34453 
34454  //-------------------------------------
34455 
34457 
34460  static const char* pixel_type() {
34461  return cimg::type<T>::string();
34462  }
34463 
34465  int dimx() const {
34466  return (int)width;
34467  }
34468 
34470  unsigned int size() const {
34471  return width;
34472  }
34473 
34476  return data;
34477  }
34478 
34479  const CImg<T> *ptr() const {
34480  return data;
34481  }
34482 
34484 #if cimg_debug>=3
34485  CImg<T> *ptr(const unsigned int l) {
34486  if (l>=size()) {
34487  cimg::warn("CImgList<%s>::ptr() : Asked for a pointer at position %u, outside the list range %u",
34488  pixel_type(),l,size());
34489  return data;
34490  }
34491  return data + l;
34492  }
34493 
34494  const CImg<T> *ptr(const unsigned int l) const {
34495  return const_cast<CImgList<T>*>(this)->ptr(l);
34496  }
34497 #else
34498  CImg<T> *ptr(const unsigned int l) {
34499  return data + l;
34500  }
34501 
34502  const CImg<T> *ptr(const unsigned int l) const {
34503  return data + l;
34504  }
34505 #endif
34506 
34509  return data;
34510  }
34511 
34513  return data;
34514  }
34515 
34518  return data + width;
34519  }
34520 
34522  return data + width;
34523  }
34524 
34527  return *data;
34528  }
34529 
34530  const CImg<T>& front() const {
34531  return *data;
34532  }
34533 
34535  const CImg<T>& back() const {
34536  return *(data + width - 1);
34537  }
34538 
34540  return *(data + width - 1);
34541  }
34542 
34544  CImg<T>& at(const int pos) {
34545  if (is_empty())
34546  throw CImgInstanceException("CImgList<%s>::at() : Instance list is empty.",
34547  pixel_type());
34548  return data[pos<0?0:pos>=(int)width?(int)width-1:pos];
34549  }
34550 
34552  T& atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
34553  return (pos<0 || pos>=(int)width)?(cimg::temporary(out_val)=out_val):data[pos].atXYZV(x,y,z,v,out_val);
34554  }
34555 
34556  T atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
34557  return (pos<0 || pos>=(int)width)?out_val:data[pos].atXYZV(x,y,z,v,out_val);
34558  }
34559 
34561  T& atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
34562  if (is_empty())
34563  throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
34564  pixel_type());
34565  return _atNXYZV(pos,x,y,z,v);
34566  }
34567 
34568  T atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
34569  if (is_empty())
34570  throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
34571  pixel_type());
34572  return _atNXYZV(pos,x,y,z,v);
34573  }
34574 
34575  T& _atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
34576  return data[pos<0?0:(pos>=(int)width?(int)width-1:pos)].atXYZV(x,y,z,v);
34577  }
34578 
34579  T _atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
34580  return data[pos<0?0:(pos>=(int)width?(int)width-1:pos)].atXYZV(x,y,z,v);
34581  }
34582 
34584  T& atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
34585  return (pos<0 || pos>=(int)width)?(cimg::temporary(out_val)=out_val):data[pos].atXYZ(x,y,z,v,out_val);
34586  }
34587 
34588  T atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
34589  return (pos<0 || pos>=(int)width)?out_val:data[pos].atXYZ(x,y,z,v,out_val);
34590  }
34591 
34593  T& atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
34594  if (is_empty())
34595  throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
34596  pixel_type());
34597  return _atNXYZ(pos,x,y,z,v);
34598  }
34599 
34600  T atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
34601  if (is_empty())
34602  throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
34603  pixel_type());
34604  return _atNXYZ(pos,x,y,z,v);
34605  }
34606 
34607  T& _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
34608  return data[pos<0?0:(pos>=(int)width?(int)width-1:pos)].atXYZ(x,y,z,v);
34609  }
34610 
34611  T _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
34612  return data[pos<0?0:(pos>=(int)width?(int)width-1:pos)].atXYZ(x,y,z,v);
34613  }
34614 
34616  T& atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
34617  return (pos<0 || pos>=(int)width)?(cimg::temporary(out_val)=out_val):data[pos].atXY(x,y,z,v,out_val);
34618  }
34619 
34620  T atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
34621  return (pos<0 || pos>=(int)width)?out_val:data[pos].atXY(x,y,z,v,out_val);
34622  }
34623 
34625  T& atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
34626  if (is_empty())
34627  throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
34628  pixel_type());
34629  return _atNXY(pos,x,y,z,v);
34630  }
34631 
34632  T atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
34633  if (is_empty())
34634  throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
34635  pixel_type());
34636  return _atNXY(pos,x,y,z,v);
34637  }
34638 
34639  T& _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
34640  return data[pos<0?0:(pos>=(int)width?(int)width-1:pos)].atXY(x,y,z,v);
34641  }
34642 
34643  T _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
34644  return data[pos<0?0:(pos>=(int)width?(int)width-1:pos)].atXY(x,y,z,v);
34645  }
34646 
34648  T& atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
34649  return (pos<0 || pos>=(int)width)?(cimg::temporary(out_val)=out_val):data[pos].atX(x,y,z,v,out_val);
34650  }
34651 
34652  T atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
34653  return (pos<0 || pos>=(int)width)?out_val:data[pos].atX(x,y,z,v,out_val);
34654  }
34655 
34657  T& atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
34658  if (is_empty())
34659  throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
34660  pixel_type());
34661  return _atNX(pos,x,y,z,v);
34662  }
34663 
34664  T atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
34665  if (is_empty())
34666  throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
34667  pixel_type());
34668  return _atNX(pos,x,y,z,v);
34669  }
34670 
34671  T& _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
34672  return data[pos<0?0:(pos>=(int)width?(int)width-1:pos)].atX(x,y,z,v);
34673  }
34674 
34675  T _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
34676  return data[pos<0?0:(pos>=(int)width?(int)width-1:pos)].atX(x,y,z,v);
34677  }
34678 
34680  T& atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
34681  return (pos<0 || pos>=(int)width)?(cimg::temporary(out_val)=out_val):(*this)(pos,x,y,z,v);
34682  }
34683 
34684  T atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
34685  return (pos<0 || pos>=(int)width)?out_val:(*this)(pos,x,y,z,v);
34686  }
34687 
34689  T& atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
34690  if (is_empty())
34691  throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
34692  pixel_type());
34693  return _atN(pos,x,y,z,v);
34694  }
34695 
34696  T atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
34697  if (is_empty())
34698  throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
34699  pixel_type());
34700  return _atN(pos,x,y,z,v);
34701  }
34702 
34703  T& _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
34704  return data[pos<0?0:(pos>=(int)width?(int)width-1:pos)](x,y,z,v);
34705  }
34706 
34707  T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
34708  return data[pos<0?0:(pos>=(int)width?(int)width-1:pos)](x,y,z,v);
34709  }
34710 
34712  CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
34713  if (is_empty()) return CImg<ucharT>(1,1,1,1,0);
34714  CImgList<charT> items;
34715  for (unsigned int l = 0; l<width-1; ++l) {
34716  CImg<charT> item = data[l].value_string(separator,0);
34717  item.back() = separator;
34718  item.transfer_to(items);
34719  }
34720  data[width-1].value_string(separator,0).transfer_to(items);
34721  CImg<charT> res; (items>'x').transfer_to(res);
34722  if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
34723  return res;
34724  }
34725 
34727  //-------------------------------------
34728  //
34730 
34731  //-------------------------------------
34732 
34734  bool is_empty() const {
34735  return (!data || !width);
34736  }
34737 
34739  bool is_sameN(const unsigned int n) const {
34740  return (width==n);
34741  }
34742 
34744  template<typename t>
34745  bool is_sameN(const CImgList<t>& list) const {
34746  return (width==list.width);
34747  }
34748 
34749  // Define useful dimension check functions.
34750  // (not documented because they are macro-generated).
34751 #define _cimglist_def_is_same1(axis) \
34752  bool is_same##axis(const unsigned int val) const { \
34753  bool res = true; for (unsigned int l = 0; l<width && res; ++l) res = data[l].is_same##axis(val); return res; \
34754  } \
34755  bool is_sameN##axis(const unsigned int n, const unsigned int val) const { \
34756  return is_sameN(n) && is_same##axis(val); \
34757  } \
34758 
34759 #define _cimglist_def_is_same2(axis1,axis2) \
34760  bool is_same##axis1##axis2(const unsigned int val1, const unsigned int val2) const { \
34761  bool res = true; for (unsigned int l = 0; l<width && res; ++l) res = data[l].is_same##axis1##axis2(val1,val2); return res; \
34762  } \
34763  bool is_sameN##axis1##axis2(const unsigned int n, const unsigned int val1, const unsigned int val2) const { \
34764  return is_sameN(n) && is_same##axis1##axis2(val1,val2); \
34765  } \
34766 
34767 #define _cimglist_def_is_same3(axis1,axis2,axis3) \
34768  bool is_same##axis1##axis2##axis3(const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
34769  bool res = true; for (unsigned int l = 0; l<width && res; ++l) res = data[l].is_same##axis1##axis2##axis3(val1,val2,val3); return res; \
34770  } \
34771  bool is_sameN##axis1##axis2##axis3(const unsigned int n, const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
34772  return is_sameN(n) && is_same##axis1##axis2##axis3(val1,val2,val3); \
34773  } \
34774 
34775 #define _cimglist_def_is_same(axis) \
34776  template<typename t> bool is_same##axis(const CImg<t>& img) const { \
34777  bool res = true; for (unsigned int l = 0; l<width && res; ++l) res = data[l].is_same##axis(img); return res; \
34778  } \
34779  template<typename t> bool is_same##axis(const CImgList<t>& list) const { \
34780  const unsigned int lmin = cimg::min(width,list.width); \
34781  bool res = true; for (unsigned int l = 0; l<lmin && res; ++l) res = data[l].is_same##axis(list[l]); return res; \
34782  } \
34783  template<typename t> bool is_sameN##axis(const unsigned int n, const CImg<t>& img) const { \
34784  return (is_sameN(n) && is_same##axis(img)); \
34785  } \
34786  template<typename t> bool is_sameN##axis(const CImgList<t>& list) const { \
34787  return (is_sameN(list) && is_same##axis(list)); \
34788  }
34789 
34798  _cimglist_def_is_same(XYZV)
34809  _cimglist_def_is_same3(X,Y,Z)
34810  _cimglist_def_is_same3(X,Y,V)
34811  _cimglist_def_is_same3(X,Z,V)
34812  _cimglist_def_is_same3(Y,Z,V)
34813 
34814  bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
34815  bool res = true;
34816  for (unsigned int l = 0; l<width && res; ++l) res = data[l].is_sameXYZV(dx,dy,dz,dv);
34817  return res;
34818  }
34819 
34820  bool is_sameNXYZV(const unsigned int n, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
34821  return is_sameN(n) && is_sameXYZV(dx,dy,dz,dv);
34822  }
34823 
34825  bool containsNXYZV(const int n, const int x=0, const int y=0, const int z=0, const int v=0) const {
34826  if (is_empty()) return false;
34827  return n>=0 && n<(int)width && x>=0 && x<data[n].dimx() && y>=0 && y<data[n].dimy() && z>=0 && z<data[n].dimz() && v>=0 && v<data[n].dimv();
34828  }
34829 
34831  bool containsN(const int n) const {
34832  if (is_empty()) return false;
34833  return n>=0 && n<(int)width;
34834  }
34835 
34837  template<typename t>
34838  bool contains(const T& pixel, t& n, t& x, t&y, t& z, t& v) const {
34839  if (is_empty()) return false;
34840  cimglist_for(*this,l) if (data[l].contains(pixel,x,y,z,v)) { n = (t)l; return true; }
34841  return false;
34842  }
34843 
34845  template<typename t>
34846  bool contains(const T& pixel, t& n, t& x, t&y, t& z) const {
34847  t v;
34848  return contains(pixel,n,x,y,z,v);
34849  }
34850 
34852  template<typename t>
34853  bool contains(const T& pixel, t& n, t& x, t&y) const {
34854  t z,v;
34855  return contains(pixel,n,x,y,z,v);
34856  }
34857 
34859  template<typename t>
34860  bool contains(const T& pixel, t& n, t& x) const {
34861  t y,z,v;
34862  return contains(pixel,n,x,y,z,v);
34863  }
34864 
34866  template<typename t>
34867  bool contains(const T& pixel, t& n) const {
34868  t x,y,z,v;
34869  return contains(pixel,n,x,y,z,v);
34870  }
34871 
34873  bool contains(const T& pixel) const {
34874  unsigned int n,x,y,z,v;
34875  return contains(pixel,n,x,y,z,v);
34876  }
34877 
34879  template<typename t>
34880  bool contains(const CImg<T>& img, t& n) const {
34881  if (is_empty()) return false;
34882  const CImg<T> *const ptr = &img;
34883  cimglist_for(*this,i) if (data+i==ptr) { n = (t)i; return true; }
34884  return false;
34885  }
34886 
34888  bool contains(const CImg<T>& img) const {
34889  unsigned int n;
34890  return contains(img,n);
34891  }
34892 
34894  //-------------------------------------
34895  //
34897 
34898  //-------------------------------------
34899 
34901  T& min() {
34902  if (is_empty())
34903  throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
34904  pixel_type());
34905  T *ptrmin = data->data;
34906  T min_value = *ptrmin;
34907  cimglist_for(*this,l) {
34908  const CImg<T>& img = data[l];
34909  cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
34910  }
34911  return *ptrmin;
34912  }
34913 
34914  const T& min() const {
34915  if (is_empty())
34916  throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
34917  pixel_type());
34918  const T *ptrmin = data->data;
34919  T min_value = *ptrmin;
34920  cimglist_for(*this,l) {
34921  const CImg<T>& img = data[l];
34922  cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
34923  }
34924  return *ptrmin;
34925  }
34926 
34928  T& max() {
34929  if (is_empty())
34930  throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
34931  pixel_type());
34932  T *ptrmax = data->data;
34933  T max_value = *ptrmax;
34934  cimglist_for(*this,l) {
34935  const CImg<T>& img = data[l];
34936  cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
34937  }
34938  return *ptrmax;
34939  }
34940 
34941  const T& max() const {
34942  if (is_empty())
34943  throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
34944  pixel_type());
34945  const T *ptrmax = data->data;
34946  T max_value = *ptrmax;
34947  cimglist_for(*this,l) {
34948  const CImg<T>& img = data[l];
34949  cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
34950  }
34951  return *ptrmax;
34952  }
34953 
34955  template<typename t>
34956  T& minmax(t& max_val) {
34957  if (is_empty())
34958  throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
34959  pixel_type());
34960  T *ptrmin = data->data;
34961  T min_value = *ptrmin, max_value = min_value;
34962  cimglist_for(*this,l) {
34963  const CImg<T>& img = data[l];
34964  cimg_for(img,ptr,T) {
34965  const T val = *ptr;
34966  if (val<min_value) { min_value = val; ptrmin = ptr; }
34967  if (val>max_value) max_value = val;
34968  }
34969  }
34970  max_val = (t)max_value;
34971  return *ptrmin;
34972  }
34973 
34974  template<typename t>
34975  const T& minmax(t& max_val) const {
34976  if (is_empty())
34977  throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
34978  pixel_type());
34979  const T *ptrmin = data->data;
34980  T min_value = *ptrmin, max_value = min_value;
34981  cimglist_for(*this,l) {
34982  const CImg<T>& img = data[l];
34983  cimg_for(img,ptr,T) {
34984  const T val = *ptr;
34985  if (val<min_value) { min_value = val; ptrmin = ptr; }
34986  if (val>max_value) max_value = val;
34987  }
34988  }
34989  max_val = (t)max_value;
34990  return *ptrmin;
34991  }
34992 
34994  template<typename t>
34995  T& maxmin(t& min_val) {
34996  if (is_empty())
34997  throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
34998  pixel_type());
34999  T *ptrmax = data->data;
35000  T min_value = *ptrmax, max_value = min_value;
35001  cimglist_for(*this,l) {
35002  const CImg<T>& img = data[l];
35003  cimg_for(img,ptr,T) {
35004  const T val = *ptr;
35005  if (val>max_value) { max_value = val; ptrmax = ptr; }
35006  if (val<min_value) min_value = val;
35007  }
35008  }
35009  min_val = (t)min_value;
35010  return *ptrmax;
35011  }
35012 
35013  template<typename t>
35014  const T& maxmin(t& min_val) const {
35015  if (is_empty())
35016  throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
35017  pixel_type());
35018  const T *ptrmax = data->data;
35019  T min_value = *ptrmax, max_value = min_value;
35020  cimglist_for(*this,l) {
35021  const CImg<T>& img = data[l];
35022  cimg_for(img,ptr,T) {
35023  const T val = *ptr;
35024  if (val>max_value) { max_value = val; ptrmax = ptr; }
35025  if (val<min_value) min_value = val;
35026  }
35027  }
35028  min_val = (t)min_value;
35029  return *ptrmax;
35030  }
35031 
35033  //---------------------------
35034  //
35036 
35037  //---------------------------
35038 
35040  template<typename t>
35041  CImgList<T>& insert(const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) {
35042  const unsigned int npos = pos==~0U?width:pos;
35043  if (npos>width)
35044  throw CImgArgumentException("CImgList<%s>::insert() : Cannot insert image (%u,%u,%u,%u,%p) at position %u in a list "
35045  "containing %u elements",
35046  pixel_type(),img.width,img.height,img.depth,img.dim,img.data,npos,width);
35047  if (shared)
35048  throw CImgArgumentException("CImgList<%s>::insert() : Cannot insert a shared image CImg<%s> in a CImgList<%s>",
35049  pixel_type(),img.pixel_type(),pixel_type());
35050  CImg<T> *new_data = (++width>allocated_width)?new CImg<T>[allocated_width?(allocated_width<<=1):(allocated_width=16)]:0;
35051  if (!width || !data) {
35052  data = new_data;
35053  *data = img;
35054  } else {
35055  if (new_data) {
35056  if (npos) std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
35057  if (npos!=width-1) std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(width-1-npos));
35058  std::memset(data,0,sizeof(CImg<T>)*(width-1));
35059  delete[] data;
35060  data = new_data;
35061  }
35062  else if (npos!=width-1) std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(width-1-npos));
35063  data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
35064  data[npos] = img;
35065  }
35066  return *this;
35067  }
35068 
35069  CImgList<T>& insert(const CImg<T>& img, const unsigned int pos=~0U, const bool shared=false) {
35070  const unsigned int npos = pos==~0U?width:pos;
35071  if (npos>width)
35072  throw CImgArgumentException("CImgList<%s>::insert() : Cannot insert at position %u into a list with %u elements",
35073  pixel_type(),npos,width);
35074  if (&img>=data && &img<data + width) return insert(+img,pos,shared);
35075  CImg<T> *new_data = (++width>allocated_width)?new CImg<T>[allocated_width?(allocated_width<<=1):(allocated_width=16)]:0;
35076  if (!width || !data) {
35077  data = new_data;
35078  if (shared && img) {
35079  data->width = img.width; data->height = img.height; data->depth = img.depth; data->dim = img.dim;
35080  data->is_shared = true; data->data = img.data;
35081  } else *data = img;
35082  }
35083  else {
35084  if (new_data) {
35085  if (npos) std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
35086  if (npos!=width-1) std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(width-1-npos));
35087  if (shared && img) {
35088  new_data[npos].width = img.width; new_data[npos].height = img.height; new_data[npos].depth = img.depth;
35089  new_data[npos].dim = img.dim; new_data[npos].is_shared = true; new_data[npos].data = img.data;
35090  } else {
35091  new_data[npos].width = new_data[npos].height = new_data[npos].depth = new_data[npos].dim = 0; new_data[npos].data = 0;
35092  new_data[npos] = img;
35093  }
35094  std::memset(data,0,sizeof(CImg<T>)*(width-1));
35095  delete[] data;
35096  data = new_data;
35097  } else {
35098  if (npos!=width-1) std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(width-1-npos));
35099  if (shared && img) {
35100  data[npos].width = img.width; data[npos].height = img.height; data[npos].depth = img.depth; data[npos].dim = img.dim;
35101  data[npos].is_shared = true; data[npos].data = img.data;
35102  } else {
35103  data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
35104  data[npos] = img;
35105  }
35106  }
35107  }
35108  return *this;
35109  }
35110 
35111  template<typename t>
35112  CImgList<T> get_insert(const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
35113  return (+*this).insert(img,pos,shared);
35114  }
35115 
35117  CImgList<T>& insert(const unsigned int n, const unsigned int pos=~0U) {
35118  CImg<T> foo;
35119  if (!n) return *this;
35120  const unsigned int npos = pos==~0U?width:pos;
35121  for (unsigned int i = 0; i<n; ++i) insert(foo,npos+i);
35122  return *this;
35123  }
35124 
35125  CImgList<T> get_insert(const unsigned int n, const unsigned int pos=~0U) const {
35126  return (+*this).insert(n,pos);
35127  }
35128 
35130  template<typename t>
35131  CImgList<T>& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) {
35132  if (!n) return *this;
35133  const unsigned int npos = pos==~0U?width:pos;
35134  insert(img,npos,shared);
35135  for (unsigned int i = 1; i<n; ++i) insert(data[npos],npos+i,shared);
35136  return *this;
35137  }
35138 
35139  template<typename t>
35140  CImgList<T> get_insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
35141  return (+*this).insert(n,img,pos,shared);
35142  }
35143 
35145  template<typename t>
35146  CImgList<T>& insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
35147  const unsigned int npos = pos==~0U?width:pos;
35148  if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos+l,shared);
35149  else insert(CImgList<T>(list),npos,shared);
35150  return *this;
35151  }
35152 
35153  template<typename t>
35154  CImgList<T> get_insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
35155  return (+*this).insert(list,pos,shared);
35156  }
35157 
35159  template<typename t>
35160  CImgList<T>& insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
35161  if (!n) return *this;
35162  const unsigned int npos = pos==~0U?width:pos;
35163  for (unsigned int i = 0; i<n; ++i) insert(list,npos,shared);
35164  return *this;
35165  }
35166 
35167  template<typename t>
35168  CImgList<T> get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
35169  return (+*this).insert(n,list,pos,shared);
35170  }
35171 
35173  CImgList<T>& remove(const unsigned int pos1, const unsigned int pos2) {
35174  const unsigned int
35175  npos1 = pos1<pos2?pos1:pos2,
35176  tpos2 = pos1<pos2?pos2:pos1,
35177  npos2 = tpos2<width?tpos2:width-1;
35178  if (npos1>=width)
35179  cimg::warn("CImgList<%s>::remove() : Cannot remove images from a list (%p,%u), at positions %u->%u.",
35180  pixel_type(),data,width,npos1,tpos2);
35181  else {
35182  if (tpos2>=width)
35183  cimg::warn("CImgList<%s>::remove() : Cannot remove all images from a list (%p,%u), at positions %u->%u.",
35184  pixel_type(),data,width,npos1,tpos2);
35185  for (unsigned int k = npos1; k<=npos2; ++k) data[k].assign();
35186  const unsigned int nb = 1 + npos2 - npos1;
35187  if (!(width-=nb)) return assign();
35188  if (width>(allocated_width>>2) || allocated_width<=8) { // Removing items without reallocation.
35189  if (npos1!=width) std::memmove(data+npos1,data+npos2+1,sizeof(CImg<T>)*(width - npos1));
35190  std::memset(data + width,0,sizeof(CImg<T>)*nb);
35191  } else { // Removing items with reallocation.
35192  allocated_width>>=2;
35193  while (allocated_width>8 && width<(allocated_width>>1)) allocated_width>>=1;
35194  CImg<T> *new_data = new CImg<T>[allocated_width];
35195  if (npos1) std::memcpy(new_data,data,sizeof(CImg<T>)*npos1);
35196  if (npos1!=width) std::memcpy(new_data+npos1,data+npos2+1,sizeof(CImg<T>)*(width-npos1));
35197  if (width!=allocated_width) std::memset(new_data+width,0,sizeof(allocated_width - width));
35198  std::memset(data,0,sizeof(CImg<T>)*(width+nb));
35199  delete[] data;
35200  data = new_data;
35201  }
35202  }
35203  return *this;
35204  }
35205 
35206  CImgList<T> get_remove(const unsigned int pos1, const unsigned int pos2) const {
35207  return (+*this).remove(pos1,pos2);
35208  }
35209 
35211  CImgList<T>& remove(const unsigned int pos) {
35212  return remove(pos,pos);
35213  }
35214 
35215  CImgList<T> get_remove(const unsigned int pos) const {
35216  return (+*this).remove(pos);
35217  }
35218 
35220  CImgList<T>& remove() {
35221  if (width) return remove(width-1);
35222  else cimg::warn("CImgList<%s>::remove() : List is empty",
35223  pixel_type());
35224  return *this;
35225  }
35226 
35228  return (+*this).remove();
35229  }
35230 
35233  for (unsigned int l = 0; l<width/2; ++l) (*this)[l].swap((*this)[width-1-l]);
35234  return *this;
35235  }
35236 
35238  return (+*this).reverse();
35239  }
35240 
35242  CImgList<T>& images(const unsigned int i0, const unsigned int i1) {
35243  return get_images(i0,i1).transfer_to(*this);
35244  }
35245 
35246  CImgList<T> get_images(const unsigned int i0, const unsigned int i1) const {
35247  if (i0>i1 || i1>=width)
35248  throw CImgArgumentException("CImgList<%s>::images() : Cannot build a sublist (%u->%u) from a list (%u,%p)",
35249  pixel_type(),i0,i1,width,data);
35250  CImgList<T> res(i1-i0+1);
35251  cimglist_for(res,l) res[l].assign(data[i0+l]);
35252  return res;
35253  }
35254 
35256  CImgList<T> get_shared_images(const unsigned int i0, const unsigned int i1) {
35257  if (i0>i1 || i1>=width)
35258  throw CImgArgumentException("CImgList<%s>::get_shared_images() : Cannot build a sublist (%u->%u) from a list (%u,%p)",
35259  pixel_type(),i0,i1,width,data);
35260  CImgList<T> res(i1-i0+1);
35261  cimglist_for(res,l) res[l].assign(data[i0+l],true);
35262  return res;
35263  }
35264 
35265  const CImgList<T> get_shared_images(const unsigned int i0, const unsigned int i1) const {
35266  if (i0>i1 || i1>=width)
35267  throw CImgArgumentException("CImgList<%s>::get_shared_images() : Cannot build a sublist (%u->%u) from a list (%u,%p)",
35268  pixel_type(),i0,i1,width,data);
35269  CImgList<T> res(i1-i0+1);
35270  cimglist_for(res,l) res[l].assign(data[i0+l],true);
35271  return res;
35272  }
35273 
35275 
35280  CImg<T> get_append(const char axis, const char align='p') const {
35281  if (align!='p' && align!='c' && align!='n')
35282  throw CImgArgumentException("CImg<%s>::get_append() : Invalid alignment parameter '%c' (should be 'p','c' or 'n').",
35283  pixel_type(),align);
35284  if (is_empty()) return CImg<T>();
35285  if (width==1) return +((*this)[0]);
35286  unsigned int dx = 0, dy = 0, dz = 0, dv = 0, pos = 0;
35287  CImg<T> res;
35288  switch (cimg::uncase(axis)) {
35289  case 'x' : { // Along the X-axis.
35290  cimglist_for(*this,l) {
35291  const CImg<T>& img = (*this)[l];
35292  dx += img.width; dy = cimg::max(dy,img.height); dz = cimg::max(dz,img.depth); dv = cimg::max(dv,img.dim);
35293  }
35294  res.assign(dx,dy,dz,dv,0);
35295  if (res) switch (cimg::uncase(align)) {
35296  case 'p' : {
35297  cimglist_for(*this,l) {
35298  res.draw_image(pos,(*this)[l]);
35299  pos+=(*this)[l].width;
35300  }
35301  } break;
35302  case 'c' : {
35303  cimglist_for(*this,l) {
35304  res.draw_image(pos,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
35305  pos+=(*this)[l].width;
35306  }
35307  } break;
35308  default : {
35309  cimglist_for(*this,l) {
35310  res.draw_image(pos,dy-(*this)[l].height,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
35311  pos+=(*this)[l].width;
35312  }
35313  }}
35314  } break;
35315  case 'y' : { // Along the Y-axis.
35316  cimglist_for(*this,l) {
35317  const CImg<T>& img = (*this)[l];
35318  dx = cimg::max(dx,img.width); dy += img.height; dz = cimg::max(dz,img.depth); dv = cimg::max(dv,img.dim);
35319  }
35320  res.assign(dx,dy,dz,dv,0);
35321  if (res) switch (cimg::uncase(align)) {
35322  case 'p' : {
35323  cimglist_for(*this,l) { res.draw_image(0,pos,(*this)[l]); pos+=(*this)[l].height; }
35324  } break;
35325  case 'c' : {
35326  cimglist_for(*this,l) {
35327  res.draw_image((dx-(*this)[l].width)/2,pos,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
35328  pos+=(*this)[l].height;
35329  }
35330  } break;
35331  default : {
35332  cimglist_for(*this,l) {
35333  res.draw_image(dx-(*this)[l].width,pos,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
35334  pos+=(*this)[l].height;
35335  }
35336  }}
35337  } break;
35338  case 'z' : { // Along the Z-axis.
35339  cimglist_for(*this,l) {
35340  const CImg<T>& img = (*this)[l];
35341  dx = cimg::max(dx,img.width); dy = cimg::max(dy,img.height); dz += img.depth; dv = cimg::max(dv,img.dim);
35342  }
35343  res.assign(dx,dy,dz,dv,0);
35344  if (res) switch (cimg::uncase(align)) {
35345  case 'p' : {
35346  cimglist_for(*this,l) { res.draw_image(0,0,pos,(*this)[l]); pos+=(*this)[l].depth; }
35347  } break;
35348  case 'c' : {
35349  cimglist_for(*this,l) {
35350  res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,pos,(dv-(*this)[l].dim)/2,(*this)[l]);
35351  pos+=(*this)[l].depth;
35352  }
35353  } break;
35354  default : {
35355  cimglist_for(*this,l) {
35356  res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,pos,dv-(*this)[l].dim,(*this)[l]);
35357  pos+=(*this)[l].depth;
35358  }
35359  }}
35360  } break;
35361  case 'v' : { // Along the V-axis.
35362  cimglist_for(*this,l) {
35363  const CImg<T>& img = (*this)[l];
35364  dx = cimg::max(dx,img.width); dy = cimg::max(dy,img.height); dz = cimg::max(dz,img.depth); dv += img.dim;
35365  }
35366  res.assign(dx,dy,dz,dv,0);
35367  if (res) switch (cimg::uncase(align)) {
35368  case 'p' : {
35369  cimglist_for(*this,l) { res.draw_image(0,0,0,pos,(*this)[l]); pos+=(*this)[l].dim; }
35370  } break;
35371  case 'c' : {
35372  cimglist_for(*this,l) {
35373  res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,pos,(*this)[l]);
35374  pos+=(*this)[l].dim;
35375  }
35376  } break;
35377  default : {
35378  cimglist_for(*this,l) {
35379  res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,dz-(*this)[l].depth,pos,(*this)[l]);
35380  pos+=(*this)[l].dim;
35381  }
35382  }}
35383  } break;
35384  default :
35385  throw CImgArgumentException("CImgList<%s>::get_append() : Invalid axis parameter '%c' (should be 'x','y','z' or 'v').",
35386  pixel_type(),axis);
35387  }
35388  return res;
35389  }
35390 
35392  CImgList<T>& split(const char axis, const int nb=0) {
35393  return get_split(axis,nb).transfer_to(*this);
35394  }
35395 
35396  CImgList<T> get_split(const char axis, const int nb=0) const {
35397  CImgList<T> res;
35398  cimglist_for(*this,l) data[l].get_split(axis,nb).transfer_to(res,~0U);
35399  return res;
35400  }
35401 
35403  template<typename t>
35405  return insert(img);
35406  }
35407 
35409  template<typename t>
35411  return insert(img,0);
35412  }
35413 
35415  template<typename t>
35417  return insert(list);
35418  }
35419 
35421  template<typename t>
35423  return insert(list,0);
35424  }
35425 
35428  return remove(width-1);
35429  }
35430 
35433  return remove(0);
35434  }
35435 
35437  CImgList<T>& erase(const iterator iter) {
35438  return remove(iter-data);
35439  }
35440 
35442  //----------------------------------
35443  //
35445 
35446  //----------------------------------
35447 
35449  CImgList<T>& load(const char *const filename) {
35450  const char *ext = cimg::split_filename(filename);
35451  const unsigned int omode = cimg::exception_mode();
35452  cimg::exception_mode() = 0;
35453  assign();
35454  try {
35455 #ifdef cimglist_load_plugin
35456  cimglist_load_plugin(filename);
35457 #endif
35458 #ifdef cimglist_load_plugin1
35459  cimglist_load_plugin1(filename);
35460 #endif
35461 #ifdef cimglist_load_plugin2
35462  cimglist_load_plugin2(filename);
35463 #endif
35464 #ifdef cimglist_load_plugin3
35465  cimglist_load_plugin3(filename);
35466 #endif
35467 #ifdef cimglist_load_plugin4
35468  cimglist_load_plugin4(filename);
35469 #endif
35470 #ifdef cimglist_load_plugin5
35471  cimglist_load_plugin5(filename);
35472 #endif
35473 #ifdef cimglist_load_plugin6
35474  cimglist_load_plugin6(filename);
35475 #endif
35476 #ifdef cimglist_load_plugin7
35477  cimglist_load_plugin7(filename);
35478 #endif
35479 #ifdef cimglist_load_plugin8
35480  cimglist_load_plugin8(filename);
35481 #endif
35482  if (!cimg::strcasecmp(ext,"tif") ||
35483  !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
35484  if (!cimg::strcasecmp(ext,"cimg") ||
35485  !cimg::strcasecmp(ext,"cimgz") ||
35486  !ext[0]) load_cimg(filename);
35487  if (!cimg::strcasecmp(ext,"rec") ||
35488  !cimg::strcasecmp(ext,"par")) load_parrec(filename);
35489  if (!cimg::strcasecmp(ext,"avi") ||
35490  !cimg::strcasecmp(ext,"mov") ||
35491  !cimg::strcasecmp(ext,"asf") ||
35492  !cimg::strcasecmp(ext,"divx") ||
35493  !cimg::strcasecmp(ext,"flv") ||
35494  !cimg::strcasecmp(ext,"mpg") ||
35495  !cimg::strcasecmp(ext,"m1v") ||
35496  !cimg::strcasecmp(ext,"m2v") ||
35497  !cimg::strcasecmp(ext,"m4v") ||
35498  !cimg::strcasecmp(ext,"mjp") ||
35499  !cimg::strcasecmp(ext,"mkv") ||
35500  !cimg::strcasecmp(ext,"mpe") ||
35501  !cimg::strcasecmp(ext,"movie") ||
35502  !cimg::strcasecmp(ext,"ogm") ||
35503  !cimg::strcasecmp(ext,"qt") ||
35504  !cimg::strcasecmp(ext,"rm") ||
35505  !cimg::strcasecmp(ext,"vob") ||
35506  !cimg::strcasecmp(ext,"wmv") ||
35507  !cimg::strcasecmp(ext,"xvid") ||
35508  !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
35509  if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
35510  if (is_empty()) throw CImgIOException("CImgList<%s>::load()",pixel_type());
35511  } catch (CImgIOException& e) {
35512  if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
35513  cimg::exception_mode() = omode;
35514  throw CImgIOException("CImgList<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
35515  } else try {
35516  assign(1);
35517  data->load(filename);
35518  } catch (CImgException&) {
35519  assign();
35520  }
35521  }
35522  cimg::exception_mode() = omode;
35523  if (is_empty())
35524  throw CImgIOException("CImgList<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
35525  return *this;
35526  }
35527 
35528  static CImgList<T> get_load(const char *const filename) {
35529  return CImgList<T>().load(filename);
35530  }
35531 
35533  CImgList<T>& load_cimg(const char *const filename) {
35534  return _load_cimg(0,filename);
35535  }
35536 
35537  static CImgList<T> get_load_cimg(const char *const filename) {
35538  return CImgList<T>().load_cimg(filename);
35539  }
35540 
35542  CImgList<T>& load_cimg(std::FILE *const file) {
35543  return _load_cimg(file,0);
35544  }
35545 
35546  static CImgList<T> get_load_cimg(std::FILE *const file) {
35547  return CImgList<T>().load_cimg(file);
35548  }
35549 
35550  CImgList<T>& _load_cimg(std::FILE *const file, const char *const filename) {
35551 #ifdef cimg_use_zlib
35552 #define _cimgz_load_cimg_case(Tss) { \
35553  Bytef *const cbuf = new Bytef[csiz]; \
35554  cimg::fread(cbuf,csiz,nfile); \
35555  raw.assign(W,H,D,V); \
35556  unsigned long destlen = (unsigned long)raw.size()*sizeof(T); \
35557  uncompress((Bytef*)raw.data,&destlen,cbuf,csiz); \
35558  delete[] cbuf; \
35559  const Tss *ptrs = raw.data; \
35560  for (unsigned int off = raw.size(); off; --off) *(ptrd++) = (T)*(ptrs++); \
35561 }
35562 #else
35563 #define _cimgz_load_cimg_case(Tss) \
35564  throw CImgIOException("CImgList<%s>::load_cimg() : File '%s' contains compressed data, zlib must be used",\
35565  pixel_type(),filename?filename:"(FILE*)");
35566 #endif
35567 
35568 #define _cimg_load_cimg_case(Ts,Tss) \
35569  if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
35570  for (unsigned int l = 0; l<N; ++l) { \
35571  j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = 0; \
35572  W = H = D = V = 0; csiz = 0; \
35573  if ((err = std::sscanf(tmp,"%u %u %u %u #%u",&W,&H,&D,&V,&csiz))<4) \
35574  throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
35575  pixel_type(),filename?filename:("(FILE*)"),W,H,D,V); \
35576  if (W*H*D*V>0) { \
35577  CImg<Tss> raw; \
35578  CImg<T> &img = data[l]; \
35579  img.assign(W,H,D,V); \
35580  T *ptrd = img.data; \
35581  if (err==5) _cimgz_load_cimg_case(Tss) \
35582  else for (int toread = (int)img.size(); toread>0; ) { \
35583  raw.assign(cimg::min(toread,cimg_iobuffer)); \
35584  cimg::fread(raw.data,raw.width,nfile); \
35585  if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
35586  toread-=raw.width; \
35587  const Tss *ptrs = raw.data; \
35588  for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
35589  } \
35590  } \
35591  } \
35592  loaded = true; \
35593  }
35594 
35595  if (!filename && !file)
35596  throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
35597  pixel_type());
35598  typedef unsigned char uchar;
35599  typedef unsigned short ushort;
35600  typedef unsigned int uint;
35601  typedef unsigned long ulong;
35602  const int cimg_iobuffer = 12*1024*1024;
35603  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
35604  bool loaded = false, endian = cimg::endianness();
35605  char tmp[256] = { 0 }, str_pixeltype[256] = { 0 }, str_endian[256] = { 0 };
35606  unsigned int j, err, N = 0, W, H, D, V, csiz;
35607  int i;
35608  j = 0; while((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;
35609  err = std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
35610  if (err<2) {
35611  if (!file) cimg::fclose(nfile);
35612  throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
35613  pixel_type(),filename?filename:"(FILE*)");
35614  }
35615  if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
35616  else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
35617  assign(N);
35618  _cimg_load_cimg_case("bool",bool);
35619  _cimg_load_cimg_case("unsigned_char",uchar);
35620  _cimg_load_cimg_case("uchar",uchar);
35621  _cimg_load_cimg_case("char",char);
35622  _cimg_load_cimg_case("unsigned_short",ushort);
35623  _cimg_load_cimg_case("ushort",ushort);
35624  _cimg_load_cimg_case("short",short);
35625  _cimg_load_cimg_case("unsigned_int",uint);
35626  _cimg_load_cimg_case("uint",uint);
35627  _cimg_load_cimg_case("int",int);
35628  _cimg_load_cimg_case("unsigned_long",ulong);
35629  _cimg_load_cimg_case("ulong",ulong);
35630  _cimg_load_cimg_case("long",long);
35631  _cimg_load_cimg_case("float",float);
35632  _cimg_load_cimg_case("double",double);
35633  if (!loaded) {
35634  if (!file) cimg::fclose(nfile);
35635  throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
35636  pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
35637  }
35638  if (!file) cimg::fclose(nfile);
35639  return *this;
35640  }
35641 
35643  CImgList<T>& load_cimg(const char *const filename,
35644  const unsigned int n0, const unsigned int n1,
35645  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35646  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35647  return _load_cimg(0,filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35648  }
35649 
35650  static CImgList<T> get_load_cimg(const char *const filename,
35651  const unsigned int n0, const unsigned int n1,
35652  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35653  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35654  return CImgList<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35655  }
35656 
35658  CImgList<T>& load_cimg(std::FILE *const file,
35659  const unsigned int n0, const unsigned int n1,
35660  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35661  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35662  return _load_cimg(file,0,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35663  }
35664 
35665  static CImgList<T> get_load_cimg(std::FILE *const file,
35666  const unsigned int n0, const unsigned int n1,
35667  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35668  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35669  return CImgList<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35670  }
35671 
35672  CImgList<T>& _load_cimg(std::FILE *const file, const char *const filename,
35673  const unsigned int n0, const unsigned int n1,
35674  const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35675  const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35676 #define _cimg_load_cimg_case2(Ts,Tss) \
35677  if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
35678  for (unsigned int l = 0; l<=nn1; ++l) { \
35679  j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = 0; \
35680  W = H = D = V = 0; \
35681  if (std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
35682  throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
35683  pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
35684  if (W*H*D*V>0) { \
35685  if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
35686  else { \
35687  const unsigned int \
35688  nx1 = x1>=W?W-1:x1, \
35689  ny1 = y1>=H?H-1:y1, \
35690  nz1 = z1>=D?D-1:z1, \
35691  nv1 = v1>=V?V-1:v1; \
35692  CImg<Tss> raw(1 + nx1 - x0); \
35693  CImg<T> &img = data[l - n0]; \
35694  img.assign(1 + nx1 - x0,1 + ny1 - y0,1 + nz1 - z0,1 + nv1 - v0); \
35695  T *ptrd = img.data; \
35696  const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
35697  if (skipvb) std::fseek(nfile,skipvb,SEEK_CUR); \
35698  for (unsigned int v = 1 + nv1 - v0; v; --v) { \
35699  const unsigned int skipzb = z0*W*H*sizeof(Tss); \
35700  if (skipzb) std::fseek(nfile,skipzb,SEEK_CUR); \
35701  for (unsigned int z = 1 + nz1 - z0; z; --z) { \
35702  const unsigned int skipyb = y0*W*sizeof(Tss); \
35703  if (skipyb) std::fseek(nfile,skipyb,SEEK_CUR); \
35704  for (unsigned int y = 1 + ny1 - y0; y; --y) { \
35705  const unsigned int skipxb = x0*sizeof(Tss); \
35706  if (skipxb) std::fseek(nfile,skipxb,SEEK_CUR); \
35707  cimg::fread(raw.data,raw.width,nfile); \
35708  if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
35709  const Tss *ptrs = raw.data; \
35710  for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
35711  const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
35712  if (skipxe) std::fseek(nfile,skipxe,SEEK_CUR); \
35713  } \
35714  const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \
35715  if (skipye) std::fseek(nfile,skipye,SEEK_CUR); \
35716  } \
35717  const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \
35718  if (skipze) std::fseek(nfile,skipze,SEEK_CUR); \
35719  } \
35720  const unsigned int skipve = (V-1-nv1)*W*H*D*sizeof(Tss); \
35721  if (skipve) std::fseek(nfile,skipve,SEEK_CUR); \
35722  } \
35723  } \
35724  } \
35725  loaded = true; \
35726  }
35727 
35728  if (!filename && !file)
35729  throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
35730  pixel_type());
35731  typedef unsigned char uchar;
35732  typedef unsigned short ushort;
35733  typedef unsigned int uint;
35734  typedef unsigned long ulong;
35735  if (n1<n0 || x1<x0 || y1<y0 || z1<z0 || v1<v0)
35736  throw CImgArgumentException("CImgList<%s>::load_cimg() : File '%s', Bad sub-region coordinates [%u->%u] "
35737  "(%u,%u,%u,%u)->(%u,%u,%u,%u).",
35738  pixel_type(),filename?filename:"(FILE*)",
35739  n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35740  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
35741  bool loaded = false, endian = cimg::endianness();
35742  char tmp[256] = { 0 }, str_pixeltype[256] = { 0 }, str_endian[256] = { 0 };
35743  unsigned int j, err, N, W, H, D, V;
35744  int i;
35745  j = 0; while((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;
35746  err = std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
35747  if (err<2) {
35748  if (!file) cimg::fclose(nfile);
35749  throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
35750  pixel_type(),filename?filename:"(FILE*)");
35751  }
35752  if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
35753  else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
35754  const unsigned int nn1 = n1>=N?N-1:n1;
35755  assign(1+nn1-n0);
35756  _cimg_load_cimg_case2("bool",bool);
35757  _cimg_load_cimg_case2("unsigned_char",uchar);
35758  _cimg_load_cimg_case2("uchar",uchar);
35759  _cimg_load_cimg_case2("char",char);
35760  _cimg_load_cimg_case2("unsigned_short",ushort);
35761  _cimg_load_cimg_case2("ushort",ushort);
35762  _cimg_load_cimg_case2("short",short);
35763  _cimg_load_cimg_case2("unsigned_int",uint);
35764  _cimg_load_cimg_case2("uint",uint);
35765  _cimg_load_cimg_case2("int",int);
35766  _cimg_load_cimg_case2("unsigned_long",ulong);
35767  _cimg_load_cimg_case2("ulong",ulong);
35768  _cimg_load_cimg_case2("long",long);
35769  _cimg_load_cimg_case2("float",float);
35770  _cimg_load_cimg_case2("double",double);
35771  if (!loaded) {
35772  if (!file) cimg::fclose(nfile);
35773  throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
35774  pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
35775  }
35776  if (!file) cimg::fclose(nfile);
35777  return *this;
35778  }
35779 
35781  CImgList<T>& load_parrec(const char *const filename) {
35782  if (!filename)
35783  throw CImgArgumentException("CImgList<%s>::load_parrec() : Cannot load (null) filename.",
35784  pixel_type());
35785  char body[1024] = { 0 }, filenamepar[1024] = { 0 }, filenamerec[1024] = { 0 };
35786  const char *ext = cimg::split_filename(filename,body);
35787  if (!std::strcmp(ext,"par")) { std::strcpy(filenamepar,filename); std::sprintf(filenamerec,"%s.rec",body); }
35788  if (!std::strcmp(ext,"PAR")) { std::strcpy(filenamepar,filename); std::sprintf(filenamerec,"%s.REC",body); }
35789  if (!std::strcmp(ext,"rec")) { std::strcpy(filenamerec,filename); std::sprintf(filenamepar,"%s.par",body); }
35790  if (!std::strcmp(ext,"REC")) { std::strcpy(filenamerec,filename); std::sprintf(filenamepar,"%s.PAR",body); }
35791  std::FILE *file = cimg::fopen(filenamepar,"r");
35792 
35793  // Parse header file
35794  CImgList<floatT> st_slices;
35795  CImgList<uintT> st_global;
35796  int err;
35797  char line[256] = { 0 };
35798  do { err=std::fscanf(file,"%255[^\n]%*c",line); } while (err!=EOF && (line[0]=='#' || line[0]=='.'));
35799  do {
35800  unsigned int sn,sizex,sizey,pixsize;
35801  float rs,ri,ss;
35802  err = 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);
35803  if (err==7) {
35804  CImg<floatT>::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,ri,rs,ss,0).transfer_to(st_slices);
35805  unsigned int i; for (i = 0; i<st_global.width && sn<=st_global[i][2]; ++i) {}
35806  if (i==st_global.width) CImg<uintT>::vector(sizex,sizey,sn).transfer_to(st_global);
35807  else {
35808  CImg<uintT> &vec = st_global[i];
35809  if (sizex>vec[0]) vec[0] = sizex;
35810  if (sizey>vec[1]) vec[1] = sizey;
35811  vec[2] = sn;
35812  }
35813  st_slices[st_slices.width-1][7] = (float)i;
35814  }
35815  } while (err==7);
35816 
35817  // Read data
35818  std::FILE *file2 = cimg::fopen(filenamerec,"rb");
35819  cimglist_for(st_global,l) {
35820  const CImg<uintT>& vec = st_global[l];
35821  CImg<T>(vec[0],vec[1],vec[2]).transfer_to(*this);
35822  }
35823 
35824  cimglist_for(st_slices,l) {
35825  const CImg<floatT>& vec = st_slices[l];
35826  const unsigned int
35827  sn = (unsigned int)vec[0]-1,
35828  pixsize = (unsigned int)vec[1],
35829  sizex = (unsigned int)vec[2],
35830  sizey = (unsigned int)vec[3],
35831  imn = (unsigned int)vec[7];
35832  const float ri = vec[4], rs = vec[5], ss = vec[6];
35833  switch (pixsize) {
35834  case 8 : {
35835  CImg<ucharT> buf(sizex,sizey);
35836  cimg::fread(buf.data,sizex*sizey,file2);
35837  if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
35838  CImg<T>& img = (*this)[imn];
35839  cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
35840  } break;
35841  case 16 : {
35842  CImg<ushortT> buf(sizex,sizey);
35843  cimg::fread(buf.data,sizex*sizey,file2);
35844  if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
35845  CImg<T>& img = (*this)[imn];
35846  cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
35847  } break;
35848  case 32 : {
35849  CImg<uintT> buf(sizex,sizey);
35850  cimg::fread(buf.data,sizex*sizey,file2);
35851  if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
35852  CImg<T>& img = (*this)[imn];
35853  cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
35854  } break;
35855  default :
35856  cimg::fclose(file);
35857  cimg::fclose(file2);
35858  throw CImgIOException("CImg<%s>::load_parrec() : File '%s', cannot handle image with pixsize = %d bits.",
35859  pixel_type(),filename,pixsize);
35860  }
35861  }
35862  cimg::fclose(file);
35863  cimg::fclose(file2);
35864  if (!width)
35865  throw CImgIOException("CImg<%s>::load_parrec() : File '%s' does not appear to be a valid PAR-REC file.",
35866  pixel_type(),filename);
35867  return *this;
35868  }
35869 
35870  static CImgList<T> get_load_parrec(const char *const filename) {
35871  return CImgList<T>().load_parrec(filename);
35872  }
35873 
35875  CImgList<T>& load_yuv(const char *const filename,
35876  const unsigned int sizex, const unsigned int sizey,
35877  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35878  const unsigned int step_frame=1, const bool yuv2rgb=true) {
35879  return _load_yuv(0,filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35880  }
35881 
35882  static CImgList<T> get_load_yuv(const char *const filename,
35883  const unsigned int sizex, const unsigned int sizey=1,
35884  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35885  const unsigned int step_frame=1, const bool yuv2rgb=true) {
35886  return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35887  }
35888 
35890  CImgList<T>& load_yuv(std::FILE *const file,
35891  const unsigned int sizex, const unsigned int sizey,
35892  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35893  const unsigned int step_frame=1, const bool yuv2rgb=true) {
35894  return _load_yuv(file,0,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35895  }
35896 
35897  static CImgList<T> get_load_yuv(std::FILE *const file,
35898  const unsigned int sizex, const unsigned int sizey=1,
35899  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35900  const unsigned int step_frame=1, const bool yuv2rgb=true) {
35901  return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35902  }
35903 
35904  CImgList<T>& _load_yuv(std::FILE *const file, const char *const filename,
35905  const unsigned int sizex, const unsigned int sizey,
35906  const unsigned int first_frame, const unsigned int last_frame,
35907  const unsigned int step_frame, const bool yuv2rgb) {
35908  if (!filename && !file)
35909  throw CImgArgumentException("CImgList<%s>::load_yuv() : Cannot load (null) filename.",
35910  pixel_type());
35911  if (sizex%2 || sizey%2)
35912  throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', image dimensions along X and Y must be "
35913  "even numbers (given are %ux%u)\n",
35914  pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35915  if (!sizex || !sizey)
35916  throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given image sequence size (%u,%u) is invalid",
35917  pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35918 
35919  const unsigned int
35920  nfirst_frame = first_frame<last_frame?first_frame:last_frame,
35921  nlast_frame = first_frame<last_frame?last_frame:first_frame,
35922  nstep_frame = step_frame?step_frame:1;
35923 
35924  CImg<ucharT> tmp(sizex,sizey,1,3), UV(sizex/2,sizey/2,1,2);
35925  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
35926  bool stopflag = false;
35927  int err;
35928  if (nfirst_frame) {
35929  err = std::fseek(nfile,nfirst_frame*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
35930  if (err) {
35931  if (!file) cimg::fclose(nfile);
35932  throw CImgIOException("CImgList<%s>::load_yuv() : File '%s' doesn't contain frame number %u "
35933  "(out of range error).",
35934  pixel_type(),filename?filename:"(FILE*)",nfirst_frame);
35935  }
35936  }
35937  unsigned int frame;
35938  for (frame = nfirst_frame; !stopflag && frame<=nlast_frame; frame+=nstep_frame) {
35939  tmp.fill(0);
35940  // *TRY* to read the luminance part, do not replace by cimg::fread !
35941  err = (int)std::fread((void*)(tmp.data),1,(size_t)(tmp.width*tmp.height),nfile);
35942  if (err!=(int)(tmp.width*tmp.height)) {
35943  stopflag = true;
35944  if (err>0)
35945  cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
35946  " or given image dimensions (%u,%u) are incorrect.",
35947  pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35948  } else {
35949  UV.fill(0);
35950  // *TRY* to read the luminance part, do not replace by cimg::fread !
35951  err = (int)std::fread((void*)(UV.data),1,(size_t)(UV.size()),nfile);
35952  if (err!=(int)(UV.size())) {
35953  stopflag = true;
35954  if (err>0)
35955  cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
35956  " or given image dimensions (%u,%u) are incorrect.",
35957  pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35958  } else {
35959  cimg_forXY(UV,x,y) {
35960  const int x2 = x*2, y2 = y*2;
35961  tmp(x2,y2,1) = tmp(x2+1,y2,1) = tmp(x2,y2+1,1) = tmp(x2+1,y2+1,1) = UV(x,y,0);
35962  tmp(x2,y2,2) = tmp(x2+1,y2,2) = tmp(x2,y2+1,2) = tmp(x2+1,y2+1,2) = UV(x,y,1);
35963  }
35964  if (yuv2rgb) tmp.YCbCrtoRGB();
35965  insert(tmp);
35966  if (nstep_frame>1) std::fseek(nfile,(nstep_frame-1)*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
35967  }
35968  }
35969  }
35970  if (stopflag && nlast_frame!=~0U && frame!=nlast_frame)
35971  cimg::warn("CImgList<%s>::load_yuv() : File '%s', frame %d not reached since only %u frames were found in the file.",
35972  pixel_type(),filename?filename:"(FILE*)",nlast_frame,frame-1,filename);
35973  if (!file) cimg::fclose(nfile);
35974  return *this;
35975  }
35976 
35978  // This piece of code has been firstly created by David Starweather (starkdg(at)users(dot)sourceforge(dot)net)
35979  // I modified it afterwards for direct inclusion in the library core.
35980  CImgList<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35981  const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false) {
35982  if (!filename)
35983  throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : Cannot load (null) filename.",
35984  pixel_type());
35985  const unsigned int
35986  nfirst_frame = first_frame<last_frame?first_frame:last_frame,
35987  nlast_frame = first_frame<last_frame?last_frame:first_frame,
35988  nstep_frame = step_frame?step_frame:1;
35989  assign();
35990 
35991 #ifndef cimg_use_ffmpeg
35992  if ((nfirst_frame || nlast_frame!=~0U || nstep_frame>1) || (resume && (pixel_format || !pixel_format)))
35993  throw CImgArgumentException("CImg<%s>::load_ffmpeg() : File '%s', reading sub-frames from a video file requires the use of ffmpeg.\n"
35994  "('cimg_use_ffmpeg' must be defined).",
35995  pixel_type(),filename);
35996  return load_ffmpeg_external(filename);
35997 #else
35998  const unsigned int ffmpeg_pixfmt = pixel_format?PIX_FMT_RGB24:PIX_FMT_GRAY8;
35999  avcodec_register_all();
36000  av_register_all();
36001  static AVFormatContext *format_ctx = 0;
36002  static AVCodecContext *codec_ctx = 0;
36003  static AVCodec *codec = 0;
36004  static AVFrame *avframe = avcodec_alloc_frame(), *converted_frame = avcodec_alloc_frame();
36005  static int vstream = 0;
36006 
36007  if (resume) {
36008  if (!format_ctx || !codec_ctx || !codec || !avframe || !converted_frame)
36009  throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : File '%s', cannot resume due to unallocated FFMPEG structures.",
36010  pixel_type(),filename);
36011  } else {
36012  // Open video file, find main video stream and codec.
36013  if (format_ctx) av_close_input_file(format_ctx);
36014  if (av_open_input_file(&format_ctx,filename,0,0,0)!=0)
36015  throw CImgIOException("CImgList<%s>::load_ffmpeg() : File '%s' cannot be opened.",
36016  pixel_type(),filename);
36017  if (!avframe || !converted_frame || av_find_stream_info(format_ctx)<0) {
36018  av_close_input_file(format_ctx); format_ctx = 0;
36019  cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve stream information.\n"
36020  "Trying with external ffmpeg executable.",
36021  pixel_type(),filename);
36022  return load_ffmpeg_external(filename);
36023  }
36024 #if cimg_debug>=3
36025  dump_format(format_ctx,0,0,0);
36026 #endif
36027 
36028  // Special command : Return informations on main video stream.
36029  // as a vector 1x4 containing : (nb_frames,width,height,fps).
36030  if (!first_frame && !last_frame && !step_frame) {
36031  for (vstream = 0; vstream<(int)(format_ctx->nb_streams); ++vstream)
36032  if (format_ctx->streams[vstream]->codec->codec_type==CODEC_TYPE_VIDEO) break;
36033  if (vstream==(int)format_ctx->nb_streams) assign();
36034  else {
36035  CImgList<doubleT> timestamps;
36036  int nb_frames;
36037  AVPacket packet;
36038  // Count frames and store timestamps.
36039  for (nb_frames = 0; av_read_frame(format_ctx,&packet)>=0; av_free_packet(&packet))
36040  if (packet.stream_index==vstream) {
36041  CImg<doubleT>::vector((double)packet.pts).transfer_to(timestamps);
36042  ++nb_frames;
36043  }
36044  // Get frame with, height and fps.
36045  const int
36046  framew = format_ctx->streams[vstream]->codec->width,
36047  frameh = format_ctx->streams[vstream]->codec->height;
36048  const float
36049  num = (float)(format_ctx->streams[vstream]->r_frame_rate).num,
36050  den = (float)(format_ctx->streams[vstream]->r_frame_rate).den,
36051  fps = num/den;
36052  // Return infos as a list.
36053  assign(2);
36054  (*this)[0].assign(1,4).fill((T)nb_frames,(T)framew,(T)frameh,(T)fps);
36055  (*this)[1] = (timestamps>'y');
36056  }
36057  av_close_input_file(format_ctx); format_ctx = 0;
36058  return *this;
36059  }
36060 
36061  for (vstream = 0; vstream<(int)(format_ctx->nb_streams) &&
36062  format_ctx->streams[vstream]->codec->codec_type!=CODEC_TYPE_VIDEO; ) ++vstream;
36063  if (vstream==(int)format_ctx->nb_streams) {
36064  cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve video stream.\n"
36065  "Trying with external ffmpeg executable.",
36066  pixel_type(),filename);
36067  av_close_input_file(format_ctx); format_ctx = 0;
36068  return load_ffmpeg_external(filename);
36069  }
36070  codec_ctx = format_ctx->streams[vstream]->codec;
36071  codec = avcodec_find_decoder(codec_ctx->codec_id);
36072  if (!codec) {
36073  cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot find video codec.\n"
36074  "Trying with external ffmpeg executable.",
36075  pixel_type(),filename);
36076  return load_ffmpeg_external(filename);
36077  }
36078  if (avcodec_open(codec_ctx,codec)<0) { // Open codec
36079  cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot open video codec.\n"
36080  "Trying with external ffmpeg executable.",
36081  pixel_type(),filename);
36082  return load_ffmpeg_external(filename);
36083  }
36084  }
36085 
36086  // Read video frames
36087  const unsigned int numBytes = avpicture_get_size(ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
36088  uint8_t *const buffer = new uint8_t[numBytes];
36089  avpicture_fill((AVPicture *)converted_frame,buffer,ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
36090  const T foo = (T)0;
36091  AVPacket packet;
36092  for (unsigned int frame = 0, next_frame = nfirst_frame; frame<=nlast_frame && av_read_frame(format_ctx,&packet)>=0; ) {
36093  if (packet.stream_index==(int)vstream) {
36094  int decoded = 0;
36095  avcodec_decode_video(codec_ctx,avframe,&decoded,packet.data,packet.size);
36096  if (decoded) {
36097  if (frame==next_frame) {
36098  SwsContext *c = sws_getContext(codec_ctx->width,codec_ctx->height,codec_ctx->pix_fmt,codec_ctx->width,
36099  codec_ctx->height,ffmpeg_pixfmt,1,0,0,0);
36100  sws_scale(c,avframe->data,avframe->linesize,0,codec_ctx->height,converted_frame->data,converted_frame->linesize);
36101  if (ffmpeg_pixfmt==PIX_FMT_RGB24) {
36102  CImg<ucharT> next_image(*converted_frame->data,3,codec_ctx->width,codec_ctx->height,1,true);
36103  next_image._get_permute_axes("yzvx",foo).transfer_to(*this);
36104  } else {
36105  CImg<ucharT> next_image(*converted_frame->data,1,codec_ctx->width,codec_ctx->height,1,true);
36106  next_image._get_permute_axes("yzvx",foo).transfer_to(*this);
36107  }
36108  next_frame+=nstep_frame;
36109  }
36110  ++frame;
36111  }
36112  av_free_packet(&packet);
36113  if (next_frame>nlast_frame) break;
36114  }
36115  }
36116  delete[] buffer;
36117 #endif
36118  return *this;
36119  }
36120 
36121  static CImgList<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
36122  const unsigned int step_frame=1, const bool pixel_format=true) {
36123  return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format);
36124  }
36125 
36127  CImgList<T>& load_ffmpeg_external(const char *const filename) {
36128  if (!filename)
36129  throw CImgArgumentException("CImgList<%s>::load_ffmpeg_external() : Cannot load (null) filename.",
36130  pixel_type());
36131  char command[1024] = { 0 }, filetmp[512] = { 0 }, filetmp2[512] = { 0 };
36132  std::FILE *file = 0;
36133  do {
36134  std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
36135  std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
36136  if ((file=std::fopen(filetmp2,"rb"))!=0) std::fclose(file);
36137  } while (file);
36138  std::sprintf(filetmp2,"%s_%%6d.ppm",filetmp);
36139 #if cimg_OS!=2
36140  std::sprintf(command,"%s -i \"%s\" %s >/dev/null 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
36141 #else
36142  std::sprintf(command,"\"%s -i \"%s\" %s\" >NUL 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
36143 #endif
36144  cimg::system(command,0);
36145  const unsigned int omode = cimg::exception_mode();
36146  cimg::exception_mode() = 0;
36147  assign();
36148  unsigned int i = 1;
36149  for (bool stopflag = false; !stopflag; ++i) {
36150  std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,i);
36151  CImg<T> img;
36152  try { img.load_pnm(filetmp2); }
36153  catch (CImgException&) { stopflag = true; }
36154  if (img) { img.transfer_to(*this); std::remove(filetmp2); }
36155  }
36156  cimg::exception_mode() = omode;
36157  if (is_empty())
36158  throw CImgIOException("CImgList<%s>::load_ffmpeg_external() : Failed to open image sequence '%s'.\n"
36159  "Check the filename and if the 'ffmpeg' tool is installed on your system.",
36160  pixel_type(),filename);
36161  return *this;
36162  }
36163 
36164  static CImgList<T> get_load_ffmpeg_external(const char *const filename) {
36165  return CImgList<T>().load_ffmpeg_external(filename);
36166  }
36167 
36169  CImgList<T>& load_gzip_external(const char *const filename) {
36170  if (!filename)
36171  throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
36172  pixel_type());
36173  char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 };
36174  const char
36175  *ext = cimg::split_filename(filename,body),
36176  *ext2 = cimg::split_filename(body,0);
36177  std::FILE *file = 0;
36178  do {
36179  if (!cimg::strcasecmp(ext,"gz")) {
36180  if (*ext2) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);
36181  else std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
36182  } else {
36183  if (*ext) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);
36184  else std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
36185  }
36186  if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
36187  } while (file);
36188  std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
36189  cimg::system(command);
36190  if (!(file = std::fopen(filetmp,"rb"))) {
36191  cimg::fclose(cimg::fopen(filename,"r"));
36192  throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
36193  pixel_type(),filename);
36194  } else cimg::fclose(file);
36195  load(filetmp);
36196  std::remove(filetmp);
36197  return *this;
36198  }
36199 
36200  static CImgList<T> get_load_gzip_external(const char *const filename) {
36201  return CImgList<T>().load_gzip_external(filename);
36202  }
36203 
36205  template<typename tf, typename tc>
36206  CImgList<T>& load_off(const char *const filename,
36207  CImgList<tf>& primitives, CImgList<tc>& colors) {
36208  return get_load_off(filename,primitives,colors).transfer_to(*this);
36209  }
36210 
36211  template<typename tf, typename tc>
36212  static CImgList<T> get_load_off(const char *const filename,
36213  CImgList<tf>& primitives, CImgList<tc>& colors) {
36214  return CImg<T>().load_off(filename,primitives,colors)<'x';
36215  }
36216 
36218  CImgList<T>& load_tiff(const char *const filename,
36219  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
36220  const unsigned int step_frame=1) {
36221  const unsigned int
36222  nfirst_frame = first_frame<last_frame?first_frame:last_frame,
36223  nstep_frame = step_frame?step_frame:1;
36224  unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
36225 #ifndef cimg_use_tiff
36226  if (nfirst_frame || nlast_frame!=~0U || nstep_frame!=1)
36227  throw CImgArgumentException("CImgList<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
36228  "('cimg_use_tiff' must be defined).",
36229  pixel_type(),filename);
36230  return assign(CImg<T>::get_load_tiff(filename));
36231 #else
36232  TIFF *tif = TIFFOpen(filename,"r");
36233  if (tif) {
36234  unsigned int nb_images = 0;
36235  do ++nb_images; while (TIFFReadDirectory(tif));
36236  if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
36237  cimg::warn("CImgList<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
36238  pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
36239  if (nfirst_frame>=nb_images) return assign();
36240  if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
36241  assign(1+(nlast_frame-nfirst_frame)/nstep_frame);
36242  TIFFSetDirectory(tif,0);
36243 #if cimg_debug>=3
36244  TIFFSetWarningHandler(0);
36245  TIFFSetErrorHandler(0);
36246 #endif
36247  cimglist_for(*this,l) data[l]._load_tiff(tif,nfirst_frame + l*nstep_frame);
36248  TIFFClose(tif);
36249  } else throw CImgException("CImgList<%s>::load_tiff() : File '%s' cannot be opened.",
36250  pixel_type(),filename);
36251  return *this;
36252 #endif
36253  }
36254 
36255  static CImgList<T> get_load_tiff(const char *const filename,
36256  const unsigned int first_frame=0, const unsigned int last_frame=~0U,
36257  const unsigned int step_frame=1) {
36258  return CImgList<T>().load_tiff(filename,first_frame,last_frame,step_frame);
36259  }
36260 
36262  //----------------------------------
36263  //
36265 
36266  //----------------------------------
36267 
36269  const CImgList<T>& print(const char* title=0, const bool display_stats=true) const {
36270  unsigned int msiz = 0;
36271  cimglist_for(*this,l) msiz += data[l].size();
36272  msiz*=sizeof(T);
36273  const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2);
36274  char ntitle[64] = { 0 };
36275  if (!title) std::sprintf(ntitle,"CImgList<%s>",pixel_type());
36276  std::fprintf(cimg_stdout,"%s: this = %p, size = %u [%u %s], data = (CImg<%s>*)%p..%p.\n",
36277  title?title:ntitle,(void*)this,width,
36278  mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
36279  mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
36280  pixel_type(),(void*)begin(),(void*)((char*)end()-1));
36281  char tmp[16] = { 0 };
36282  cimglist_for(*this,ll) {
36283  std::sprintf(tmp,"[%d]",ll);
36284  std::fprintf(cimg_stdout," ");
36285  data[ll].print(tmp,display_stats);
36286  if (ll==3 && width>8) { ll = width-5; std::fprintf(cimg_stdout," ...\n"); }
36287  }
36288  return *this;
36289  }
36290 
36292 
36301  const CImgList<T>& display(CImgDisplay& disp, const char axis='x', const char align='p') const {
36302  get_append(axis,align).display(disp);
36303  return *this;
36304  }
36305 
36307 
36317  const bool display_info, const char axis='x', const char align='p') const {
36318  if (is_empty())
36319  throw CImgInstanceException("CImgList<%s>::display() : Instance list (%u,%u) is empty.",
36320  pixel_type(),width,data);
36321  const CImg<T> visu = get_append(axis,align);
36322  if (display_info) print(disp.title);
36323  visu.display(disp,false);
36324  return *this;
36325  }
36326 
36328  const CImgList<T>& display(const char *const title=0,
36329  const bool display_info=true, const char axis='x', const char align='p') const {
36330  const CImg<T> visu = get_append(axis,align);
36331  char ntitle[64] = { 0 };
36332  if (!title) std::sprintf(ntitle,"CImgList<%s>",pixel_type());
36333  if (display_info) print(title?title:ntitle);
36334  visu.display(title?title:ntitle,false);
36335  return *this;
36336  }
36337 
36339 
36342  const CImgList<T>& save(const char *const filename, const int number=-1) const {
36343  if (is_empty())
36344  throw CImgInstanceException("CImgList<%s>::save() : File '%s, instance list (%u,%p) is empty.",
36345  pixel_type(),filename?filename:"(null)",width,data);
36346  if (!filename)
36347  throw CImgArgumentException("CImg<%s>::save() : Instance list (%u,%p), specified filename is (null).",
36348  pixel_type(),width,data);
36349  const char *ext = cimg::split_filename(filename);
36350  char nfilename[1024] = { 0 };
36351  const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
36352 #ifdef cimglist_save_plugin
36353  cimglist_save_plugin(fn);
36354 #endif
36355 #ifdef cimglist_save_plugin1
36356  cimglist_save_plugin1(fn);
36357 #endif
36358 #ifdef cimglist_save_plugin2
36359  cimglist_save_plugin2(fn);
36360 #endif
36361 #ifdef cimglist_save_plugin3
36362  cimglist_save_plugin3(fn);
36363 #endif
36364 #ifdef cimglist_save_plugin4
36365  cimglist_save_plugin4(fn);
36366 #endif
36367 #ifdef cimglist_save_plugin5
36368  cimglist_save_plugin5(fn);
36369 #endif
36370 #ifdef cimglist_save_plugin6
36371  cimglist_save_plugin6(fn);
36372 #endif
36373 #ifdef cimglist_save_plugin7
36374  cimglist_save_plugin7(fn);
36375 #endif
36376 #ifdef cimglist_save_plugin8
36377  cimglist_save_plugin8(fn);
36378 #endif
36379 #ifdef cimg_use_tiff
36380  if (!cimg::strcasecmp(ext,"tif") ||
36381  !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
36382 #endif
36383  if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
36384  if (!cimg::strcasecmp(ext,"cimg") || !ext[0]) return save_cimg(fn,false);
36385  if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
36386  if (!cimg::strcasecmp(ext,"avi") ||
36387  !cimg::strcasecmp(ext,"mov") ||
36388  !cimg::strcasecmp(ext,"asf") ||
36389  !cimg::strcasecmp(ext,"divx") ||
36390  !cimg::strcasecmp(ext,"flv") ||
36391  !cimg::strcasecmp(ext,"mpg") ||
36392  !cimg::strcasecmp(ext,"m1v") ||
36393  !cimg::strcasecmp(ext,"m2v") ||
36394  !cimg::strcasecmp(ext,"m4v") ||
36395  !cimg::strcasecmp(ext,"mjp") ||
36396  !cimg::strcasecmp(ext,"mkv") ||
36397  !cimg::strcasecmp(ext,"mpe") ||
36398  !cimg::strcasecmp(ext,"movie") ||
36399  !cimg::strcasecmp(ext,"ogm") ||
36400  !cimg::strcasecmp(ext,"qt") ||
36401  !cimg::strcasecmp(ext,"rm") ||
36402  !cimg::strcasecmp(ext,"vob") ||
36403  !cimg::strcasecmp(ext,"wmv") ||
36404  !cimg::strcasecmp(ext,"xvid") ||
36405  !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
36406  if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
36407  if (width==1) data[0].save(fn,-1); else cimglist_for(*this,l) data[l].save(fn,l);
36408  return *this;
36409  }
36410 
36412  // This piece of code has been originally written by David. G. Starkweather.
36413  const CImgList<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
36414  const unsigned int fps=25) const {
36415  if (is_empty())
36416  throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', instance list (%u,%p) is empty.",
36417  pixel_type(),filename?filename:"(null)",width,data);
36418  if (!filename)
36419  throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : Instance list (%u,%p), specified filename is (null).",
36420  pixel_type(),width,data);
36421  if (!fps)
36422  throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
36423  pixel_type(),filename);
36424  const unsigned int nlast_frame = last_frame==~0U?width-1:last_frame;
36425  if (first_frame>=width || nlast_frame>=width)
36426  throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
36427  pixel_type(),filename,first_frame,last_frame,width);
36428  for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
36429  throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', images of the sequence have different dimensions.",
36430  pixel_type(),filename);
36431 
36432 #ifndef cimg_use_ffmpeg
36433  return save_ffmpeg_external(filename,first_frame,last_frame);
36434 #else
36435  avcodec_register_all();
36436  av_register_all();
36437  const int
36438  frame_dimx = data[first_frame].dimx(),
36439  frame_dimy = data[first_frame].dimy(),
36440  frame_dimv = data[first_frame].dimv();
36441  if (frame_dimv!=1 && frame_dimv!=3)
36442  throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', image[0] (%u,%u,%u,%u,%p) has not 1 or 3 channels.",
36443  pixel_type(),filename,data[0].width,data[0].height,data[0].depth,data[0].dim,data);
36444 
36445  PixelFormat dest_pxl_fmt = PIX_FMT_YUV420P;
36446  PixelFormat src_pxl_fmt = (frame_dimv == 3)?PIX_FMT_RGB24:PIX_FMT_GRAY8;
36447 
36448  int sws_flags = SWS_FAST_BILINEAR; // Interpolation method (keeping same size images for now).
36449  AVOutputFormat *fmt = 0;
36450  fmt = guess_format(0,filename,0);
36451  if (!fmt) fmt = guess_format("mpeg",0,0); // Default format "mpeg".
36452  if (!fmt)
36453  throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', could not determine file format from filename.",
36454  pixel_type(),filename);
36455 
36456  AVFormatContext *oc = 0;
36457  oc = av_alloc_format_context();
36458  if (!oc) // Failed to allocate format context.
36459  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate structure for format context.",
36460  pixel_type(),filename);
36461 
36462  AVCodec *codec = 0;
36463  AVFrame *picture = 0;
36464  AVFrame *tmp_pict = 0;
36465  oc->oformat = fmt;
36466  std::sprintf(oc->filename,"%s",filename);
36467 
36468  // Add video stream.
36469  int stream_index = 0;
36470  AVStream *video_str = 0;
36471  if (fmt->video_codec!=CODEC_ID_NONE) {
36472  video_str = av_new_stream(oc,stream_index);
36473  if (!video_str) { // Failed to allocate stream.
36474  av_free(oc);
36475  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate video stream structure.",
36476  pixel_type(),filename);
36477  }
36478  } else { // No codec identified.
36479  av_free(oc);
36480  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no proper codec identified.",
36481  pixel_type(),filename);
36482  }
36483 
36484  AVCodecContext *c = video_str->codec;
36485  c->codec_id = fmt->video_codec;
36486  c->codec_type = CODEC_TYPE_VIDEO;
36487  c->bit_rate = 400000;
36488  c->width = frame_dimx;
36489  c->height = frame_dimy;
36490  c->time_base.num = 1;
36491  c->time_base.den = fps;
36492  c->gop_size = 12;
36493  c->pix_fmt = dest_pxl_fmt;
36494  if (c->codec_id == CODEC_ID_MPEG2VIDEO) c->max_b_frames = 2;
36495  if (c->codec_id == CODEC_ID_MPEG1VIDEO) c->mb_decision = 2;
36496 
36497  if (av_set_parameters(oc,0)<0) { // Parameters not properly set.
36498  av_free(oc);
36499  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', parameters for avcodec not properly set.",
36500  pixel_type(),filename);
36501  }
36502 
36503  // Open codecs and alloc buffers.
36504  codec = avcodec_find_encoder(c->codec_id);
36505  if (!codec) { // Failed to find codec.
36506  av_free(oc);
36507  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no codec found.",
36508  pixel_type(),filename);
36509  }
36510  if (avcodec_open(c,codec)<0) // Failed to open codec.
36511  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to open codec.",
36512  pixel_type(),filename);
36513  tmp_pict = avcodec_alloc_frame();
36514  if (!tmp_pict) { // Failed to allocate memory for tmp_pict frame.
36515  avcodec_close(video_str->codec);
36516  av_free(oc);
36517  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
36518  pixel_type(),filename);
36519  }
36520  tmp_pict->linesize[0] = (src_pxl_fmt==PIX_FMT_RGB24)?3*frame_dimx:frame_dimx;
36521  tmp_pict->type = FF_BUFFER_TYPE_USER;
36522  int tmp_size = avpicture_get_size(src_pxl_fmt,frame_dimx,frame_dimy);
36523  uint8_t *tmp_buffer = (uint8_t*)av_malloc(tmp_size);
36524  if (!tmp_buffer) { // Failed to allocate memory for tmp buffer.
36525  av_free(tmp_pict);
36526  avcodec_close(video_str->codec);
36527  av_free(oc);
36528  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
36529  pixel_type(),filename);
36530  }
36531 
36532  // Associate buffer with tmp_pict.
36533  avpicture_fill((AVPicture*)tmp_pict,tmp_buffer,src_pxl_fmt,frame_dimx,frame_dimy);
36534  picture = avcodec_alloc_frame();
36535  if (!picture) { // Failed to allocate picture frame.
36536  av_free(tmp_pict->data[0]);
36537  av_free(tmp_pict);
36538  avcodec_close(video_str->codec);
36539  av_free(oc);
36540  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame.",
36541  pixel_type(),filename);
36542  }
36543 
36544  int size = avpicture_get_size(c->pix_fmt,frame_dimx,frame_dimy);
36545  uint8_t *buffer = (uint8_t*)av_malloc(size);
36546  if (!buffer) { // Failed to allocate picture frame buffer.
36547  av_free(picture);
36548  av_free(tmp_pict->data[0]);
36549  av_free(tmp_pict);
36550  avcodec_close(video_str->codec);
36551  av_free(oc);
36552  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame buffer.",
36553  pixel_type(),filename);
36554  }
36555 
36556  // Associate the buffer with picture.
36557  avpicture_fill((AVPicture*)picture,buffer,c->pix_fmt,frame_dimx,frame_dimy);
36558 
36559  // Open file.
36560  if (!(fmt->flags&AVFMT_NOFILE)) {
36561  if (url_fopen(&oc->pb,filename,URL_WRONLY)<0)
36562  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s' cannot be opened.",
36563  pixel_type(),filename);
36564  }
36565 
36566  if (av_write_header(oc)<0)
36567  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', could not write header.",
36568  pixel_type(),filename);
36569  double video_pts;
36570  SwsContext *img_convert_context = 0;
36571  img_convert_context = sws_getContext(frame_dimx,frame_dimy,src_pxl_fmt,
36572  c->width,c->height,c->pix_fmt,sws_flags,0,0,0);
36573  if (!img_convert_context) { // Failed to get swscale context.
36574  // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
36575  av_free(picture->data);
36576  av_free(picture);
36577  av_free(tmp_pict->data[0]);
36578  av_free(tmp_pict);
36579  avcodec_close(video_str->codec);
36580  av_free(oc);
36581  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%', failed to get conversion context.",
36582  pixel_type(),filename);
36583  }
36584  int ret = 0, out_size;
36585  uint8_t *video_outbuf = 0;
36586  int video_outbuf_size = 1000000;
36587  video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);
36588  if (!video_outbuf) {
36589  // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
36590  av_free(picture->data);
36591  av_free(picture);
36592  av_free(tmp_pict->data[0]);
36593  av_free(tmp_pict);
36594  avcodec_close(video_str->codec);
36595  av_free(oc);
36596  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', memory allocation error.",
36597  pixel_type(),filename);
36598  }
36599 
36600  // Loop through each desired image in list.
36601  for (unsigned int i = first_frame; i<=nlast_frame; ++i) {
36602  CImg<uint8_t> currentIm = data[i], red, green, blue, gray;
36603  if (src_pxl_fmt == PIX_FMT_RGB24) {
36604  red = currentIm.get_shared_channel(0);
36605  green = currentIm.get_shared_channel(1);
36606  blue = currentIm.get_shared_channel(2);
36607  cimg_forXY(currentIm,X,Y) { // Assign pizel values to data buffer in interlaced RGBRGB ... format.
36608  tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X] = red(X,Y);
36609  tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 1] = green(X,Y);
36610  tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 2] = blue(X,Y);
36611  }
36612  } else {
36613  gray = currentIm.get_shared_channel(0);
36614  cimg_forXY(currentIm,X,Y) tmp_pict->data[0][Y*tmp_pict->linesize[0] + X] = gray(X,Y);
36615  }
36616 
36617  if (video_str) video_pts = (video_str->pts.val * video_str->time_base.num)/(video_str->time_base.den);
36618  else video_pts = 0.0;
36619  if (!video_str) break;
36620  if (sws_scale(img_convert_context,tmp_pict->data,tmp_pict->linesize,0,c->height,picture->data,picture->linesize)<0) break;
36621  out_size = avcodec_encode_video(c,video_outbuf,video_outbuf_size,picture);
36622  if (out_size>0) {
36623  AVPacket pkt;
36624  av_init_packet(&pkt);
36625  pkt.pts = av_rescale_q(c->coded_frame->pts,c->time_base,video_str->time_base);
36626  if (c->coded_frame->key_frame) pkt.flags|=PKT_FLAG_KEY;
36627  pkt.stream_index = video_str->index;
36628  pkt.data = video_outbuf;
36629  pkt.size = out_size;
36630  ret = av_write_frame(oc,&pkt);
36631  } else if (out_size<0) break;
36632  if (ret) break; // Error occured in writing frame.
36633  }
36634 
36635  // Close codec.
36636  if (video_str) {
36637  avcodec_close(video_str->codec);
36638  av_free(picture->data[0]);
36639  av_free(picture);
36640  av_free(tmp_pict->data[0]);
36641  av_free(tmp_pict);
36642  }
36643  if (av_write_trailer(oc)<0)
36644  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to write trailer.",
36645  pixel_type(),filename);
36646  av_freep(&oc->streams[stream_index]->codec);
36647  av_freep(&oc->streams[stream_index]);
36648  if (!(fmt->flags&AVFMT_NOFILE)) {
36649  /*if (url_fclose(oc->pb)<0)
36650  throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to close file.",
36651  pixel_type(),filename);
36652  */
36653  }
36654  av_free(oc);
36655  av_free(video_outbuf);
36656 #endif
36657  return *this;
36658  }
36659 
36660  // Save an image sequence into a YUV file (internal).
36661  const CImgList<T>& _save_yuv(std::FILE *const file, const char *const filename, const bool rgb2yuv) const {
36662  if (is_empty())
36663  throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', instance list (%u,%p) is empty.",
36664  pixel_type(),filename?filename:"(FILE*)",width,data);
36665  if (!file && !filename)
36666  throw CImgArgumentException("CImg<%s>::save_yuv() : Instance list (%u,%p), specified file is (null).",
36667  pixel_type(),width,data);
36668  if ((*this)[0].dimx()%2 || (*this)[0].dimy()%2)
36669  throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', image dimensions must be even numbers (current are %ux%u).",
36670  pixel_type(),filename?filename:"(FILE*)",(*this)[0].dimx(),(*this)[0].dimy());
36671 
36672  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
36673  cimglist_for(*this,l) {
36674  CImg<ucharT> YCbCr((*this)[l]);
36675  if (rgb2yuv) YCbCr.RGBtoYCbCr();
36676  cimg::fwrite(YCbCr.data,YCbCr.width*YCbCr.height,nfile);
36677  cimg::fwrite(YCbCr.get_resize(YCbCr.width/2, YCbCr.height/2,1,3,3).ptr(0,0,0,1),
36678  YCbCr.width*YCbCr.height/2,nfile);
36679  }
36680  if (!file) cimg::fclose(nfile);
36681  return *this;
36682  }
36683 
36685  const CImgList<T>& save_yuv(const char *const filename=0, const bool rgb2yuv=true) const {
36686  return _save_yuv(0,filename,rgb2yuv);
36687  }
36688 
36690  const CImgList<T>& save_yuv(std::FILE *const file, const bool rgb2yuv=true) const {
36691  return _save_yuv(file,0,rgb2yuv);
36692  }
36693 
36695 
36700  const CImgList<T>& _save_cimg(std::FILE *const file, const char *const filename, const bool compression) const {
36701  if (is_empty())
36702  throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
36703  pixel_type(),filename?filename:"(FILE*)",width,data);
36704  if (!file && !filename)
36705  throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
36706  pixel_type(),width,data);
36707  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
36708  const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little";
36709  if (std::strstr(ptype,"unsigned")==ptype) std::fprintf(nfile,"%u unsigned_%s %s_endian\n",width,ptype+9,etype);
36710  else std::fprintf(nfile,"%u %s %s_endian\n",width,ptype,etype);
36711  cimglist_for(*this,l) {
36712  const CImg<T>& img = data[l];
36713  std::fprintf(nfile,"%u %u %u %u",img.width,img.height,img.depth,img.dim);
36714  if (img.data) {
36715  CImg<T> tmp;
36716  if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp.data,tmp.size()); }
36717  const CImg<T>& ref = cimg::endianness()?tmp:img;
36718  bool compressed = false;
36719  if (compression) {
36720 #ifdef cimg_use_zlib
36721  const unsigned long siz = sizeof(T)*ref.size();
36722  unsigned long csiz = siz + siz/100 + 16;
36723  Bytef *const cbuf = new Bytef[csiz];
36724  if (compress(cbuf,&csiz,(Bytef*)ref.data,siz)) {
36725  cimg::warn("CImgList<%s>::save_cimg() : File '%s', failed to save compressed data.\n Data will be saved uncompressed.",
36726  pixel_type(),filename?filename:"(FILE*)");
36727  compressed = false;
36728  } else {
36729  std::fprintf(nfile," #%lu\n",csiz);
36730  cimg::fwrite(cbuf,csiz,nfile);
36731  delete[] cbuf;
36732  compressed = true;
36733  }
36734 #else
36735  cimg::warn("CImgList<%s>::save_cimg() : File '%s', cannot save compressed data unless zlib is used "
36736  "('cimg_use_zlib' must be defined).\n Data will be saved uncompressed.",
36737  pixel_type(),filename?filename:"(FILE*)");
36738  compressed = false;
36739 #endif
36740  }
36741  if (!compressed) {
36742  std::fputc('\n',nfile);
36743  cimg::fwrite(ref.data,ref.size(),nfile);
36744  }
36745  } else std::fputc('\n',nfile);
36746  }
36747  if (!file) cimg::fclose(nfile);
36748  return *this;
36749  }
36750 
36752  const CImgList<T>& save_cimg(std::FILE *file, const bool compress=false) const {
36753  return _save_cimg(file,0,compress);
36754  }
36755 
36757  const CImgList<T>& save_cimg(const char *const filename, const bool compress=false) const {
36758  return _save_cimg(0,filename,compress);
36759  }
36760 
36761  // Insert the instance image into into an existing .cimg file, at specified coordinates.
36762  const CImgList<T>& _save_cimg(std::FILE *const file, const char *const filename,
36763  const unsigned int n0,
36764  const unsigned int x0, const unsigned int y0,
36765  const unsigned int z0, const unsigned int v0) const {
36766 #define _cimg_save_cimg_case(Ts,Tss) \
36767  if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \
36768  for (unsigned int l = 0; l<lmax; ++l) { \
36769  j = 0; while((i=std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j] = 0; \
36770  W = H = D = V = 0; \
36771  if (std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
36772  throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
36773  pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
36774  if (W*H*D*V>0) { \
36775  if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
36776  else { \
36777  const CImg<T>& img = (*this)[l - n0]; \
36778  const T *ptrs = img.data; \
36779  const unsigned int \
36780  x1 = x0 + img.width - 1, \
36781  y1 = y0 + img.height - 1, \
36782  z1 = z0 + img.depth - 1, \
36783  v1 = v0 + img.dim - 1, \
36784  nx1 = x1>=W?W-1:x1, \
36785  ny1 = y1>=H?H-1:y1, \
36786  nz1 = z1>=D?D-1:z1, \
36787  nv1 = v1>=V?V-1:v1; \
36788  CImg<Tss> raw(1+nx1-x0); \
36789  const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
36790  if (skipvb) std::fseek(nfile,skipvb,SEEK_CUR); \
36791  for (unsigned int v = 1 + nv1 - v0; v; --v) { \
36792  const unsigned int skipzb = z0*W*H*sizeof(Tss); \
36793  if (skipzb) std::fseek(nfile,skipzb,SEEK_CUR); \
36794  for (unsigned int z = 1 + nz1 - z0; z; --z) { \
36795  const unsigned int skipyb = y0*W*sizeof(Tss); \
36796  if (skipyb) std::fseek(nfile,skipyb,SEEK_CUR); \
36797  for (unsigned int y = 1 + ny1 - y0; y; --y) { \
36798  const unsigned int skipxb = x0*sizeof(Tss); \
36799  if (skipxb) std::fseek(nfile,skipxb,SEEK_CUR); \
36800  raw.assign(ptrs, raw.width); \
36801  ptrs+=img.width; \
36802  if (endian) cimg::invert_endianness(raw.data,raw.width); \
36803  cimg::fwrite(raw.data,raw.width,nfile); \
36804  const unsigned int skipxe = (W - 1 - nx1)*sizeof(Tss); \
36805  if (skipxe) std::fseek(nfile,skipxe,SEEK_CUR); \
36806  } \
36807  const unsigned int skipye = (H - 1 - ny1)*W*sizeof(Tss); \
36808  if (skipye) std::fseek(nfile,skipye,SEEK_CUR); \
36809  } \
36810  const unsigned int skipze = (D - 1 - nz1)*W*H*sizeof(Tss); \
36811  if (skipze) std::fseek(nfile,skipze,SEEK_CUR); \
36812  } \
36813  const unsigned int skipve = (V - 1 - nv1)*W*H*D*sizeof(Tss); \
36814  if (skipve) std::fseek(nfile,skipve,SEEK_CUR); \
36815  } \
36816  } \
36817  } \
36818  saved = true; \
36819  }
36820  if (is_empty())
36821  throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
36822  pixel_type(),filename?filename:"(FILE*)",width,data);
36823  if (!file && !filename)
36824  throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
36825  pixel_type(),width,data);
36826  typedef unsigned char uchar;
36827  typedef unsigned short ushort;
36828  typedef unsigned int uint;
36829  typedef unsigned long ulong;
36830  std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+");
36831  bool saved = false, endian = cimg::endianness();
36832  char tmp[256] = { 0 }, str_pixeltype[256] = { 0 }, str_endian[256] = { 0 };
36833  unsigned int j, err, N, W, H, D, V;
36834  int i;
36835  j = 0; while((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0;
36836  err = std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
36837  if (err<2) {
36838  if (!file) cimg::fclose(nfile);
36839  throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Unknow CImg RAW header.",
36840  pixel_type(),filename?filename:"(FILE*)");
36841  }
36842  if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
36843  else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
36844  const unsigned int lmax = cimg::min(N,n0+width);
36845  _cimg_save_cimg_case("bool",bool);
36846  _cimg_save_cimg_case("unsigned_char",uchar);
36847  _cimg_save_cimg_case("uchar",uchar);
36848  _cimg_save_cimg_case("char",char);
36849  _cimg_save_cimg_case("unsigned_short",ushort);
36850  _cimg_save_cimg_case("ushort",ushort);
36851  _cimg_save_cimg_case("short",short);
36852  _cimg_save_cimg_case("unsigned_int",uint);
36853  _cimg_save_cimg_case("uint",uint);
36854  _cimg_save_cimg_case("int",int);
36855  _cimg_save_cimg_case("unsigned_long",ulong);
36856  _cimg_save_cimg_case("ulong",ulong);
36857  _cimg_save_cimg_case("long",long);
36858  _cimg_save_cimg_case("float",float);
36859  _cimg_save_cimg_case("double",double);
36860  if (!saved) {
36861  if (!file) cimg::fclose(nfile);
36862  throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', cannot save images of pixels coded as '%s'.",
36863  pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
36864  }
36865  if (!file) cimg::fclose(nfile);
36866  return *this;
36867  }
36868 
36870  const CImgList<T>& save_cimg(const char *const filename,
36871  const unsigned int n0,
36872  const unsigned int x0, const unsigned int y0,
36873  const unsigned int z0, const unsigned int v0) const {
36874  return _save_cimg(0,filename,n0,x0,y0,z0,v0);
36875  }
36876 
36878  const CImgList<T>& save_cimg(std::FILE *const file,
36879  const unsigned int n0,
36880  const unsigned int x0, const unsigned int y0,
36881  const unsigned int z0, const unsigned int v0) const {
36882  return _save_cimg(file,0,n0,x0,y0,z0,v0);
36883  }
36884 
36885  // Create an empty .cimg file with specified dimensions (internal)
36886  static void _save_empty_cimg(std::FILE *const file, const char *const filename,
36887  const unsigned int nb,
36888  const unsigned int dx, const unsigned int dy,
36889  const unsigned int dz, const unsigned int dv) {
36890  std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
36891  const unsigned int siz = dx*dy*dz*dv*sizeof(T);
36892  std::fprintf(nfile,"%u %s\n",nb,pixel_type());
36893  for (unsigned int i=nb; i; --i) {
36894  std::fprintf(nfile,"%u %u %u %u\n",dx,dy,dz,dv);
36895  for (unsigned int off=siz; off; --off) std::fputc(0,nfile);
36896  }
36897  if (!file) cimg::fclose(nfile);
36898  }
36899 
36901  static void save_empty_cimg(const char *const filename,
36902  const unsigned int nb,
36903  const unsigned int dx, const unsigned int dy=1,
36904  const unsigned int dz=1, const unsigned int dv=1) {
36905  return _save_empty_cimg(0,filename,nb,dx,dy,dz,dv);
36906  }
36907 
36909  static void save_empty_cimg(std::FILE *const file,
36910  const unsigned int nb,
36911  const unsigned int dx, const unsigned int dy=1,
36912  const unsigned int dz=1, const unsigned int dv=1) {
36913  return _save_empty_cimg(file,0,nb,dx,dy,dz,dv);
36914  }
36915 
36917 #ifdef cimg_use_tiff
36918  const CImgList<T>& save_tiff(const char *const filename) const {
36919  if (is_empty())
36920  throw CImgInstanceException("CImgList<%s>::save_tiff() : File '%s', instance list (%u,%p) is empty.",
36921  pixel_type(),filename?filename:"(null)",width,data);
36922  if (!filename)
36923  throw CImgArgumentException("CImgList<%s>::save_tiff() : Specified filename is (null) for instance list (%u,%p).",
36924  pixel_type(),width,data);
36925  TIFF *tif = TIFFOpen(filename,"w");
36926  if (tif) {
36927  for (unsigned int dir = 0, l = 0; l<width; ++l) {
36928  const CImg<T>& img = (*this)[l];
36929  if (img) {
36930  if (img.depth==1) img._save_tiff(tif,dir++);
36931  else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++);
36932  }
36933  }
36934  TIFFClose(tif);
36935  } else
36936  throw CImgException("CImgList<%s>::save_tiff() : File '%s', error while opening stream for tiff file.",
36937  pixel_type(),filename);
36938  return *this;
36939  }
36940 #endif
36941 
36943  const CImgList<T>& save_gzip_external(const char *const filename) const {
36944  if (!filename)
36945  throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
36946  pixel_type());
36947  char command[1024] = { 0 }, filetmp[512] = { 0 }, body[512] = { 0 };
36948  const char
36949  *ext = cimg::split_filename(filename,body),
36950  *ext2 = cimg::split_filename(body,0);
36951  std::FILE *file;
36952  do {
36953  if (!cimg::strcasecmp(ext,"gz")) {
36954  if (*ext2) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2);
36955  else std::sprintf(filetmp,"%s%c%s.cimg",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
36956  } else {
36957  if (*ext) std::sprintf(filetmp,"%s%c%s.%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext);
36958  else std::sprintf(filetmp,"%s%c%s.cimg",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
36959  }
36960  if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
36961  } while (file);
36962  save(filetmp);
36963  std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
36964  cimg::system(command);
36965  file = std::fopen(filename,"rb");
36966  if (!file)
36967  throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
36968  pixel_type(),filename);
36969  else cimg::fclose(file);
36970  std::remove(filetmp);
36971  return *this;
36972  }
36973 
36975  const CImgList<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
36976  const char *const codec="mpeg2video") const {
36977  if (is_empty())
36978  throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', instance list (%u,%p) is empty.",
36979  pixel_type(),filename?filename:"(null)",width,data);
36980  if (!filename)
36981  throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : Instance list (%u,%p), specified filename is (null).",
36982  pixel_type(),width,data);
36983  char command[1024] = { 0 }, filetmp[512] = { 0 }, filetmp2[512] = { 0 };
36984  std::FILE *file = 0;
36985  const unsigned int nlast_frame = last_frame==~0U?width-1:last_frame;
36986  if (first_frame>=width || nlast_frame>=width)
36987  throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
36988  pixel_type(),filename,first_frame,last_frame,width);
36989  for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
36990  throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', all images of the sequence must be of the same dimension.",
36991  pixel_type(),filename);
36992  do {
36993  std::sprintf(filetmp,"%s%c%s",cimg::temporary_path(),cimg_file_separator,cimg::filenamerand());
36994  std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
36995  if ((file=std::fopen(filetmp2,"rb"))!=0) std::fclose(file);
36996  } while (file);
36997  for (unsigned int l = first_frame; l<=nlast_frame; ++l) {
36998  std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,l+1);
36999  if (data[l].depth>1 || data[l].dim!=3) data[l].get_resize(-100,-100,1,3).save_pnm(filetmp2);
37000  else data[l].save_pnm(filetmp2);
37001  }
37002 #if cimg_OS!=2
37003  std::sprintf(command,"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\" >/dev/null 2>&1",filetmp,codec,filename);
37004 #else
37005  std::sprintf(command,"\"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\"\" >NUL 2>&1",filetmp,codec,filename);
37006 #endif
37007  cimg::system(command);
37008  file = std::fopen(filename,"rb");
37009  if (!file)
37010  throw CImgIOException("CImg<%s>::save_ffmpeg_external() : Failed to save image sequence '%s'.\n\n",
37011  pixel_type(),filename);
37012  else cimg::fclose(file);
37013  cimglist_for(*this,lll) { std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,lll+1); std::remove(filetmp2); }
37014  return *this;
37015  }
37016 
37018  //----------------------------------
37019  //
37021 
37022  //----------------------------------
37023 
37026  return get_crop_font().transfer_to(*this);
37027  }
37028 
37030  CImgList<T> res;
37031  cimglist_for(*this,l) {
37032  const CImg<T>& letter = (*this)[l];
37033  int xmin = letter.width, xmax = 0;
37034  cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
37035  if (xmin>xmax) CImg<T>(letter.width,letter.height,1,letter.dim,0).transfer_to(res);
37036  else letter.get_crop(xmin,0,xmax,letter.height-1).transfer_to(res);
37037  }
37038  res[' '].resize(res['f'].width);
37039  res[' '+256].resize(res['f'].width);
37040  return res;
37041  }
37042 
37044 
37048  static CImgList<T> font(const unsigned int font_width, const bool variable_size=true) {
37049  if (font_width<=11) {
37050  static CImgList<T> font7x11, nfont7x11;
37051  if (!variable_size && !font7x11) font7x11 = _font(cimg::font7x11,7,11,1,0,false);
37052  if (variable_size && !nfont7x11) nfont7x11 = _font(cimg::font7x11,7,11,1,0,true);
37053  return variable_size?nfont7x11:font7x11;
37054  }
37055  if (font_width<=13) {
37056  static CImgList<T> font10x13, nfont10x13;
37057  if (!variable_size && !font10x13) font10x13 = _font(cimg::font10x13,10,13,1,0,false);
37058  if (variable_size && !nfont10x13) nfont10x13 = _font(cimg::font10x13,10,13,1,0,true);
37059  return variable_size?nfont10x13:font10x13;
37060  }
37061  if (font_width<=17) {
37062  static CImgList<T> font8x17, nfont8x17;
37063  if (!variable_size && !font8x17) font8x17 = _font(cimg::font8x17,8,17,1,0,false);
37064  if (variable_size && !nfont8x17) nfont8x17 = _font(cimg::font8x17,8,17,1,0,true);
37065  return variable_size?nfont8x17:font8x17;
37066  }
37067  if (font_width<=19) {
37068  static CImgList<T> font10x19, nfont10x19;
37069  if (!variable_size && !font10x19) font10x19 = _font(cimg::font10x19,10,19,2,0,false);
37070  if (variable_size && !nfont10x19) nfont10x19 = _font(cimg::font10x19,10,19,2,0,true);
37071  return variable_size?nfont10x19:font10x19;
37072  }
37073  if (font_width<=24) {
37074  static CImgList<T> font12x24, nfont12x24;
37075  if (!variable_size && !font12x24) font12x24 = _font(cimg::font12x24,12,24,2,0,false);
37076  if (variable_size && !nfont12x24) nfont12x24 = _font(cimg::font12x24,12,24,2,0,true);
37077  return variable_size?nfont12x24:font12x24;
37078  }
37079  if (font_width<=32) {
37080  static CImgList<T> font16x32, nfont16x32;
37081  if (!variable_size && !font16x32) font16x32 = _font(cimg::font16x32,16,32,2,0,false);
37082  if (variable_size && !nfont16x32) nfont16x32 = _font(cimg::font16x32,16,32,2,0,true);
37083  return variable_size?nfont16x32:font16x32;
37084  }
37085  if (font_width<=38) {
37086  static CImgList<T> font19x38, nfont19x38;
37087  if (!variable_size && !font19x38) font19x38 = _font(cimg::font19x38,19,38,3,0,false);
37088  if (variable_size && !nfont19x38) nfont19x38 = _font(cimg::font19x38,19,38,3,0,true);
37089  return variable_size?nfont19x38:font19x38;
37090  }
37091  static CImgList<T> font29x57, nfont29x57;
37092  if (!variable_size && !font29x57) font29x57 = _font(cimg::font29x57,29,57,5,0,false);
37093  if (variable_size && !nfont29x57) nfont29x57 = _font(cimg::font29x57,29,57,5,0,true);
37094  return variable_size?nfont29x57:font29x57;
37095  }
37096 
37097  static CImgList<T> _font(const unsigned int *const font, const unsigned int w, const unsigned int h,
37098  const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true) {
37099  CImgList<T> res = CImgList<T>(256,w,h,1,3);
37100  res.insert(256); cimglist_for_in(res,256,511,l) res[l].assign(w,h,1,1);
37101  const unsigned int *ptr = font;
37102  unsigned int m = 0, val = 0;
37103  for (unsigned int y = 0; y<h; ++y)
37104  for (unsigned int x = 0; x<256*w; ++x) {
37105  m>>=1; if (!m) { m = 0x80000000; val = *(ptr++); }
37106  CImg<T>& img = res[x/w], &mask = res[x/w+256];
37107  unsigned int xm = x%w;
37108  img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0);
37109  }
37110  if (variable_size) res.crop_font();
37111  if (paddingx || paddingy) cimglist_for(res,l) res[l].resize(res[l].dimx() + paddingx,res[l].dimy() + paddingy,1,-100,0);
37112  return res;
37113  }
37114 
37116  CImgList<T>& FFT(const char axis, const bool invert=false) {
37117  if (is_empty()) return *this;
37118  if (width==1) insert(1);
37119  if (width>2) cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
37120  pixel_type(),width,data);
37121  CImg<T>::FFT(data[0],data[1],axis,invert);
37122  return *this;
37123  }
37124 
37125  CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
37126  return CImgList<Tfloat>(*this,false).FFT(axis,invert);
37127  }
37128 
37130  CImgList<T>& FFT(const bool invert=false) {
37131  if (is_empty()) return *this;
37132  if (width==1) insert(1);
37133  if (width>2) cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
37134  pixel_type(),width,data);
37135  CImg<T>::FFT(data[0],data[1],invert);
37136  return *this;
37137  }
37138 
37139  CImgList<Tfloat> get_FFT(const bool invert=false) const {
37140  return CImgList<Tfloat>(*this,false).FFT(invert);
37141  }
37142 
37145  cimglist_for(*this,l) {
37146  CImg<T>& p = data[l];
37147  const unsigned int siz = p.size();
37148  if (siz==2 || siz==3 || siz==6 || siz==9) cimg::swap(p[0],p[1]);
37149  else if (siz==4 || siz==12) cimg::swap(p[0],p[3],p[1],p[2]);
37150  }
37151  return *this;
37152  }
37153 
37155  return (+*this).reverse_object3d();
37156  }
37157 
37159  };
37160 
37161  /*
37162  #---------------------------------------------
37163  #
37164  # Completion of previously declared functions
37165  #
37166  #----------------------------------------------
37167  */
37168 
37169 namespace cimg {
37170 
37172 
37189  template<typename t>
37190  inline int dialog(const char *title, const char *msg,
37191  const char *button1_txt, const char *button2_txt,
37192  const char *button3_txt, const char *button4_txt,
37193  const char *button5_txt, const char *button6_txt,
37194  const CImg<t>& logo, const bool centering = false) {
37195 #if cimg_display!=0
37196  const unsigned char
37197  black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };
37198 
37199  // Create buttons and canvas graphics
37200  CImgList<unsigned char> buttons, cbuttons, sbuttons;
37201  if (button1_txt) { CImg<unsigned char>().draw_text(0,0,button1_txt,black,gray,1,13).transfer_to(buttons);
37202  if (button2_txt) { CImg<unsigned char>().draw_text(0,0,button2_txt,black,gray,1,13).transfer_to(buttons);
37203  if (button3_txt) { CImg<unsigned char>().draw_text(0,0,button3_txt,black,gray,1,13).transfer_to(buttons);
37204  if (button4_txt) { CImg<unsigned char>().draw_text(0,0,button4_txt,black,gray,1,13).transfer_to(buttons);
37205  if (button5_txt) { CImg<unsigned char>().draw_text(0,0,button5_txt,black,gray,1,13).transfer_to(buttons);
37206  if (button6_txt) { CImg<unsigned char>().draw_text(0,0,button6_txt,black,gray,1,13).transfer_to(buttons);
37207  }}}}}}
37208  if (!buttons.width)
37209  throw CImgArgumentException("cimg::dialog() : No buttons have been defined. At least one is necessary");
37210 
37211  unsigned int bw = 0, bh = 0;
37212  cimglist_for(buttons,l) { bw = cimg::max(bw,buttons[l].width); bh = cimg::max(bh,buttons[l].height); }
37213  bw+=8; bh+=8;
37214  if (bw<64) bw=64;
37215  if (bw>128) bw=128;
37216  if (bh<24) bh=24;
37217  if (bh>48) bh=48;
37218 
37219  CImg<unsigned char> button(bw,bh,1,3);
37220  button.draw_rectangle(0,0,bw-1,bh-1,gray);
37221  button.draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white);
37222  button.draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black);
37223  button.draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2);
37224  CImg<unsigned char> sbutton(bw,bh,1,3);
37225  sbutton.draw_rectangle(0,0,bw-1,bh-1,gray);
37226  sbutton.draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black);
37227  sbutton.draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black);
37228  sbutton.draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white);
37229  sbutton.draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black);
37230  sbutton.draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2);
37231  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);
37232  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);
37233  CImg<unsigned char> cbutton(bw,bh,1,3);
37234  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);
37235  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);
37236  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);
37237 
37238  cimglist_for(buttons,ll) {
37239  CImg<unsigned char>(cbutton).draw_image(1+(bw-buttons[ll].dimx())/2,1+(bh-buttons[ll].dimy())/2,buttons[ll]).
37240  transfer_to(cbuttons);
37241  CImg<unsigned char>(sbutton).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]).
37242  transfer_to(sbuttons);
37243  CImg<unsigned char>(button).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]).
37244  transfer_to(buttons[ll]);
37245  }
37246 
37247  CImg<unsigned char> canvas;
37248  if (msg) CImg<unsigned char>().draw_text(0,0,"%s",black,gray,1,13,msg).transfer_to(canvas);
37249  const unsigned int
37250  bwall = (buttons.width-1)*(12+bw) + bw,
37251  w = cimg::max(196U,36+logo.width+canvas.width, 24+bwall),
37252  h = cimg::max(96U,36+canvas.height+bh,36+logo.height+bh),
37253  lx = 12 + (canvas.data?0:((w-24-logo.width)/2)),
37254  ly = (h-12-bh-logo.height)/2,
37255  tx = lx+logo.width+12,
37256  ty = (h-12-bh-canvas.height)/2,
37257  bx = (w-bwall)/2,
37258  by = h-12-bh;
37259 
37260  if (canvas.data)
37261  canvas = CImg<unsigned char>(w,h,1,3).
37262  draw_rectangle(0,0,w-1,h-1,gray).
37263  draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
37264  draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black).
37265  draw_image(tx,ty,canvas);
37266  else
37267  canvas = CImg<unsigned char>(w,h,1,3).
37268  draw_rectangle(0,0,w-1,h-1,gray).
37269  draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
37270  draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black);
37271  if (logo.data) canvas.draw_image(lx,ly,logo);
37272 
37273  unsigned int xbuttons[6] = { 0 };
37274  cimglist_for(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(xbuttons[lll],by,buttons[lll]); }
37275 
37276  // Open window and enter events loop
37277  CImgDisplay disp(canvas,title?title:" ",0,false,centering?true:false);
37278  if (centering) disp.move((CImgDisplay::screen_dimx()-disp.dimx())/2,
37279  (CImgDisplay::screen_dimy()-disp.dimy())/2);
37280  bool stopflag = false, refresh = false;
37281  int oselected = -1, oclicked = -1, selected = -1, clicked = -1;
37282  while (!disp.is_closed && !stopflag) {
37283  if (refresh) {
37284  if (clicked>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[clicked],by,cbuttons[clicked]).display(disp);
37285  else {
37286  if (selected>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[selected],by,sbuttons[selected]).display(disp);
37287  else canvas.display(disp);
37288  }
37289  refresh = false;
37290  }
37291  disp.wait(15);
37292  if (disp.is_resized) disp.resize(disp);
37293 
37294  if (disp.button&1) {
37295  oclicked = clicked;
37296  clicked = -1;
37297  cimglist_for(buttons,l)
37298  if (disp.mouse_y>=(int)by && disp.mouse_y<(int)(by+bh) &&
37299  disp.mouse_x>=(int)xbuttons[l] && disp.mouse_x<(int)(xbuttons[l]+bw)) {
37300  clicked = selected = l;
37301  refresh = true;
37302  }
37303  if (clicked!=oclicked) refresh = true;
37304  } else if (clicked>=0) stopflag = true;
37305 
37306  if (disp.key) {
37307  oselected = selected;
37308  switch (disp.key) {
37309  case cimg::keyESC : selected=-1; stopflag=true; break;
37310  case cimg::keyENTER : if (selected<0) selected = 0; stopflag = true; break;
37311  case cimg::keyTAB :
37312  case cimg::keyARROWRIGHT :
37313  case cimg::keyARROWDOWN : selected = (selected+1)%buttons.width; break;
37314  case cimg::keyARROWLEFT :
37315  case cimg::keyARROWUP : selected = (selected+buttons.width-1)%buttons.width; break;
37316  }
37317  disp.key = 0;
37318  if (selected!=oselected) refresh = true;
37319  }
37320  }
37321  if (!disp) selected = -1;
37322  return selected;
37323 #else
37324  std::fprintf(cimg_stdout,"<%s>\n\n%s\n\n",title,msg);
37325  return -1+0*(int)(button1_txt-button2_txt+button3_txt-button4_txt+button5_txt-button6_txt+logo.width+(int)centering);
37326 #endif
37327  }
37328 
37329  inline int dialog(const char *title, const char *msg,
37330  const char *button1_txt, const char *button2_txt, const char *button3_txt,
37331  const char *button4_txt, const char *button5_txt, const char *button6_txt,
37332  const bool centering) {
37333  return dialog(title,msg,button1_txt,button2_txt,button3_txt,button4_txt,button5_txt,button6_txt,
37334  CImg<unsigned char>::logo40x38(),centering);
37335  }
37336 
37338  inline double eval(const char *const expression, const double x, const double y, const double z, const double v) {
37339  static const CImg<float> empty;
37340  return empty.eval(expression,x,y,z,v);
37341  }
37342 
37343  // End of cimg:: namespace
37344 }
37345 
37346  // End of cimg_library:: namespace
37347 }
37348 
37349 #ifdef _cimg_redefine_None
37350 #define None 0
37351 #endif
37352 #ifdef _cimg_redefine_min
37353 #define min(a,b) (((a)<(b))?(a):(b))
37354 #endif
37355 #ifdef _cimg_redefine_max
37356 #define max(a,b) (((a)>(b))?(a):(b))
37357 #endif
37358 
37359 #endif
37360 // Local Variables:
37361 // mode: c++
37362 // End:
#define _cimg_freturn(x)
Definition: CImg.h:12224
int dimx() const
Return display width.
Definition: CImg.h:6623
volatile bool is_keyPAUSE
Definition: CImg.h:6187
CImg< T > & min(const CImg< t > &img)
Pointwise min operator between two images.
Definition: CImg.h:12790
CImg< T > & draw_triangle(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const CImg< tl > &light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1)
Draw a 2D Pseudo-Phong-shaded textured triangle, with z-buffering and perspective correction...
Definition: CImg.h:25399
const CImgList< T > & save_yuv(std::FILE *const file, const bool rgb2yuv=true) const
Save an image sequence into a YUV file.
Definition: CImg.h:36690
CImg< T > get_erode(const unsigned int n, const unsigned int cond=1) const
Definition: CImg.h:19004
T & max()
Return a reference to the maximum pixel value of the instance list.
Definition: CImg.h:34928
static CImg< floatT > torus3d(CImgList< tf > &primitives, const float radius1=100, const float radius2=30, const unsigned int subdivisions1=24, const unsigned int subdivisions2=12)
Create and return a 3D torus.
Definition: CImg.h:21922
#define _CImgList_stdarg(t)
#define cimg_file_separator
Definition: CImg.h:144
volatile bool is_keyBACKSPACE
Definition: CImg.h:6198
CImg< T > & invert_endianness()
Invert endianness of the image buffer.
Definition: CImg.h:14951
#define FALSE
Definition: vinci.h:133
CImg< T > & _draw_polygon(const t &points, const unsigned int W, const unsigned int H, const tc *const color, const float opacity, const unsigned int pattern)
Definition: CImg.h:25790
static unsigned int format(const unsigned char val)
Definition: CImg.h:2115
#define _cimg_fopcode1(op, i1)
Definition: CImg.h:12226
CImg< T > & tensor()
Realign pixel values of the instance image as a symmetric tensor.
Definition: CImg.h:13372
#define cimg_for5x5(img, x, y, z, v, I)
Definition: CImg.h:1176
const unsigned char logo40x38[4576]
Definition: CImg.h:4440
static CImg< floatT > isocurve3d(CImgList< tf > &primitives, const tfunc &func, const float isovalue, const float x0, const float y0, const float x1, const float y1, const int sizex=256, const int sizey=256)
Get isocurve as a 3D object.
Definition: CImg.h:21328
#define _cimg_fill1(x, y, z, v, off, siz, t)
const unsigned int key4
Definition: CImg.h:2688
if(dy > dx)
const unsigned int keyPAD3
Definition: CImg.h:2748
CImg< T > & max(const CImg< t > &img)
Pointwise max operator between two images.
Definition: CImg.h:12841
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const CImg< tc > &color, const float opacity=1)
Draw a 2D filled colored triangle.
Definition: CImg.h:23810
CImg< T > & draw_text(const int x0, const int y0, const char *const text, const tc1 *const foreground_color, const tc2 *const background_color, const float opacity, const CImgList< t > &font,...)
Draw a text.
Definition: CImg.h:26338
CImg< T > & mirror(const char axis)
Mirror an image along the specified axis.
Definition: CImg.h:17147
CImg< T > get_shared_channels(const unsigned int v0, const unsigned int v1)
Return a shared-memory image referencing a set of channels (v0-&gt;v1) of the instance image...
Definition: CImg.h:18554
const char * gzip_path(const char *const user_path=0, const bool reinit_path=false)
Return or set path to the &#39;gzip&#39; command.
Definition: CImg.h:5377
cimg::superset< T, unsigned char >::type Tuchar
Definition: CImg.h:9773
static CImg< T > get_load_cimg(const char *const filename, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1, const char axis='z', const char align='p')
Definition: CImg.h:30566
const unsigned int keyP
Definition: CImg.h:2709
_cimg_math_parser(const char *const expression, const char *const funcname=0)
Definition: CImg.h:12232
CImg< T > & load_off(std::FILE *const file, CImgList< tf > &primitives, CImgList< tc > &colors)
Load a 3D object from a .OFF file.
Definition: CImg.h:31040
#define cimg_forXZV(img, x, z, v)
Definition: CImg.h:605
static CImg< T > get_load_raw(const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int sizez=1, const unsigned int sizev=1, const bool multiplexed=false, const bool invert_endianness=false)
Definition: CImg.h:30935
const CImg< T > & _save_ascii(std::FILE *const file, const char *const filename) const
Definition: CImg.h:32357
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const CImg< tc1 > &color1, const CImg< tc2 > &color2, const CImg< tc3 > &color3, const float opacity=1)
Definition: CImg.h:24161
static CImg< T > get_load_pnm(const char *const filename)
Definition: CImg.h:29816
cimg::superset< T, float >::type Tfloat
Definition: CImg.h:33910
volatile bool is_keyF7
Definition: CImg.h:6181
CImg< T > & equalize(const unsigned int nb_levels, const T value_min=(T) 0, const T value_max=(T) 0)
Compute the histogram-equalized version of the instance image.
Definition: CImg.h:15305
const unsigned int keyF5
Definition: CImg.h:2676
const CImg< T > & save_tiff(const char *const filename) const
Save a file in TIFF format.
Definition: CImg.h:33198
*********************************************************************Illinois Open Source License ****University of Illinois NCSA **Open Source License University of Illinois All rights reserved ****Developed by
Definition: roccomf90.h:7
T & at(const int off, const T out_val)
Read a pixel value with Dirichlet boundary conditions.
Definition: CImg.h:11188
const CImg< T > & save_dlm(const char *const filename) const
Save the image as a DLM file.
Definition: CImg.h:32448
unsigned int prand(const double z)
Return a random variable following a Poisson distribution of parameter z.
Definition: CImg.h:4856
const CImg< T > & display_object3d(CImgDisplay &disp, const CImg< tp > &vertices, const CImgList< tf > &primitives, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=true, const float focale=500, const float specular_light=0.2f, const float specular_shine=0.1f, const bool display_axes=true, float *const pose_matrix=0) const
High-level interface for displaying a 3d object.
Definition: CImg.h:31731
CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1, const unsigned int depth=1, const unsigned int dim=1)
Construct an image list containing n images with specified size.
Definition: CImg.h:33980
const CImg< T > get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) const
Definition: CImg.h:18521
CImg< T > get_crop(const int x0, const int y0, const int x1, const int y1, const bool border_condition=false) const
Definition: CImg.h:18245
CImgList< T > operator+() const
Operator+() (unary).
Definition: CImg.h:34423
static CImg< T > get_load_inr(std::FILE *const file, float *voxsize=0)
Definition: CImg.h:30608
static CImg< T > get_load_gzip_external(const char *const filename)
Definition: CImg.h:31286
static CImgList< T > get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool pixel_format=true)
Definition: CImg.h:36121
T atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const
Definition: CImg.h:34632
CImg< Tfloat > get_CMYKtoCMY() const
Definition: CImg.h:16215
volatile bool is_keyF11
Definition: CImg.h:6185
CImg< T > & append(const CImg< T > &img, const char axis='x', const char align='p')
Definition: CImg.h:18648
#define _cimg_for_triangle2(img, xl, cl, xr, cr, y, x0, y0, c0, x1, y1, c1, x2, y2, c2)
Definition: CImg.h:23509
CImg< T > & draw_grid(const float deltax, const float deltay, const float offsetx, const float offsety, const bool invertx, const bool inverty, const CImg< tc > &color, const float opacity=1, const unsigned int patternx=~0U, const unsigned int patterny=~0U)
Draw grid.
Definition: CImg.h:26752
volatile bool is_keyQ
Definition: CImg.h:6203
const unsigned int keyQ
Definition: CImg.h:2700
static CImg< T > diagonal(const T &a0, const T &a1, const T &a2, const T &a3)
Return a 4x4 diagonal matrix with specified coefficients.
Definition: CImg.h:14372
CImg< T > & assign(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1)
In-place version of the previous constructor.
Definition: CImg.h:10125
CImg< T > & _draw_polygon(const t &points, const unsigned int N, const tc *const color, const float opacity)
Definition: CImg.h:25699
#define _cimg_blur_patch3d_fast(N)
CImg< T > & log10()
Compute the log10 of each each pixel value.
Definition: CImg.h:12560
cimg::last< T, short >::type shortT
Definition: CImg.h:9787
static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const int dmin=128, const int dmax=-85, const bool return_last=false)
Definition: CImg.h:6437
CImg< T > & operator*=(const CImg< t > &img)
Operator*=().
Definition: CImg.h:10695
CImg< uintT > get_label_regions() const
Definition: CImg.h:15638
CImg< T > & operator^=(const CImg< t > &img)
Operator^=().
Definition: CImg.h:10946
bool is_sameV(const unsigned int dv) const
Return true if image (*this) has the specified number of channels.
Definition: CImg.h:11912
CImgDisplay(const CImg< T > &img, const char *title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false)
Create a display window from an image.
Definition: CImg.h:6349
int fread(T *const ptr, const unsigned int nmemb, std::FILE *stream)
Read file data, and check for possible errors.
Definition: CImg.h:5569
volatile int mouse_x
X-coordinate of the mouse pointer on the display.
Definition: CImg.h:6135
CImg< _cimg_Tfloat > exp(const CImg< T > &instance)
Definition: CImg.h:6016
unsigned int _sleep(const unsigned int milliseconds, unsigned long &timer)
Definition: CImg.h:4635
iterator begin()
Return an iterator to the first image pixel.
Definition: CImg.h:11152
volatile bool is_keyAPPRIGHT
Definition: CImg.h:6242
volatile bool is_keyARROWRIGHT
Definition: CImg.h:6247
CImg< T > & draw_polygon(const CImgList< t > &points, const CImg< tc > &color, const float opacity=1)
Draw a filled polygon in the instance image.
Definition: CImg.h:25766
This class represents a window which can display CImg images and handles mouse and keyboard events...
Definition: CImg.h:6114
CImgList(const CImgList< t > &list, const bool shared)
Advanced copy constructor.
Definition: CImg.h:34112
const char * gunzip_path(const char *const user_path=0, const bool reinit_path=false)
Return or set path to the &#39;gunzip&#39; command.
Definition: CImg.h:5408
CImgDisplay()
Create an empty display window.
Definition: CImg.h:6318
CImg< floatT > get_histogram(const unsigned int nb_levels, const T value_min=(T) 0, const T value_max=(T) 0) const
Definition: CImg.h:15273
cimg::superset< t1, t2 >::type min(const t1 &a, const t2 &b)
Return the minimum value between two numbers.
Definition: CImg.h:4728
T & atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val)
Read a pixel value with Dirichlet boundary conditions for the two first coordinates (pos...
Definition: CImg.h:34648
const unsigned int keyF12
Definition: CImg.h:2683
CImg< T > & draw_line(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const CImg< tc > &color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a 2D colored line, with z-buffering.
Definition: CImg.h:22514
void strescape(char *const s)
Replace explicit escape sequences &#39;&#39; in C-strings.
Definition: CImg.h:4962
bool containsN(const int n) const
Return true if the list contains the image (n).
Definition: CImg.h:34831
const CImg< T > & save_cimg(std::FILE *const file, const unsigned int n0, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0) const
Insert the image into an existing .cimg file, at specified coordinates.
Definition: CImg.h:33305
Tfloat sum() const
Return the sum of all the pixel values in an image.
Definition: CImg.h:13022
bool contains(const T &pixel, t &n, t &x, t &y, t &z) const
Return true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z).
Definition: CImg.h:34846
CImg< T > & draw_rectangle(const int x0, const int y0, const int x1, const int y1, const CImg< tc > &color, const float opacity, const unsigned int pattern)
Draw a 2D outlined colored rectangle.
Definition: CImg.h:25690
T atXYZV(const int x, const int y, const int z, const int v, const T out_val) const
Definition: CImg.h:11227
double grand()
Return a random variable following a gaussian distribution and a standard deviation of 1...
Definition: CImg.h:4845
CImg< T > & operator&=(const t val)
Operator&amp;=().
Definition: CImg.h:10831
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, const T val7, const T val8, const T val9, const T val10, const T val11, const T val12)
Fill sequentially pixel values.
Definition: CImg.h:14703
CImg< T > & operator>>=(const int n)
Operator&gt;&gt;=().
Definition: CImg.h:10984
volatile bool is_key9
Definition: CImg.h:6196
volatile bool is_keyPAD3
Definition: CImg.h:6251
CImg< T > & draw_ellipse(const int x0, const int y0, const CImg< t > &tensor, const tc *const color, const float opacity, const unsigned int pattern)
Draw an outlined ellipse.
Definition: CImg.h:26088
CImg< T > & draw_spline(const CImg< t > &points, const CImg< tc > &color, const float opacity=1, const bool close_set=false, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored lines in the instance image.
Definition: CImg.h:23472
volatile bool is_keyPAD6
Definition: CImg.h:6254
CImg< T > & draw_triangle(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg< tc > &color, const CImg< tl > &light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1)
Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
Definition: CImg.h:24808
CImg< T > & _draw_scanline(const tc *const color, const float opacity=1)
Definition: CImg.h:22171
void warn(const char *format,...)
Display a warning message.
Definition: CImg.h:4470
CImg< T > get_blur_bilateral(const float sigma_s, const float sigma_r, const int bgrid_s=-33, const int bgrid_r=32, const bool interpolation_type=true) const
Definition: CImg.h:19627
T & atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0)
Read a pixel value with Neumann boundary conditions for the first coordinates (pos).
Definition: CImg.h:34689
volatile bool is_key5
Definition: CImg.h:6192
volatile bool is_keySPACE
Definition: CImg.h:6240
CImg< T > & back()
Definition: CImg.h:34539
CImg< T > get_resize(const CImgDisplay &disp, const int interpolation_type=1, const int border_condition=-1, const bool center=false) const
Definition: CImg.h:17005
CImg< T > resize_object3d() const
Resize a 3D object so that its max dimension if one.
Definition: CImg.h:21125
CImg< T > & draw_circle(const int x0, const int y0, int radius, const CImg< tc > &color, const float opacity, const unsigned int pattern)
Draw an outlined circle.
Definition: CImg.h:25943
CImg< T > & draw_line(const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a 2D textured line, with perspective correction.
Definition: CImg.h:22706
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7, const T &a8, const T &a9, const T &a10, const T &a11, const T &a12, const T &a13)
Return a vector with specified coefficients.
Definition: CImg.h:14250
CImg< T > get_channels(const unsigned int v0, const unsigned int v1) const
Definition: CImg.h:18470
CImgDisplay & set_title(const char *format,...)
Set the window title.
Definition: CImg.h:6820
CImg< T > & sinh()
Compute the hyperbolic sine of each pixel value.
Definition: CImg.h:12620
CImg< T > & solve(const CImg< t > &A)
Solve a linear system AX=B where B=*this.
Definition: CImg.h:13559
const T * ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const
Definition: CImg.h:11126
#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)
Definition: CImg.h:23612
CImg< T > & draw_text(const int x0, const int y0, const char *const text, const tc *const foreground_color, const int, const float opacity, const CImgList< t > &font,...)
Draw a text.
Definition: CImg.h:26358
CImg< _cimg_Tt > operator*(const t val) const
Operator*().
Definition: CImg.h:10701
CImg< intT > _autocrop(const T value, const char axis) const
Definition: CImg.h:18355
CImg< T > get_vector() const
Definition: CImg.h:13338
CImg< T > & _load_rgb(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh)
Definition: CImg.h:29966
static const char * format()
Definition: CImg.h:2105
CImg< T > & draw_polygon(const CImgList< t > &points, const tc *const color, const float opacity=1)
Draw a filled polygon in the instance image.
Definition: CImg.h:25756
#define _cimg_fopcode5(op, i1, i2, i3, i4, i5)
Definition: CImg.h:12229
CImg< Tfloat > operator%(const char *const expression) const
Operator%().
Definition: CImg.h:10819
#define cimg_forX(img, x)
Definition: CImg.h:593
void swap(T &a, T &b)
Exchange values of variables a and b.
Definition: CImg.h:4522
volatile bool is_keyPADMUL
Definition: CImg.h:6260
CImgList< T > & insert(const unsigned int n, const CImg< t > &img, const unsigned int pos=~0U, const bool shared=false)
Insert n copies of the image img into the current image list, at position pos.
Definition: CImg.h:35131
CImg< T > & draw_line(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a 2D textured line, with z-buffering and perspective correction.
Definition: CImg.h:22818
volatile int window_x
X-pos of the display on the screen.
Definition: CImg.h:6129
CImgDisplay & wait()
Wait for an event occuring on the current display.
Definition: CImg.h:6876
const unsigned int keyCAPSLOCK
Definition: CImg.h:2713
CImg< Tfloat > get_RGBtoHSV() const
Definition: CImg.h:15821
CImg< T > & pow(const double p)
Compute the power by p of each pixel value.
Definition: CImg.h:12722
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7, const T &a8, const T &a9, const T &a10)
Return a vector with specified coefficients.
Definition: CImg.h:14215
const CImg< T > & _save_rgb(std::FILE *const file, const char *const filename) const
Definition: CImg.h:33002
float frames_per_second()
Return the frame per second rate.
Definition: CImg.h:6667
Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const
Read a pixel value using linear interpolation and Neumann boundary conditions (first three coordinate...
Definition: CImg.h:11476
static CImg< T > get_load_off(const char *const filename, CImgList< tf > &primitives, CImgList< tc > &colors)
Definition: CImg.h:31034
bool is_sameYZV(const unsigned int dy, const unsigned int dz, const unsigned int dv) const
Return true if image (*this) has the specified height, depth and number of channels.
Definition: CImg.h:12027
CImg< T > & draw_gaussian(const float xc, const float yc, const CImg< t > &tensor, const tc *const color, const float opacity=1)
Draw an anisotropic 2D gaussian function.
Definition: CImg.h:27363
CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val)
Construct an image with given size (dx,dy,dz,dv) and with pixel having a default value val...
Definition: CImg.h:9893
#define _cimglist_def_is_same(axis)
Definition: CImg.h:34775
subroutine rs(nm, n, a, w, matz, z, fv1, fv2, ierr)
iterator begin()
Returns an iterator to the beginning of the vector (STL-compliant name).
Definition: CImg.h:34508
bool is_sameXY(const CImgDisplay &disp) const
Return true if image (*this) and the display disp have same width and same height.
Definition: CImg.h:11934
CImg< T > & fill(const char *const expression, const bool repeat_flag)
Fill image values according to the given expression, which can be a formula or a list of values...
Definition: CImg.h:14850
CImgList(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const CImg< t4 > &img4, const CImg< t5 > &img5, const bool shared=false)
Construct an image list from five images.
Definition: CImg.h:34060
const CImg< T > & save_other(const char *const filename, const unsigned int quality=100) const
Definition: CImg.h:33819
CImg< T > & slices(const unsigned int z0, const unsigned int z1)
Get a set of slices.
Definition: CImg.h:18448
bool is_sameXV(const unsigned int dx, const unsigned int dv) const
Return true if image (*this) has the specified width and number of channels.
Definition: CImg.h:11950
CImg< T > get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f, const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0, const unsigned int fast_approx=1) const
Definition: CImg.h:19516
bool is_sameX(const CImgDisplay &disp) const
Return true if images (*this) and the display disp have same width.
Definition: CImg.h:11880
CImg< T > & _load_ascii(std::FILE *const file, const char *const filename)
Definition: CImg.h:29283
unsigned long fps_frames
Definition: CImg.h:6268
const CImg< T > & save_cimg(const char *const filename, const bool compress=false) const
Save the image as a .cimg file.
Definition: CImg.h:33284
CImg< T > & cosh()
Compute the hyperbolic cosine of each pixel value.
Definition: CImg.h:12610
CImg< T > & draw_image(const int x0, const int y0, const int z0, const CImg< t > &sprite, const float opacity=1)
Draw an image.
Definition: CImg.h:26202
const CImgList< T > get_shared_images(const unsigned int i0, const unsigned int i1) const
Definition: CImg.h:35265
#define _cimg_iskey_case(k)
volatile bool is_keyJ
Definition: CImg.h:6223
const unsigned int keyV
Definition: CImg.h:2728
bool is_key(const bool remove=false)
Test if any key has been pressed.
Definition: CImg.h:6498
T & atNXYZV(const int pos, const int x, const int y, const int z, const int v)
Read a pixel value with Neumann boundary conditions.
Definition: CImg.h:34561
volatile bool is_keyF6
Definition: CImg.h:6180
CImg< T > & _load_pandore(std::FILE *const file, const char *const filename)
Definition: CImg.h:30718
static const char * string()
Definition: CImg.h:2110
CImg< T > get_fill(const T val) const
Definition: CImg.h:14439
CImg(const CImgDisplay &disp)
Construct an image from the content of a CImgDisplay instance.
Definition: CImg.h:10072
const unsigned int keyF8
Definition: CImg.h:2679
const CImg< T > & save_cpp(std::FILE *const file) const
Save the image as a CPP source file.
Definition: CImg.h:32417
volatile bool is_keyU
Definition: CImg.h:6209
Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const
Read a pixel value using linear interpolation and Neumann boundary conditions (first two coordinates)...
Definition: CImg.h:11530
CImg< T > & draw_image(const int x0, const int y0, const int z0, const int v0, const CImg< t > &sprite, const float opacity=1)
Draw an image.
Definition: CImg.h:26116
static CImg< T > get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1)
Definition: CImg.h:29953
CImg< T > & index(const CImg< t > &palette, const bool dithering=false, const bool map_indexes=false)
Index multi-valued pixels of the instance image, regarding to a predefined palette.
Definition: CImg.h:15343
const CImg< T > & save_rgb(std::FILE *const file) const
Save the image as a RGB file.
Definition: CImg.h:33053
CImg< T > & draw_rectangle(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const tc *const color, const float opacity=1)
Draw a 3D filled colored rectangle in the instance image, at coordinates (x0,y0,z0)-(x1,y1,z1).
Definition: CImg.h:25594
const T & maxmin(t &min_val) const
Definition: CImg.h:12966
#define _cimg_for_triangle3(img, xl, txl, tyl, xr, txr, tyr, y, x0, y0, tx0, ty0, x1, y1, tx1, ty1, x2, y2, tx2, ty2)
Definition: CImg.h:23553
CImg< T > & operator<<=(const int n)
Operator&lt;&lt;=().
Definition: CImg.h:10973
CImg< _cimg_Tfloat > sqrt(const CImg< T > &instance)
Definition: CImg.h:6011
CImgList< T > & assign(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int dim, const T val)
In-place version of the corresponding constructor.
Definition: CImg.h:34179
CImg< T > & draw_spline(const CImgList< t > &points, const tc *const color, const float opacity=1, const bool close_set=false, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored splines in the instance image.
Definition: CImg.h:23443
CImg< T > get_blur_median(const unsigned int n) const
Definition: CImg.h:19815
CImg< Tfloat > get_sqr() const
Definition: CImg.h:12525
CImg< T > get_columns(const unsigned int x0, const unsigned int x1) const
Definition: CImg.h:18416
CImg< T > & crop(const int x0, const int y0, const int z0, const int v0, const int x1, const int y1, const int z1, const int v1, const bool border_condition=false)
Get a square region of the image.
Definition: CImg.h:18184
cimg::last< T, unsigned int >::type uintT
Definition: CImg.h:9788
CImg< T > & CMYtoRGB()
Convert (C,M,Y) pixels of a color image into the (R,G,B) color space.
Definition: CImg.h:16154
CImgList(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const bool shared=false)
Construct an image list from three images.
Definition: CImg.h:34044
CImg< T > & draw_point(const int x0, const int y0, const tc *const color, const float opacity=1)
Draw a 2D colored point (pixel).
Definition: CImg.h:22192
_marching3d_func_float(const CImg< T > &pref)
Definition: CImg.h:21783
static CImg< T > get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1)
Definition: CImg.h:29999
const unsigned int keyPAGEUP
Definition: CImg.h:2698
static CImg< floatT > ellipsoid3d(CImgList< tf > &primitives, const CImg< t > &tensor, const unsigned int subdivisions=3)
Create and return a 3D ellipsoid.
Definition: CImg.h:22071
CImg< Tfloat > get_blur(const float sigma, const bool cond=true) const
Definition: CImg.h:19230
cimg::last< T, unsigned long >::type ulongT
Definition: CImg.h:9790
CImgDisplay & toggle_fullscreen(const bool redraw=true)
Toggle fullscreen mode.
Definition: CImg.h:6779
volatile bool is_keyCTRLLEFT
Definition: CImg.h:6237
CImg< T > & tan()
Compute the tangent of each pixel.
Definition: CImg.h:12600
CImg< T > & load_off(const char *const filename, CImgList< tf > &primitives, CImgList< tc > &colors)
Load a 3D object from a .OFF file.
Definition: CImg.h:31029
CImg< T > & normalize(const T value_min, const T value_max)
Linearly normalize values of the instance image between value_min and value_max.
Definition: CImg.h:15073
CImg< T > & pow(const char *const expression)
Compute the power of each pixel value.
Definition: CImg.h:12753
volatile int window_y
Y-pos of the display on the screen.
Definition: CImg.h:6132
const unsigned int key5
Definition: CImg.h:2689
#define cimg_display
Definition: CImg.h:172
#define _cimg_load_cimg_case(Ts, Tss)
const CImg< T > & save_raw(std::FILE *const file, const bool multiplexed=false) const
Save the image as a RAW file.
Definition: CImg.h:33569
const NT & d
void srand()
Definition: CImg.h:4658
CImg< T > & load_dcraw_external(const char *const filename)
Load a RAW Color Camera image file, using external tool &#39;dcraw&#39;.
Definition: CImg.h:31359
CImgDisplay & set_mouse(const int posx, const int posy)
Move mouse pointer to a specific location.
Definition: CImg.h:6813
volatile bool is_keyM
Definition: CImg.h:6234
const T ror(const T a, const unsigned int n=1)
Return a right bitwise-rotated number.
Definition: CImg.h:4677
cimg::superset< T, int >::type Tint
Definition: CImg.h:33907
CImgList< T > & load_yuv(const char *const filename, const unsigned int sizex, const unsigned int sizey, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true)
Load an image sequence from a YUV file.
Definition: CImg.h:35875
CImg< T > & _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, const tc *const color, const float opacity, const unsigned int pattern)
Definition: CImg.h:25951
CImg< T > & sin()
Compute the sinus of each pixel value.
Definition: CImg.h:12590
CImgList< T > & reverse()
Reverse list order.
Definition: CImg.h:35232
bool is_shared
Variable telling if pixel buffer of the instance image is shared with another one.
Definition: CImg.h:9747
T & min()
Return a reference to the minimum pixel value of the instance image.
Definition: CImg.h:12881
CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const char *const values, const bool repeat_values)
Construct an image with given size and with specified values given in a string.
Definition: CImg.h:9928
CImg< T > & label_regions()
Create a map of indexed labels counting disconnected regions with same intensities.
Definition: CImg.h:15634
const_iterator end() const
Definition: CImg.h:11165
CImg< T > & front()
Returns a reference to the first element (STL-compliant name).
Definition: CImg.h:34526
const char * option(const char *const name, const int argc, const char *const *const argv, const char *defaut, const char *const usage=0)
Definition: CImg.h:5604
CImgList< T > & operator,(const CImg< t > &img)
Operator,().
Definition: CImg.h:34429
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc *const color, const CImg< tl > &light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1)
Draw a 2D Pseudo-Phong-shaded triangle.
Definition: CImg.h:24608
volatile bool is_keyPAD4
Definition: CImg.h:6252
static CImg< T > diagonal(const T &a0, const T &a1)
Return a 2x2 diagonal matrix with specified coefficients.
Definition: CImg.h:14362
bool is_sameV(const CImg< t > &img) const
Return true if images (*this) and img have same dim.
Definition: CImg.h:11918
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const CImg< tc > &color, const float brightness0, const float brightness1, const float brightness2, const float opacity=1)
Draw a 2D Gouraud-shaded colored triangle.
Definition: CImg.h:24033
const unsigned int keyG
Definition: CImg.h:2718
const unsigned int keyK
Definition: CImg.h:2721
bool is_sameXV(const CImg< t > &img) const
Return true if images have same width and same number of channels.
Definition: CImg.h:11956
CImg< T > & fill(const CImg< t > &values, const bool repeat_values=true)
Fill image values according to the values found in the specified image.
Definition: CImg.h:14885
CImgDisplay & fullscreen(const bool redraw=true)
Set fullscreen mode.
Definition: CImg.h:6765
T mod(const T &x, const T &m)
Return the modulo of a number.
Definition: CImg.h:4788
cimg::last< T, short >::type shortT
Definition: CImg.h:33916
const CImg< T > & display_object3d(const char *const title, const CImg< tp > &vertices, const CImgList< tf > &primitives, const CImgList< tc > &colors, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=true, const float focale=500, const float specular_light=0.2f, const float specular_shine=0.1f, const bool display_axes=true, float *const pose_matrix=0) const
High-level interface for displaying a 3d object.
Definition: CImg.h:31715
CImg< T > & draw_spline(const CImgList< t > &points, CImg< tc > &color, const float opacity=1, const bool close_set=false, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored splines in the instance image.
Definition: CImg.h:23454
const char * filenamerand()
Definition: CImg.h:4996
CImg< T > * ptr()
Return a pointer to the image buffer.
Definition: CImg.h:34475
CImg< T > get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const
Return a new image corresponding to the square matrix located at (x,y,z) of the current vector-valued...
Definition: CImg.h:13281
CImg< Tfloat > get_LabtoXYZ() const
Definition: CImg.h:16354
CImgList< T > & load_parrec(const char *const filename)
Load an image list from a PAR/REC (Philips) file.
Definition: CImg.h:35781
j indices k indices k
Definition: Indexing.h:6
CImg(const CImg< T > &img)
Definition: CImg.h:10006
void int int REAL REAL * y
Definition: read.cpp:74
static unsigned int format(const unsigned short val)
Definition: CImg.h:2142
CImg< Tfloat > get_stats(const unsigned int variance_method=1) const
Definition: CImg.h:13152
const CImgList< T > & display(const char *const title=0, const bool display_info=true, const char axis='x', const char align='p') const
Display the current CImgList instance in a new display window.
Definition: CImg.h:36328
const unsigned int keyCTRLLEFT
Definition: CImg.h:2734
CImgDisplay & show()
Show a closed display.
Definition: CImg.h:6786
const unsigned int keyF11
Definition: CImg.h:2682
T & atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0)
Read a pixel value with Neumann boundary conditions for the two first coordinates (pos...
Definition: CImg.h:34657
cimg::superset< T, long >::type Tlong
Definition: CImg.h:33909
CImgList< T > & assign(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const CImg< t4 > &img4, const bool shared=false)
In-place version of the corresponding constructor.
Definition: CImg.h:34242
T _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const
Definition: CImg.h:34611
bool is_overlapped(const CImg< t > &img) const
Return true if the memory buffers of the two images overlaps.
Definition: CImg.h:12115
bool contains(const T &pixel, t &n, t &x, t &y, t &z, t &v) const
Return true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z,v).
Definition: CImg.h:34838
const unsigned int keyJ
Definition: CImg.h:2720
CImg< T > & assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1)
Definition: CImg.h:10188
CImg< T > operator--(int)
Operator–() (postfix).
Definition: CImg.h:10640
CImg< Tuchar > get_YUVtoRGB() const
Definition: CImg.h:16125
CImgList< T > & assign(const char *const filename)
In-place version of the corresponding constructor.
Definition: CImg.h:34291
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7, const T &a8, const T &a9, const T &a10, const T &a11)
Return a vector with specified coefficients.
Definition: CImg.h:14226
const CImg< T > & _save_jpeg(std::FILE *const file, const char *const filename, const unsigned int quality) const
Definition: CImg.h:32554
CImgList(const CImgDisplay &disp)
Construct an image list from a display.
Definition: CImg.h:34123
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4)
Fill sequentially all pixel values with values val0 and val1 and val2 and val3 and val4...
Definition: CImg.h:14492
CImgList< Tfloat > get_eigen() const
Definition: CImg.h:13695
CImg< T > & _draw_object3d(void *const pboard, CImg< floatT > &zbuffer, const float X, const float Y, const float Z, const CImg< tp > &vertices, const CImgList< tf > &primitives, const CImgList< tc > &colors, const to &opacities, const unsigned int nb_opacities, const unsigned int render_type, const bool double_sided, const float focale, const float lightx, const float lighty, const float lightz, const float specular_light, const float specular_shine)
Definition: CImg.h:27625
#define _cimg_exception_err(etype, disp_flag)
Definition: CImg.h:2021
const CImg< T > & save_gzip_external(const char *const filename) const
Save an image as a gzipped file, using external tool &#39;gzip&#39;.
Definition: CImg.h:33718
static CImg< floatT > plane3d(CImgList< tf > &primitives, const float size_x=100, const float size_y=100, const unsigned int subdivisions_x=10, const unsigned int subdivisions_y=10, const bool double_sided=false)
Create and return a 3D XY-plane.
Definition: CImg.h:21972
volatile unsigned int & key
Key value if pressed.
Definition: CImg.h:6154
#define cimg_OS
Definition: CImg.h:96
static CImgList< T > get_load_yuv(const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true)
Definition: CImg.h:35882
const CImg< T > & display_object3d(const char *const title, const CImg< tp > &vertices, const CImgList< tf > &primitives, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=true, const float focale=500, const float specular_light=0.2f, const float specular_shine=0.1f, const bool display_axes=true, float *const pose_matrix=0) const
High-level interface for displaying a 3d object.
Definition: CImg.h:31746
CImg< T > get_blur_bilateral(const float sigma_x, const float sigma_y, const float sigma_z, const float sigma_r, const int bgrid_x, const int bgrid_y, const int bgrid_z, const int bgrid_r, const bool interpolation_type=true) const
Definition: CImg.h:19614
CImgList()
Default constructor.
Definition: CImg.h:33971
float real
Definition: gridutil.h:70
const CImg< T > & display(CImgDisplay &disp, const bool display_info) const
Display an image in a window with a title title, and wait a &#39;is_closed&#39; or &#39;keyboard&#39; event...
Definition: CImg.h:31469
CImgList(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int dim, const T val)
Construct an image list containing n images with specified size, filled with specified value...
Definition: CImg.h:33988
static const char * string()
Definition: CImg.h:2128
NT dx
static CImgList< T > get_load_parrec(const char *const filename)
Definition: CImg.h:35870
CImg< _cimg_Tfloat > pseudoinvert(const CImg< T > &instance)
Definition: CImg.h:6091
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 T val7, const T val8, const T val9, const T val10, const T val11, const T val12, const T val13, const T val14) const
Definition: CImg.h:14803
CImg< T > get_diagonal() const
Definition: CImg.h:13408
cimg::superset< T, double >::type Tdouble
Definition: CImg.h:9782
CImg< T > & draw_grid(const CImg< tx > &xvalues, const CImg< ty > &yvalues, const tc *const color, const float opacity=1, const unsigned int patternx=~0U, const unsigned int patterny=~0U)
Draw grid.
Definition: CImg.h:26700
CImgList< Tfloat > get_hessian(const char *const axes=0) const
Get components of the Hessian matrix of an image.
Definition: CImg.h:20120
T & temporary(const T &)
Return a reference to a temporary variable of type T.
Definition: CImg.h:4515
static CImg< T > get_load_cimg(const char *const filename, const char axis='z', const char align='p')
Definition: CImg.h:30538
#define _cimg_blur_patch2d(N)
const T & operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const
Definition: CImg.h:34382
CImg< T > & line(const unsigned int y0)
Get a line.
Definition: CImg.h:18421
CImg< intT > get_select_graph(CImgDisplay &disp, const unsigned int plot_type=1, const unsigned int vertex_type=1, const char *const labelx=0, const double xmin=0, const double xmax=0, const char *const labely=0, const double ymin=0, const double ymax=0) const
Select sub-graph in a graph.
Definition: CImg.h:28923
CImg< Tfloat > get_XYZtoxyY() const
Definition: CImg.h:16380
CImg< T > & draw_line(const int x0, const int y0, const int x1, const int y1, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a 2D textured line.
Definition: CImg.h:22603
bool is_sameZV(const CImg< t > &img) const
Return true if images have same depth and same number of channels.
Definition: CImg.h:11989
CImg< T > & LabtoRGB()
Convert a (L,a,b) image to a (R,G,B) one.
Definition: CImg.h:16419
double s
Definition: blastest.C:80
T atXYZ(const int x, const int y, const int z, const int v, const T out_val) const
Definition: CImg.h:11262
const CImg< T > & display_object3d(const char *const title, const CImg< tp > &vertices, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=true, const float focale=500, const float specular_light=0.2f, const float specular_shine=0.1f, const bool display_axes=true, float *const pose_matrix=0) const
High-level interface for displaying a 3d object.
Definition: CImg.h:31775
T & _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0)
Definition: CImg.h:34639
CImg< T > & HSLtoRGB()
Convert color pixels from (H,S,L) to (R,G,B).
Definition: CImg.h:15911
CImgDisplay & normalscreen(const bool redraw=true)
Set normal screen mode.
Definition: CImg.h:6771
static CImg< T > get_load_off(std::FILE *const file, CImgList< tf > &primitives, CImgList< tc > &colors)
Definition: CImg.h:31045
CImg< T > & erode(const unsigned int n, const unsigned int cond=1)
Erode the image by a square structuring element of size n.
Definition: CImg.h:18999
#define cimg_fitscreen(dx, dy, dz)
Definition: CImg.h:6436
static int _marching3d_indice(const unsigned int edge, const CImg< t > &indices1, const CImg< t > &indices2, const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny)
Definition: CImg.h:21754
CImg< Tfloat > operator/(const char *const expression) const
Operator/().
Definition: CImg.h:10763
T & at(const int off)
Read a pixel value with Neumann boundary conditions.
Definition: CImg.h:11197
CImg< T > & translate_object3d(const float tx, const float ty=0, const float tz=0)
Translate a 3D object.
Definition: CImg.h:21077
CImg< T > & load_pandore(std::FILE *const file)
Load an image from a PANDORE file.
Definition: CImg.h:30710
const unsigned int keyF10
Definition: CImg.h:2681
CImgList< T > & assign(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const CImg< t4 > &img4, const CImg< t5 > &img5, const CImg< t6 > &img6, const bool shared=false)
In-place version of the corresponding constructor.
Definition: CImg.h:34261
static long format(const long val)
Definition: CImg.h:2187
CImg< T > & load_graphicsmagick_external(const char *const filename)
Load an image using GraphicsMagick&#39;s external tool &#39;gm&#39;.
Definition: CImg.h:31221
CImgList< T > & assign(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const CImg< t4 > &img4, const CImg< t5 > &img5, const CImg< t6 > &img6, const CImg< t7 > &img7, const CImg< t8 > &img8, const bool shared=false)
In-place version of the corresponding constructor.
Definition: CImg.h:34281
static CImg< T > tensor(const T &a1, const T &a2, const T &a3)
Return a 2x2 symmetric matrix tensor with specified coefficients.
Definition: CImg.h:14347
const CImgList< T > & save_yuv(const char *const filename=0, const bool rgb2yuv=true) const
Save an image sequence into a YUV file.
Definition: CImg.h:36685
CImg< T > & resize_tripleXY()
Upscale an image by a factor 3x.
Definition: CImg.h:17088
CImg< Tfloat > get_pow(const CImg< t > &img) const
Definition: CImg.h:12748
cimg::last< T, double >::type doubleT
Definition: CImg.h:9793
T _atXY(const int x, const int y, const int z=0, const int v=0) const
Definition: CImg.h:11319
CImgList< T > & remove(const unsigned int pos1, const unsigned int pos2)
Remove the images from positions pos1 to pos2.
Definition: CImg.h:35173
bool is_sameYV(const CImg< t > &img) const
Return true if images have same height and same number of channels.
Definition: CImg.h:11978
void strclean(char *const s)
Remove useless spaces and symmetric delimiters &#39;, " and ` from a C-string.
Definition: CImg.h:4950
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 T val7, const T val8, const T val9, const T val10, const T val11, const T val12) const
Definition: CImg.h:14730
bool endianness()
Return the current endianness of the CPU.
Definition: CImg.h:4572
CImg< T > & RGBtoxyY()
Convert a (R,G,B) image to a (x,y,Y) one.
Definition: CImg.h:16428
const_iterator begin() const
Definition: CImg.h:34512
Class representing an image (up to 4 dimensions wide), each pixel being of type T.
Definition: CImg.h:1905
CImg< T > & operator%=(const CImg< t > &img)
Operator%=().
Definition: CImg.h:10800
const unsigned int font19x38[19 *38 *256/32]
Definition: CImg.h:3403
const CImg< T > & display_object3d(CImgDisplay &disp, const CImg< tp > &vertices, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=true, const float focale=500, const float specular_light=0.2f, const float specular_shine=0.1f, const bool display_axes=true, float *const pose_matrix=0) const
High-level interface for displaying a 3d object.
Definition: CImg.h:31761
const CImg< T > & symmetric_eigen(CImg< t > &val, CImg< t > &vec) const
Compute the eigenvalues and eigenvectors of a symmetric matrix.
Definition: CImg.h:13703
T & _at(const int off)
Definition: CImg.h:11211
const CImg< T > & _save_pnm(std::FILE *const file, const char *const filename, const unsigned int bytes_per_pixel=0) const
Definition: CImg.h:32900
double round(const double x, const double y, const int rounding_type=0)
Return a rounded number.
Definition: CImg.h:4871
CImg< T > get_permute_axes(const char *order) const
Definition: CImg.h:17604
double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double v=0)
Evaluate math expression.
Definition: CImg.h:37338
CImg< T > & load_jpeg(const char *const filename)
Load an image from a JPEG file.
Definition: CImg.h:29493
unsigned int width
Variable representing the width of the instance image (i.e. dimensions along the X-axis).
Definition: CImg.h:9711
static CImgList< T > get_load_tiff(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1)
Definition: CImg.h:36255
const CImg< T > get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const
Definition: CImg.h:18535
CImg & set_linear_atXYZ(const T &val, const float fx, const float fy=0, const float fz=0, const int v=0, const bool add=false)
Set a pixel value, with 3D float coordinates, using linear interpolation.
Definition: CImg.h:11744
CImg< T > & draw_polygon(const CImgList< t > &points, const tc *const color, const float opacity, const unsigned int pattern)
Draw a polygon outline.
Definition: CImg.h:25827
CImg< T > & draw_object3d(const float x0, const float y0, const float z0, const CImg< tp > &vertices, const CImgList< tf > &primitives, const CImgList< tc > &colors, const unsigned int render_type=4, const bool double_sided=false, const float focale=500, const float lightx=0, const float lighty=0, const float lightz=-5000, const float specular_light=0.2f, const float specular_shine=0.1f, CImg< floatT > &zbuffer=cimg_library::CImg< floatT >::empty())
Draw a 3D object.
Definition: CImg.h:27580
CImgList< T > get_insert(const CImgList< t > &list, const unsigned int pos=~0U, const bool shared=false) const
Definition: CImg.h:35154
Vector_n max(const Array_n_const &v1, const Array_n_const &v2)
Definition: Vector_n.h:354
#define _cimg_draw_fill_test(x, y, z, res)
static int _marching2d_indice(const unsigned int edge, const CImg< t > &indices1, const CImg< t > &indices2, const unsigned int x, const unsigned int nx)
Definition: CImg.h:21418
static const char * format()
Definition: CImg.h:2168
#define _cimg_test_temporary_path(p)
const CImg< T > & save_imagemagick_external(const char *const filename, const unsigned int quality=100) const
Save the image using ImageMagick&#39;s convert.
Definition: CImg.h:33756
CImg(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1)
Constructs a new image with given size (dx,dy,dz,dv).
Definition: CImg.h:9874
NT p1
char * title
Display title.
Definition: CImg.h:6144
CImg< T > & draw_gaussian(const float xc, const float yc, const float sigma, const CImg< tc > &color, const float opacity=1)
Draw an isotropic 2D gaussian function.
Definition: CImg.h:27436
CImg< floatT > get_distance(const T isovalue, const float sizex=1, const float sizey=1, const float sizez=1, const bool compute_sqrt=true) const
Definition: CImg.h:20447
A Window object contains multiple panes and multiple data attributes.
Definition: Window.h:42
CImg< T > & _load_off(std::FILE *const file, const char *const filename, CImgList< tf > &primitives, CImgList< tc > &colors)
Definition: CImg.h:31050
unsigned int height
Height of the display.
Definition: CImg.h:6120
cimg::last< T, char >::type charT
Definition: CImg.h:9785
cimg::superset< T, short >::type Tshort
Definition: CImg.h:33905
CImg< t > _get_permute_axes(const char *permut, const t &) const
Definition: CImg.h:17431
CImgList(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const CImg< t4 > &img4, const CImg< t5 > &img5, const CImg< t6 > &img6, const bool shared=false)
Construct an image list from six images.
Definition: CImg.h:34070
cimg::last< T, long >::type longT
Definition: CImg.h:9791
Tfloat mean() const
Return the mean pixel value of the instance image.
Definition: CImg.h:13032
CImg< T > get_mirror(const char axis) const
Definition: CImg.h:17212
static CImg< floatT > isocurve3d(CImgList< tf > &primitives, const char *const expression, const float isovalue, const float x0, const float y0, const float x1, const float y1, const int sizex=256, const int sizey=256)
Definition: CImg.h:21410
CImg< T > & load_inr(std::FILE *const file, float *const voxsize=0)
Load an image from an INRIMAGE-4 file.
Definition: CImg.h:30604
CImg< T > get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0)
Return a shared memory image referencing a set of planes (z0-&gt;z1,v0) of the instance image...
Definition: CImg.h:18526
#define _cimg_Ttfloat
Definition: CImg.h:2302
CImg< T > & load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p')
Load a video sequence using FFMPEG&#39;s external tool &#39;ffmpeg&#39;.
Definition: CImg.h:31212
const char *const *const t_bold
Definition: CImg.h:1924
CImg< T > operator-() const
Operator-() (unary).
Definition: CImg.h:10647
CImg< _cimg_Tt > get_append(const CImg< T > &img, const char axis='x', const char align='p') const
Definition: CImg.h:18655
CImg< T > & operator|=(const CImg< t > &img)
Operator|=().
Definition: CImg.h:10901
volatile bool is_keyARROWUP
Definition: CImg.h:6236
CImg< T > & operator()(const unsigned int pos)
Equivalent to CImgList&lt;T&gt;::operator[].
Definition: CImg.h:34369
CImgIOException(const char *format,...)
Definition: CImg.h:2052
CImg< T > & select(const char *const title, const int select_type=2, unsigned int *const XYZ=0, const unsigned char *const color=0)
Simple interface to select a shape from an image.
Definition: CImg.h:28595
CImg< _cimg_Tt > get_max(const CImg< t > &img) const
Definition: CImg.h:12850
const unsigned int keySHIFTRIGHT
Definition: CImg.h:2732
static CImgList< T > get_load_cimg(std::FILE *const file, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1)
Definition: CImg.h:35665
volatile bool is_keyPADDIV
Definition: CImg.h:6261
cimg::superset< T, bool >::type Tbool
Definition: CImg.h:9772
#define _cimg_save_cimg_case(Ts, Tss)
CImg< T > get_cut(const T value_min, const T value_max) const
Definition: CImg.h:15179
T & atNXY(const int pos, const int x, const int y, const int z=0, const int v=0)
Read a pixel value with Neumann boundary conditions for the three first coordinates (pos...
Definition: CImg.h:34625
CImg< T > operator++(int)
Operator++() (postfix).
Definition: CImg.h:10562
#define _cimg_draw_fill_set(x, y, z)
CImgList< T > & _load_cimg(std::FILE *const file, const char *const filename)
Definition: CImg.h:35550
CImgList< T > & assign(const CImgDisplay &disp)
In-place version of the corresponding constructor.
Definition: CImg.h:34296
const CImg< T > & eigen(CImg< t > &val, CImg< t > &vec) const
Compute the eigenvalues and eigenvectors of a matrix.
Definition: CImg.h:13660
CImg< Tfloat > get_atan() const
Definition: CImg.h:12665
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, const T val7, const T val8, const T val9, const T val10, const T val11)
Fill sequentially pixel values.
Definition: CImg.h:14672
cimg::superset< T, long >::type Tlong
Definition: CImg.h:9780
CImg< T > & blur_bilateral(const float sigma_s, const float sigma_r, const int bgrid_s=-33, const int bgrid_r=32, const bool interpolation_type=true)
Blur an image using the bilateral filter.
Definition: CImg.h:19621
CImg< T > & correlate(const CImg< t > &mask, const unsigned int cond=1, const bool weighted_correl=false)
Compute the correlation of the instance image by a mask.
Definition: CImg.h:18685
volatile bool is_keyPAD1
Definition: CImg.h:6249
const unsigned int keyPADADD
Definition: CImg.h:2755
const CImg< T > & save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int fps=25) const
Save the image as a video sequence file, using FFMPEG library.
Definition: CImg.h:33574
CImg< T > & dilate(const unsigned int n, const unsigned int cond=1)
Dilate the image by a square structuring element of size n.
Definition: CImg.h:19099
CImg< T > & assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const double val0, const double val1,...)
In-place version of the previous constructor.
Definition: CImg.h:10164
CImg< T > & load_other(const char *const filename)
Load an image using ImageMagick&#39;s or GraphicsMagick&#39;s executables.
Definition: CImg.h:31393
#define cimg_forYZ(img, y, z)
Definition: CImg.h:599
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const CImg< tc > &color, const float opacity, const unsigned int pattern)
Draw a 2D outlined colored triangle.
Definition: CImg.h:23836
T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const
Definition: CImg.h:34707
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc *const color, const float opacity, const unsigned int pattern)
Draw a 2D outlined colored triangle.
Definition: CImg.h:23819
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
Definition: CImg.h:14551
CImg< Tfloat > get_pow(const char *const expression) const
Definition: CImg.h:12774
CImgList< T > get_remove() const
Definition: CImg.h:35227
cimg::last< T, float >::type floatT
Definition: CImg.h:9792
CImg< T > & autocrop(const T *const color, const char *const axes="zyx")
Autocrop an image, regarding of the specified backround color.
Definition: CImg.h:18302
CImg< T > * ptr(const unsigned int l)
Return a pointer to the image buffer.
Definition: CImg.h:34498
void _update_iskey(const unsigned int key, const bool pressed=true)
Definition: CImg.h:6586
const CImgList< T > & print(const char *title=0, const bool display_stats=true) const
Print informations about the list on the standard output.
Definition: CImg.h:36269
CImg< T > & draw_rectangle(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const CImg< tc > &color, const float opacity, const unsigned int pattern)
Draw a 3D outlined colored rectangle in the instance image.
Definition: CImg.h:25634
CImgDisplay & assign(const CImgDisplay &disp)
In-place version of the previous constructor.
Definition: CImg.h:6425
static const char * format()
Definition: CImg.h:2132
const CImgList< T > & save_cimg(const char *const filename, const bool compress=false) const
Save an image list into a CImg file (RAW binary file + simple header)
Definition: CImg.h:36757
volatile bool is_keyB
Definition: CImg.h:6232
CImg< _cimg_Tt > get_mul(const CImg< t > &img) const
Definition: CImg.h:12698
CImg< T > & load_cimg(const char *const filename, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1, const char axis='z', const char align='p')
Load a sub-image (list) from a .cimg file.
Definition: CImg.h:30555
volatile bool is_keyCAPSLOCK
Definition: CImg.h:6216
CImg< T > & draw_text(const int x0, const int y0, const char *const text, const int, const tc *const background_color, const float opacity=1, const unsigned int font_size=11,...)
Draw a text.
Definition: CImg.h:26424
CImg< T > & draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, const CImg< tc > &color, const float opacity, const unsigned int pattern)
Draw an outlined ellipse.
Definition: CImg.h:26073
CImg< Tfloat > get_RGBtoCMYK() const
Definition: CImg.h:16450
bool is_sameXZV(const unsigned int dx, const unsigned int dz, const unsigned int dv) const
Return true if image (*this) has the specified width, height and number of channels.
Definition: CImg.h:12016
CImg< T > get_quantize(const unsigned int n, const bool keep_range=true) const
Definition: CImg.h:15215
CImgDisplay & resize(const bool redraw=true)
Resize a display window in its current size.
Definition: CImg.h:6725
const CImg< T > & display_graph(const char *const title=0, const unsigned int plot_type=1, const unsigned int vertex_type=1, const char *const labelx=0, const double xmin=0, const double xmax=0, const char *const labely=0, const double ymin=0, const double ymax=0) const
High-level interface for displaying a graph.
Definition: CImg.h:32239
CImgList(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const CImg< t4 > &img4, const CImg< t5 > &img5, const CImg< t6 > &img6, const CImg< t7 > &img7, const CImg< t8 > &img8, const bool shared=false)
Construct an image list from eight images.
Definition: CImg.h:34090
CImgList< T > & assign(const CImgList< t > &list, const bool shared=false)
In-place version of the copy constructor.
Definition: CImg.h:34202
CImg< T > & RGBtoLab()
Convert a (R,G,B) image to a (L,a,b) one.
Definition: CImg.h:16410
static CImg< floatT > sphere3d(CImgList< tf > &primitives, const float radius=50, const unsigned int subdivisions=3)
Create and return a 3D sphere.
Definition: CImg.h:22007
Definition: points.h:30
CImg< T > & draw_triangle(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float brightness0, const float brightness1, const float brightness2, const float opacity=1)
Draw a 2D Gouraud-shaded textured triangle, with z-buffering and perspective correction.
Definition: CImg.h:25037
#define _cimg_load_pandore_case(nbdim, nwidth, nheight, ndepth, dim, stype1, stype2, stype3, ltype)
CImg< T > & load_dlm(std::FILE *const file)
Load an image from a DLM file.
Definition: CImg.h:29323
CImgList(const char *const filename)
Construct an image list from a filename.
Definition: CImg.h:34118
const CImg< T > & save_png(std::FILE *const file, const unsigned int bytes_per_pixel=0) const
Save a file in PNG format.
Definition: CImg.h:32895
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5)
Return a vector with specified coefficients.
Definition: CImg.h:14168
CImgList< T > & assign()
In-place version of the default constructor and default destructor.
Definition: CImg.h:34151
volatile bool is_keyTAB
Definition: CImg.h:6202
const unsigned int keyC
Definition: CImg.h:2727
bool is_sameX(const CImg< t > &img) const
Return true if images (*this) and img have same width.
Definition: CImg.h:11875
const char * graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false)
Return path of the GraphicsMagick&#39;s gm tool.
Definition: CImg.h:5198
T atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const
Definition: CImg.h:34696
CImgDisplay & move(const int posx, const int posy)
Move window.
Definition: CImg.h:6796
const unsigned int keyF9
Definition: CImg.h:2680
#define _cimg_save_pandore_case(sy, sz, sv, stype, id)
unsigned int opcode(const char op, const unsigned int arg1=0, const unsigned int arg2=0, const unsigned int arg3=0, const unsigned int arg4=0, const unsigned int arg5=0)
Definition: CImg.h:12257
CImg< T > & unroll(const char axis)
Unroll all images values into specified axis.
Definition: CImg.h:17610
volatile bool is_keyPADSUB
Definition: CImg.h:6259
CImg< T > & rotate(const float angle, const float cx, const float cy, const float zoom, const unsigned int border_conditions=3, const unsigned int interpolation=1)
Rotate an image around a center point (cx,cy).
Definition: CImg.h:17745
CImg< T > get_append(const CImg< T > &img, const char axis='x', const char align='p') const
Definition: CImg.h:18661
CImg< _cimg_Ttfloat > get_correlate(const CImg< t > &mask, const unsigned int cond=1, const bool weighted_correl=false) const
Definition: CImg.h:18690
T atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const
Definition: CImg.h:34600
const CImg< T > & save_pnm(const char *const filename, const unsigned int bytes_per_pixel=0) const
Save the image as a PNM file.
Definition: CImg.h:32992
const unsigned int keyARROWLEFT
Definition: CImg.h:2742
CImg< T > & draw_axis(const CImg< t > &xvalues, const int y, const CImg< tc > &color, const float opacity=1, const unsigned int pattern=~0U)
Draw a labeled horizontal axis on the instance image.
Definition: CImg.h:26589
CImg< T > get_blur_anisotropic(const CImg< t > &G, const float amplitude=60, const float dl=0.8f, const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0, const unsigned int fast_approx=1) const
Definition: CImg.h:19500
const T * const_iterator
Const iterator type for CImg&lt;T&gt;.
Definition: CImg.h:9766
const double valuePI
Definition of the mathematical constant PI.
Definition: CImg.h:2761
volatile unsigned int window_width
Width of the underlying window.
Definition: CImg.h:6123
Tfloat magnitude(const int magnitude_type=2) const
Return the norm of the current vector/matrix. ntype = norm type (0=L2, 1=L1, -1=Linf).
Definition: CImg.h:13191
CImg(const char *const filename)
Construct an image from an image file.
Definition: CImg.h:9975
CImg< _cimg_Tfloat > operator*(const char *const expression, const CImg< T > &img)
Definition: CImg.h:5981
const unsigned int key2
Definition: CImg.h:2686
CImg< T > & draw_fill(const int x, const int y, const int z, const tc *const color, const float opacity, CImg< t > &region, const float sigma=0, const bool high_connexity=false)
Draw a 3D filled region starting from a point (x,y,\ z) in the instance image.
Definition: CImg.h:26929
CImg< T > & _load_inr(std::FILE *const file, const char *const filename, float *const voxsize)
Definition: CImg.h:30659
const CImgList< T > & save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int fps=25) const
Save an image sequence, using FFMPEG library.
Definition: CImg.h:36413
CImg< T > & draw_quiver(const CImg< t1 > &flow, const CImg< t2 > &color, const float opacity=1, const unsigned int sampling=25, const float factor=-20, const bool arrows=true, const unsigned int pattern=~0U)
Draw a vector field in the instance image, using a colormap.
Definition: CImg.h:26516
static CImg< T > vector(const T &a0, const T &a1, const T &a2)
Return a vector with specified coefficients.
Definition: CImg.h:14147
volatile int wheel
Wheel state of the mouse.
Definition: CImg.h:6151
#define CImg_3x3x3(I, T)
Definition: CImg.h:461
CImgList(const unsigned int n, const CImg< t > &img, const bool shared=false)
Construct a list containing n copies of the image img.
Definition: CImg.h:34023
CImg< T > & load_dlm(const char *const filename)
Load an image from a DLM file.
Definition: CImg.h:29314
CImg< T > & acos()
Compute the arc-cosine of each pixel value.
Definition: CImg.h:12640
CImg< T > & identity_matrix()
Get an identity matrix having same dimension than instance image.
Definition: CImg.h:13416
static double format(const double val)
Definition: CImg.h:2205
CImg< T > & load_pandore(const char *const filename)
Load an image from a PANDORE file.
Definition: CImg.h:30701
static CImg< T > diagonal(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4)
Return a 5x5 diagonal matrix with specified coefficients.
Definition: CImg.h:14377
#define CImg_5x5(I, T)
Definition: CImg.h:439
cimg::superset< T, bool >::type Tbool
Definition: CImg.h:33901
CImg< T > & xyYtoXYZ()
Convert (x,y,Y) pixels of a color image into the (X,Y,Z)_709 color space.
Definition: CImg.h:16385
CImgList< T > & operator=(const CImgDisplay &disp)
Operator=().
Definition: CImg.h:34399
Tfloat linear_atX(const float fx, const int y, const int z, const int v, const T out_val) const
Read a pixel value using linear interpolation and Dirichlet boundary conditions (first coordinate)...
Definition: CImg.h:11557
CImg< T > & draw_polygon(const CImgList< t > &points, const CImg< tc > &color, const float opacity, const unsigned int pattern)
Draw a polygon outline.
Definition: CImg.h:25836
CImg< T > & fill(const T val)
Fill an image by a value val.
Definition: CImg.h:14432
CImg< _cimg_Tt > get_erode(const CImg< t > &mask, const unsigned int cond=1, const bool weighted_erosion=false) const
Definition: CImg.h:18920
#define _cimg_valign3d(i, j, k)
double sqrt(double d)
Definition: double.h:73
CImg< T > & draw_point(const CImgList< t > &points, const tc *const color, const float opacity=1)
Draw a cloud of colored points.
Definition: CImg.h:22276
const CImg< T > & back() const
Return a reference to the last image (STL-compliant name).
Definition: CImg.h:34535
CImg< T > & max(const char *const expression)
Pointwise max operator between an image and a string.
Definition: CImg.h:12855
CImg< T > & draw_image(const int x0, const int y0, const int z0, const int v0, const CImg< ti > &sprite, const CImg< tm > &mask, const float opacity=1, const float mask_valmax=1)
Draw a sprite image in the instance image (masked version).
Definition: CImg.h:26243
CImg< T > & operator--()
Operator–() (prefix).
Definition: CImg.h:10634
const unsigned int keyESC
Definition: CImg.h:2671
CImg< _cimg_Tt > operator-(const CImg< t > &img) const
Operator-().
Definition: CImg.h:10664
CImg< T > get_crop(const int x0, const int y0, const int z0, const int v0, const int x1, const int y1, const int z1, const int v1, const bool border_condition=false) const
Definition: CImg.h:18190
CImg< T > & draw_gaussian(const float xc, const float yc, const float zc, const float sigma, const tc *const color, const float opacity=1)
Draw an isotropic 3D gaussian function.
Definition: CImg.h:27492
volatile bool is_keyPAGEDOWN
Definition: CImg.h:6215
bool is_sameYZV(const CImg< t > &img) const
Return true if images have same heigth, same depth and same number of channels.
Definition: CImg.h:12033
static CImg< T > get_load_inr(const char *const filename, float *const voxsize=0)
Definition: CImg.h:30599
CImgList< T > & FFT(const char axis, const bool invert=false)
Compute a 1-D Fast Fourier Transform, along specified axis.
Definition: CImg.h:37116
static CImg< T > tensor(const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6)
Return a 3x3 symmetric matrix with specified coefficients.
Definition: CImg.h:14352
CImg< T > get_shared_lines(const unsigned int y0, const unsigned int y1, const unsigned int z0=0, const unsigned int v0=0)
Return a shared-memory image referencing a set of lines of the instance image.
Definition: CImg.h:18496
CImg< T > & norm(const int norm_type=2)
Compute L2-norm of each multi-valued pixel of the instance image.
Definition: CImg.h:15127
CImg< Tfloat > get_max(const char *const expression) const
Definition: CImg.h:12876
CImg< T > & deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true)
Compute the result of the Deriche filter.
Definition: CImg.h:19118
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const CImg< tl > &light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1)
Draw a 2D Pseudo-Phong-shaded textured triangle.
Definition: CImg.h:25180
~CImgDisplay()
Destructor.
Definition: CImg.h:6313
CImg< T > & column(const unsigned int x0)
Get one column.
Definition: CImg.h:18403
_marching2d_func(const CImg< T > &pref)
Definition: CImg.h:21431
CImg< Tfloat > get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const
Definition: CImg.h:14128
bool contains(const T &pixel, t &n) const
Return true if one of the image list contains the specified referenced value. If true, set coordinates (n).
Definition: CImg.h:34867
T & minmax(t &max_val)
Return a reference to the minimum pixel value of the instance list.
Definition: CImg.h:34956
T & _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0)
Definition: CImg.h:34671
T & max()
Return a reference to the maximum pixel value of the instance image.
Definition: CImg.h:12900
CImg< _cimg_Tt > operator+(const t val) const
Operator+().
Definition: CImg.h:10579
#define cimg_forXYV(img, x, y, v)
Definition: CImg.h:604
static CImg< T > & empty()
Return a reference to an empty image.
Definition: CImg.h:10351
int fclose(std::FILE *file)
Close a file, and check for possible errors.
Definition: CImg.h:5507
#define _cimg_draw_fill_test_neighbor(x, y, z, cond)
const CImg< T > & save_inr(std::FILE *const file, const float *const voxsize=0) const
Save the image as an INRIMAGE-4 file.
Definition: CImg.h:33367
const T * ptr() const
Definition: CImg.h:11084
cimg::superset< T, char >::type Tchar
Definition: CImg.h:9774
bool is_empty() const
Return true if current image is empty.
Definition: CImg.h:11864
const CImg< T > * ptr() const
Definition: CImg.h:34479
CImg< T > & draw_rectangle(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const tc *const color, const float opacity, const unsigned int pattern)
Draw a 3D outlined colored rectangle in the instance image.
Definition: CImg.h:25614
const CImg< T > & _save_pandore(std::FILE *const file, const char *const filename, const unsigned int colorspace) const
Definition: CImg.h:33385
CImgList< T > & insert(const CImg< T > &img, const unsigned int pos=~0U, const bool shared=false)
Definition: CImg.h:35069
CImg< T > & cut(const T value_min, const T value_max)
Cut values of the instance image between value_min and value_max.
Definition: CImg.h:15172
volatile bool is_keyF2
Definition: CImg.h:6176
CImg< Tfloat > get_sinh() const
Definition: CImg.h:12625
CImg< T > & div(const CImg< t > &img)
Pointwise division between two images.
Definition: CImg.h:12704
CImg< T > & xyYtoRGB()
Convert a (x,y,Y) image to a (R,G,B) one.
Definition: CImg.h:16437
CImg< T > & assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const int val0, const int val1,...)
In-place version of the previous constructor.
Definition: CImg.h:10156
const CImgList< T > & _save_yuv(std::FILE *const file, const char *const filename, const bool rgb2yuv) const
Definition: CImg.h:36661
NT & den
CImgList< T > & transfer_to(CImgList< T > &list)
Definition: CImg.h:34309
CImg< T > & fillX(const unsigned int y, const unsigned int z, const unsigned int v, const double a0,...)
Definition: CImg.h:14908
bool is_sameYZ(const unsigned int dy, const unsigned int dz) const
Return true if image (*this) has the specified height and depth.
Definition: CImg.h:11961
static const char * string()
Definition: CImg.h:2191
const CImgList< T > & _save_cimg(std::FILE *const file, const char *const filename, const unsigned int n0, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0) const
Definition: CImg.h:36762
CImg< T > & dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg< t > &previous)
Return minimal path in a graph, using the Dijkstra algorithm.
Definition: CImg.h:14111
CImg< T > get_shared()
Return a shared version of the instance image.
Definition: CImg.h:10077
T * data
Pointer to the first pixel of the pixel buffer.
Definition: CImg.h:9750
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, const T val7, const T val8)
Fill sequentially pixel values.
Definition: CImg.h:14583
CImg< T > & load_png(std::FILE *const file)
Load an image from a PNG file.
Definition: CImg.h:29660
CImg< T > & set_vector_at(const CImg< t > &vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0)
Set the image vec as the vector valued pixel located at (x,y,z) of the current vector-valued image...
Definition: CImg.h:13298
volatile bool is_keyPAD2
Definition: CImg.h:6250
CImg< Tfloat > get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const
Definition: CImg.h:21120
const unsigned int keyY
Definition: CImg.h:2705
#define cimg_version
Definition: CImg.h:56
bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const unsigned int key4, const bool remove)
Test if a key sequence has been typed.
Definition: CImg.h:6522
int dimy() const
Return the number of rows of the instance image (size along the Y-axis, i.e image height)...
Definition: CImg.h:11051
const unsigned int keyPADMUL
Definition: CImg.h:2757
float operator()(const float x, const float y, const float z) const
Definition: CImg.h:21776
volatile bool is_keyINSERT
Definition: CImg.h:6199
CImg< T > get_fill(const T val0, const T val1) const
Definition: CImg.h:14452
int window_dimy() const
Return display window height.
Definition: CImg.h:6638
bool contains(const T &pixel, t &x, t &y, t &z) const
Return true if specified referenced value is inside image boundaries. If true, returns pixel coordina...
Definition: CImg.h:12071
CImg< T > & operator^=(const char *const expression)
Operator^=().
Definition: CImg.h:10927
CImg< T > & fillY(const unsigned int x, const unsigned int z, const unsigned int v, const int a0,...)
Fill image values along the Y-axis at the specified pixel position (x,z,v).
Definition: CImg.h:14914
T atXY(const int x, const int y, const int z=0, const int v=0) const
Definition: CImg.h:11308
volatile bool is_keyF9
Definition: CImg.h:6183
static CImgList< T > get_load(const char *const filename)
Definition: CImg.h:35528
CImg< T > & draw_image(const int x0, const int y0, const int z0, const int v0, const CImg< T > &sprite, const float opacity=1)
Definition: CImg.h:26158
CImg< T > & load_analyze(const char *const filename, float *const voxsize=0)
Load an image from an ANALYZE7.5/NIFTI file.
Definition: CImg.h:30408
unsigned int height
Variable representing the height of the instance image (i.e. dimensions along the Y-axis)...
Definition: CImg.h:9722
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 T val7) const
Definition: CImg.h:14577
bool is_sameN(const unsigned int n) const
Return true if list if of specified size.
Definition: CImg.h:34739
cimg::superset< T, int >::type Tint
Definition: CImg.h:9778
CImg< T > & draw_line(const CImgList< t > &points, const tc *const color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored lines in the instance image.
Definition: CImg.h:23006
static CImg< T > get_load_bmp(const char *const filename)
Definition: CImg.h:29366
CImg< T > & load_png(const char *const filename)
Load an image from a PNG file.
Definition: CImg.h:29651
#define cimg_for_outXYZV(img, x0, y0, z0, v0, x1, y1, z1, v1, x, y, z, v)
Definition: CImg.h:665
CImg< T > get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const
Return a new image corresponding to the diffusion tensor located at (x,y,z) of the current vector-val...
Definition: CImg.h:13289
volatile bool is_keyA
Definition: CImg.h:6217
Tfloat dot(const CImg< t > &img) const
Return the dot product of the current vector/matrix with the vector/matrix img.
Definition: CImg.h:13256
CImg< T > & draw_object3d(const float x0, const float y0, const float z0, const CImg< tp > &vertices, const CImgList< tf > &primitives, const CImgList< tc > &colors, const CImg< to > &opacities, const unsigned int render_type=4, const bool double_sided=false, const float focale=500, const float lightx=0, const float lighty=0, const float lightz=-5000, const float specular_light=0.2f, const float specular_shine=0.1f, CImg< floatT > &zbuffer=cimg_library::CImg< floatT >::empty())
Definition: CImg.h:27550
volatile bool is_keyX
Definition: CImg.h:6229
CImg< Tfloat > operator+(const char *const expression) const
Operator+().
Definition: CImg.h:10584
CImg< T > & rand(const T val_min, const T val_max)
Fill the instance image with random values between specified range.
Definition: CImg.h:14961
T & _atNXYZV(const int pos, const int x, const int y, const int z, const int v)
Definition: CImg.h:34575
const char t_normal[]
Definition: CImg.h:1923
const T & back() const
Return a reference to the last image pixel (STL-compliant name).
Definition: CImg.h:11179
CImg< Tfloat > get_normalize(const T value_min, const T value_max) const
Definition: CImg.h:15083
cimg::last< T, unsigned char >::type ucharT
Definition: CImg.h:33913
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5)
Fill sequentially all pixel values with values val0 and val1 and val2 and val3 and val4 and val5...
Definition: CImg.h:14511
cimg::last< T, bool >::type boolT
Definition: CImg.h:33912
const unsigned int keyPAD1
Definition: CImg.h:2746
CImg< T > & CMYKtoRGB()
Convert a (C,M,Y,K) image to a (R,G,B) one.
Definition: CImg.h:16455
bool containsNXYZV(const int n, const int x=0, const int y=0, const int z=0, const int v=0) const
Return true if the list contains the pixel (n,x,y,z,v).
Definition: CImg.h:34825
CImgList< T > & operator=(const char *const filename)
Operator=().
Definition: CImg.h:34414
CImgDisplay & flush()
Clear all events of the current display.
Definition: CImg.h:6848
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, const T val7, const T val8, const T val9)
Fill sequentially pixel values.
Definition: CImg.h:14612
const unsigned int keyI
Definition: CImg.h:2707
CImg< T > & fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const int a0,...)
Fill image values along the Z-axis at the specified pixel position (x,y,v).
Definition: CImg.h:14925
CImg< Tfloat > get_sin() const
Definition: CImg.h:12595
CImg< T > & fillV(const unsigned int x, const unsigned int y, const unsigned int z, const int a0,...)
Fill image values along the V-axis at the specified pixel position (x,y,z).
Definition: CImg.h:14938
Tfloat det() const
Return the determinant of the image, viewed as a matrix.
Definition: CImg.h:13227
CImg< T > & draw_triangle(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg< tc > &color, const float brightness0, const float brightness1, const float brightness2, const float opacity=1)
Draw a Gouraud triangle with z-buffer consideration.
Definition: CImg.h:24134
CImg< T > & _load_analyze(std::FILE *const file, const char *const filename, float *const voxsize=0)
Definition: CImg.h:30425
volatile bool is_resized
Resized state of the window.
Definition: CImg.h:6165
const T & minmax(t &max_val) const
Definition: CImg.h:34975
static CImg< T > vector(const T &a0, const T &a1)
Return a vector with specified coefficients.
Definition: CImg.h:14140
CImg< floatT > get_isocurve3d(CImgList< tf > &primitives, const float isovalue, const int size_x=-100, const int size_y=-100) const
Create and return a isocurve of the instance image as a 3D object.
Definition: CImg.h:21228
CImg< T > get_resize(const CImg< t > &src, const int interpolation_type=1, const int border_condition=-1, const bool center=false) const
Definition: CImg.h:16981
CImgList(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const CImg< t4 > &img4, const CImg< t5 > &img5, const CImg< t6 > &img6, const CImg< t7 > &img7, const bool shared=false)
Construct an image list from seven images.
Definition: CImg.h:34080
CImg< T > & draw_spline(const int x0, const int y0, const float u0, const float v0, const int x1, const int y1, const float u1, const float v1, const CImg< tc > &color, const float opacity=1, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a cubic spline curve in the instance image.
Definition: CImg.h:23159
CImg< T > get_rotate(const float angle, const float cx, const float cy, const float zoom, const unsigned int border_conditions=3, const unsigned int interpolation=1) const
Definition: CImg.h:17750
CImgList< T > & assign(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int dim, const int val0, const int val1,...)
In-place version of the corresponding constructor.
Definition: CImg.h:34187
~CImg()
Destructor.
Definition: CImg.h:9845
CImg< _cimg_Tfloat > tan(const CImg< T > &instance)
Definition: CImg.h:6046
volatile bool is_keyK
Definition: CImg.h:6224
CImg< _cimg_Ttfloat > get_solve_tridiagonal(const CImg< t > &a, const CImg< t > &b, const CImg< t > &c) const
Definition: CImg.h:13654
iterator end()
Return an iterator pointing after the last image pixel (STL-compliant name).
Definition: CImg.h:11161
const T & operator[](const unsigned int off) const
Definition: CImg.h:10409
CImg< T > & draw_triangle(const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float brightness0, const float brightness1, const float brightness2, const float opacity=1)
Draw a 2D Gouraud-shaded textured triangle, with perspective correction.
Definition: CImg.h:24931
bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const unsigned int key4, const unsigned int key5, const unsigned int key6, const unsigned int key7, const unsigned int key8, const unsigned int key9, const bool remove)
Test if a key sequence has been typed.
Definition: CImg.h:6559
static CImg< T > get_load_pandore(const char *const filename)
Definition: CImg.h:30705
CImg< T > & noise(const double sigma, const unsigned int noise_type=0)
Add random noise to the values of the instance image.
Definition: CImg.h:15000
static CImgList< T > get_load_ffmpeg_external(const char *const filename)
Definition: CImg.h:36164
CImg< T > & draw_image(const int x0, const int y0, const CImg< t > &sprite, const float opacity=1)
Draw an image.
Definition: CImg.h:26209
const unsigned int keyA
Definition: CImg.h:2714
CImg< Tfloat > get_xyYtoXYZ() const
Definition: CImg.h:16405
CImg< T > & XYZtoLab()
Convert (X,Y,Z)_709 pixels of a color image into the (L*,a*,b*) color space.
Definition: CImg.h:16290
volatile bool is_key8
Definition: CImg.h:6195
static const char * format()
Definition: CImg.h:2123
CImgList< T > get_insert(const unsigned int n, const unsigned int pos=~0U) const
Definition: CImg.h:35125
static CImg< T > matrix(const T &a0, const T &a1, const T &a2, const T &a3)
Return a 2x2 square matrix with specified coefficients.
Definition: CImg.h:14294
volatile bool is_keyF8
Definition: CImg.h:6182
CImgList< T > & load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false)
Load an image from a video file, using ffmpeg libraries.
Definition: CImg.h:35980
bool contains(const T &pixel, t &x) const
Return true if specified referenced value is inside image boundaries. If true, returns pixel coordina...
Definition: CImg.h:12097
float atof(const char *const str)
Read a float number from a C-string.
Definition: CImg.h:4905
const unsigned int keyU
Definition: CImg.h:2706
CImgList(const CImgList< t > &list)
Default copy constructor.
Definition: CImg.h:34100
cimg::last< T, double >::type doubleT
Definition: CImg.h:33922
unsigned int size() const
Return the size of the list.
Definition: CImg.h:34470
CImg< T > & load_bmp(const char *const filename)
Load an image from a BMP file.
Definition: CImg.h:29362
CImgDisplay & display(const CImg< T > &img)
Display an image in a window.
Definition: CImg.h:6689
bool is_key(const unsigned int key1, const unsigned int key2, const bool remove)
Test if a key sequence has been typed.
Definition: CImg.h:6510
static CImg< floatT > isosurface3d(CImgList< tf > &primitives, const tfunc &func, const float isovalue, const float x0, const float y0, const float z0, const float x1, const float y1, const float z1, const int size_x=32, const int size_y=32, const int size_z=32)
Get isosurface as a 3D object.
Definition: CImg.h:21460
T & atXYZ(const int x, const int y, const int z, const int v=0)
Read a pixel value with Neumann boundary conditions for the three first coordinates (x...
Definition: CImg.h:11267
const unsigned int keyN
Definition: CImg.h:2730
CImg< T > & convolve(const CImg< t > &mask, const unsigned int cond=1, const bool weighted_convol=false)
Compute the convolution of the image by a mask.
Definition: CImg.h:18899
CImgDisplay & assign(const CImg< T > &img, const char *title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false)
In-place version of the previous constructor.
Definition: CImg.h:6404
CImg< T > & draw_graph(const CImg< t > &data, const CImg< tc > &color, const float opacity=1, const unsigned int plot_type=1, const unsigned int vertex_type=1, const double ymin=0, const double ymax=0, const bool expand=false, const unsigned int pattern=~0U)
Draw a 1D graph on the instance image.
Definition: CImg.h:26908
Tfloat _linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const
Definition: CImg.h:11402
CImg< T > & operator+=(const char *const expression)
Operator+=().
Definition: CImg.h:10524
CImg< _cimg_Ttfloat > get_solve(const CImg< t > &A) const
Definition: CImg.h:13600
CImg< T > & draw_line(const CImg< t > &points, const CImg< tc > &color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored lines in the instance image.
Definition: CImg.h:23036
CImg< T > get_autocrop(const T value, const char *const axes="vzyx") const
Definition: CImg.h:18297
CImg< T > get_line(const unsigned int y0) const
Definition: CImg.h:18425
const CImg< T > * ptr(const unsigned int l) const
Definition: CImg.h:34502
int strncasecmp(const char *const s1, const char *const s2, const int l)
Compare the first n characters of two C-strings, ignoring the case.
Definition: CImg.h:4915
const char * temporary_path(const char *const user_path=0, const bool reinit_path=false)
Return or set path to store temporary files.
Definition: CImg.h:5017
CImg & set_linear_atXY(const T &val, const float fx, const float fy=0, const int z=0, const int v=0, const bool add=false)
Set a pixel value, with 2D float coordinates, using linear interpolation.
Definition: CImg.h:11804
static CImg< T > logo40x38()
Definition: CImg.h:33848
static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs, t *ptrd, const unsigned int wd, const unsigned int hd)
Definition: CImg.h:6742
volatile bool is_keyALTGR
Definition: CImg.h:6241
CImg< T > & load_yuv(const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p')
Load an image sequence from a YUV file.
Definition: CImg.h:30998
const CImg< T > & save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const char *const codec="mpeg2video") const
Save the image as a video sequence file, using the external tool &#39;ffmpeg&#39;.
Definition: CImg.h:33670
CImg< T > & RGBtoCMYK()
Convert a (R,G,B) image to a (C,M,Y,K) one.
Definition: CImg.h:16446
CImg< T > & edge_tensors(const float sharpness=0.7f, const float anisotropy=0.3f, const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false)
Get a diffusion tensor for edge-preserving anisotropic smoothing of an image.
Definition: CImg.h:20276
CImgList< T > & assign(const CImg< t > &img, const bool shared=false)
In-place version of the corresponding constructor.
Definition: CImg.h:34218
const unsigned int keyPAD6
Definition: CImg.h:2751
CImg< T > get_noise(const double sigma, const unsigned int noise_type=0) const
Definition: CImg.h:15055
double length(Vector3D *const v, int n)
#define _cimg_fopcode3(op, i1, i2, i3)
Definition: CImg.h:12228
CImg< T > & assign(const CImgDisplay &disp)
In-place version of the previous constructor.
Definition: CImg.h:10322
static unsigned int format(const unsigned int val)
Definition: CImg.h:2160
*********************************************************************Illinois Open Source License ****University of Illinois NCSA **Open Source License University of Illinois All rights reserved ****Developed free of to any person **obtaining a copy of this software and associated documentation to deal with the Software without including without limitation the rights to and or **sell copies of the and to permit persons to whom the **Software is furnished to do subject to the following this list of conditions and the following disclaimers ****Redistributions in binary form must reproduce the above **copyright this list of conditions and the following **disclaimers in the documentation and or other materials **provided with the distribution ****Neither the names of the Center for Simulation of Advanced the University of nor the names of its **contributors may be used to endorse or promote products derived **from this Software without specific prior written permission ****THE SOFTWARE IS PROVIDED AS WITHOUT WARRANTY OF ANY **EXPRESS OR INCLUDING BUT NOT LIMITED TO THE WARRANTIES **OF FITNESS FOR A PARTICULAR PURPOSE AND **NONINFRINGEMENT IN NO EVENT SHALL THE CONTRIBUTORS OR **COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES OR OTHER WHETHER IN AN ACTION OF TORT OR **ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE **USE OR OTHER DEALINGS WITH THE SOFTWARE v
Definition: roccomf90.h:20
CImg< T > & operator%=(const t val)
Operator%=().
Definition: CImg.h:10775
CImg< T > & erode(const CImg< t > &mask, const unsigned int cond=1, const bool weighted_erosion=false)
Return the erosion of the image by a structuring element.
Definition: CImg.h:18915
Class representing list of images CImg&lt;T&gt;.
Definition: CImg.h:1906
static void save_empty_cimg(std::FILE *const file, const unsigned int nb, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1)
Create an empty .cimg file with specified dimensions.
Definition: CImg.h:36909
const unsigned int font12x24[12 *24 *256/32]
Definition: CImg.h:3030
int offset(const int x, const int y=0, const int z=0, const int v=0) const
Return the offset of the pixel coordinates (x,y,z,v) with respect to the data pointer data...
Definition: CImg.h:11147
static void wait(CImgDisplay &disp1, CImgDisplay &disp2)
Wait for any event occuring either on the display disp1 or disp2.
Definition: CImg.h:6888
T atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) const
Definition: CImg.h:34620
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 T val7, const T val8, const T val9, const T val10) const
Definition: CImg.h:14666
CImg< T > & XYZtoRGB()
Convert (X,Y,Z)_709 pixels of a color image into the (R,G,B) color space.
Definition: CImg.h:16263
CImg< T > & CMYtoCMYK()
Convert color pixels from (C,M,Y) to (C,M,Y,K).
Definition: CImg.h:16181
CImg< T > & draw_text(const int x0, const int y0, const char *const text, const CImg< tc1 > &foreground_color, const CImg< tc2 > &background_color, const float opacity, const CImgList< t > &font,...)
Draw a text.
Definition: CImg.h:26348
CImg< Tuchar > get_CMYKtoRGB() const
Definition: CImg.h:16459
CImg< T > & sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0)
Sharpen image using anisotropic shock filters or inverse diffusion.
Definition: CImg.h:19922
void invert_endianness(T *const buffer, const unsigned int size)
Invert endianness of a memory buffer.
Definition: CImg.h:4579
T at(const int off) const
Definition: CImg.h:11204
CImg< T > & draw_point(const CImg< t > &points, const CImg< tc > &color, const float opacity=1)
Draw a cloud of colored points.
Definition: CImg.h:22303
CImg< T > get_fill(const char *const values, const bool repeat_values) const
Definition: CImg.h:14879
CImg< Tfloat > get_sqrt() const
Definition: CImg.h:12535
cimg::last< T, bool >::type boolT
Definition: CImg.h:9783
CImgList< T > get_insert(const unsigned int n, const CImgList< t > &list, const unsigned int pos=~0U, const bool shared=false) const
Definition: CImg.h:35168
CImgWarningException(const char *format,...)
Definition: CImg.h:2064
volatile bool is_keyF10
Definition: CImg.h:6184
void __draw_object3d(const unsigned int, const unsigned int, const CImg< to > &, const CImg< tc > &, const int nx0, const int ny0, const CImg< T > &sprite, const float opac)
Definition: CImg.h:27619
int fwrite(const T *ptr, const unsigned int nmemb, std::FILE *stream)
Write data to a file, and check for possible errors.
Definition: CImg.h:5587
CImg< T > & draw_text(const int x0, const int y0, const char *const text, const tc1 *const foreground_color, const tc2 *const background_color, const float opacity=1, const unsigned int font_size=11,...)
Draw a text.
Definition: CImg.h:26388
volatile bool is_key3
Definition: CImg.h:6190
static const char * format()
Definition: CImg.h:2150
const CImg< T > get_shared() const
Definition: CImg.h:10081
unsigned int & exception_mode()
Get/set the current CImg exception mode.
Definition: CImg.h:1940
CImg< Tfloat > get_translate_object3d(const float tx, const float ty=0, const float tz=0) const
Definition: CImg.h:21086
CImg< T > & RGBtoYUV()
Convert color pixels from (R,G,B) to (Y,U,V).
Definition: CImg.h:16078
bool is_sameNXYZV(const unsigned int n, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const
Definition: CImg.h:34820
static const char * string()
Definition: CImg.h:2155
Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const
Definition: CImg.h:11483
CImg< _cimg_Tt > operator/(const t val) const
Operator/().
Definition: CImg.h:10758
const_iterator begin() const
Definition: CImg.h:11156
static const int scheme
static CImg< T > diagonal(const T &a0, const T &a1, const T &a2)
Return a 3x3 diagonal matrix with specified coefficients.
Definition: CImg.h:14367
CImg< T > & load_raw(std::FILE *const file, const unsigned int sizex, const unsigned int sizey=1, const unsigned int sizez=1, const unsigned int sizev=1, const bool multiplexed=false, const bool invert_endianness=false)
Load an image from a .RAW file.
Definition: CImg.h:30943
const CImgDisplay & snapshot(CImg< T > &img) const
Take a snapshot of the display in the specified image.
Definition: CImg.h:6841
static bool is_float()
Definition: CImg.h:2093
T & atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val)
Read a pixel value with Dirichlet boundary conditions for the four first coordinates (pos...
Definition: CImg.h:34584
CImg< T > & draw_spline(const CImg< t > &points, const tc *const color, const float opacity=1, const bool close_set=false, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored lines in the instance image.
Definition: CImg.h:23463
CImgList< T > & operator=(const CImgList< t > &list)
Operator=().
Definition: CImg.h:34405
static const char * format()
Definition: CImg.h:2186
const unsigned int keyEND
Definition: CImg.h:2711
volatile bool is_keyL
Definition: CImg.h:6225
CImg< Tfloat > get_RGBtoXYZ() const
Definition: CImg.h:16258
CImg< T > & load_inr(const char *const filename, float *const voxsize=0)
Load an image from an INRIMAGE-4 file.
Definition: CImg.h:30595
bool contains(const CImg< T > &img) const
Return true if the list contains the image img.
Definition: CImg.h:34888
const unsigned int key9
Definition: CImg.h:2693
CImg< _cimg_Tfloat > cosh(const CImg< T > &instance)
Definition: CImg.h:6066
CImg< T > & operator&=(const CImg< t > &img)
Operator&amp;=().
Definition: CImg.h:10856
static CImg< T > get_load_jpeg(const char *const filename)
Definition: CImg.h:29497
T atXY(const int x, const int y, const int z, const int v, const T out_val) const
Definition: CImg.h:11296
CImg< T > & load_cimg(std::FILE *const file, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1, const char axis='z', const char align='p')
Load a sub-image (list) from a non-compressed .cimg file.
Definition: CImg.h:30575
CImg< Tfloat > get_asin() const
Definition: CImg.h:12655
#define cimg_forXYZ(img, x, y, z)
Definition: CImg.h:603
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float opacity=1, const float brightness=1)
Draw a 2D textured triangle.
Definition: CImg.h:24191
#define _cimg_median_sort(a, b)
T _atXYZV(const int x, const int y, const int z, const int v) const
Definition: CImg.h:11251
T & min()
Return a reference to the minimum pixel value of the instance list.
Definition: CImg.h:34901
CImg< Tfloat > get_XYZtoLab() const
Definition: CImg.h:16318
static CImg< T > matrix(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7, const T &a8, const T &a9, const T &a10, const T &a11, const T &a12, const T &a13, const T &a14, const T &a15)
Return a 4x4 square matrix with specified coefficients.
Definition: CImg.h:14314
static CImg< T > get_load_graphicsmagick_external(const char *const filename)
Definition: CImg.h:31250
const unsigned int keyALTGR
Definition: CImg.h:2738
Tfloat MSE(const CImg< t > &img) const
Compute the MSE (Mean-Squared Error) between two images.
Definition: CImg.h:13113
CImgList< T > & load_cimg(const char *const filename, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1)
Load a sub-image list from a non compressed .cimg file.
Definition: CImg.h:35643
static void save_empty_cimg(const char *const filename, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1)
Save an empty .cimg file with specified dimensions.
Definition: CImg.h:33314
const unsigned int keyMENU
Definition: CImg.h:2740
CImg< T > & HSVtoRGB()
Convert color pixels from (H,S,V) to (R,G,B).
Definition: CImg.h:15826
CImgList< T > & assign(const unsigned int n, const unsigned int width, const unsigned int height=1, const unsigned int depth=1, const unsigned int dim=1)
In-place version of the corresponding constructor.
Definition: CImg.h:34171
const CImg< T > & save_yuv(const char *const filename, const bool rgb2yuv=true) const
Save the image as a YUV video sequence file.
Definition: CImg.h:33594
CImg< T > & operator*=(const t val)
Operator*=().
Definition: CImg.h:10670
static void wait_all()
Wait for a window event in any CImg window.
Definition: CImg.h:6908
NT p0
CImgList< T > get_shared()
Return a shared instance of the list.
Definition: CImg.h:34128
CImg< T > & draw_axis(const CImg< tx > &xvalues, const CImg< ty > &yvalues, const CImg< tc > &color, const float opacity=1, const unsigned int patternx=~0U, const unsigned int patterny=~0U)
Draw a labeled horizontal+vertical axis on the instance image.
Definition: CImg.h:26663
CImg< T > & draw_image(const int x0, const int y0, const CImg< ti > &sprite, const CImg< tm > &mask, const float opacity=1, const float mask_valmax=1)
Draw an image.
Definition: CImg.h:26305
*********************************************************************Illinois Open Source License ****University of Illinois NCSA **Open Source License University of Illinois All rights reserved ****Developed free of to any person **obtaining a copy of this software and associated documentation to deal with the Software without including without limitation the rights to ** copy
Definition: roccomf90.h:20
volatile bool is_keyN
Definition: CImg.h:6233
CImgList(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int dim, const double val0, const double val1,...)
Construct an image list containing n images with specified size and specified pixel values (double ve...
Definition: CImg.h:34015
CImg< T > & operator|=(const t val)
Operator|=().
Definition: CImg.h:10876
static const char * pixel_type()
Return the type of the pixel values.
Definition: CImg.h:11041
CImg< T > & draw_rectangle(const int x0, const int y0, const int x1, const int y1, const tc *const color, const float opacity, const unsigned int pattern)
Draw a 2D outlined colored rectangle.
Definition: CImg.h:25669
const char *const *const *const t_purple
Definition: CImg.h:1925
T & atNXYZ(const int pos, const int x, const int y, const int z, const int v=0)
Read a pixel value with Neumann boundary conditions for the four first coordinates (pos...
Definition: CImg.h:34593
CImg< T > & load(const char *const filename)
Load an image from a file.
Definition: CImg.h:29130
int dimy() const
Return display height.
Definition: CImg.h:6628
volatile bool is_keyHOME
Definition: CImg.h:6200
CImg< Tfloat > get_cos() const
Definition: CImg.h:12585
CImg< T > & translate_object3d()
Translate a 3D object so that it becomes centered.
Definition: CImg.h:21091
const CImg< T > & save_cimg(std::FILE *const file, const bool compress=false) const
Definition: CImg.h:33290
const CImgList< T > & save(const char *const filename, const int number=-1) const
Save an image list into a file.
Definition: CImg.h:36342
const T & max() const
Definition: CImg.h:34941
T _atXYZ(const int x, const int y, const int z, const int v=0) const
Definition: CImg.h:11286
T & atXY(const int x, const int y, const int z=0, const int v=0)
Read a pixel value with Neumann boundary conditions for the two first coordinates (x...
Definition: CImg.h:11301
CImgList< T > & _load_cimg(std::FILE *const file, const char *const filename, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1)
Definition: CImg.h:35672
~CImgList()
Destructor.
Definition: CImg.h:33966
CImg< T > & blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f, const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0, const unsigned int fast_approx=1)
Blur an image following in an anisotropic way.
Definition: CImg.h:19508
CImg< _cimg_Tfloat > log(const CImg< T > &instance)
Definition: CImg.h:6021
CImgDisplay & paint()
Re-paint image content in window.
Definition: CImg.h:6835
CImgDisplay & assign()
In-place version of the destructor.
Definition: CImg.h:6388
CImg< T > & mul(const CImg< t > &img)
Pointwise multiplication between two images.
Definition: CImg.h:12685
bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const unsigned int key4, const unsigned int key5, const unsigned int key6, const unsigned int key7, const unsigned int key8, const bool remove)
Test if a key sequence has been typed.
Definition: CImg.h:6551
const CImg< T > & save_magick(const char *const filename, const unsigned int bytes_per_pixel=0) const
Save the image using built-in ImageMagick++ library.
Definition: CImg.h:32654
static const char * format()
Definition: CImg.h:2114
CImg< T > & pseudoinvert()
Compute the pseudo-inverse (Moore-Penrose) of the matrix.
Definition: CImg.h:13543
bool operator==(const CImg< t > &img) const
Operator==().
Definition: CImg.h:10996
const unsigned int font10x13[256 *10 *13/32]
Definition: CImg.h:2805
#define cimg_get3x3(img, x, y, z, v, I)
Definition: CImg.h:484
CImg< T > & blur_median(const unsigned int n)
Apply a median filter.
Definition: CImg.h:19811
bool is_sameXY(const CImg< t > &img) const
Return true if images have same width and same height.
Definition: CImg.h:11929
unsigned int size() const
Return the number of image buffer elements.
Definition: CImg.h:11075
rational * A
Definition: vinci_lass.c:67
_marching2d_func_float(const CImg< T > &pref)
Definition: CImg.h:21439
static const char * format(const T val)
Definition: CImg.h:2097
const unsigned int keyAPPLEFT
Definition: CImg.h:2735
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 T val7, const T val8, const T val9, const T val10, const T val11, const T val12, const T val13) const
Definition: CImg.h:14765
CImg< T > operator|(const char *const expression, const CImg< T > &img)
Definition: CImg.h:5996
static unsigned char max()
Definition: CImg.h:2113
CImgList< t > & transfer_to(CImgList< t > &list, const unsigned int pos=~0U)
Definition: CImg.h:10344
const char * medcon_path(const char *const user_path=0, const bool reinit_path=false)
Return or set path of the XMedcon tool.
Definition: CImg.h:5302
CImg< T > get_sort(const bool increasing=true) const
Definition: CImg.h:13789
CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const int val0, const int val1,...)
Construct an image with given size (dx,dy,dz,dv) and with specified pixel values (int version)...
Definition: CImg.h:9901
CImg< Tfloat > get_log10() const
Definition: CImg.h:12565
const CImg< T > & save_off(const char *const filename, const CImgList< tf > &primitives, const CImgList< tc > &colors) const
Save OFF files.
Definition: CImg.h:33657
CImg< T > & draw_spline(const CImg< tp > &points, const CImg< tt > &tangents, const tc *const color, const float opacity=1, const bool close_set=false, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored splines in the instance image.
Definition: CImg.h:23425
CImg< T > get_rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) const
Definition: CImg.h:17641
CImg< _cimg_Tt > operator%(const t val) const
Operator%().
Definition: CImg.h:10814
const T & minmax(t &max_val) const
Definition: CImg.h:12935
unsigned int width
Size of the list (number of images).
Definition: CImg.h:33883
CImg< T > & operator/=(const CImg< t > &img)
Operator/=().
Definition: CImg.h:10752
CImg< T > & draw_point(const int x0, const int y0, const CImg< tc > &color, const float opacity=1)
Draw a 2D colored point (pixel).
Definition: CImg.h:22199
volatile unsigned int & released_key
Key value if released.
Definition: CImg.h:6158
CImg< T > & min(const char *const expression)
Pointwise min operator between an image and a string.
Definition: CImg.h:12804
CImg< intT > _get_select(CImgDisplay &disp, const char *const title, const int coords_type, unsigned int *const XYZ, const unsigned char *const color, const int origX, const int origY, const int origZ) const
Definition: CImg.h:28616
CImg< T > & assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val)
In-place version of the previous constructor.
Definition: CImg.h:10151
bool containsXYZV(const int x, const int y=0, const int z=0, const int v=0) const
Return true if pixel (x,y,z,v) is inside image boundaries.
Definition: CImg.h:12049
CImg< T > & draw_point(const int x0, const int y0, const int z0, const tc *const color, const float opacity=1)
Draw a 3D colored point (voxel).
Definition: CImg.h:22206
CImg< T > get_edge_tensors(const float sharpness=0.7f, const float anisotropy=0.3f, const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) const
Definition: CImg.h:20322
CImg< T > & stats(const unsigned int variance_method=1)
Compute a statistics vector (min,max,mean,variance,xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax).
Definition: CImg.h:13148
#define _cimg_deriche2_apply
volatile bool is_keyALT
Definition: CImg.h:6239
const unsigned int keyW
Definition: CImg.h:2701
CImg< T > & blur(const float sigma, const bool cond=true)
Return a blurred version of the image, using a Canny-Deriche filter.
Definition: CImg.h:19225
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const CImg< tc > &color, const CImg< tl > &light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1)
Draw a 2D Pseudo-Phong-shaded triangle.
Definition: CImg.h:24687
cimg::superset< T, unsigned short >::type Tushort
Definition: CImg.h:9775
const unsigned int keyF6
Definition: CImg.h:2677
double eval(const double x, const double y, const double z, const double v)
Definition: CImg.h:12512
CImg< _cimg_Tt > operator/(const CImg< t > &img) const
Operator/().
Definition: CImg.h:10769
CImg< T > & draw_image(const int x0, const int y0, const int z0, const CImg< ti > &sprite, const CImg< tm > &mask, const float opacity=1, const float mask_valmax=1)
Draw an image.
Definition: CImg.h:26297
unsigned long timer
Definition: CImg.h:6268
CImg< T > transpose(const CImg< T > &instance)
Definition: CImg.h:6081
CImg< _cimg_Tfloat > asin(const CImg< T > &instance)
Definition: CImg.h:6056
const CImg< T > & save_raw(const char *const filename, const bool multiplexed=false) const
Save the image as a RAW file.
Definition: CImg.h:33564
CImg(const CImg< t > &img, const char *const dimensions, const T val)
Construct an image using dimensions of another image, and fill it with given values.
Definition: CImg.h:10059
CImg< T > & transpose()
Transpose the current matrix.
Definition: CImg.h:13441
CImg< T > operator^(const char *const expression, const CImg< T > &img)
Definition: CImg.h:6001
CImg< T > & load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1)
Load an image from a RGBA file.
Definition: CImg.h:29995
cimg::last< T, unsigned short >::type ushortT
Definition: CImg.h:9786
static CImg< T > get_load_parrec(const char *const filename, const char axis='v', const char align='p')
Definition: CImg.h:30923
CImg< T > & assign(const CImg< t > &img, const char *const dimensions, const T val)
In-place version of the previous constructor.
Definition: CImg.h:10311
T & atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val)
Read a pixel value with Dirichlet boundary conditions for the three first coordinates (pos...
Definition: CImg.h:34616
CImg< T > & draw_object3d(const float x0, const float y0, const float z0, const CImg< tp > &vertices, const CImgList< tf > &primitives, const CImgList< tc > &colors, const CImgList< to > &opacities, const unsigned int render_type=4, const bool double_sided=false, const float focale=500, const float lightx=0, const float lighty=0, const float lightz=-5000, const float specular_light=0.2f, const float specular_shine=0.1f, CImg< floatT > &zbuffer=cimg_library::CImg< floatT >::empty())
Draw a 3D object.
Definition: CImg.h:27522
static const char * pixel_type()
Return a string describing the type of the image pixels in the list (template parameter T)...
Definition: CImg.h:34460
bool contains(const T &pixel) const
Return true if one of the image list contains the specified referenced value.
Definition: CImg.h:34873
CImg< T > & _quicksort(const int min, const int max, CImg< t > &permutations, const bool increasing)
Definition: CImg.h:13794
CImg< _cimg_Tt > operator-(const t val) const
Operator-().
Definition: CImg.h:10653
double F1(double x)
Simple test function fixture returns .
CImg< T > & dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U)
Return minimal path in a graph, using the Dijkstra algorithm.
Definition: CImg.h:14124
static CImg< T > get_load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1)
Definition: CImg.h:30008
unsigned int width
Width of the display.
Definition: CImg.h:6117
CImgList< T > operator<(const char axis) const
Operator&lt;().
Definition: CImg.h:34445
CImg< T > & normalize()
Normalize multi-valued pixels of the instance image, with respect to their L2-norm.
Definition: CImg.h:15099
static CImg< T > get_load_raw(std::FILE *const file, const unsigned int sizex, const unsigned int sizey=1, const unsigned int sizez=1, const unsigned int sizev=1, const bool multiplexed=false, const bool invert_endianness=false)
Definition: CImg.h:30950
CImg< Tuchar > get_RGBtoYCbCr() const
Definition: CImg.h:16046
bool is_sameYV(const unsigned int dy, const unsigned int dv) const
Return true if image (*this) has the specified height and number of channels.
Definition: CImg.h:11972
static CImg< T > dijkstra(const tf &distance, const unsigned int nb_nodes, const unsigned int starting_node, const unsigned int ending_node, CImg< t > &previous)
Compute minimal path in a graph, using the Dijkstra algorithm.
Definition: CImg.h:14048
double F2(double x)
Simple test function fixture returns .
CImg< _cimg_Tt > operator+(const CImg< t > &img) const
Operator+().
Definition: CImg.h:10590
T & atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val)
Read a pixel value with Dirichlet boundary conditions.
Definition: CImg.h:34552
CImg< T > & vector()
Unroll all images values into a one-column vector.
Definition: CImg.h:13334
const unsigned int keyH
Definition: CImg.h:2719
T _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const
Definition: CImg.h:34675
#define cimg_for3x3(img, x, y, z, v, I)
Definition: CImg.h:1081
const unsigned int keyX
Definition: CImg.h:2726
CImg< T > & draw_line(const int x0, const int y0, const int x1, const int y1, const CImg< tc > &color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a 2D colored line.
Definition: CImg.h:22393
CImg< Tuchar > get_xyYtoRGB() const
Definition: CImg.h:16441
CImgList< _cimg_Tt > operator,(CImgList< t > &list) const
Operator,().
Definition: CImg.h:11019
CImg< T > & operator-=(const t val)
Operator-=().
Definition: CImg.h:10596
volatile bool is_keyDELETE
Definition: CImg.h:6213
#define _cimg_gs2x_for3x3(img, x, y, z, v, I)
const unsigned int keySPACE
Definition: CImg.h:2737
T & maxmin(t &min_val)
Return a reference to the minimum pixel value of the instance list.
Definition: CImg.h:34995
CImg< T > & operator=(const CImgDisplay &disp)
Operator=().
Definition: CImg.h:10511
CImg< T > get_slices(const unsigned int z0, const unsigned int z1) const
Definition: CImg.h:18452
CImg< _cimg_Tfloat > sinh(const CImg< T > &instance)
Definition: CImg.h:6071
bool is_key(const unsigned int key1, const bool remove)
Test if a key has been pressed.
Definition: CImg.h:6504
CImg< T > & _LU(CImg< t > &indx, bool &d)
Definition: CImg.h:13994
CImgList< T > get_insert(const unsigned int n, const CImg< t > &img, const unsigned int pos=~0U, const bool shared=false) const
Definition: CImg.h:35140
CImgList< T > & _load_yuv(std::FILE *const file, const char *const filename, const unsigned int sizex, const unsigned int sizey, const unsigned int first_frame, const unsigned int last_frame, const unsigned int step_frame, const bool yuv2rgb)
Definition: CImg.h:35904
static float _distance_f(const int x, const int i, const float gi2, const float fact)
Definition: CImg.h:20537
CImgList< T > & operator=(const CImgList< T > &list)
Definition: CImg.h:34409
CImg< T > & operator-=(const char *const expression)
Operator-=().
Definition: CImg.h:10602
void int int int REAL REAL REAL * z
Definition: write.cpp:76
CImg< T > & operator=(const CImg< T > &img)
Definition: CImg.h:10506
CImg< T > & crop(const int x0, const int x1, const bool border_condition=false)
Get a rectangular part of the instance image.
Definition: CImg.h:18258
static void save_empty_cimg(const char *const filename, const unsigned int nb, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1)
Create an empty .cimg file with specified dimensions.
Definition: CImg.h:36901
CImg< T > & operator+=(const t val)
Operator+=().
Definition: CImg.h:10518
bool is_sameY(const unsigned int dy) const
Return true if image (*this) has the specified height.
Definition: CImg.h:11885
#define _cimg_Tfloat
Definition: CImg.h:2301
CImg< T > & draw_spline(const int x0, const int y0, const float u0, const float v0, const int x1, const int y1, const float u1, const float v1, const tc *const color, const float opacity=1, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a cubic spline curve in the instance image.
Definition: CImg.h:23122
CImg< T > & load_yuv(std::FILE *const file, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p')
Load an image sequence from a YUV file.
Definition: CImg.h:31013
CImg< T > & crop(const int x0, const int y0, const int x1, const int y1, const bool border_condition=false)
Get a rectangular part of the instance image.
Definition: CImg.h:18239
float operator()(const float x, const float y, const float z) const
Definition: CImg.h:21794
#define cimg_for_inXYZ(img, x0, y0, z0, x1, y1, z1, x, y, z)
Definition: CImg.h:621
volatile bool is_keyP
Definition: CImg.h:6212
#define cimglist_apply(list, fn)
Definition: CImg.h:1881
CImgDisplay & operator=(const CImg< t > &img)
Definition: CImg.h:6465
CImg< T > & draw_gaussian(const float xc, const float sigma, const CImg< tc > &color, const float opacity=1)
Draw a 1D gaussian function in the instance image.
Definition: CImg.h:27349
int strcasecmp(const char *const s1, const char *const s2)
Compare two C-strings, ignoring the case.
Definition: CImg.h:4928
T * iterator
Iterator type for CImg&lt;T&gt;.
Definition: CImg.h:9758
static CImgList< T > get_load_cimg(const char *const filename)
Definition: CImg.h:35537
CImg< T > & draw_spline(const CImg< tp > &points, const CImg< tt > &tangents, const CImg< tc > &color, const float opacity=1, const bool close_set=false, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored splines in the instance image.
Definition: CImg.h:23434
CImg< T > get_slice(const unsigned int z0) const
Definition: CImg.h:18443
const unsigned int font8x17[8 *17 *256/32]
Definition: CImg.h:2868
const CImg< T > & save_off(std::FILE *const file, const CImgList< tf > &primitives, const CImgList< tc > &colors) const
Save OFF files.
Definition: CImg.h:33664
T & _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0)
Definition: CImg.h:34607
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, const T val13, const T val14, const T val15)
Fill sequentially pixel values.
Definition: CImg.h:14811
NT & sin
T & atXY(const int x, const int y, const int z, const int v, const T out_val)
Read a pixel value with Dirichlet boundary conditions for the two first coordinates (x...
Definition: CImg.h:11292
const CImg< T > & save_ascii(std::FILE *const file) const
Save the image as an ASCII file (ASCII Raw + simple header).
Definition: CImg.h:32381
CImg< T > & sqrt()
Compute the square root of each pixel value.
Definition: CImg.h:12530
const unsigned int keyPAD9
Definition: CImg.h:2754
bool is_sameYZ(const CImg< t > &img) const
Return true if images have same height and same depth.
Definition: CImg.h:11967
static const char * format()
Definition: CImg.h:2159
CImg< T > & assign()
In-place version of the default constructor/destructor.
Definition: CImg.h:10103
const unsigned int keyENTER
Definition: CImg.h:2723
CImgList< Tfloat > get_FFT(const bool invert=false) const
Definition: CImg.h:37139
CImg< T > & load_bmp(std::FILE *const file)
Load an image from a BMP file.
Definition: CImg.h:29371
cimg::last< T, char >::type charT
Definition: CImg.h:33914
CImg< T > & permute_axes(const char *order)
Permute axes order.
Definition: CImg.h:17600
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7, const T &a8, const T &a9, const T &a10, const T &a11, const T &a12)
Return a vector with specified coefficients.
Definition: CImg.h:14237
const unsigned int keyO
Definition: CImg.h:2708
T atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) const
Definition: CImg.h:34588
volatile bool is_keySHIFTLEFT
Definition: CImg.h:6227
#define cimg_for3XYZ(img, x, y, z)
Definition: CImg.h:745
float operator()(const float x, const float y) const
Definition: CImg.h:21440
CImg< _cimg_Tfloat > cos(const CImg< T > &instance)
Definition: CImg.h:6036
Tfloat linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const
Read a pixel value using linear interpolation and Neumann boundary conditions.
Definition: CImg.h:11395
CImg< t > & transfer_to(CImg< t > &img)
Transfer the content of the instance image into another one in a way that memory copies are avoided i...
Definition: CImg.h:10332
int dimz() const
Return the number of slices of the instance image (size along the Z-axis).
Definition: CImg.h:11056
const unsigned int keyE
Definition: CImg.h:2702
const unsigned int keyM
Definition: CImg.h:2731
CImg< T > & load_ascii(const char *const filename)
Load an image from an ASCII file.
Definition: CImg.h:29266
char * number_filename(const char *const filename, const int number, const unsigned int n, char *const string)
Create a numbered version of a filename.
Definition: CImg.h:5483
CImg< T > & draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, const tc *const color, const float opacity, const unsigned int pattern)
Draw an outlined ellipse.
Definition: CImg.h:26065
CImgDisplay & operator=(const CImgList< t > &list)
Definition: CImg.h:6471
CImgList< T > & assign(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int dim, const double val0, const double val1,...)
In-place version of the corresponding constructor.
Definition: CImg.h:34194
CImg< Tfloat > get_tan() const
Definition: CImg.h:12605
void winformat_string(char *const s)
Definition: CImg.h:5007
const unsigned int keyT
Definition: CImg.h:2704
const unsigned int keyPAD2
Definition: CImg.h:2747
CImg< T > & haar(const bool invert=false, const unsigned int nb_scales=1)
Compute the Haar multiscale wavelet transform.
Definition: CImg.h:20729
CImg< T > get_channel(const unsigned int v0) const
Definition: CImg.h:18461
static CImg< T > get_load_yuv(std::FILE *const file, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p')
Definition: CImg.h:31020
const T & min() const
Definition: CImg.h:12890
static CImg< T > get_load_bmp(std::FILE *const file)
Definition: CImg.h:29375
CImg< _cimg_Tfloat > invert(const CImg< T > &instance)
Definition: CImg.h:6086
volatile bool is_key6
Definition: CImg.h:6193
CImg< T > * data
Pointer to the first list element.
Definition: CImg.h:33889
const unsigned int keyL
Definition: CImg.h:2722
static int screen_dimy()
Return the height of the screen resolution.
Definition: CImg.h:6660
CImg< Tfloat > get_RGBtoYUV() const
Definition: CImg.h:16098
CImg< Tfloat > get_deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) const
Definition: CImg.h:19203
CImg< T > operator>>(const int n) const
Operator&gt;&gt;().
Definition: CImg.h:10990
CImg< T > & operator^=(const t val)
Operator^=().
Definition: CImg.h:10921
CImg< T > get_resize_tripleXY() const
Definition: CImg.h:17092
CImgList< T > get_split(const char axis, const int nb=0) const
Definition: CImg.h:35396
CImg< Tfloat > get_tanh() const
Definition: CImg.h:12635
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7, const T &a8, const T &a9, const T &a10, const T &a11, const T &a12, const T &a13, const T &a14)
Return a vector with specified coefficients.
Definition: CImg.h:14263
int dimx() const
Return the number of columns of the instance image (size along the X-axis, i.e image width)...
Definition: CImg.h:11046
CImg< T > & load_analyze(std::FILE *const file, float *const voxsize=0)
Load an image from an ANALYZE7.5/NIFTI file.
Definition: CImg.h:30417
CImg< T > & tanh()
Compute the hyperbolic tangent of each pixel value.
Definition: CImg.h:12630
const unsigned int keyAPPRIGHT
Definition: CImg.h:2739
static CImg< T > get_load_png(std::FILE *const file)
Definition: CImg.h:29664
CImg< _cimg_Tt > operator%(const CImg< t > &img) const
Operator%().
Definition: CImg.h:10825
CImg< T > & draw_circle(const int x0, const int y0, int radius, const tc *const color, const float opacity, const unsigned int)
Draw an outlined circle.
Definition: CImg.h:25913
const unsigned int font29x57[29 *57 *256/32]
Definition: CImg.h:3729
CImg< T > & draw_axis(const CImg< t > &xvalues, const int y, const tc *const color, const float opacity=1, const unsigned int pattern=~0U)
Draw a labeled horizontal axis on the instance image.
Definition: CImg.h:26565
T & atN(const int pos, const int x, const int y, const int z, const int v, const T out_val)
Read a pixel value with Dirichlet boundary conditions for the first coordinates (pos).
Definition: CImg.h:34680
CImg< T > & draw_fill(const int x, const int y, const int z, const CImg< tc > &color, const float opacity=1, const float sigma=0, const bool high_connexity=false)
Draw a 3D filled region starting from a point (x,y,\ z) in the instance image.
Definition: CImg.h:27137
CImg< T > operator>(const char axis) const
Operator&gt;().
Definition: CImg.h:34440
volatile bool is_keyAPPLEFT
Definition: CImg.h:6238
CImg< T > & draw_axis(const int x, const CImg< t > &yvalues, const CImg< tc > &color, const float opacity=1, const unsigned int pattern=~0U)
Draw a labeled vertical axis on the instance image.
Definition: CImg.h:26625
const unsigned int keyHOME
Definition: CImg.h:2697
volatile bool is_keyEND
Definition: CImg.h:6214
static CImg< T > get_load_cimg(std::FILE *const file, const char axis='z', const char align='p')
Definition: CImg.h:30550
bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const unsigned int key4, const unsigned int key5, const bool remove)
Test if a key sequence has been typed.
Definition: CImg.h:6529
CImg< T > get_max(const T val) const
Definition: CImg.h:12835
const CImg< T > get_shared_channel(const unsigned int v0) const
Definition: CImg.h:18577
CImgList< T > get_shared_images(const unsigned int i0, const unsigned int i1)
Get a shared sub-list.
Definition: CImg.h:35256
CImg< T > & load_jpeg(std::FILE *const file)
Load an image from a JPEG file.
Definition: CImg.h:29502
CImg< T > & resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100, const int interpolation_type=1, const int border_condition=-1, const bool center=false)
Resize an image.
Definition: CImg.h:16630
bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const
Definition: CImg.h:34814
CImg< T > & select(CImgDisplay &disp, const int select_type=2, unsigned int *const XYZ=0, const unsigned char *const color=0)
Simple interface to select a shape from an image.
Definition: CImg.h:28588
CImgArgumentException(const char *format,...)
Definition: CImg.h:2046
const CImg< T > & print(const char *title=0, const bool display_stats=true) const
Display informations about the image on the standard error output.
Definition: CImg.h:31432
static const char * string()
Definition: CImg.h:2101
CImgList< T > & swap(CImgList< T > &list)
Swap all fields of two CImgList instances (use with care !)
Definition: CImg.h:34325
const unsigned int keyPAGEDOWN
Definition: CImg.h:2712
#define cimg_debug
Definition: CImg.h:160
static CImg< T > get_load_pandore(std::FILE *const file)
Definition: CImg.h:30714
CImg< T > & draw_grid(const CImg< tx > &xvalues, const CImg< ty > &yvalues, const CImg< tc > &color, const float opacity=1, const unsigned int patternx=~0U, const unsigned int patterny=~0U)
Draw grid.
Definition: CImg.h:26718
volatile bool is_keyF3
Definition: CImg.h:6177
#define cimg_for2x2(img, x, y, z, v, I)
Definition: CImg.h:1053
blockLoc i
Definition: read.cpp:79
cimg::superset< t1, t2 >::type max(const t1 &a, const t2 &b)
Return the maximum value between two numbers.
Definition: CImg.h:4749
double angle(Vector_3< double > v1, Vector_3< double > v2)
Compute the angle between two vectors.
Definition: geometry.C:61
const CImgList< T > & save_gzip_external(const char *const filename) const
Save a file in TIFF format.
Definition: CImg.h:36943
const unsigned int keyF
Definition: CImg.h:2717
CImg< T > get_fill(const T val0, const T val1, const T val2) const
Definition: CImg.h:14469
const CImg< T > & save_bmp(const char *const filename) const
Save the image as a BMP file.
Definition: CImg.h:32544
cimg::last< T, unsigned short >::type ushortT
Definition: CImg.h:33915
const CImg< T > & save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const
Save the image using GraphicsMagick&#39;s gm.
Definition: CImg.h:33689
CImg< T > get_fill(const T val0, const T val1, const T val2, const T val3, const T val4) const
Definition: CImg.h:14506
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3)
Return a vector with specified coefficients.
Definition: CImg.h:14154
T & _atXYZ(const int x, const int y, const int z, const int v=0)
Definition: CImg.h:11281
CImgList< Tfloat > get_FFT(const char axis, const bool invert=false) const
Compute a 1D Fast Fourier Transform, along a specified axis.
Definition: CImg.h:20818
volatile unsigned int keys[512]
Definition: CImg.h:6155
volatile bool is_key2
Definition: CImg.h:6189
CImg< _cimg_Tfloat > log10(const CImg< T > &instance)
Definition: CImg.h:6026
static CImg< T > get_load_magick(const char *const filename)
Definition: CImg.h:29646
CImg< charT > value_string(const char separator=',', const unsigned int max_size=0) const
Return a C-string containing the values of all images in the instance list.
Definition: CImg.h:34712
double crand()
Return a random variable between [-1,1] with respect to an uniform distribution.
Definition: CImg.h:4840
const char *const *const *const *const t_green
Definition: CImg.h:1925
T & _atXY(const int x, const int y, const int z=0, const int v=0)
Definition: CImg.h:11315
#define _cimg_create_ext_operators(typ)
Definition: CImg.h:5926
const CImg< T > & display(const char *const title=0, const bool display_info=true) const
Display an image in a window with a title title, and wait a &#39;is_closed&#39; or &#39;keyboard&#39; event...
Definition: CImg.h:31474
T & minmax(t &max_val)
Return a reference to the minimum pixel value and return also the maximum pixel value.
Definition: CImg.h:12920
static const char * string()
Definition: CImg.h:2119
float operator()(const float x, const float y) const
Definition: CImg.h:21432
CImg< T > & haar(const char axis, const bool invert=false, const unsigned int nb_scales=1)
Compute the Haar multiscale wavelet transform (monodimensional version).
Definition: CImg.h:20600
volatile bool is_keyE
Definition: CImg.h:6205
CImg< T > get_shared_plane(const unsigned int z0, const unsigned int v0=0)
Return a shared-memory image referencing one plane (z0,v0) of the instance image. ...
Definition: CImg.h:18545
void int int REAL * x
Definition: read.cpp:74
static CImg< T > get_load_dcraw_external(const char *const filename)
Definition: CImg.h:31388
volatile bool is_keyPAD9
Definition: CImg.h:6257
static CImg< T > get_load_analyze(const char *const filename, float *const voxsize=0)
Definition: CImg.h:30412
const CImg< T > & save_dlm(std::FILE *const file) const
Save the image as a DLM file.
Definition: CImg.h:32453
const CImg< T > & display_object3d(CImgDisplay &disp, const CImg< tp > &vertices, const CImgList< tf > &primitives, const CImgList< tc > &colors, const to &opacities, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=true, const float focale=500, const float specular_light=0.2f, const float specular_shine=0.1f, const bool display_axes=true, float *const pose_matrix=0) const
High-level interface for displaying a 3d object.
Definition: CImg.h:31664
CImg< T > & RGBtoHSV()
Convert color pixels from (R,G,B) to (H,S,V).
Definition: CImg.h:15787
static int format(const short val)
Definition: CImg.h:2151
CImg< T > & load_ascii(std::FILE *const file)
Load an image from an ASCII file.
Definition: CImg.h:29275
CImg< T > & assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1)
In-place version of the previous constructor.
Definition: CImg.h:10179
CImg< T > & _draw_point(const t &points, const unsigned int W, const unsigned int H, const tc *const color, const float opacity)
Definition: CImg.h:22232
static unsigned short min()
Definition: CImg.h:2139
volatile bool is_keyF1
Definition: CImg.h:6175
CImg< T > & draw_triangle(const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float opacity=1, const float brightness=1)
Draw a 2D textured triangle, with perspective correction.
Definition: CImg.h:24307
float operator()(const float x, const float y, const float z) const
Definition: CImg.h:21784
#define TRUE
Definition: vinci.h:134
CImg< T > & fill(const T val0, const T val1)
Fill sequentially all pixel values with values val0 and val1 respectively.
Definition: CImg.h:14444
static unsigned long max()
Definition: CImg.h:2176
const CImg< T > & SVD(CImg< t > &U, CImg< t > &S, CImg< t > &V, const bool sorting=true, const unsigned int max_iter=40, const float lambda=0) const
Compute the SVD of a general matrix.
Definition: CImg.h:13843
static CImg< floatT > elevation3d(CImgList< tf > &primitives, const char *const expression, const float x0, const float y0, const float x1, const float y1, const int sizex=256, const int sizey=256)
Definition: CImg.h:21319
CImg< Tfloat > get_acos() const
Definition: CImg.h:12645
static void wait(CImgDisplay &disp1, CImgDisplay &disp2, CImgDisplay &disp3, CImgDisplay &disp4)
Wait for any event occuring either on the display disp1, disp2, disp3 or disp4.
Definition: CImg.h:6900
static CImg< T > get_load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p')
Definition: CImg.h:31216
volatile bool is_keyESC
Current state of the corresponding key (exists for all referenced keys).
Definition: CImg.h:6174
volatile bool is_keyF
Definition: CImg.h:6220
static unsigned long min()
Definition: CImg.h:2175
const char *const t_red
Definition: CImg.h:1924
volatile bool is_moved
Moved state of the window.
Definition: CImg.h:6168
CImg< T > & fillY(const unsigned int x, const unsigned int z, const unsigned int v, const double a0,...)
Definition: CImg.h:14919
CImg< T > & assign(const CImg< t > &img)
In-place version of the default copy constructor.
Definition: CImg.h:10259
CImgDisplay & display(const CImgList< T > &list, const char axis='x', const char align='p')
Display an image list CImgList&lt;T&gt; into a display window.
Definition: CImg.h:6705
CImgList< Tfloat > get_FFT(const bool invert=false) const
Compute a N-D Fast-Fourier Transform.
Definition: CImg.h:20825
#define _cimg_Tt
Definition: CImg.h:2300
CImg< T > & exp()
Compute the exponential of each pixel value.
Definition: CImg.h:12540
volatile bool is_keyF4
Definition: CImg.h:6178
CImgList< T > & insert(const unsigned int n, const unsigned int pos=~0U)
Insert n empty images img into the current image list, at position pos.
Definition: CImg.h:35117
CImg< T > & draw_gaussian(const float xc, const float yc, const float zc, const CImg< t > &tensor, const tc *const color, const float opacity=1)
Draw an anisotropic 3D gaussian function.
Definition: CImg.h:27451
const CImg< T > & save_inr(const char *const filename, const float *const voxsize=0) const
Save the image as an INRIMAGE-4 file.
Definition: CImg.h:33362
_marching3d_func_expr(const char *const expr)
Definition: CImg.h:21791
CImg(const CImg< t > &img, const char *const dimensions)
Construct an image using dimensions of another image.
Definition: CImg.h:10053
const unsigned int keySHIFTLEFT
Definition: CImg.h:2724
CImg< T > & assign(const CImg< t > &img, const bool shared)
In-place version of the advanced constructor.
Definition: CImg.h:10277
const CImg< T > & save_cpp(const char *const filename) const
Save the image as a CPP source file.
Definition: CImg.h:32412
CImg< T > & abs()
Compute the absolute value of each pixel value.
Definition: CImg.h:12570
static CImg< T > get_load(const char *const filename)
Definition: CImg.h:29261
CImg< T > get_autocrop(const T *const color, const char *const axes="zyx") const
Definition: CImg.h:18342
CImg< T > & cos()
Compute the cosinus of each pixel value.
Definition: CImg.h:12580
const CImg< T > get_shared_plane(const unsigned int z0, const unsigned int v0=0) const
Definition: CImg.h:18549
CImg< T > & _load_rgba(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh)
Definition: CImg.h:30012
static unsigned short max()
Definition: CImg.h:2140
CImg< T > & matrix()
Realign pixel values of the instance image as a square matrix.
Definition: CImg.h:13343
const unsigned int keyARROWUP
Definition: CImg.h:2733
bool is_sameXZV(const CImg< t > &img) const
Return true if images have same width, same depth and same number of channels.
Definition: CImg.h:12022
CImg< intT > get_select(CImgDisplay &disp, const int select_type=2, unsigned int *const XYZ=0, const unsigned char *const color=0) const
Simple interface to select a shape from an image.
Definition: CImg.h:28602
#define _cimg_blur_patch3d(N)
CImg< T > & displacement_field(const CImg< T > &target, const float smooth=0.1f, const float precision=0.1f, const unsigned int nb_scales=0, const unsigned int itermax=1000, const bool backward=true)
Estimate a displacement field between instance image and given target image.
Definition: CImg.h:20331
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6)
Fill sequentially pixel values.
Definition: CImg.h:14533
CImg< T > & draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, const CImg< tc > &color, const float opacity=1)
Draw a filled ellipse.
Definition: CImg.h:26024
const CImgList< T > & save_cimg(std::FILE *file, const bool compress=false) const
Save an image list into a CImg file (RAW binary file + simple header)
Definition: CImg.h:36752
CImg< Tfloat > get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const
Definition: CImg.h:20604
const NT & n
CImg< T > & draw_triangle(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const tc *const color, const CImg< tl > &light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1)
Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
Definition: CImg.h:24701
static CImg< T > get_load_dlm(std::FILE *const file)
Definition: CImg.h:29327
#define cimg_foroff(img, off)
Definition: CImg.h:590
CImgDisplay & show_mouse()
Show mouse pointer.
Definition: CImg.h:6803
volatile bool is_keyENTER
Definition: CImg.h:6226
const unsigned int key3
Definition: CImg.h:2687
volatile bool is_keyO
Definition: CImg.h:6211
T _at(const int off) const
Definition: CImg.h:11216
CImg< T > get_fill(const T val0, const T val1, const T val2, const T val3) const
Definition: CImg.h:14487
CImg< T > get_matrix() const
Definition: CImg.h:13367
T atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) const
Definition: CImg.h:34684
volatile bool is_keyZ
Definition: CImg.h:6228
volatile bool is_keyV
Definition: CImg.h:6231
CImgList< T > get_remove(const unsigned int pos1, const unsigned int pos2) const
Definition: CImg.h:35206
volatile bool is_keyF12
Definition: CImg.h:6186
static CImg< Tuchar > default_LUT256()
Return a default indexed color palette with 256 (R,G,B) entries.
Definition: CImg.h:15715
superset< t1, typename superset< t2, t3 >::type >::type type
Definition: CImg.h:2291
CImg< _cimg_Tfloat > atan(const CImg< T > &instance)
Definition: CImg.h:6061
CImg< T > & draw_point(const int x0, const int y0, const int z0, const CImg< tc > &color, const float opacity=1)
Draw a 3D colored point (voxel).
Definition: CImg.h:22225
CImgList< T > get_remove(const unsigned int pos) const
Definition: CImg.h:35215
CImgList< T > & FFT(const bool invert=false)
Compute a N-D Fast Fourier Transform.
Definition: CImg.h:37130
unsigned int compile(char *const ss, char *const se)
Definition: CImg.h:12266
CImgDisplay(const CImgDisplay &disp)
Create a display window by copying another one.
Definition: CImg.h:6379
bool is_object3d(const CImgList< tf > &primitives, const bool check_primitives=true, const bool throw_exception=false, const char *const calling_function=0) const
Return true if the couple (instance,primitives) stands for a valid 3D object.
Definition: CImg.h:12122
CImg< T > & fill(const T val0, const T val1, const T val2)
Fill sequentially all pixel values with values val0 and val1 and val2.
Definition: CImg.h:14457
CImg< T > get_threshold(const T value, const bool soft_threshold=false, const bool strict_threshold=false) const
Definition: CImg.h:15246
CImgList< T > & load_ffmpeg_external(const char *const filename)
Load an image from a video file (MPEG,AVI) using the external tool &#39;ffmpeg&#39;.
Definition: CImg.h:36127
CImg< _cimg_Tt > get_cross(const CImg< t > &img) const
Definition: CImg.h:13469
CImgList< T > & images(const unsigned int i0, const unsigned int i1)
Get a sub-list.
Definition: CImg.h:35242
CImg< T > & draw_triangle(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const tc *const color, const float brightness0, const float brightness1, const float brightness2, const float opacity=1)
Draw a 2D Gouraud-shaded colored triangle, with z-buffering.
Definition: CImg.h:24046
const unsigned int keyARROWRIGHT
Definition: CImg.h:2744
T & _atX(const int x, const int y=0, const int z=0, const int v=0)
Definition: CImg.h:11347
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc *const color, const float opacity=1)
Draw a 2D filled colored triangle.
Definition: CImg.h:23796
CImgList< T > & assign(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const bool shared=false)
In-place version of the corresponding constructor.
Definition: CImg.h:34234
CImg< T > & load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1)
Load an image from a RGB file.
Definition: CImg.h:29958
CImgList< T > get_crop_font() const
Definition: CImg.h:37029
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc1 *const color1, const tc2 *const color2, const tc3 *const color3, const float opacity=1)
Draw a colored triangle with interpolated colors.
Definition: CImg.h:24148
CImg< T > operator|(const t val) const
Operator|().
Definition: CImg.h:10915
const CImg< T > get_shared_channels(const unsigned int v0, const unsigned int v1) const
Definition: CImg.h:18563
T sign(const T x)
Return the sign of a number.
Definition: CImg.h:4770
volatile bool is_keyD
Definition: CImg.h:6219
#define cimg_for3XY(img, x, y)
Definition: CImg.h:739
CImgList< T > get_split(const T value, const bool keep_values, const bool shared, const char axis='y') const
Definition: CImg.h:18622
const CImg< T > & save_rgba(const char *const filename) const
Save the image as a RGBA file.
Definition: CImg.h:33115
volatile bool is_keySHIFTRIGHT
Definition: CImg.h:6235
const unsigned int keyB
Definition: CImg.h:2729
CImg< Tfloat > get_RGBtoCMY() const
Definition: CImg.h:16149
static const char * format()
Definition: CImg.h:2177
const CImg< T > & save(const char *const filename, const int number=-1) const
Save the image as a file.
Definition: CImg.h:32256
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4)
Return a vector with specified coefficients.
Definition: CImg.h:14161
CImg< T > & draw_spline(const CImgList< tp > &points, const CImgList< tt > &tangents, const CImg< tc > &color, const float opacity=1, const bool close_set=false, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored splines in the instance image.
Definition: CImg.h:23416
int window_dimx() const
Return display window width.
Definition: CImg.h:6633
CImg< T > & draw_spline(const int x0, const int y0, const float u0, const float v0, const int x1, const int y1, const float u1, const float v1, const CImg< t > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const float opacity=1, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a cubic spline curve in the instance image.
Definition: CImg.h:23243
#define cimg_forXY(img, x, y)
Definition: CImg.h:597
CImg< T > & LabtoXYZ()
Convert (L,a,b) pixels of a color image into the (X,Y,Z) color space.
Definition: CImg.h:16323
CImg< T > & blur_anisotropic(const CImg< t > &G, const float amplitude=60, const float dl=0.8f, const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0, const unsigned int fast_approx=1)
Blur the image anisotropically following a field of diffusion tensors.
Definition: CImg.h:19246
const CImg< T > & save_png(const char *const filename, const unsigned int bytes_per_pixel=0) const
Save a file in PNG format.
Definition: CImg.h:32890
T & maxmin(t &min_val)
Return a reference to the maximum pixel value and return also the minimum pixel value.
Definition: CImg.h:12951
CImg()
Default constructor.
Definition: CImg.h:9857
const unsigned int keyPAD7
Definition: CImg.h:2752
volatile bool is_keyY
Definition: CImg.h:6208
CImgList(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int dim, const int val0, const int val1,...)
Construct an image list containing n images with specified size and specified pixel values (int versi...
Definition: CImg.h:33996
bool is_sameXYZV(const CImg< t > &img) const
Return true if images (*this) and img have same width, same height, same depth and same number of cha...
Definition: CImg.h:12044
static void save_empty_cimg(std::FILE *const file, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1)
Save an empty .cimg file with specified dimensions.
Definition: CImg.h:33321
CImg< T > & cross(const CImg< t > &img)
Compute the cross product between two 3d vectors.
Definition: CImg.h:13457
CImgList< T > & pop_back()
Remove last element of the list (STL-compliant name).
Definition: CImg.h:35427
#define _cimg_fopcode2(op, i1, i2)
Definition: CImg.h:12227
volatile bool is_keyW
Definition: CImg.h:6204
CImgList< T > & assign(const unsigned int n, const CImg< t > &img, const bool shared=false)
In-place version of the corresponding constructor.
Definition: CImg.h:34210
CImg< T > operator&(const t val) const
Operator&amp;().
Definition: CImg.h:10870
const T rol(const T a, const unsigned int n=1)
Return a left bitwise-rotated number.
Definition: CImg.h:4671
const unsigned int font16x32[16 *32 *256/32]
Definition: CImg.h:3169
CImgList< T > & split(const char axis, const int nb=0)
Return a list where each image has been split along the specified axis.
Definition: CImg.h:35392
CImg< T > & draw_gaussian(const float xc, const float yc, const float zc, const float sigma, const CImg< tc > &color, const float opacity=1)
Draw an isotropic 3D gaussian function.
Definition: CImg.h:27499
#define cimglist_for(list, l)
Definition: CImg.h:1877
CImg< T > & draw_text(const int x0, const int y0, const char *const text, const int, const tc *const background_color, const float opacity, const CImgList< t > &font,...)
Draw a text.
Definition: CImg.h:26368
CImg< Tfloat > get_displacement_field(const CImg< T > &target, const float smoothness=0.1f, const float precision=0.1f, const unsigned int nb_scales=0, const unsigned int itermax=1000, const bool backward=true) const
Definition: CImg.h:20337
CImg< T > & draw_plasma(const int x0, const int y0, const int x1, const int y1, const float alpha=1, const float beta=1, const float opacity=1)
Draw a plasma random texture.
Definition: CImg.h:27177
CImgList< T > get_split(const char axis, const int nb=0) const
Split image into a list.
Definition: CImg.h:18582
CImg< T > & operator/=(const char *const expression)
Operator/=().
Definition: CImg.h:10733
CImg< T > & YCbCrtoRGB()
Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
Definition: CImg.h:16051
CImg< T > & load_pnm(const char *const filename)
Load an image from a PNM file.
Definition: CImg.h:29812
CImg< T > & load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false, const char axis='z', const char align='p')
Load a video sequence using FFMPEG av&#39;s libraries.
Definition: CImg.h:30985
CImg< T > & resize(const CImgDisplay &disp, const int interpolation_type=1, const int border_condition=-1, const bool center=false)
Resize an image.
Definition: CImg.h:17000
const CImg< T > & _display(CImgDisplay &disp, const char *const title, const bool display_info) const
Definition: CImg.h:31479
CImg< Tfloat > get_pseudoinvert() const
Definition: CImg.h:13547
static CImgList< T > & empty()
Return a reference to an empty list.
Definition: CImg.h:34333
CImg< T > get_resize_doubleXY() const
Definition: CImg.h:17039
volatile bool is_keyPAD5
Definition: CImg.h:6253
const unsigned int key0
Definition: CImg.h:2694
T atX(const int x, const int y, const int z, const int v, const T out_val) const
Definition: CImg.h:11328
volatile bool is_keyPAD7
Definition: CImg.h:6255
static CImgList< T > _font(const unsigned int *const font, const unsigned int w, const unsigned int h, const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true)
Definition: CImg.h:37097
CImg< T > & operator-=(const CImg< t > &img)
Operator-=().
Definition: CImg.h:10621
bool is_sameZ(const CImg< t > &img) const
Return true if images (*this) and img have same depth.
Definition: CImg.h:11907
T & atX(const int x, const int y, const int z, const int v, const T out_val)
Read a pixel value with Dirichlet boundary conditions for the first coordinates (x).
Definition: CImg.h:11324
const unsigned int keyPAD4
Definition: CImg.h:2749
const unsigned int keyPADSUB
Definition: CImg.h:2756
std::vector< std::vector< bool > > mask
Masks the points that are shared (true) share (false) not shared.
Definition: hdf2pltV2.C:62
int system(const char *const command, const char *const module_name=0)
Definition: CImg.h:4491
CImg< _cimg_Ttfloat > get_convolve(const CImg< t > &mask, const unsigned int cond=1, const bool weighted_convol=false) const
Definition: CImg.h:18904
static CImg< Tuchar > rainbow_LUT256()
Return a rainbow indexed color palette with 256 (R,G,B) entries.
Definition: CImg.h:15738
CImgList< T > & load(const char *const filename)
Load an image list from a file.
Definition: CImg.h:35449
CImg< T > & load_medcon_external(const char *const filename)
Load a DICOM image file, using XMedcon&#39;s external tool &#39;medcon&#39;.
Definition: CImg.h:31325
CImg< T > get_resize_halfXY() const
Definition: CImg.h:17015
CImg< Tfloat > get_abs() const
Definition: CImg.h:12575
CImg< T > & draw_text(const int x0, const int y0, const char *const text, const tc *const foreground_color, const int background_color=0, const float opacity=1, const unsigned int font_size=11,...)
Draw a text.
Definition: CImg.h:26412
const CImg< T > & save_jpeg(std::FILE *const file, const unsigned int quality=100) const
Save a file in JPEG format.
Definition: CImg.h:32649
CImgList< T > & load_cimg(const char *const filename)
Load an image list from a .cimg file.
Definition: CImg.h:35533
CImg< T > & blur_bilateral(const float sigma_x, const float sigma_y, const float sigma_z, const float sigma_r, const int bgrid_x, const int bgrid_y, const int bgrid_z, const int bgrid_r, const bool interpolation_type=true)
Blur an image using the bilateral filter.
Definition: CImg.h:19537
CImg< T > get_invert_endianness() const
Definition: CImg.h:14956
bool contains(const T &pixel, t &n, t &x) const
Return true if one of the image list contains the specified referenced value. If true, set coordinates (n,x).
Definition: CImg.h:34860
CImg< T > & _solve(const CImg< t > &A, const CImg< ti > &indx)
Definition: CImg.h:13605
static unsigned long format(const unsigned long val)
Definition: CImg.h:2178
CImgDisplay(const unsigned int dimw, const unsigned int dimh, const char *title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false)
Create a display window with a specified size pwidth x height.
Definition: CImg.h:6332
CImg< T > get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const
Return a new image corresponding to the vector located at (x,y,z) of the current vector-valued image...
Definition: CImg.h:13270
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7, const T &a8)
Return a vector with specified coefficients.
Definition: CImg.h:14193
#define cimg_for(img, ptr, T_ptr)
Definition: CImg.h:589
CImg< T > & CMYKtoCMY()
Convert (C,M,Y,K) pixels of a color image into the (C,M,Y) color space.
Definition: CImg.h:16211
CImg< T > get_append(const char axis, const char align='p') const
Return a single image which is the concatenation of all images of the current CImgList instance...
Definition: CImg.h:35280
CImg< T > & draw_plasma(const float alpha=1, const float beta=1, const float opacity=1)
Draw a plasma random texture.
Definition: CImg.h:27243
const T & front() const
Return reference to the first image pixel (STL-compliant name).
Definition: CImg.h:11170
CImg< T > & draw_image(const CImg< ti > &sprite, const CImg< tm > &mask, const float opacity=1, const float mask_valmax=1)
Draw an image.
Definition: CImg.h:26321
double _pythagore(double a, double b)
Definition: CImg.h:4881
CImg< T > & BayertoRGB(const unsigned int interpolation_type=3)
Convert a Bayer-coded image to a (R,G,B) color image.
Definition: CImg.h:16494
char message[16384]
Message associated with the error that thrown the exception.
Definition: CImg.h:2032
CImgList< T > & load_cimg(std::FILE *const file)
Load an image list from a .cimg file.
Definition: CImg.h:35542
CImg< T > & draw_circle(const int x0, const int y0, int radius, const tc *const color, const float opacity=1)
Draw a filled circle.
Definition: CImg.h:25869
CImg< T > & draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, const tc *const color, const float opacity=1)
Draw a filled ellipse.
Definition: CImg.h:26017
CImg< T > & draw_spline(const CImgList< tp > &points, const CImgList< tt > &tangents, const tc *const color, const float opacity=1, const bool close_set=false, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored splines in the instance image.
Definition: CImg.h:23406
volatile int mouse_y
Y-coordinate of the mouse pointer on the display.
Definition: CImg.h:6138
static CImg< floatT > cone3d(CImgList< tf > &primitives, const float radius=50, const float size_z=100, const unsigned int subdivisions=24)
Create and return a 3D cone.
Definition: CImg.h:21845
#define _CImg_stdarg(img, a0, a1, N, t)
T & operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0)
Return a reference to (x,y,z,v) pixel of the pos-th image of the list.
Definition: CImg.h:34378
CImg< T > & draw_rectangle(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const CImg< tc > &color, const float opacity=1)
Draw a 3D filled colored rectangle in the instance image, at coordinates (x0,y0,z0)-(x1,y1,z1).
Definition: CImg.h:25606
CImg< T > & operator/=(const t val)
Operator/=().
Definition: CImg.h:10727
CImg< T > & draw_line(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const tc *const color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a 3D colored line.
Definition: CImg.h:22524
const unsigned int font7x11[7 *11 *256/32]
Definition: CImg.h:2764
CImgList< T > & push_front(const CImg< t > &img)
Insert image img at the front of the list (STL-compliant name).
Definition: CImg.h:35410
CImg< T > & draw_axis(const int x, const CImg< t > &yvalues, const tc *const color, const float opacity=1, const unsigned int pattern=~0U)
Draw a labeled vertical axis on the instance image.
Definition: CImg.h:26597
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
Definition: CImg.h:20000
CImg< T > & _draw_scanline(const int x0, const int x1, const int y, const tc *const color, const float opacity=1, const float brightness=1, const bool init=false)
Definition: CImg.h:22095
static double format(const float val)
Definition: CImg.h:2196
CImg< T > & load_parrec(const char *const filename, const char axis='v', const char align='p')
Load an image from a PAR-REC (Philips) file.
Definition: CImg.h:30916
CImg< T > & RGBtoCMY()
Convert color pixels from (R,G,B) to (C,M,Y).
Definition: CImg.h:16130
const CImgList< T > & _save_cimg(std::FILE *const file, const char *const filename, const bool compression) const
Save an image list into a .cimg file.
Definition: CImg.h:36700
CImg< T > & draw_line(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const CImg< tc > &color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a 3D colored line.
Definition: CImg.h:22571
cimg::superset< T, float >::type Tfloat
Definition: CImg.h:9781
Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const
Definition: CImg.h:11537
static CImg< T > identity_matrix(const unsigned int N)
Return a NxN identity matrix.
Definition: CImg.h:14382
const CImg< T > & display_object3d(CImgDisplay &disp, const CImg< tp > &vertices, const CImgList< tf > &primitives, const CImgList< tc > &colors, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=true, const float focale=500, const float specular_light=0.2f, const float specular_shine=0.1f, const bool display_axes=true, float *const pose_matrix=0) const
High-level interface for displaying a 3d object.
Definition: CImg.h:31699
volatile bool is_keyR
Definition: CImg.h:6206
Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const
Definition: CImg.h:11644
CImg< t > get_map(const CImg< t > &palette) const
Definition: CImg.h:15576
CImg< Tfloat > get_blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) const
Definition: CImg.h:19220
CImg< T > & draw_fill(const int x, const int y, const int z, const tc *const color, const float opacity=1, const float sigma=0, const bool high_connexity=false)
Draw a 3D filled region starting from a point (x,y,\ z) in the instance image.
Definition: CImg.h:27128
const CImg< T > & save_jpeg(const char *const filename, const unsigned int quality=100) const
Save a file in JPEG format.
Definition: CImg.h:32644
T abs(const T a)
Return the absolute value of a number.
Definition: CImg.h:4687
CImg< T > & autocrop(const CImg< t > &color, const char *const axes="zyx")
Autocrop an image, regarding of the specified backround color.
Definition: CImg.h:18347
CImg< T > & sort(const bool increasing=true)
Sort image values.
Definition: CImg.h:13784
CImg(const CImg< T > &img, const bool shared)
Definition: CImg.h:10042
CImg(const CImg< t > &img)
Default copy constructor.
Definition: CImg.h:9998
#define cimg_strescape(ci, co)
volatile bool is_keyC
Definition: CImg.h:6230
CImg< Tuchar > get_YCbCrtoRGB() const
Definition: CImg.h:16073
CImgDisplay & close()
Close a visible display.
Definition: CImg.h:6791
volatile bool is_keyPAGEUP
Definition: CImg.h:6201
CImg< Tuchar > get_CMYtoRGB() const
Definition: CImg.h:16176
Tfloat trace() const
Return the trace of the image, viewed as a matrix.
Definition: CImg.h:13217
volatile bool is_keyPAD8
Definition: CImg.h:6256
CImg< Tuchar > get_XYZtoRGB() const
Definition: CImg.h:16285
static CImgList< T > get_load_yuv(std::FILE *const file, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true)
Definition: CImg.h:35897
volatile bool is_key1
Definition: CImg.h:6188
static CImg< Tuchar > contrast_LUT256()
Return a contrasted indexed color palette with 256 (R,G,B) entries.
Definition: CImg.h:15756
static CImg< T > dijkstra(const tf &distance, const unsigned int nb_nodes, const unsigned int starting_node, const unsigned int ending_node=~0U)
Return minimal path in a graph, using the Dijkstra algorithm.
Definition: CImg.h:14097
static CImg< T > get_load_other(const char *const filename)
Definition: CImg.h:31416
CImg< T > & load_pnm(std::FILE *const file)
Load an image from a PNM file.
Definition: CImg.h:29821
static void FFT(CImg< T > &real, CImg< T > &imag, const bool invert=false)
Compute a N-D Fast Fourier Transform.
Definition: CImg.h:21024
#define cimg_forV(img, v)
Definition: CImg.h:596
bool is_sameZ(const unsigned int dz) const
Return true if image (*this) has the specified depth.
Definition: CImg.h:11901
static const char * string()
Definition: CImg.h:2200
const unsigned int keyPAD0
Definition: CImg.h:2745
T _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const
Definition: CImg.h:34643
int window_posx() const
Return X-coordinate of the window.
Definition: CImg.h:6643
CImg< T > & draw_grid(const float deltax, const float deltay, const float offsetx, const float offsety, const bool invertx, const bool inverty, const tc *const color, const float opacity=1, const unsigned int patternx=~0U, const unsigned int patterny=~0U)
Draw grid.
Definition: CImg.h:26726
CImg< T > & _draw_spline(const tp &points, const unsigned int W, const unsigned int H, const tc *const color, const float opacity, const bool close_set, const float precision, const unsigned int pattern, const bool init_hatch)
Definition: CImg.h:23329
static void _load_inr_header(std::FILE *file, int out[8], float *const voxsize)
Definition: CImg.h:30613
CImgList(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const CImg< t4 > &img4, const bool shared=false)
Construct an image list from four images.
Definition: CImg.h:34052
CImg< T > & warp(const CImg< t > &warp, const bool relative=false, const bool interpolation=true, const unsigned int border_conditions=0)
Warp an image.
Definition: CImg.h:17863
static CImgList< T > get_load_cimg(const char *const filename, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1)
Definition: CImg.h:35650
const unsigned int keyZ
Definition: CImg.h:2725
CImg< T > & RGBtoHSI()
Convert color pixels from (R,G,B) to (H,S,I).
Definition: CImg.h:15948
cimg::last< T, long >::type longT
Definition: CImg.h:33920
static int screen_dimx()
Return the width of the screen resolution.
Definition: CImg.h:6655
CImg< T > get_crop(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const bool border_condition=false) const
Definition: CImg.h:18224
CImgList< T > & clear()
In-place version of the default constructor.
Definition: CImg.h:34146
Vector_n min(const Array_n_const &v1, const Array_n_const &v2)
Definition: Vector_n.h:346
CImg< T > & draw_rectangle(const int x0, const int y0, const int z0, const int v0, const int x1, const int y1, const int z1, const int v1, const T val, const float opacity=1)
Draw a 4D filled rectangle in the instance image, at coordinates (x0,y0,z0,v0)-(x1,y1,z1,v1).
Definition: CImg.h:25546
const CImg< T > & save_ascii(const char *const filename) const
Save the image as an ASCII file (ASCII Raw + simple header).
Definition: CImg.h:32376
CImg< T > & append_object3d(CImgList< tf > &primitives, const CImg< tp > &obj_vertices, const CImgList< tff > &obj_primitives)
Append a 3D object to another one.
Definition: CImg.h:21143
const CImgList< T > get_shared() const
Return a shared instance of the list.
Definition: CImg.h:34135
CImg< Tfloat > get_log() const
Definition: CImg.h:12555
CImg< T > & draw_image(const CImg< t > &sprite, const float opacity=1)
Draw an image.
Definition: CImg.h:26223
const CImg< T > & save_rgba(std::FILE *const file) const
Save the image as a RGBA file.
Definition: CImg.h:33120
CImg< Tuchar > get_BayertoRGB(const unsigned int interpolation_type=3) const
Definition: CImg.h:16498
CImgList< T > get_images(const unsigned int i0, const unsigned int i1) const
Definition: CImg.h:35246
static CImg< T > diagonal(const T &a0)
Return a 1x1 diagonal matrix with specified coefficients.
Definition: CImg.h:14357
char uncase(const char x)
Remove the &#39;case&#39; of an ASCII character.
Definition: CImg.h:4888
CImg< T > & lines(const unsigned int y0, const unsigned int y1)
Get a set of lines.
Definition: CImg.h:18430
CImg< T > & draw_gaussian(const float xc, const float yc, const float zc, const CImg< t > &tensor, const CImg< tc > &color, const float opacity=1)
Draw an anisotropic 3D gaussian function.
Definition: CImg.h:27477
const char * file_type(std::FILE *const file, const char *const filename)
Try to guess the image format of a filename, using its magick numbers.
Definition: CImg.h:5516
T & atXYZV(const int x, const int y, const int z, const int v, const T out_val)
Read a pixel value with Dirichlet boundary conditions.
Definition: CImg.h:11222
CImg< T > & draw_point(const CImg< t > &points, const tc *const color, const float opacity=1)
Draw a cloud of colored points.
Definition: CImg.h:22296
CImg< T > get_fill(const CImg< t > &values, const bool repeat_values=true) const
Definition: CImg.h:14894
CImg< T > get_shared_points(const unsigned int x0, const unsigned int x1, const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0)
Get a shared-memory image referencing a set of points of the instance image.
Definition: CImg.h:18475
CImg< T > & load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1)
Load an image from a RGB file.
Definition: CImg.h:29949
CImgList< T > & load_off(const char *const filename, CImgList< tf > &primitives, CImgList< tc > &colors)
Load a 3D object from a .OFF file.
Definition: CImg.h:36206
#define _cimg_blur_patch2d_fast(N)
const CImg< T > & save_pandore(const char *const filename, const unsigned int colorspace=0) const
Save the image as a PANDORE-5 file.
Definition: CImg.h:33533
static CImgDisplay & empty()
Return a reference to an empty display.
Definition: CImg.h:6431
CImgDisplay(const CImgList< T > &list, const char *title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false)
Create a display window from an image list.
Definition: CImg.h:6366
volatile bool is_key7
Definition: CImg.h:6194
CImgList(const CImg< t1 > &img1, const CImg< t2 > &img2, const bool shared=false)
Construct an image list from two images.
Definition: CImg.h:34037
CImg< T > & resize_doubleXY()
Upscale an image by a factor 2x.
Definition: CImg.h:17035
const T & operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const
Definition: CImg.h:10455
CImg< T > get_crop(const int x0, const int x1, const bool border_condition=false) const
Definition: CImg.h:18262
CImg< T > & sqr()
Compute the square value of each pixel.
Definition: CImg.h:12520
bool is_sameXY(const unsigned int dx, const unsigned int dy) const
Return true if image (*this) has the specified width and height.
Definition: CImg.h:11923
CImg< T > * iterator
Define a CImgList&lt;T&gt;::iterator.
Definition: CImg.h:33892
CImg< T > & draw_axis(const CImg< tx > &xvalues, const CImg< ty > &yvalues, const tc *const color, const float opacity=1, const unsigned int patternx=~0U, const unsigned int patterny=~0U)
Draw a labeled horizontal+vertical axis on the instance image.
Definition: CImg.h:26633
const CImg< T > & _save_rgba(std::FILE *const file, const char *const filename) const
Definition: CImg.h:33058
volatile bool is_keyI
Definition: CImg.h:6210
#define cimg_for4x4(img, x, y, z, v, I)
Definition: CImg.h:1120
CImgList< T > & insert(const CImgList< t > &list, const unsigned int pos=~0U, const bool shared=false)
Insert a copy of the image list list into the current image list, starting from position pos...
Definition: CImg.h:35146
CImgDisplay & render(const CImg< T > &img)
Render image buffer into GDI native image format.
Definition: CImg.h:6828
CImg< T > & assign(const char *const filename)
In-place version of the previous constructor.
Definition: CImg.h:10244
Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int v, const T out_val) const
Read a pixel value using linear interpolation and Dirichlet boundary conditions (first three coordina...
Definition: CImg.h:11451
CImg< T > get_resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100, const int interpolation_type=1, const int border_condition=-1, const bool center=false) const
Definition: CImg.h:16650
CImgList< T > & load_tiff(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1)
Load a TIFF file.
Definition: CImg.h:36218
const unsigned int keyR
Definition: CImg.h:2703
cimg::superset< T, short >::type Tshort
Definition: CImg.h:9776
CImg< _cimg_Tfloat > sin(const CImg< T > &instance)
Definition: CImg.h:6041
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, const T val13)
Fill sequentially pixel values.
Definition: CImg.h:14736
CImg< T > & threshold(const T value, const bool soft_threshold=false, const bool strict_threshold=false)
Threshold values of the instance image.
Definition: CImg.h:15234
CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1, const bool shared=false)
Definition: CImg.h:9954
CImgList< T > get_insert(const CImg< t > &img, const unsigned int pos=~0U, const bool shared=false) const
Definition: CImg.h:35112
static CImg< T > get_load_yuv(const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p')
Definition: CImg.h:31005
CImg< Tuchar > get_HSVtoRGB() const
Definition: CImg.h:15865
static CImg< T > get_load_analyze(std::FILE *const file, float *const voxsize=0)
Definition: CImg.h:30421
#define cimg_stdout
Definition: CImg.h:136
CImg< floatT > get_isosurface3d(CImgList< tf > &primitives, const float isovalue, const int size_x=-100, const int size_y=-100, const int size_z=-100) const
Create and return a isosurface of the instance image as a 3D object.
Definition: CImg.h:21264
CImgList< T > & reverse_object3d()
Invert primitives orientation of a 3D object.
Definition: CImg.h:37144
CImg< T > & map(const CImg< t > &palette)
Map predefined palette on the scalar (indexed) instance image.
Definition: CImg.h:15571
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, const T val7, const T val8, const T val9, const T val10)
Fill sequentially pixel values.
Definition: CImg.h:14641
CImg< Tuchar > get_HSLtoRGB() const
Definition: CImg.h:15942
const char * split_filename(const char *const filename, char *const body=0)
Split a filename into two strings &#39;body&#39; and &#39;extension&#39;.
Definition: CImg.h:5470
#define _cimglist_def_is_same3(axis1, axis2, axis3)
Definition: CImg.h:34767
CImg< T > & _load_raw(std::FILE *const file, const char *const filename, const unsigned int sizex, const unsigned int sizey, const unsigned int sizez, const unsigned int sizev, const bool multiplexed, const bool invert_endianness)
Definition: CImg.h:30957
const CImg< T > & save_bmp(std::FILE *const file) const
Save the image as a BMP file.
Definition: CImg.h:32549
const T & min() const
Definition: CImg.h:34914
const CImg< T > & _save_dlm(std::FILE *const file, const char *const filename) const
Definition: CImg.h:32422
CImg< T > & sort(CImg< t > &permutations, const bool increasing=true)
Sort values of a vector and get permutations.
Definition: CImg.h:13768
Tfloat linear_atXYZV(const float fx, const float fy, const float fz, const float fv, const T out_val) const
Read a pixel value using linear interpolation and Dirichlet boundary conditions.
Definition: CImg.h:11356
T & _atXYZV(const int x, const int y, const int z, const int v)
Definition: CImg.h:11246
bool contains(const T &pixel, t &x, t &y, t &z, t &v) const
Return true if specified referenced value is inside image boundaries. If true, returns pixel coordina...
Definition: CImg.h:12055
static const char * format()
Definition: CImg.h:2204
volatile bool is_keyPADADD
Definition: CImg.h:6258
cimg::superset< T, char >::type Tchar
Definition: CImg.h:33903
CImg< T > & blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true)
Return a blurred version of the image, using a Canny-Deriche filter.
Definition: CImg.h:19211
j indices j
Definition: Indexing.h:6
T value_type
Value type.
Definition: CImg.h:33898
CImgList< _cimg_Tt > operator,(const CImg< t > &img) const
Operator,().
Definition: CImg.h:11013
CImg< charT > value_string(const char separator=',', const unsigned int max_size=0) const
Return a C-string containing the values of the instance image.
Definition: CImg.h:11838
CImg< T > & set_tensor_at(const CImg< t > &ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0)
Set the image vec as the tensor valued pixel located at (x,y,z) of the current vector-valued image...
Definition: CImg.h:13316
bool strpare(char *const s, const char delimiter=' ', const bool symmetric=false)
Remove useless delimiters on the borders of a C-string.
Definition: CImg.h:4935
CImg< T > get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0, const int dx=-100, const int dy=-100, const int dz=-100) const
Definition: CImg.h:18151
CImg< intT > get_select(const char *const title, const int select_type=2, unsigned int *const XYZ=0, const unsigned char *const color=0) const
Simple interface to select a shape from an image.
Definition: CImg.h:28609
const unsigned int keyF4
Definition: CImg.h:2675
CImg< T > get_unroll(const char axis) const
Definition: CImg.h:17624
CImg< T > & round(const float x, const int rounding_type=0)
Compute image with rounded pixel values.
Definition: CImg.h:14976
CImg< T > get_identity_matrix() const
Definition: CImg.h:13420
static CImg< T > get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false, const char axis='z', const char align='p')
Definition: CImg.h:30991
Tfloat PSNR(const CImg< t > &img, const Tfloat valmax=(Tfloat) 255) const
Compute the PSNR between two images.
Definition: CImg.h:13130
NT dy
CImgList< T > & assign(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const CImg< t4 > &img4, const CImg< t5 > &img5, const CImg< t6 > &img6, const CImg< t7 > &img7, const bool shared=false)
In-place version of the corresponding constructor.
Definition: CImg.h:34271
CImg< T > operator&(const char *const expression, const CImg< T > &img)
Definition: CImg.h:5991
T * ptr()
Return a pointer to the pixel buffer.
Definition: CImg.h:11080
const CImg< T > & _save_raw(std::FILE *const file, const char *const filename, const bool multiplexed) const
Definition: CImg.h:33543
CImgException(const char *format,...)
Definition: CImg.h:2034
CImgList< Tfloat > get_gradient(const char *const axes=0, const int scheme=3) const
Compute the list of images, corresponding to the XY-gradients of an image.
Definition: CImg.h:20014
const unsigned int keyINSERT
Definition: CImg.h:2696
CImg< T > & columns(const unsigned int x0, const unsigned int x1)
Get a set of columns.
Definition: CImg.h:18412
bool is_sameXZ(const unsigned int dx, const unsigned int dz) const
Return true if image (*this) has the specified width and depth.
Definition: CImg.h:11939
CImg< T > & assign(const CImg< t > &img, const char *const dimensions, const char *const values, const bool repeat_values)
In-place version of the previous constructor.
Definition: CImg.h:10317
const char * imagemagick_path(const char *const user_path=0, const bool reinit_path=false)
Return or set path to the ImageMagick&#39;s convert tool.
Definition: CImg.h:5094
unsigned int wait(const unsigned int milliseconds)
Wait for a certain number of milliseconds since the last call.
Definition: CImg.h:4650
bool is_sameY(const CImg< t > &img) const
Return true if images (*this) and img have same height.
Definition: CImg.h:11891
T atNXYZV(const int pos, const int x, const int y, const int z, const int v) const
Definition: CImg.h:34568
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, const T val7)
Fill sequentially pixel values.
Definition: CImg.h:14556
CImg< T > & at(const int pos)
Read an image in specified position.
Definition: CImg.h:34544
volatile bool is_keyG
Definition: CImg.h:6221
CImgList< T > & erase(const iterator iter)
Remove the element pointed by iterator iter (STL-compliant name).
Definition: CImg.h:35437
CImgList< T > & transfer_to(CImgList< t > &list)
Transfer the content of the instance image list into another one.
Definition: CImg.h:34302
const double pi
const CImg< T > & _save_bmp(std::FILE *const file, const char *const filename) const
Definition: CImg.h:32458
unsigned long time()
Get the value of a system timer with a millisecond precision.
Definition: CImg.h:4605
CImg< T > & resize(const CImg< t > &src, const int interpolation_type=1, const int border_condition=-1, const bool center=false)
Resize an image.
Definition: CImg.h:16975
#define _cimg_Labf(x)
CImg(const CImg< t > &img, const bool shared)
Advanced copy constructor.
Definition: CImg.h:10030
CImg< T > & projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0, const int dx=-100, const int dy=-100, const int dz=-100)
Return a 2D representation of a 3D image, with three slices.
Definition: CImg.h:18146
CImg< T > & _draw_line(const t &points, const unsigned int W, const unsigned int H, const tc *const color, const float opacity, const unsigned int pattern, const bool init_hatch)
Definition: CImg.h:22950
T _atNXYZV(const int pos, const int x, const int y, const int z, const int v) const
Definition: CImg.h:34579
bool is_fullscreen
Fullscreen state of the display.
Definition: CImg.h:6264
bool is_sameXYZ(const CImg< t > &img) const
Return true if images have same width, same height and same depth.
Definition: CImg.h:12000
const unsigned int keyS
Definition: CImg.h:2715
static CImg< floatT > box3d(CImgList< tf > &primitives, const float size_x=200, const float size_y=100, const float size_z=100)
Create and return a 3D box object.
Definition: CImg.h:21819
unsigned int normalization
Normalization type used for the display.
Definition: CImg.h:6141
CImg< T > operator<<(const int n) const
Operator&lt;&lt;().
Definition: CImg.h:10979
NT q
const CImg< T > & save_pandore(std::FILE *const file, const unsigned int colorspace=0) const
Save the image as a PANDORE-5 file.
Definition: CImg.h:33538
Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const
Read a pixel value using cubic interpolation and Neumann boundary conditions.
Definition: CImg.h:11637
T atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const
Definition: CImg.h:34664
iterator end()
Returns an iterator just past the last element (STL-compliant name).
Definition: CImg.h:34517
T at(const int off, const T out_val) const
Definition: CImg.h:11192
static CImg< T > get_load_jpeg(std::FILE *const file)
Definition: CImg.h:29506
CImg< T > & draw_graph(const CImg< t > &data, const tc *const color, const float opacity=1, const unsigned int plot_type=1, const int vertex_type=1, const double ymin=0, const double ymax=0, const bool expand=false, const unsigned int pattern=~0U)
Draw a 1D graph on the instance image.
Definition: CImg.h:26788
static CImg< T > matrix(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7, const T &a8)
Return a 3x3 square matrix with specified coefficients.
Definition: CImg.h:14303
T _atX(const int x, const int y=0, const int z=0, const int v=0) const
Definition: CImg.h:11351
CImgDisplay & operator=(const CImgDisplay &disp)
Operator=().
Definition: CImg.h:6476
int window_posy() const
Return Y-coordinate of the window.
Definition: CImg.h:6648
static CImg< T > rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false)
Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w.
Definition: CImg.h:14395
const CImg< T > & save_medcon_external(const char *const filename) const
Save an image as a Dicom file (need &#39;(X)Medcon&#39; : http://xmedcon.sourceforge.net ) ...
Definition: CImg.h:33784
const int nrow
Definition: ex1.C:95
static CImg< T > get_load_ascii(const char *const filename)
Definition: CImg.h:29270
CImg< T > & draw_quiver(const CImg< t1 > &flow, const t2 *const color, const float opacity=1, const unsigned int sampling=25, const float factor=-20, const bool arrows=true, const unsigned int pattern=~0U)
Draw a vector field in the instance image, using a colormap.
Definition: CImg.h:26498
static const char * format()
Definition: CImg.h:2195
CImg< T > & _load_png(std::FILE *const file, const char *const filename)
Definition: CImg.h:29669
CImg< T > & append(const CImg< t > &img, const char axis='x', const char align='p')
Append an image.
Definition: CImg.h:18642
CImg< T > & clear()
In-place version of the default constructor (STL-compliant name).
Definition: CImg.h:10090
T atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) const
Definition: CImg.h:34556
CImg< T > & _draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc *const color, const float opacity, const float brightness)
Definition: CImg.h:23774
#define cimg_forZV(img, z, v)
Definition: CImg.h:602
#define cimg_forXYZV(img, x, y, z, v)
Definition: CImg.h:607
volatile unsigned int window_height
Height of the underlying window.
Definition: CImg.h:6126
const unsigned int keyPAD5
Definition: CImg.h:2750
CImg< Tuchar > get_LabtoRGB() const
Definition: CImg.h:16423
CImg< T > & _load_bmp(std::FILE *const file, const char *const filename)
Definition: CImg.h:29379
volatile bool is_event
Event state of the window.
Definition: CImg.h:6171
CImg< T > & draw_point(const CImgList< t > &points, const CImg< tc > &color, const float opacity=1)
Draw a cloud of colored points.
Definition: CImg.h:22284
const CImg< T > & save_cimg(const char *const filename, const unsigned int n0, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0) const
Insert the image into an existing .cimg file, at specified coordinates.
Definition: CImg.h:33296
CImg< typename cimg::superset< t, unsigned int >::type > get_index(const CImg< t > &palette, const bool dithering=false, const bool map_indexes=true) const
Definition: CImg.h:15349
T sqr(const T val)
Return the square of a number.
Definition: CImg.h:4717
CImg< T > & draw_image(const int x0, const CImg< t > &sprite, const float opacity=1)
Draw an image.
Definition: CImg.h:26216
CImgDisplay & resize(const int width, const int height, const bool redraw=true)
Resize window.
Definition: CImg.h:6733
CImg< T > & transfer_to(CImg< T > &img)
Definition: CImg.h:10338
CImg< T > & operator=(const T val)
Operator=().
Definition: CImg.h:10470
bool is_empty() const
Return true if list is empty.
Definition: CImg.h:34734
const CImg< T > & display_graph(CImgDisplay &disp, const unsigned int plot_type=1, const unsigned int vertex_type=1, const char *const labelx=0, const double xmin=0, const double xmax=0, const char *const labely=0, const double ymin=0, const double ymax=0) const
High-level interface for displaying a graph.
Definition: CImg.h:32133
CImg< T > & draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv, const tc *const color, const float opacity=1)
Draw an anisotropic 2D gaussian function.
Definition: CImg.h:27403
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 T val7, const T val8, const T val9) const
Definition: CImg.h:14635
const unsigned int keyF7
Definition: CImg.h:2678
Tfloat cubic_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const
Read a pixel value using cubic interpolation and Dirichlet boundary conditions.
Definition: CImg.h:11590
Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const
Definition: CImg.h:11575
CImg< T > & draw_rectangle(const int x0, const int y0, const int x1, const int y1, const tc *const color, const float opacity=1)
Draw a 2D filled colored rectangle in the instance image, at coordinates (x0,y0)-(x1,y1).
Definition: CImg.h:25653
CImgList< Tfloat > get_SVD(const bool sorting=true, const unsigned int max_iter=40, const float lambda=0) const
Definition: CImg.h:13985
CImg< T > get_column(const unsigned int x0) const
Definition: CImg.h:18407
CImgList< T > & push_back(const CImgList< t > &list)
Insert list list at the end of the current list (STL-compliant name).
Definition: CImg.h:35416
const CImg< T > & save_pnm(std::FILE *const file, const unsigned int bytes_per_pixel=0) const
Save the image as a PNM file.
Definition: CImg.h:32997
CImg< T > & draw_gaussian(const float xc, const float yc, const float sigma, const tc *const color, const float opacity=1)
Draw an isotropic 2D gaussian function.
Definition: CImg.h:27429
#define cimg_for3x3x3(img, x, y, z, v, I)
Definition: CImg.h:1808
CImg< T > & draw_triangle(const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const CImg< tl > &light, const int lx0, const int ly0, const int lx1, const int ly1, const int lx2, const int ly2, const float opacity=1)
Draw a 2D Pseudo-Phong-shaded textured triangle, with perspective correction.
Definition: CImg.h:25280
CImg< T > & draw_line(const CImg< t > &points, const tc *const color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored lines in the instance image.
Definition: CImg.h:23028
CImgList< T > & assign(const CImg< t1 > &img1, const CImg< t2 > &img2, const CImg< t3 > &img3, const CImg< t4 > &img4, const CImg< t5 > &img5, const bool shared=false)
In-place version of the corresponding constructor.
Definition: CImg.h:34251
#define _cimg_for_triangle1(img, xl, xr, y, x0, y0, x1, y1, x2, y2)
Definition: CImg.h:23480
CImg< _cimg_Tt > get_dilate(const CImg< t > &mask, const unsigned int cond=1, const bool weighted_dilatation=false) const
Definition: CImg.h:19020
CImg< T > & draw_fill(const int x, const int y, const tc *const color, const float opacity=1, const float sigma=0, const bool high_connexity=false)
Draw a 2D filled region starting from a point (x,y) in the instance image.
Definition: CImg.h:27152
CImg< T > operator^(const t val) const
Operator^().
Definition: CImg.h:10960
#define cimg_forZ(img, z)
Definition: CImg.h:595
CImg< T > get_shared_channel(const unsigned int v0)
Return a shared-memory image referencing one channel v0 of the instance image.
Definition: CImg.h:18573
CImg< T > get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) const
Definition: CImg.h:14528
const unsigned int key7
Definition: CImg.h:2691
static CImg< T > get_load_tiff(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1)
Definition: CImg.h:30086
CImg< _cimg_Tfloat > abs(const CImg< T > &instance)
Definition: CImg.h:6031
CImg< T > & draw_mandelbrot(const int x0, const int y0, const int x1, const int y1, const CImg< tc > &color_palette, const float opacity=1, const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2, const unsigned int itermax=255, const bool normalized_iteration=false, const bool julia_set=false, const double paramr=0, const double parami=0)
Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
Definition: CImg.h:27250
volatile bool is_keyPAD0
Definition: CImg.h:6248
CImg< T > & slice(const unsigned int z0)
Get a slice.
Definition: CImg.h:18439
CImg< T > & invert(const bool use_LU=true)
Invert the current matrix.
Definition: CImg.h:13474
void sleep(const unsigned int milliseconds)
Sleep for a certain numbers of milliseconds.
Definition: CImg.h:4624
CImg< T > operator+() const
Operator+() (unary).
Definition: CImg.h:10573
CImg< T > & draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0, const int x1, const int y1, const int z1, const float u1, const float v1, const float w1, const tc *const color, const float opacity=1, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a cubic spline curve in the instance image (for volumetric images).
Definition: CImg.h:23173
cimg::last< T, int >::type intT
Definition: CImg.h:33918
cimg::superset< T, double >::type Tdouble
Definition: CImg.h:33911
CImgDisplay & resize(const CImg< T > &img, const bool redraw=true)
Resize a display window with the size of an image.
Definition: CImg.h:6715
T median() const
Return the median value of the image.
Definition: CImg.h:13015
CImg< T > & draw_triangle(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const tc *const color, const float opacity=1, const float brightness=1)
Draw a 2D filled colored triangle, with z-buffering.
Definition: CImg.h:23846
volatile bool is_key0
Definition: CImg.h:6197
CImg< T > & XYZtoxyY()
Convert (X,Y,Z)_709 pixels of a color image into the (x,y,Y) color space.
Definition: CImg.h:16359
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7, const T &a8, const T &a9, const T &a10, const T &a11, const T &a12, const T &a13, const T &a14, const T &a15)
Return a vector with specified coefficients.
Definition: CImg.h:14276
CImg< T > & translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0, const int border_condition=0)
Translate the image.
Definition: CImg.h:17229
CImg< T > & _load_pnm(std::FILE *const file, const char *const filename)
Definition: CImg.h:29829
NT abs(const NT &x)
Definition: number_utils.h:130
CImg< T > & fillV(const unsigned int x, const unsigned int y, const unsigned int z, const double a0,...)
Definition: CImg.h:14944
CImg< T > & max(const T val)
Pointwise max operator between an image and a value.
Definition: CImg.h:12830
CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1, const bool shared=false)
Construct an image from a raw memory buffer.
Definition: CImg.h:9941
static CImg< T > get_load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1)
Definition: CImg.h:29962
CImgList< T > & operator,(const CImgList< t > &list)
Operator,().
Definition: CImg.h:34435
#define _cimg_load_cimg_case2(Ts, Tss)
CImg< T > & histogram(const unsigned int nb_levels, const T value_min=(T) 0, const T value_max=(T) 0)
Compute the histogram of the instance image.
Definition: CImg.h:15269
CImg< Tfloat > get_norm(const int norm_type=2) const
Definition: CImg.h:15131
bool is_empty() const
Return true is display is empty.
Definition: CImg.h:6493
CImg< T > & distance(const T isovalue, const float sizex=1, const float sizey=1, const float sizez=1, const bool compute_sqrt=true)
Compute the Euclidean distance map to a shape of specified isovalue.
Definition: CImg.h:20441
CImgDisplay & resize(const CImgDisplay &disp, const bool redraw=true)
Resize a display window using the size of the given display disp.
Definition: CImg.h:6720
cimg::superset< T, unsigned int >::type Tuint
Definition: CImg.h:33906
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6)
Return a vector with specified coefficients.
Definition: CImg.h:14175
bool is_sameN(const CImgList< t > &list) const
Return true if list if of specified size.
Definition: CImg.h:34745
const CImgList< T > & display(CImgDisplay &disp, const bool display_info, const char axis='x', const char align='p') const
Display the current CImgList instance in a new display window.
Definition: CImg.h:36316
bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const unsigned int key4, const unsigned int key5, const unsigned int key6, const unsigned int key7, const bool remove)
Test if a key sequence has been typed.
Definition: CImg.h:6543
static CImg< T > matrix(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7, const T &a8, const T &a9, const T &a10, const T &a11, const T &a12, const T &a13, const T &a14, const T &a15, const T &a16, const T &a17, const T &a18, const T &a19, const T &a20, const T &a21, const T &a22, const T &a23, const T &a24)
Return a 5x5 square matrix with specified coefficients.
Definition: CImg.h:14327
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6, const T val7, const T val8, const T val9, const T val10, const T val11, const T val12, const T val13, const T val14)
Fill sequentially pixel values.
Definition: CImg.h:14773
#define _cimg_load_inr_case(Tf, sign, pixsize, Ts)
T atXYZ(const int x, const int y, const int z, const int v=0) const
Definition: CImg.h:11274
const CImg< T > & operator[](const unsigned int pos) const
Definition: CImg.h:34357
static void _save_empty_cimg(std::FILE *const file, const char *const filename, const unsigned int nb, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv)
Definition: CImg.h:36886
volatile bool is_closed
Closed state of the window.
Definition: CImg.h:6162
CImgList< T > & assign(const CImg< t1 > &img1, const CImg< t2 > &img2, const bool shared=false)
In-place version of the corresponding constructor.
Definition: CImg.h:34226
volatile unsigned int buttons[512]
Button state of the mouse.
Definition: CImg.h:6147
const CImg< T > & _save_cpp(std::FILE *const file, const char *const filename) const
Definition: CImg.h:32386
CImg< T > get_warp(const CImg< t > &warp, const bool relative=false, const bool interpolation=true, const unsigned int border_conditions=0) const
Definition: CImg.h:17869
T minmod(const T a, const T b)
Return the minmod of two numbers.
Definition: CImg.h:4828
const unsigned int keyALT
Definition: CImg.h:2736
const unsigned int key6
Definition: CImg.h:2690
CImg< T > & draw_axis(const float x0, const float x1, const float y0, const float y1, const tc *const color, const float opacity=1, const int subdivisionx=-60, const int subdivisiony=-60, const float precisionx=0, const float precisiony=0, const unsigned int patternx=~0U, const unsigned int patterny=~0U)
Draw a labeled horizontal+vertical axis on the instance image.
Definition: CImg.h:26671
#define cimg_forY(img, y)
Definition: CImg.h:594
#define CImg_2x2(I, T)
Definition: CImg.h:415
T * ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0)
Return a pointer to the pixel value located at (x,y,z,v).
Definition: CImg.h:11122
Tfloat linear_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const
Read a pixel value using linear interpolation and Dirichlet boundary conditions (first two coordinate...
Definition: CImg.h:11516
CImg< T > get_autocrop(const CImg< t > &color, const char *const axes="zyx") const
Definition: CImg.h:18351
CImg< _cimg_Tt > operator*(const CImg< t > &img) const
Operator*().
Definition: CImg.h:10712
CImg< T > & channels(const unsigned int v0, const unsigned int v1)
Get a set of channels.
Definition: CImg.h:18466
CImg< T > & _load_jpeg(std::FILE *const file, const char *const filename)
Definition: CImg.h:29510
const unsigned int keyPADDIV
Definition: CImg.h:2758
#define _cimglist_def_is_same1(axis)
Definition: CImg.h:34751
const unsigned int keyTAB
Definition: CImg.h:2699
CImg< T > & assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const char *const values, const bool repeat_values)
In-place version of the corresponding constructor.
Definition: CImg.h:10172
CImg< Tfloat > get_HSItoRGB() const
Definition: CImg.h:16019
const unsigned int keyD
Definition: CImg.h:2716
CImg< Tfloat > get_cosh() const
Definition: CImg.h:12615
CImg< T > & operator*=(const char *const expression)
Operator*=().
Definition: CImg.h:10676
static CImg< floatT > elevation3d(CImgList< tf > &primitives, const tfunc &func, const float x0, const float y0, const float x1, const float y1, const int size_x=256, const int size_y=256)
Get elevation3d of a function.
Definition: CImg.h:21284
CImg< T > get_equalize(const unsigned int nblevels, const T val_min=(T) 0, const T val_max=(T) 0) const
Definition: CImg.h:15321
double rand()
Return a random variable between [0,1] with respect to an uniform distribution.
Definition: CImg.h:4833
CImg< T > & draw_polygon(const CImg< t > &points, const CImg< tc > &color, const float opacity=1)
Draw a filled polygon in the instance image.
Definition: CImg.h:25783
cimg::last< T, unsigned int >::type uintT
Definition: CImg.h:33917
const CImg< T > get_shared_points(const unsigned int x0, const unsigned int x1, const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const
Definition: CImg.h:18485
CImg< T > get_transpose() const
Definition: CImg.h:13451
CImg< T > & load_raw(const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int sizez=1, const unsigned int sizev=1, const bool multiplexed=false, const bool invert_endianness=false)
Load an image from a .RAW file.
Definition: CImg.h:30928
CImg< _cimg_Tfloat > acos(const CImg< T > &instance)
Definition: CImg.h:6051
bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const
Return true if image (*this) has the specified width, height, depth and number of channels...
Definition: CImg.h:12038
bool is_sameXYZ(const unsigned int dx, const unsigned int dy, const unsigned int dz) const
Return true if image (*this) has the specified width, height and depth.
Definition: CImg.h:11994
volatile unsigned int & button
Definition: CImg.h:6148
CImg< Tfloat > get_RGBtoHSI() const
Definition: CImg.h:15977
CImgDisplay & hide_mouse()
Hide mouse pointer.
Definition: CImg.h:6808
CImg< T > & draw_arrow(const int x0, const int y0, const int x1, const int y1, const tc *const color, const float opacity=1, const float angle=30, const float length=-10, const unsigned int pattern=~0U)
Draw a colored arrow in the instance image.
Definition: CImg.h:23057
CImg< T > get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0)
Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image...
Definition: CImg.h:18517
CImgList< T > & insert(const CImg< t > &img, const unsigned int pos=~0U, const bool shared=false)
Insert a copy of the image img into the current image list, at position pos.
Definition: CImg.h:35041
CImg< Tfloat > get_invert(const bool use_LU=true) const
Definition: CImg.h:13538
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 T val7, const T val8, const T val9, const T val10, const T val11) const
Definition: CImg.h:14697
static CImg< floatT > isosurface3d(CImgList< tf > &primitives, const char *const expression, const float isovalue, const float x0, const float y0, const float z0, const float x1, const float y1, const float z1, const int dx=32, const int dy=32, const int dz=32)
Definition: CImg.h:21745
const unsigned int keyBACKSPACE
Definition: CImg.h:2695
CImg< T > & load_imagemagick_external(const char *const filename)
Load an image using ImageMagick&#39;s external tool &#39;convert&#39;.
Definition: CImg.h:31291
static CImg< T > get_load_imagemagick_external(const char *const filename)
Definition: CImg.h:31320
CImgList< T > & assign(const unsigned int n)
In-place version of the corresponding constructor.
Definition: CImg.h:34159
CImg< T > & fillX(const unsigned int y, const unsigned int z, const unsigned int v, const int a0,...)
Fill image values along the X-axis at the specified pixel position (y,z,v).
Definition: CImg.h:14899
void __draw_object3d(const unsigned int n_primitive, const unsigned int nb_opacities, const CImgList< to > &opacities, const CImg< tc > &color, const int nx0, const int ny0, const CImg< T > &sprite, const float opac)
Definition: CImg.h:27611
CImg< T > & quantize(const unsigned int nb_levels, const bool keep_range=true)
Uniformly quantize values of the instance image into nb_levels levels.
Definition: CImg.h:15197
void int * nj
Definition: read.cpp:74
CImg< T > & draw_rectangle(const int x0, const int y0, const int x1, const int y1, const CImg< tc > &color, const float opacity=1)
Draw a 2D filled colored rectangle in the instance image, at coordinates (x0,y0)-(x1,y1).
Definition: CImg.h:25661
CImg< T > & operator%=(const char *const expression)
Operator%=().
Definition: CImg.h:10781
CImg< T > & fill(const T val0, const T val1, const T val2, const T val3)
Fill sequentially all pixel values with values val0 and val1 and val2 and val3.
Definition: CImg.h:14474
CImgList< T > & crop_font()
Create an auto-cropped font (along the X axis) from a input font font.
Definition: CImg.h:37025
const CImg< T > & operator()(const unsigned int pos) const
Definition: CImg.h:34373
const unsigned int keyPAD8
Definition: CImg.h:2753
CImg< T > & draw_line(const int x0, const int y0, const int x1, const int y1, const tc *const color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a 2D colored line.
Definition: CImg.h:22330
const T & maxmin(t &min_val) const
Definition: CImg.h:35014
cimg::last< T, float >::type floatT
Definition: CImg.h:33921
long double dist(long double *coord1, long double *coord2, int size)
cimg::last< T, unsigned long >::type ulongT
Definition: CImg.h:33919
CImg< T > get_translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0, const int border_condition=0) const
Definition: CImg.h:17424
CImg< Tfloat > get_RGBtoxyY() const
Definition: CImg.h:16432
static unsigned int format(const signed char val)
Definition: CImg.h:2133
CImg< T > & load_cimg(std::FILE *const file, const char axis='z', const char align='p')
Load an image (list) from a .cimg file.
Definition: CImg.h:30543
const CImg< T > & save_yuv(std::FILE *const file, const bool rgb2yuv=true) const
Save the image as a YUV video sequence file.
Definition: CImg.h:33600
volatile bool is_key4
Definition: CImg.h:6191
static int _distance_sep(const int i, const int u, const int gi2, const int gu2, const float fact)
Definition: CImg.h:20541
CImgList< Tfloat > get_FFT(const char axis, const bool invert=false) const
Definition: CImg.h:37125
CImg< Tfloat > get_exp() const
Definition: CImg.h:12545
T & atXYZ(const int x, const int y, const int z, const int v, const T out_val)
Read a pixel value with Dirichlet boundary conditions for the three first coordinates (x...
Definition: CImg.h:11257
static void wait(CImgDisplay &disp1)
Wait for any event occuring on the display disp1.
Definition: CImg.h:6882
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 T val7, const T val8) const
Definition: CImg.h:14606
const CImgList< T > & save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const char *const codec="mpeg2video") const
Save an image sequence using the external tool &#39;ffmpeg&#39;.
Definition: CImg.h:36975
CImg< _cimg_Tt > get_min(const CImg< t > &img) const
Definition: CImg.h:12799
#define CImg_2x2x2(I, T)
Definition: CImg.h:451
static int format(const int val)
Definition: CImg.h:2169
const CImgList< T > & save_cimg(std::FILE *const file, const unsigned int n0, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0) const
Insert the instance image into into an existing .cimg file, at specified coordinates.
Definition: CImg.h:36878
CImg< T > & fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const double a0,...)
Definition: CImg.h:14931
const char * ffmpeg_path(const char *const user_path=0, const bool reinit_path=false)
Return or set path to the &#39;ffmpeg&#39; command.
Definition: CImg.h:5346
CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const double val0, const double val1,...)
Construct an image with given size (dx,dy,dz,dv) and with specified pixel values (double version)...
Definition: CImg.h:9921
const char * argument(const unsigned int nb, const int argc, const char *const *const argv, const unsigned int nb_singles=0,...)
Definition: CImg.h:5682
#define cimg_for6x6(img, x, y, z, v, I)
Definition: CImg.h:1247
CImgList< T > operator<(const char axis) const
Operator&lt;().
Definition: CImg.h:11024
static CImg< floatT > cylinder3d(CImgList< tf > &primitives, const float radius=50, const float size_z=100, const unsigned int subdivisions=24)
Create and return a 3D cylinder.
Definition: CImg.h:21882
static const char * format(const bool val)
Definition: CImg.h:2106
CImg< T > get_rand(const T val_min, const T val_max) const
Definition: CImg.h:14967
static CImg< T > sequence(const unsigned int N, const T a0, const T a1)
Return a N-numbered sequence vector from a0 to a1.
Definition: CImg.h:14389
CImgDisplay & assign(const CImgList< T > &list, const char *title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false)
In-place version of the previous constructor.
Definition: CImg.h:6415
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const tc *const color, const float brightness0, const float brightness1, const float brightness2, const float opacity=1)
Draw a 2D Gouraud-shaded colored triangle.
Definition: CImg.h:23972
CImg< T > & _load_dlm(std::FILE *const file, const char *const filename)
Definition: CImg.h:29331
cimg::last< T, unsigned char >::type ucharT
Definition: CImg.h:9784
const unsigned int keyF2
Definition: CImg.h:2673
const unsigned int keyARROWDOWN
Definition: CImg.h:2743
bool is_sameXYV(const CImg< t > &img) const
Return true if images have same width, same height and same number of channels.
Definition: CImg.h:12011
static CImgList< T > get_load_cimg(std::FILE *const file)
Definition: CImg.h:35546
T & operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0)
Fast access to pixel value for reading or writing.
Definition: CImg.h:10451
CImg< T > & draw_triangle(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float opacity=1, const float brightness=1)
Draw a 2D textured triangle, with z-buffering and perspective correction.
Definition: CImg.h:24434
CImg< _cimg_Tfloat > tanh(const CImg< T > &instance)
Definition: CImg.h:6076
CImg< T > & draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv, const CImg< tc > &color, const float opacity=1)
Draw an anisotropic 2D gaussian function.
Definition: CImg.h:27415
CImg< T > & channel(const unsigned int v0)
Get a channel.
Definition: CImg.h:18457
T atXYZV(const int x, const int y, const int z, const int v) const
Definition: CImg.h:11239
for(;;)
bool operator!=(const CImg< t > &img) const
Operator!=().
Definition: CImg.h:11007
CImgList< T > get_reverse() const
Definition: CImg.h:35237
#define _cimglist_def_is_same2(axis1, axis2)
Definition: CImg.h:34759
int dialog(const char *title, const char *msg, const char *button1_txt="OK", const char *button2_txt=0, const char *button3_txt=0, const char *button4_txt=0, const char *button5_txt=0, const char *button6_txt=0, const bool centering=false)
Definition: CImg.h:37329
CImg< T > & min(const T val)
Pointwise min operator between an image and a value.
Definition: CImg.h:12779
CImg< T > get_sequence(const T a0, const T a1) const
Definition: CImg.h:13436
Tfloat variancemean(const unsigned int variance_method, t &mean) const
Return the variance and the mean of the image.
Definition: CImg.h:13064
static T_Key key
Definition: vinci_lass.c:76
CImg< Tfloat > get_atan2(const CImg< t > &img) const
Definition: CImg.h:12679
static CImg< T > matrix(const T &a0)
Return a 1x1 square matrix with specified coefficients.
Definition: CImg.h:14289
CImgList< T > & pop_front()
Remove first element of the list (STL-compliant name).
Definition: CImg.h:35432
const CImg< T > & _save_off(std::FILE *const file, const char *const filename, const CImgList< tf > &primitives, const CImgList< tc > &colors) const
Definition: CImg.h:33607
CImgList< T > & load_gzip_external(const char *const filename)
Load a gzipped list, using external tool &#39;gunzip&#39;.
Definition: CImg.h:36169
T & atX(const int x, const int y=0, const int z=0, const int v=0)
Read a pixel value with Neumann boundary conditions for the first coordinates (x).
Definition: CImg.h:11333
CImg< T > & draw_ellipse(const int x0, const int y0, const CImg< t > &tensor, const CImg< tc > &color, const float opacity=1)
Draw a filled ellipse.
Definition: CImg.h:26047
CImg< T > get_dilate(const unsigned int n, const unsigned int cond=1) const
Definition: CImg.h:19104
CImg< T > & set_matrix_at(const CImg< t > &mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0)
Set the image vec as the square matrix-valued pixel located at (x,y,z) of the current vector-valued i...
Definition: CImg.h:13310
CImg< Tfloat > get_pow(const double p) const
Definition: CImg.h:12733
bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const bool remove)
Test if a key sequence has been typed.
Definition: CImg.h:6516
CImg< T > get_tensor() const
Definition: CImg.h:13376
_marching3d_func(const CImg< T > &pref)
Definition: CImg.h:21775
T & atXYZV(const int x, const int y, const int z, const int v)
Read a pixel value with Neumann boundary conditions.
Definition: CImg.h:11232
static CImg< T > get_load_dlm(const char *const filename)
Definition: CImg.h:29318
unsigned int nearest_pow2(const T x)
Return the nearest power of 2 higher than a given number.
Definition: CImg.h:4776
const CImg< T > & _display_object3d(CImgDisplay &disp, const char *const title, const CImg< tp > &vertices, const CImgList< tf > &primitives, const CImgList< tc > &colors, const to &opacities, const bool centering, const int render_static, const int render_motion, const bool double_sided, const float focale, const float specular_light, const float specular_shine, const bool display_axes, float *const pose_matrix) const
Definition: CImg.h:31788
CImg< T > & atan()
Compute the arc-tangent of each pixel.
Definition: CImg.h:12660
const CImg< T > & front() const
Definition: CImg.h:34530
volatile bool is_keyARROWLEFT
Definition: CImg.h:6245
CImg< T > & draw_polygon(const CImg< t > &points, const tc *const color, const float opacity=1)
Draw a filled polygon in the instance image.
Definition: CImg.h:25773
cimg::superset< T, unsigned long >::type Tulong
Definition: CImg.h:9779
CImg< T > & HSItoRGB()
Convert color pixels from (H,S,I) to (R,G,B).
Definition: CImg.h:15982
bool is_key(const unsigned int *const keyseq, const unsigned int N, const bool remove=true)
Test if a key sequence has been typed.
Definition: CImg.h:6567
CImgList< T > & push_back(const CImg< t > &img)
Insert image img at the end of the list (STL-compliant name).
Definition: CImg.h:35404
volatile bool is_keyF5
Definition: CImg.h:6179
CImg< Tfloat > operator-(const char *const expression) const
Operator-().
Definition: CImg.h:10658
CImg< _cimg_Tfloat > operator/(const char *const expression, const CImg< T > &img)
Definition: CImg.h:5986
const CImgList< T > & display(CImgDisplay &disp, const char axis='x', const char align='p') const
Display the current CImgList instance in an existing CImgDisplay window (by reference).
Definition: CImg.h:36301
CImg< T > & draw_line(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const tc *const color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a 2D colored line, with z-buffering.
Definition: CImg.h:22402
unsigned int depth
Variable representing the depth of the instance image (i.e. dimensions along the Z-axis).
Definition: CImg.h:9733
bool is_sameY(const CImgDisplay &disp) const
Return true if images (*this) and the display disp have same height.
Definition: CImg.h:11896
CImg< T > & draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0, const int x1, const int y1, const int z1, const float u1, const float v1, const float w1, const CImg< tc > &color, const float opacity=1, const float precision=4, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a cubic spline curve in the instance image (for volumetric images).
Definition: CImg.h:23214
CImg< T > & dilate(const CImg< t > &mask, const unsigned int cond=1, const bool weighted_dilatation=false)
Dilate the image by a structuring element.
Definition: CImg.h:19015
const T & max() const
Definition: CImg.h:12909
CImg< T > & draw_fill(const int x, const int y, const CImg< tc > &color, const float opacity=1, const float sigma=0, const bool high_connexity=false)
Draw a 2D filled region starting from a point (x,y) in the instance image.
Definition: CImg.h:27161
const char * basename(const char *const s)
Compute the basename of a filename.
Definition: CImg.h:4989
CImg< T > & assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const bool shared)
In-place version of the previous constructor, allowing to force the shared state of the instance imag...
Definition: CImg.h:10208
#define _cimg_gs3x_for3x3(img, x, y, z, v, I)
CImg< T > & assign(const CImg< t > &img, const char *const dimensions)
In-place version of the previous constructor.
Definition: CImg.h:10283
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7)
Return a vector with specified coefficients.
Definition: CImg.h:14184
const CImg< T > & _save_png(std::FILE *const file, const char *const filename, const unsigned int bytes_per_pixel=0) const
Definition: CImg.h:32714
CImg< T > & RGBtoYCbCr()
Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
Definition: CImg.h:16024
CImg< Tfloat > get_min(const char *const expression) const
Definition: CImg.h:12825
CImg< T > & draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const CImg< tc > &texture, const int tx0, const int ty0, const int tx1, const int ty1, const int tx2, const int ty2, const float brightness0, const float brightness1, const float brightness2, const float opacity=1)
Draw a 2D Gouraud-shaded textured triangle.
Definition: CImg.h:24843
_marching2d_func_expr(const char *const expr)
Definition: CImg.h:21447
#define _cimg_valign2d(i, j)
CImg< T > & RGBtoBayer()
Convert a (R,G,B) image to a Bayer-coded representation.
Definition: CImg.h:16467
static const char * string()
Definition: CImg.h:2182
static const char * format()
Definition: CImg.h:2096
CImg< T > & blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3, const unsigned int lookup_size=4, const float smoothness=0, const bool fast_approx=true)
Blur an image in its patch-based space.
Definition: CImg.h:19633
CImg< T > & pow(const CImg< t > &img)
Compute the power of each pixel value.
Definition: CImg.h:12739
CImg< T > & assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const bool shared)
Definition: CImg.h:10217
static const char * string()
Definition: CImg.h:2085
const CImg< T > * const_iterator
Define a CImgList&lt;T&gt;::const_iterator.
Definition: CImg.h:33895
static CImg< T > vector(const T &a0, const T &a1, const T &a2, const T &a3, const T &a4, const T &a5, const T &a6, const T &a7, const T &a8, const T &a9)
Return a vector with specified coefficients.
Definition: CImg.h:14204
static CImgList< T > get_load_gzip_external(const char *const filename)
Definition: CImg.h:36200
const char * dcraw_path(const char *const user_path=0, const bool reinit_path=false)
Return or set path to the &#39;dcraw&#39; command.
Definition: CImg.h:5439
Tfloat variance(const unsigned int variance_method=1) const
Return the variance of the image.
Definition: CImg.h:13057
static CImg< T > get_load_pnm(std::FILE *const file)
Definition: CImg.h:29825
CImg< T > & draw_gaussian(const float xc, const float sigma, const tc *const color, const float opacity=1)
Draw a 1D gaussian function in the instance image.
Definition: CImg.h:27328
CImg< T > & diagonal()
Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image...
Definition: CImg.h:13404
CImg< T > & draw_triangle(CImg< floatT > &zbuffer, const int x0, const int y0, const float z0, const int x1, const int y1, const float z1, const int x2, const int y2, const float z2, const CImg< tc > &color, const float opacity=1, const float brightness=1)
Draw a 2D filled colored triangle, with z-buffering.
Definition: CImg.h:23947
CImg< Tfloat > get_CMYtoCMYK() const
Definition: CImg.h:16185
CImg< T > & autocrop(const T value, const char *const axes="vzyx")
Autocrop an image, regarding of the specified backround value.
Definition: CImg.h:18267
CImg< Tfloat > operator*(const char *const expression) const
Operator*().
Definition: CImg.h:10706
CImgList(const CImg< t > &img, const bool shared=false)
Construct an image list from one image.
Definition: CImg.h:34030
CImg< T > & load_tiff(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1)
Load an image from a TIFF file.
Definition: CImg.h:30043
double pow(double value, const Exponent &exp)
CImg< T > & draw_mandelbrot(const CImg< tc > &color_palette, const float opacity=1, const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2, const unsigned int itermax=255, const bool normalized_iteration=false, const bool julia_set=false, const double paramr=0, const double parami=0)
Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
Definition: CImg.h:27311
CImg< T > & operator=(const char *const expression)
Operator=().
Definition: CImg.h:10482
CImg< T > & operator+=(const CImg< t > &img)
Operator+=().
Definition: CImg.h:10543
#define _cimg_Labfi(x)
const unsigned int key8
Definition: CImg.h:2692
CImg< T > & draw_axis(const float x0, const float x1, const float y0, const float y1, const CImg< tc > &color, const float opacity=1, const int subdivisionx=-60, const int subdivisiony=-60, const float precisionx=0, const float precisiony=0, const unsigned int patternx=~0U, const unsigned int patterny=~0U)
Draw a labeled horizontal+vertical axis on the instance image.
Definition: CImg.h:26690
CImgList< T > get_reverse_object3d() const
Definition: CImg.h:37154
const CImgList< T > & save_cimg(const char *const filename, const unsigned int n0, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0) const
Insert the instance image into into an existing .cimg file, at specified coordinates.
Definition: CImg.h:36870
cimg::superset< T, unsigned char >::type Tuchar
Definition: CImg.h:33902
cimg::last< T, int >::type intT
Definition: CImg.h:9789
#define CImg_3x3(I, T)
Definition: CImg.h:421
T atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) const
Definition: CImg.h:34652
#define cimglist_for_in(list, l0, l1, l)
Definition: CImg.h:1878
CImgList< T > & load_cimg(std::FILE *const file, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1)
Load a sub-image list from a non compressed .cimg file.
Definition: CImg.h:35658
CImg< T > & operator++()
Operator++() (prefix).
Definition: CImg.h:10556
CImg< Tfloat > get_RGBtoHSL() const
Definition: CImg.h:15906
const CImg< T > & save_analyze(const char *const filename, const float *const voxsize=0) const
Save the image as an ANALYZE7.5 or NIFTI file.
Definition: CImg.h:33219
CImg< T > & operator|=(const char *const expression)
Operator|=().
Definition: CImg.h:10882
volatile unsigned int released_keys[512]
Definition: CImg.h:6159
CImg< T > & resize_object3d(const float sx, const float sy=-100, const float sz=-100)
Resize a 3D object.
Definition: CImg.h:21107
const CImg< T > & display(CImgDisplay &disp) const
Display an image into a CImgDisplay window.
Definition: CImg.h:31463
CImg< Tfloat > get_normalize() const
Definition: CImg.h:15110
CImg< _cimg_Tfloat > operator-(const char *const expression, const CImg< T > &img)
Definition: CImg.h:5976
CImg< T > & YUVtoRGB()
Convert color pixels from (Y,U,V) to (R,G,B).
Definition: CImg.h:16103
const CImg< T > & display_object3d(const char *const title, const CImg< tp > &vertices, const CImgList< tf > &primitives, const CImgList< tc > &colors, const to &opacities, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=true, const float focale=500, const float specular_light=0.2f, const float specular_shine=0.1f, const bool display_axes=true, float *const pose_matrix=0) const
High-level interface for displaying a 3d object.
Definition: CImg.h:31681
CImg< T > & swap(CImg< T > &img)
Swap all fields of two images. Use with care !
Definition: CImg.h:10357
CImg< T > get_min(const T val) const
Definition: CImg.h:12784
const CImg< T > & save_rgb(const char *const filename) const
Save the image as a RGB file.
Definition: CImg.h:33048
const unsigned int keyF1
Definition: CImg.h:2672
CImg< T > & draw_polygon(const CImg< t > &points, const tc *const color, const float opacity, const unsigned int pattern)
Draw a polygon outline.
Definition: CImg.h:25844
bool contains(const CImg< T > &img, t &n) const
Return true if the list contains the image &#39;img&#39;. If true, returns the position (n) of the image in t...
Definition: CImg.h:34880
CImg< T > & draw_line(const CImgList< t > &points, const CImg< tc > &color, const float opacity=1, const unsigned int pattern=~0U, const bool init_hatch=true)
Draw a set of consecutive colored lines in the instance image.
Definition: CImg.h:23015
static CImg< T > vector(const T &a0)
Return a vector with specified coefficients.
Definition: CImg.h:14134
const CImg< T > get_shared_lines(const unsigned int y0, const unsigned int y1, const unsigned int z0=0, const unsigned int v0=0) const
Definition: CImg.h:18506
std::FILE * fopen(const char *const path, const char *const mode)
Open a file, and check for possible errors.
Definition: CImg.h:5494
NT & cos
CImg< Tfloat > get_structure_tensor(const unsigned int scheme=1) const
Definition: CImg.h:20186
CImgDisplayException(const char *format,...)
Definition: CImg.h:2058
CImg< T > & operator=(const CImg< t > &img)
Operator=().
Definition: CImg.h:10502
static CImg< T > tensor(const T &a1)
Return a 1x1 symmetric matrix with specified coefficients.
Definition: CImg.h:14342
static CImgList< T > get_load_off(const char *const filename, CImgList< tf > &primitives, CImgList< tc > &colors)
Definition: CImg.h:36212
#define cimg_forXV(img, x, v)
Definition: CImg.h:600
static const char * string()
Definition: CImg.h:2146
double eval(const char *const expression, const double x=0, const double y=0, const double z=0, const double v=0) const
Evaluate math expression.
Definition: CImg.h:13140
#define cimg_for2x2x2(img, x, y, z, v, I)
Definition: CImg.h:1774
CImgInstanceException(const char *format,...)
Definition: CImg.h:2040
bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const unsigned int key4, const unsigned int key5, const unsigned int key6, const bool remove)
Test if a key sequence has been typed.
Definition: CImg.h:6536
const unsigned int font10x19[10 *19 *256/32]
Definition: CImg.h:2935
CImgDisplay & wait(const unsigned int milliseconds)
Synchronized waiting function. Same as cimg::wait().
Definition: CImg.h:6870
unsigned int dim
Variable representing the number of channels of the instance image (i.e. dimensions along the V-axis)...
Definition: CImg.h:9744
bool contains(const T &pixel) const
Return true if specified referenced value is inside the image boundaries.
Definition: CImg.h:12105
CImg< T > & load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1)
Load an image from a RGBA file.
Definition: CImg.h:30004
CImg< T > & load_gzip_external(const char *const filename)
Load a gzipped image file, using external tool &#39;gunzip&#39;.
Definition: CImg.h:31255
Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const
Read a pixel value using linear interpolation and Neumann boundary conditions (first coordinate)...
Definition: CImg.h:11568
static CImg< T > get_load_medcon_external(const char *const filename)
Definition: CImg.h:31354
CImg< T > & structure_tensor(const unsigned int scheme=1)
Compute the structure tensor field of an image.
Definition: CImg.h:20182
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 T val7, const T val8, const T val9, const T val10, const T val11, const T val12, const T val13, const T val14, const T val15) const
Definition: CImg.h:14842
void info()
Print informations about CImg environement variables.
Definition: CImg.h:5702
CImg< floatT > get_elevation3d(CImgList< tf > &primitives, CImgList< tc > &colors, const CImg< te > &elevation) const
Create and return a 3D elevation of the instance image.
Definition: CImg.h:21187
CImg< Tfloat > get_resize_object3d() const
Definition: CImg.h:21137
CImg< T > & draw_fill(const int x, const int y, const int z, const CImg< tc > &color, const float opacity, CImg< t > &region, const float sigma=0, const bool high_connexity=false)
Draw a 3D filled region starting from a point (x,y,\ z) in the instance image.
Definition: CImg.h:27112
CImg< T > & draw_text(const int x0, const int y0, const char *const text, const CImg< tc1 > &foreground_color, const CImg< tc2 > &background_color, const float opacity=1, const unsigned int font_size=11,...)
Draw a text.
Definition: CImg.h:26400
volatile bool is_keyS
Definition: CImg.h:6218
CImg< Tfloat > get_distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) const
Definition: CImg.h:20590
CImg< T > get_sort(CImg< t > &permutations, const bool increasing=true) const
Definition: CImg.h:13779
static void wait(CImgDisplay &disp1, CImgDisplay &disp2, CImgDisplay &disp3)
Wait for any event occuring either on the display disp1, disp2 or disp3.
Definition: CImg.h:6894
CImg< T > & operator[](const unsigned int pos)
Return a reference to the i-th element of the image list.
Definition: CImg.h:34346
CImg< Tfloat > get_haar(const bool invert=false, const unsigned int nb_scales=1) const
Definition: CImg.h:20733
CImg< T > get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg< t > &previous) const
Definition: CImg.h:14116
bool contains(const T &pixel, t &x, t &y) const
Return true if specified referenced value is inside image boundaries. If true, returns pixel coordina...
Definition: CImg.h:12085
#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)
Definition: CImg.h:23686
CImgList(const CImgList< T > &list)
Definition: CImg.h:34105
CImg< T > & draw_ellipse(const int x0, const int y0, const CImg< t > &tensor, const CImg< tc > &color, const float opacity, const unsigned int pattern)
Draw an outlined ellipse.
Definition: CImg.h:26098
CImg< T > get_round(const float x, const unsigned int rounding_type=0) const
Definition: CImg.h:14981
CImg< T > & solve_tridiagonal(const CImg< t > &a, const CImg< t > &b, const CImg< t > &c)
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 ].
Definition: CImg.h:13629
T kth_smallest(const unsigned int k) const
Return the kth smallest element of the image.
Definition: CImg.h:12981
CImg< T > & atan2(const CImg< t > &img)
Compute the arc-tangent of each pixel.
Definition: CImg.h:12671
static CImg< T > get_load_cimg(std::FILE *const file, const unsigned int n0, const unsigned int n1, const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0, const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1, const char axis='z', const char align='p')
Definition: CImg.h:30586
unsigned int allocated_width
Allocation size of the list.
Definition: CImg.h:33886
CImg< _cimg_Tt > get_div(const CImg< t > &img) const
Definition: CImg.h:12717
CImg< T > & draw_gaussian(const float xc, const float yc, const CImg< t > &tensor, const CImg< tc > &color, const float opacity=1)
Draw an anisotropic 2D gaussian function.
Definition: CImg.h:27396
cimg::superset< T, unsigned short >::type Tushort
Definition: CImg.h:33904
CImg< T > & _draw_text(const int x0, const int y0, const char *const text, const tc1 *const foreground_color, const tc2 *const background_color, const float opacity, const CImgList< t > &font)
Definition: CImg.h:26435
static const char * string()
Definition: CImg.h:2173
T & operator[](const unsigned int off)
Fast access to pixel value for reading or writing, using an offset to the image pixel.
Definition: CImg.h:10405
T & _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0)
Definition: CImg.h:34703
CImg< T > & draw_arrow(const int x0, const int y0, const int x1, const int y1, const CImg< tc > &color, const float opacity=1, const float angle=30, const float length=-10, const unsigned int pattern=~0U)
Draw a colored arrow in the instance image.
Definition: CImg.h:23081
#define cimg_forYZV(img, y, z, v)
Definition: CImg.h:606
bool contains(const T &pixel, t &n, t &x, t &y) const
Return true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y).
Definition: CImg.h:34853
const unsigned int key1
Definition: CImg.h:2685
bool is_sameXYV(const unsigned int dx, const unsigned int dy, const unsigned int dv) const
Return true if image (*this) has the specified width, height and depth.
Definition: CImg.h:12005
static const char * string()
Definition: CImg.h:2164
CImg< T > operator~() const
Operator~().
Definition: CImg.h:10965
CImg< T > & crop(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const bool border_condition=false)
Get a rectangular part of the instance image.
Definition: CImg.h:18218
volatile bool is_keyCTRLRIGHT
Definition: CImg.h:6244
bool is_sameZV(const unsigned int dz, const unsigned int dv) const
Return true if image (*this) has the specified depth and number of channels.
Definition: CImg.h:11983
volatile bool is_keyT
Definition: CImg.h:6207
const unsigned int keyF3
Definition: CImg.h:2674
CImg< T > & load_magick(const char *const filename)
Load an image from a file, using Magick++ library.
Definition: CImg.h:29585
CImg< Tfloat > get_RGBtoLab() const
Definition: CImg.h:16414
cimg::superset< T, unsigned int >::type Tuint
Definition: CImg.h:9777
CImg< T > & RGBtoHSL()
Convert color pixels from (R,G,B) to (H,S,L).
Definition: CImg.h:15870
const unsigned int keyDELETE
Definition: CImg.h:2710
CImgList< T > & operator=(const CImg< t > &img)
Operator=().
Definition: CImg.h:34394
CImg< T > & draw_circle(const int x0, const int y0, int radius, const CImg< tc > &color, const float opacity=1)
Draw a filled circle.
Definition: CImg.h:25899
Tfloat cubic_atX(const float fx, const int y, const int z, const int v, const T out_val) const
Read a pixel value using cubic interpolation and Dirichlet boundary conditions (first coordinates)...
Definition: CImg.h:11697
unsigned long fps_timer
Definition: CImg.h:6268
volatile bool is_keyMENU
Definition: CImg.h:6243
CImgDisplay & assign(const unsigned int dimw, const unsigned int dimh, const char *title=0, const unsigned int normalization_type=3, const bool fullscreen_flag=false, const bool closed_flag=false)
In-place version of the previous constructor.
Definition: CImg.h:6393
const unsigned int keyCTRLRIGHT
Definition: CImg.h:2741
cimg::superset< T, unsigned long >::type Tulong
Definition: CImg.h:33908
CImg< T > & rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1)
Rotate an image.
Definition: CImg.h:17637
#define cimg_for_inXY(img, x0, y0, x1, y1, x, y)
Definition: CImg.h:615
volatile bool is_keyH
Definition: CImg.h:6222
static int format(const char val)
Definition: CImg.h:2124
double eval(const CImg< t > &img, const double x, const double y, const double z, const double v)
Definition: CImg.h:12423
CImgList(const unsigned int n)
Construct an image list containing n empty images.
Definition: CImg.h:33975
unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const
Definition: CImg.h:33372
CImg< T > & _draw_spline(const tp &points, const tt &tangents, const unsigned int W, const unsigned int H, const tc *const color, const float opacity, const bool close_set, const float precision, const unsigned int pattern, const bool init_hatch)
Definition: CImg.h:23285
const_iterator end() const
Definition: CImg.h:34521
static void FFT(CImg< T > &real, CImg< T > &imag, const char axis, const bool invert=false)
Compute a 1D Fast Fourier Transform, along a specified axis.
Definition: CImg.h:20832
#define cimg_forXZ(img, x, z)
Definition: CImg.h:598
bool is_sameXZ(const CImg< t > &img) const
Return true if images have same width and same depth.
Definition: CImg.h:11945
CImg< T > & log()
Compute the log of each each pixel value.
Definition: CImg.h:12550
static CImg< T > get_load_ascii(std::FILE *const file)
Definition: CImg.h:29279
float operator()(const float x, const float y) const
Definition: CImg.h:21450
CImgList< Tfloat > get_symmetric_eigen() const
Definition: CImg.h:13760
CImgList< T > & load_yuv(std::FILE *const file, const unsigned int sizex, const unsigned int sizey, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1, const bool yuv2rgb=true)
Load an image sequence from a YUV file.
Definition: CImg.h:35890
static unsigned char min()
Definition: CImg.h:2112
volatile bool is_keyARROWDOWN
Definition: CImg.h:6246
CImg< T > get_RGBtoBayer() const
Definition: CImg.h:16471
static CImgList< T > font(const unsigned int font_width, const bool variable_size=true)
Return a CImg pre-defined font with desired size.
Definition: CImg.h:37048
T value_type
Value type.
Definition: CImg.h:9769
CImgList< T > & insert(const unsigned int n, const CImgList< t > &list, const unsigned int pos=~0U, const bool shared=false)
Insert n copies of the list list at position pos of the current list.
Definition: CImg.h:35160
CImg< T > & draw_image(const int x0, const CImg< ti > &sprite, const CImg< tm > &mask, const float opacity=1, const float mask_valmax=1)
Draw an image.
Definition: CImg.h:26313
CImg< T > get_lines(const unsigned int y0, const unsigned int y1) const
Definition: CImg.h:18434
const CImg< T > & _save_inr(std::FILE *const file, const char *const filename, const float *const voxsize) const
Definition: CImg.h:33328
CImg< T > & distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f)
Compute distance function from 0-valued isophotes by the application of an Hamilton-Jacobi PDE...
Definition: CImg.h:20547
CImg< T > & draw_ellipse(const int x0, const int y0, const CImg< t > &tensor, const tc *const color, const float opacity=1)
Draw a filled ellipse.
Definition: CImg.h:26038
T atX(const int x, const int y=0, const int z=0, const int v=0) const
Definition: CImg.h:11340
CImg< T > & operator&=(const char *const expression)
Operator&amp;=().
Definition: CImg.h:10837
CImgList< t > & transfer_to(CImgList< t > &list, const unsigned int pos)
Definition: CImg.h:34315
Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const
Definition: CImg.h:11722
CImg< T > & load_cimg(const char *const filename, const char axis='z', const char align='p')
Load an image (list) from a .cimg file.
Definition: CImg.h:30531
CImg(const CImg< t > &img, const char *const dimensions, const char *const values, const bool repeat_values)
Construct an image using dimensions of another image, and fill it with given values.
Definition: CImg.h:10066
Instances of this class are thrown when errors occur during a CImg library function call...
Definition: CImg.h:2020
CImg< Tfloat > get_translate_object3d() const
Definition: CImg.h:21102
Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const
Read a pixel value using cubic interpolation and Neumann boundary conditions (first coordinates)...
Definition: CImg.h:11715
CImg< T > & asin()
Compute the arc-sinus of each pixel value.
Definition: CImg.h:12650
superset< t1, typename superset2< t2, t3, t4 >::type >::type type
Definition: CImg.h:2295
#define _cimg_get_label_test(p, q)
CImg< _cimg_Tfloat > sqr(const CImg< T > &instance)
Definition: CImg.h:6006
int dimx() const
Return the size of the list.
Definition: CImg.h:34465
bool is_sameX(const unsigned int dx) const
Return true if image (*this) has the specified width.
Definition: CImg.h:11869
#define _cimg_fopcode0(op)
Definition: CImg.h:12225
CImgList< T > & push_front(const CImgList< t > &list)
Insert list list at the front of the current list (STL-compliant name).
Definition: CImg.h:35422
CImg< T > get_blur_patch(const float sigma_s, const float sigma_p, const unsigned int patch_size=3, const unsigned int lookup_size=4, const float smoothness=0, const bool fast_approx=true) const
Definition: CImg.h:19638
const unsigned int keyPAUSE
Definition: CImg.h:2684
CImg< T > & draw_polygon(const CImg< t > &points, const CImg< tc > &color, const float opacity, const unsigned int pattern)
Draw a polygon outline.
Definition: CImg.h:25852
CImg< T > & sequence(const T a0, const T a1)
Return a N-numbered sequence vector from a0 to a1.
Definition: CImg.h:13425
CImg< T > & RGBtoXYZ()
Convert color pixels from (R,G,B) to (X,Y,Z)_709.
Definition: CImg.h:16239
int dimv() const
Return the number of vector channels of the instance image (size along the V-axis).
Definition: CImg.h:11061
int xln(const int x)
Return 1 + log_10(x).
Definition: CImg.h:4722
static CImg< T > get_load_png(const char *const filename)
Definition: CImg.h:29655
CImg< T > & resize_halfXY()
Half-resize an image, using a special optimized filter.
Definition: CImg.h:17011