Wed, 05 Aug 2009 17:32:05 +0100
updated README
1 /*
2 #
3 # File : CImg.h
4 # ( C++ header file )
5 #
6 # Description : The C++ Template Image Processing Library.
7 # This file is the main part of the CImg Library project.
8 # ( http://cimg.sourceforge.net )
9 #
10 # Project manager : David Tschumperle.
11 # ( http://www.greyc.ensicaen.fr/~dtschump/ )
12 #
13 # The complete contributor list can be seen in the 'README.txt' file.
14 #
15 # Licenses : This file is "dual-licensed", you have to choose one
16 # of the two licenses below to apply on this file.
17 #
18 # CeCILL-C
19 # The CeCILL-C license is close to the GNU LGPL.
20 # ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
21 #
22 # or CeCILL v2.0
23 # The CeCILL license is compatible with the GNU GPL.
24 # ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
25 #
26 # This software is governed either by the CeCILL or the CeCILL-C license
27 # under French law and abiding by the rules of distribution of free software.
28 # You can use, modify and or redistribute the software under the terms of
29 # the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA
30 # at the following URL : "http://www.cecill.info".
31 #
32 # As a counterpart to the access to the source code and rights to copy,
33 # modify and redistribute granted by the license, users are provided only
34 # with a limited warranty and the software's author, the holder of the
35 # economic rights, and the successive licensors have only limited
36 # liability.
37 #
38 # In this respect, the user's attention is drawn to the risks associated
39 # with loading, using, modifying and/or developing or reproducing the
40 # software by the user in light of its specific status of free software,
41 # that may mean that it is complicated to manipulate, and that also
42 # therefore means that it is reserved for developers and experienced
43 # professionals having in-depth computer knowledge. Users are therefore
44 # encouraged to load and test the software's suitability as regards their
45 # requirements in conditions enabling the security of their systems and/or
46 # data to be ensured and, more generally, to use and operate it in the
47 # same conditions as regards security.
48 #
49 # The fact that you are presently reading this means that you have had
50 # knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms.
51 #
52 */
54 // Define version number of the current file.
55 //
56 #ifndef cimg_version
57 #define cimg_version 130
59 /*-----------------------------------------------------------
60 #
61 # Test/auto-set CImg configuration variables
62 # and include required headers.
63 #
64 # If you find that default configuration variables are
65 # not adapted, you can override their values before including
66 # the header file "CImg.h" (using the #define directive).
67 #
68 ------------------------------------------------------------*/
70 // Include required standard C++ headers.
71 //
72 #include <cstdio>
73 #include <cstdlib>
74 #include <cstdarg>
75 #include <cstring>
76 #include <cmath>
77 #include <ctime>
79 // Operating system configuration.
80 //
81 // Define 'cimg_OS' to : 0 for an unknown OS (will try to minize library dependancies).
82 // 1 for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...).
83 // 2 for Microsoft Windows.
84 //
85 #ifndef cimg_OS
86 #if defined(unix) || defined(__unix) || defined(__unix__) \
87 || defined(linux) || defined(__linux) || defined(__linux__) \
88 || defined(sun) || defined(__sun) \
89 || defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) \
90 || defined(__FreeBSD__) || defined __DragonFly__ \
91 || defined(sgi) || defined(__sgi) \
92 || defined(__MACOSX__) || defined(__APPLE__) \
93 || defined(__CYGWIN__)
94 #define cimg_OS 1
95 #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
96 || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
97 #define cimg_OS 2
98 #else
99 #define cimg_OS 0
100 #endif
101 #elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2)
102 #error CImg Library : Configuration variable 'cimg_OS' is badly defined.
103 #error (valid values are '0=unknown OS', '1=Unix-like OS', '2=Microsoft Windows').
104 #endif
106 // Compiler configuration.
107 //
108 // Try to detect Microsoft VC++ compilers.
109 // (lot of workarounds are needed afterwards to
110 // make CImg working, particularly with VC++ 6.0).
111 //
112 #ifdef _MSC_VER
113 #pragma warning(push)
114 #pragma warning(disable:4311)
115 #pragma warning(disable:4312)
116 #pragma warning(disable:4800)
117 #pragma warning(disable:4804)
118 #pragma warning(disable:4996)
119 #define _CRT_SECURE_NO_DEPRECATE 1
120 #define _CRT_NONSTDC_NO_DEPRECATE 1
121 #if _MSC_VER<1300
122 #define cimg_use_visualcpp6
123 #define cimg_std
124 #define _WIN32_WINNT 0x0500
125 #endif
126 #endif
128 // Include OS-specific headers.
129 //
130 #if cimg_OS==1
131 #include <sys/time.h>
132 #include <unistd.h>
133 #elif cimg_OS==2
134 #include <windows.h>
135 #ifndef _WIN32_IE
136 #define _WIN32_IE 0x0400
137 #endif
138 #include <shlobj.h>
139 #endif
141 // Define defaut pipe for output messages
142 //
143 // Define 'cimg_stdout' to : stdout to print CImg messages on the standard output.
144 // stderr to print CImg messages on the standart error output (default behavior).
145 //
146 #ifndef cimg_std
147 #define cimg_std std
148 #endif
149 #ifndef cimg_stdout
150 #define cimg_stdout stderr
151 #endif
153 // Output messages configuration.
154 //
155 // Define 'cimg_debug' to : 0 to hide debug messages (quiet mode, but exceptions are still thrown).
156 // 1 to display debug messages on the console.
157 // 2 to display debug messages with dialog windows (default behavior).
158 // 3 to do as 1 + add extra warnings (may slow down the code !).
159 // 4 to do as 2 + add extra warnings (may slow down the code !).
160 //
161 // Define 'cimg_strict_warnings' to replace warning messages by exception throwns.
162 //
163 // Define 'cimg_use_vt100' to allow output of color messages (require VT100-compatible terminal).
164 //
165 #ifndef cimg_debug
166 #define cimg_debug 2
167 #elif !(cimg_debug==0 || cimg_debug==1 || cimg_debug==2 || cimg_debug==3 || cimg_debug==4)
168 #error CImg Library : Configuration variable 'cimg_debug' is badly defined.
169 #error (valid values are '0=quiet', '1=console', '2=dialog', '3=console+warnings', '4=dialog+warnings').
170 #endif
172 // Display framework configuration.
173 //
174 // Define 'cimg_display' to : 0 to disable display capabilities.
175 // 1 to use X-Window framework (X11).
176 // 2 to use Microsoft GDI32 framework.
177 // 3 to use Apple Carbon framework.
178 //
179 #ifndef cimg_display
180 #if cimg_OS==0
181 #define cimg_display 0
182 #elif cimg_OS==1
183 #if defined(__MACOSX__) || defined(__APPLE__)
184 #define cimg_display 1
185 #else
186 #define cimg_display 1
187 #endif
188 #elif cimg_OS==2
189 #define cimg_display 2
190 #endif
191 #elif !(cimg_display==0 || cimg_display==1 || cimg_display==2 || cimg_display==3)
192 #error CImg Library : Configuration variable 'cimg_display' is badly defined.
193 #error (valid values are '0=disable', '1=X-Window (X11)', '2=Microsoft GDI32', '3=Apple Carbon').
194 #endif
196 // Include display-specific headers.
197 //
198 #if cimg_display==1
199 #include <X11/Xlib.h>
200 #include <X11/Xutil.h>
201 #include <X11/keysym.h>
202 #include <pthread.h>
203 #ifdef cimg_use_xshm
204 #include <sys/ipc.h>
205 #include <sys/shm.h>
206 #include <X11/extensions/XShm.h>
207 #endif
208 #ifdef cimg_use_xrandr
209 #include <X11/extensions/Xrandr.h>
210 #endif
211 #elif cimg_display==3
212 #include <Carbon/Carbon.h>
213 #include <pthread.h>
214 #endif
216 // OpenMP configuration.
217 // (http://www.openmp.org)
218 //
219 // Define 'cimg_use_openmp' to enable OpenMP support.
220 //
221 // OpenMP directives can be used in few CImg functions to get
222 // advantages of multi-core CPUs. Using OpenMP is not mandatory.
223 //
224 #ifdef cimg_use_openmp
225 #include "omp.h"
226 #endif
228 // LibPNG configuration.
229 // (http://www.libpng.org)
230 //
231 // Define 'cimg_use_png' to enable LibPNG support.
232 //
233 // LibPNG can be used in functions 'CImg<T>::{load,save}_png()'
234 // to get a builtin support of PNG files. Using LibPNG is not mandatory.
235 //
236 #ifdef cimg_use_png
237 extern "C" {
238 #include "png.h"
239 }
240 #endif
242 // LibJPEG configuration.
243 // (http://en.wikipedia.org/wiki/Libjpeg)
244 //
245 // Define 'cimg_use_jpeg' to enable LibJPEG support.
246 //
247 // LibJPEG can be used in functions 'CImg<T>::{load,save}_jpeg()'
248 // to get a builtin support of JPEG files. Using LibJPEG is not mandatory.
249 //
250 #ifdef cimg_use_jpeg
251 extern "C" {
252 #include "jpeglib.h"
253 }
254 #endif
256 // LibTIFF configuration.
257 // (http://www.libtiff.org)
258 //
259 // Define 'cimg_use_tiff' to enable LibTIFF support.
260 //
261 // LibTIFF can be used in functions 'CImg[List]<T>::{load,save}_tiff()'
262 // to get a builtin support of TIFF files. Using LibTIFF is not mandatory.
263 //
264 #ifdef cimg_use_tiff
265 extern "C" {
266 #include "tiffio.h"
267 }
268 #endif
270 // FFMPEG Avcodec and Avformat libraries configuration.
271 // (http://www.ffmpeg.org)
272 //
273 // Define 'cimg_use_ffmpeg' to enable FFMPEG lib support.
274 //
275 // Avcodec and Avformat libraries can be used in functions
276 // 'CImg[List]<T>::load_ffmpeg()' to get a builtin
277 // support of various image sequences files.
278 // Using FFMPEG libraries is not mandatory.
279 //
280 #ifdef cimg_use_ffmpeg
281 extern "C" {
282 #include "avformat.h"
283 #include "avcodec.h"
284 #include "swscale.h"
285 }
286 #endif
288 // Zlib configuration
289 // (http://www.zlib.net)
290 //
291 // Define 'cimg_use_zlib' to enable Zlib support.
292 //
293 // Zlib can be used in functions 'CImg[List]<T>::{load,save}_cimg()'
294 // to allow compressed data in '.cimg' files. Using Zlib is not mandatory.
295 //
296 #ifdef cimg_use_zlib
297 extern "C" {
298 #include "zlib.h"
299 }
300 #endif
302 // Magick++ configuration.
303 // (http://www.imagemagick.org/Magick++)
304 //
305 // Define 'cimg_use_magick' to enable Magick++ support.
306 //
307 // Magick++ library can be used in functions 'CImg<T>::{load,save}()'
308 // to get a builtin support of various image formats (PNG,JPEG,TIFF,...).
309 // Using Magick++ is not mandatory.
310 //
311 #ifdef cimg_use_magick
312 #include "Magick++.h"
313 #endif
315 // FFTW3 configuration.
316 // (http://www.fftw.org)
317 //
318 // Define 'cimg_use_fftw3' to enable libFFTW3 support.
319 //
320 // FFTW3 library can be used in functions 'CImg[List]<T>::FFT()' to
321 // efficiently compile the Fast Fourier Transform of image data.
322 //
323 #ifdef cimg_use_fftw3
324 extern "C" {
325 #include "fftw3.h"
326 }
327 #endif
329 // Board configuration.
330 // (http://libboard.sourceforge.net/)
331 //
332 // Define 'cimg_use_board' to enable Board support.
333 //
334 // Board library can be used in functions 'CImg<T>::draw_object3d()'
335 // to draw objects 3D in vector-graphics canvas that can be saved
336 // as .PS or .SVG files afterwards.
337 //
338 #ifdef cimg_use_board
339 #include "Board.h"
340 #endif
342 // Lapack configuration.
343 // (http://www.netlib.org/lapack)
344 //
345 // Define 'cimg_use_lapack' to enable LAPACK support.
346 //
347 // Lapack can be used in various CImg functions dealing with
348 // matrix computation and algorithms (eigenvalues, inverse, ...).
349 // Using Lapack is not mandatory.
350 //
351 #ifdef cimg_use_lapack
352 extern "C" {
353 extern void sgetrf_(int*, int*, float*, int*, int*, int*);
354 extern void sgetri_(int*, float*, int*, int*, float*, int*, int*);
355 extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*);
356 extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*);
357 extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*);
358 extern void dgetrf_(int*, int*, double*, int*, int*, int*);
359 extern void dgetri_(int*, double*, int*, int*, double*, int*, int*);
360 extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*);
361 extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*, int*, double*, int*, double*, int*, int*);
362 extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*);
363 }
364 #endif
366 // Check if min/max macros are defined.
367 //
368 // CImg does not compile if macros 'min' or 'max' are defined,
369 // because min() and max() functions are also defined in the cimg:: namespace.
370 // so it '#undef' these macros if necessary, and restore them to reasonable
371 // values at the end of the file.
372 //
373 #ifdef min
374 #undef min
375 #define _cimg_redefine_min
376 #endif
377 #ifdef max
378 #undef max
379 #define _cimg_redefine_max
380 #endif
382 // Set the current working directory for native MacOSX bundled applications.
383 //
384 // By default, MacOS bundled applications set the cwd at the root directory '/',
385 // the code below allows to set it to the current exec directory instead when
386 // a CImg-based program is executed.
387 //
388 #if cimg_OS==1 && cimg_display==3
389 static struct _cimg_macosx_setcwd {
390 _cimg_macosx_setcwd() {
391 FSRef location;
392 ProcessSerialNumber psn;
393 char filePath[512];
394 if (GetCurrentProcess(&psn)!=noErr) return;
395 if (GetProcessBundleLocation(&psn,&location)!=noErr) return;
396 FSRefMakePath(&location,(UInt8*)filePath,sizeof(filePath)-1);
397 int p = cimg_std::strlen(filePath);
398 while (filePath[p] != '/') --p;
399 filePath[p] = 0;
400 chdir(filePath);
401 }
402 } cimg_macosx_setcwd;
403 #endif
405 /*------------------------------------------------------------------------------
406 #
407 # Define user-friendly macros.
408 #
409 # User macros are prefixed by 'cimg_' and can be used in your own code.
410 # They are particularly useful for option parsing, and image loops creation.
411 #
412 ------------------------------------------------------------------------------*/
414 // Define the program usage, and retrieve command line arguments.
415 //
416 #define cimg_usage(usage) cimg_library::cimg::option((char*)0,argc,argv,(char*)0,usage)
417 #define cimg_help(str) cimg_library::cimg::option((char*)0,argc,argv,str,(char*)0)
418 #define cimg_option(name,defaut,usage) cimg_library::cimg::option(name,argc,argv,defaut,usage)
419 #define cimg_argument(pos) cimg_library::cimg::argument(pos,argc,argv)
420 #define cimg_argument1(pos,s0) cimg_library::cimg::argument(pos,argc,argv,1,s0)
421 #define cimg_argument2(pos,s0,s1) cimg_library::cimg::argument(pos,argc,argv,2,s0,s1)
422 #define cimg_argument3(pos,s0,s1,s2) cimg_library::cimg::argument(pos,argc,argv,3,s0,s1,s2)
423 #define cimg_argument4(pos,s0,s1,s2,s3) cimg_library::cimg::argument(pos,argc,argv,4,s0,s1,s2,s3)
424 #define cimg_argument5(pos,s0,s1,s2,s3,s4) cimg_library::cimg::argument(pos,argc,argv,5,s0,s1,s2,s3,s4)
425 #define cimg_argument6(pos,s0,s1,s2,s3,s4,s5) cimg_library::cimg::argument(pos,argc,argv,6,s0,s1,s2,s3,s4,s5)
426 #define cimg_argument7(pos,s0,s1,s2,s3,s4,s5,s6) cimg_library::cimg::argument(pos,argc,argv,7,s0,s1,s2,s3,s4,s5,s6)
427 #define cimg_argument8(pos,s0,s1,s2,s3,s4,s5,s6,s7) cimg_library::cimg::argument(pos,argc,argv,8,s0,s1,s2,s3,s4,s5,s6,s7)
428 #define cimg_argument9(pos,s0,s1,s2,s3,s4,s5,s6,s7,s8) cimg_library::cimg::argument(pos,argc,argv,9,s0,s1,s2,s3,s4,s5,s6,s7,s8)
430 // Define and manipulate local neighborhoods.
431 //
432 #define CImg_2x2(I,T) T I[4]; \
433 T& I##cc = I[0]; T& I##nc = I[1]; \
434 T& I##cn = I[2]; T& I##nn = I[3]; \
435 I##cc = I##nc = \
436 I##cn = I##nn = 0
438 #define CImg_3x3(I,T) T I[9]; \
439 T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \
440 T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \
441 T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \
442 I##pp = I##cp = I##np = \
443 I##pc = I##cc = I##nc = \
444 I##pn = I##cn = I##nn = 0
446 #define CImg_4x4(I,T) T I[16]; \
447 T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \
448 T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \
449 T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \
450 T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \
451 I##pp = I##cp = I##np = I##ap = \
452 I##pc = I##cc = I##nc = I##ac = \
453 I##pn = I##cn = I##nn = I##an = \
454 I##pa = I##ca = I##na = I##aa = 0
456 #define CImg_5x5(I,T) T I[25]; \
457 T& I##bb = I[0]; T& I##pb = I[1]; T& I##cb = I[2]; T& I##nb = I[3]; T& I##ab = I[4]; \
458 T& I##bp = I[5]; T& I##pp = I[6]; T& I##cp = I[7]; T& I##np = I[8]; T& I##ap = I[9]; \
459 T& I##bc = I[10]; T& I##pc = I[11]; T& I##cc = I[12]; T& I##nc = I[13]; T& I##ac = I[14]; \
460 T& I##bn = I[15]; T& I##pn = I[16]; T& I##cn = I[17]; T& I##nn = I[18]; T& I##an = I[19]; \
461 T& I##ba = I[20]; T& I##pa = I[21]; T& I##ca = I[22]; T& I##na = I[23]; T& I##aa = I[24]; \
462 I##bb = I##pb = I##cb = I##nb = I##ab = \
463 I##bp = I##pp = I##cp = I##np = I##ap = \
464 I##bc = I##pc = I##cc = I##nc = I##ac = \
465 I##bn = I##pn = I##cn = I##nn = I##an = \
466 I##ba = I##pa = I##ca = I##na = I##aa = 0
468 #define CImg_2x2x2(I,T) T I[8]; \
469 T& I##ccc = I[0]; T& I##ncc = I[1]; \
470 T& I##cnc = I[2]; T& I##nnc = I[3]; \
471 T& I##ccn = I[4]; T& I##ncn = I[5]; \
472 T& I##cnn = I[6]; T& I##nnn = I[7]; \
473 I##ccc = I##ncc = \
474 I##cnc = I##nnc = \
475 I##ccn = I##ncn = \
476 I##cnn = I##nnn = 0
478 #define CImg_3x3x3(I,T) T I[27]; \
479 T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \
480 T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \
481 T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \
482 T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \
483 T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \
484 T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \
485 T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \
486 T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \
487 T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \
488 I##ppp = I##cpp = I##npp = \
489 I##pcp = I##ccp = I##ncp = \
490 I##pnp = I##cnp = I##nnp = \
491 I##ppc = I##cpc = I##npc = \
492 I##pcc = I##ccc = I##ncc = \
493 I##pnc = I##cnc = I##nnc = \
494 I##ppn = I##cpn = I##npn = \
495 I##pcn = I##ccn = I##ncn = \
496 I##pnn = I##cnn = I##nnn = 0
498 #define cimg_get2x2(img,x,y,z,v,I) \
499 I[0] = (img)(x,y,z,v), I[1] = (img)(_n1##x,y,z,v), I[2] = (img)(x,_n1##y,z,v), I[3] = (img)(_n1##x,_n1##y,z,v)
501 #define cimg_get3x3(img,x,y,z,v,I) \
502 I[0] = (img)(_p1##x,_p1##y,z,v), I[1] = (img)(x,_p1##y,z,v), I[2] = (img)(_n1##x,_p1##y,z,v), I[3] = (img)(_p1##x,y,z,v), \
503 I[4] = (img)(x,y,z,v), I[5] = (img)(_n1##x,y,z,v), I[6] = (img)(_p1##x,_n1##y,z,v), I[7] = (img)(x,_n1##y,z,v), \
504 I[8] = (img)(_n1##x,_n1##y,z,v)
506 #define cimg_get4x4(img,x,y,z,v,I) \
507 I[0] = (img)(_p1##x,_p1##y,z,v), I[1] = (img)(x,_p1##y,z,v), I[2] = (img)(_n1##x,_p1##y,z,v), I[3] = (img)(_n2##x,_p1##y,z,v), \
508 I[4] = (img)(_p1##x,y,z,v), I[5] = (img)(x,y,z,v), I[6] = (img)(_n1##x,y,z,v), I[7] = (img)(_n2##x,y,z,v), \
509 I[8] = (img)(_p1##x,_n1##y,z,v), I[9] = (img)(x,_n1##y,z,v), I[10] = (img)(_n1##x,_n1##y,z,v), I[11] = (img)(_n2##x,_n1##y,z,v), \
510 I[12] = (img)(_p1##x,_n2##y,z,v), I[13] = (img)(x,_n2##y,z,v), I[14] = (img)(_n1##x,_n2##y,z,v), I[15] = (img)(_n2##x,_n2##y,z,v)
512 #define cimg_get5x5(img,x,y,z,v,I) \
513 I[0] = (img)(_p2##x,_p2##y,z,v), I[1] = (img)(_p1##x,_p2##y,z,v), I[2] = (img)(x,_p2##y,z,v), I[3] = (img)(_n1##x,_p2##y,z,v), \
514 I[4] = (img)(_n2##x,_p2##y,z,v), I[5] = (img)(_p2##x,_p1##y,z,v), I[6] = (img)(_p1##x,_p1##y,z,v), I[7] = (img)(x,_p1##y,z,v), \
515 I[8] = (img)(_n1##x,_p1##y,z,v), I[9] = (img)(_n2##x,_p1##y,z,v), I[10] = (img)(_p2##x,y,z,v), I[11] = (img)(_p1##x,y,z,v), \
516 I[12] = (img)(x,y,z,v), I[13] = (img)(_n1##x,y,z,v), I[14] = (img)(_n2##x,y,z,v), I[15] = (img)(_p2##x,_n1##y,z,v), \
517 I[16] = (img)(_p1##x,_n1##y,z,v), I[17] = (img)(x,_n1##y,z,v), I[18] = (img)(_n1##x,_n1##y,z,v), I[19] = (img)(_n2##x,_n1##y,z,v), \
518 I[20] = (img)(_p2##x,_n2##y,z,v), I[21] = (img)(_p1##x,_n2##y,z,v), I[22] = (img)(x,_n2##y,z,v), I[23] = (img)(_n1##x,_n2##y,z,v), \
519 I[24] = (img)(_n2##x,_n2##y,z,v)
521 #define cimg_get6x6(img,x,y,z,v,I) \
522 I[0] = (img)(_p2##x,_p2##y,z,v), I[1] = (img)(_p1##x,_p2##y,z,v), I[2] = (img)(x,_p2##y,z,v), I[3] = (img)(_n1##x,_p2##y,z,v), \
523 I[4] = (img)(_n2##x,_p2##y,z,v), I[5] = (img)(_n3##x,_p2##y,z,v), I[6] = (img)(_p2##x,_p1##y,z,v), I[7] = (img)(_p1##x,_p1##y,z,v), \
524 I[8] = (img)(x,_p1##y,z,v), I[9] = (img)(_n1##x,_p1##y,z,v), I[10] = (img)(_n2##x,_p1##y,z,v), I[11] = (img)(_n3##x,_p1##y,z,v), \
525 I[12] = (img)(_p2##x,y,z,v), I[13] = (img)(_p1##x,y,z,v), I[14] = (img)(x,y,z,v), I[15] = (img)(_n1##x,y,z,v), \
526 I[16] = (img)(_n2##x,y,z,v), I[17] = (img)(_n3##x,y,z,v), I[18] = (img)(_p2##x,_n1##y,z,v), I[19] = (img)(_p1##x,_n1##y,z,v), \
527 I[20] = (img)(x,_n1##y,z,v), I[21] = (img)(_n1##x,_n1##y,z,v), I[22] = (img)(_n2##x,_n1##y,z,v), I[23] = (img)(_n3##x,_n1##y,z,v), \
528 I[24] = (img)(_p2##x,_n2##y,z,v), I[25] = (img)(_p1##x,_n2##y,z,v), I[26] = (img)(x,_n2##y,z,v), I[27] = (img)(_n1##x,_n2##y,z,v), \
529 I[28] = (img)(_n2##x,_n2##y,z,v), I[29] = (img)(_n3##x,_n2##y,z,v), I[30] = (img)(_p2##x,_n3##y,z,v), I[31] = (img)(_p1##x,_n3##y,z,v), \
530 I[32] = (img)(x,_n3##y,z,v), I[33] = (img)(_n1##x,_n3##y,z,v), I[34] = (img)(_n2##x,_n3##y,z,v), I[35] = (img)(_n3##x,_n3##y,z,v)
532 #define cimg_get7x7(img,x,y,z,v,I) \
533 I[0] = (img)(_p3##x,_p3##y,z,v), I[1] = (img)(_p2##x,_p3##y,z,v), I[2] = (img)(_p1##x,_p3##y,z,v), I[3] = (img)(x,_p3##y,z,v), \
534 I[4] = (img)(_n1##x,_p3##y,z,v), I[5] = (img)(_n2##x,_p3##y,z,v), I[6] = (img)(_n3##x,_p3##y,z,v), I[7] = (img)(_p3##x,_p2##y,z,v), \
535 I[8] = (img)(_p2##x,_p2##y,z,v), I[9] = (img)(_p1##x,_p2##y,z,v), I[10] = (img)(x,_p2##y,z,v), I[11] = (img)(_n1##x,_p2##y,z,v), \
536 I[12] = (img)(_n2##x,_p2##y,z,v), I[13] = (img)(_n3##x,_p2##y,z,v), I[14] = (img)(_p3##x,_p1##y,z,v), I[15] = (img)(_p2##x,_p1##y,z,v), \
537 I[16] = (img)(_p1##x,_p1##y,z,v), I[17] = (img)(x,_p1##y,z,v), I[18] = (img)(_n1##x,_p1##y,z,v), I[19] = (img)(_n2##x,_p1##y,z,v), \
538 I[20] = (img)(_n3##x,_p1##y,z,v), I[21] = (img)(_p3##x,y,z,v), I[22] = (img)(_p2##x,y,z,v), I[23] = (img)(_p1##x,y,z,v), \
539 I[24] = (img)(x,y,z,v), I[25] = (img)(_n1##x,y,z,v), I[26] = (img)(_n2##x,y,z,v), I[27] = (img)(_n3##x,y,z,v), \
540 I[28] = (img)(_p3##x,_n1##y,z,v), I[29] = (img)(_p2##x,_n1##y,z,v), I[30] = (img)(_p1##x,_n1##y,z,v), I[31] = (img)(x,_n1##y,z,v), \
541 I[32] = (img)(_n1##x,_n1##y,z,v), I[33] = (img)(_n2##x,_n1##y,z,v), I[34] = (img)(_n3##x,_n1##y,z,v), I[35] = (img)(_p3##x,_n2##y,z,v), \
542 I[36] = (img)(_p2##x,_n2##y,z,v), I[37] = (img)(_p1##x,_n2##y,z,v), I[38] = (img)(x,_n2##y,z,v), I[39] = (img)(_n1##x,_n2##y,z,v), \
543 I[40] = (img)(_n2##x,_n2##y,z,v), I[41] = (img)(_n3##x,_n2##y,z,v), I[42] = (img)(_p3##x,_n3##y,z,v), I[43] = (img)(_p2##x,_n3##y,z,v), \
544 I[44] = (img)(_p1##x,_n3##y,z,v), I[45] = (img)(x,_n3##y,z,v), I[46] = (img)(_n1##x,_n3##y,z,v), I[47] = (img)(_n2##x,_n3##y,z,v), \
545 I[48] = (img)(_n3##x,_n3##y,z,v)
547 #define cimg_get8x8(img,x,y,z,v,I) \
548 I[0] = (img)(_p3##x,_p3##y,z,v), I[1] = (img)(_p2##x,_p3##y,z,v), I[2] = (img)(_p1##x,_p3##y,z,v), I[3] = (img)(x,_p3##y,z,v), \
549 I[4] = (img)(_n1##x,_p3##y,z,v), I[5] = (img)(_n2##x,_p3##y,z,v), I[6] = (img)(_n3##x,_p3##y,z,v), I[7] = (img)(_n4##x,_p3##y,z,v), \
550 I[8] = (img)(_p3##x,_p2##y,z,v), I[9] = (img)(_p2##x,_p2##y,z,v), I[10] = (img)(_p1##x,_p2##y,z,v), I[11] = (img)(x,_p2##y,z,v), \
551 I[12] = (img)(_n1##x,_p2##y,z,v), I[13] = (img)(_n2##x,_p2##y,z,v), I[14] = (img)(_n3##x,_p2##y,z,v), I[15] = (img)(_n4##x,_p2##y,z,v), \
552 I[16] = (img)(_p3##x,_p1##y,z,v), I[17] = (img)(_p2##x,_p1##y,z,v), I[18] = (img)(_p1##x,_p1##y,z,v), I[19] = (img)(x,_p1##y,z,v), \
553 I[20] = (img)(_n1##x,_p1##y,z,v), I[21] = (img)(_n2##x,_p1##y,z,v), I[22] = (img)(_n3##x,_p1##y,z,v), I[23] = (img)(_n4##x,_p1##y,z,v), \
554 I[24] = (img)(_p3##x,y,z,v), I[25] = (img)(_p2##x,y,z,v), I[26] = (img)(_p1##x,y,z,v), I[27] = (img)(x,y,z,v), \
555 I[28] = (img)(_n1##x,y,z,v), I[29] = (img)(_n2##x,y,z,v), I[30] = (img)(_n3##x,y,z,v), I[31] = (img)(_n4##x,y,z,v), \
556 I[32] = (img)(_p3##x,_n1##y,z,v), I[33] = (img)(_p2##x,_n1##y,z,v), I[34] = (img)(_p1##x,_n1##y,z,v), I[35] = (img)(x,_n1##y,z,v), \
557 I[36] = (img)(_n1##x,_n1##y,z,v), I[37] = (img)(_n2##x,_n1##y,z,v), I[38] = (img)(_n3##x,_n1##y,z,v), I[39] = (img)(_n4##x,_n1##y,z,v), \
558 I[40] = (img)(_p3##x,_n2##y,z,v), I[41] = (img)(_p2##x,_n2##y,z,v), I[42] = (img)(_p1##x,_n2##y,z,v), I[43] = (img)(x,_n2##y,z,v), \
559 I[44] = (img)(_n1##x,_n2##y,z,v), I[45] = (img)(_n2##x,_n2##y,z,v), I[46] = (img)(_n3##x,_n2##y,z,v), I[47] = (img)(_n4##x,_n2##y,z,v), \
560 I[48] = (img)(_p3##x,_n3##y,z,v), I[49] = (img)(_p2##x,_n3##y,z,v), I[50] = (img)(_p1##x,_n3##y,z,v), I[51] = (img)(x,_n3##y,z,v), \
561 I[52] = (img)(_n1##x,_n3##y,z,v), I[53] = (img)(_n2##x,_n3##y,z,v), I[54] = (img)(_n3##x,_n3##y,z,v), I[55] = (img)(_n4##x,_n3##y,z,v), \
562 I[56] = (img)(_p3##x,_n4##y,z,v), I[57] = (img)(_p2##x,_n4##y,z,v), I[58] = (img)(_p1##x,_n4##y,z,v), I[59] = (img)(x,_n4##y,z,v), \
563 I[60] = (img)(_n1##x,_n4##y,z,v), I[61] = (img)(_n2##x,_n4##y,z,v), I[62] = (img)(_n3##x,_n4##y,z,v), I[63] = (img)(_n4##x,_n4##y,z,v);
565 #define cimg_get9x9(img,x,y,z,v,I) \
566 I[0] = (img)(_p4##x,_p4##y,z,v), I[1] = (img)(_p3##x,_p4##y,z,v), I[2] = (img)(_p2##x,_p4##y,z,v), I[3] = (img)(_p1##x,_p4##y,z,v), \
567 I[4] = (img)(x,_p4##y,z,v), I[5] = (img)(_n1##x,_p4##y,z,v), I[6] = (img)(_n2##x,_p4##y,z,v), I[7] = (img)(_n3##x,_p4##y,z,v), \
568 I[8] = (img)(_n4##x,_p4##y,z,v), I[9] = (img)(_p4##x,_p3##y,z,v), I[10] = (img)(_p3##x,_p3##y,z,v), I[11] = (img)(_p2##x,_p3##y,z,v), \
569 I[12] = (img)(_p1##x,_p3##y,z,v), I[13] = (img)(x,_p3##y,z,v), I[14] = (img)(_n1##x,_p3##y,z,v), I[15] = (img)(_n2##x,_p3##y,z,v), \
570 I[16] = (img)(_n3##x,_p3##y,z,v), I[17] = (img)(_n4##x,_p3##y,z,v), I[18] = (img)(_p4##x,_p2##y,z,v), I[19] = (img)(_p3##x,_p2##y,z,v), \
571 I[20] = (img)(_p2##x,_p2##y,z,v), I[21] = (img)(_p1##x,_p2##y,z,v), I[22] = (img)(x,_p2##y,z,v), I[23] = (img)(_n1##x,_p2##y,z,v), \
572 I[24] = (img)(_n2##x,_p2##y,z,v), I[25] = (img)(_n3##x,_p2##y,z,v), I[26] = (img)(_n4##x,_p2##y,z,v), I[27] = (img)(_p4##x,_p1##y,z,v), \
573 I[28] = (img)(_p3##x,_p1##y,z,v), I[29] = (img)(_p2##x,_p1##y,z,v), I[30] = (img)(_p1##x,_p1##y,z,v), I[31] = (img)(x,_p1##y,z,v), \
574 I[32] = (img)(_n1##x,_p1##y,z,v), I[33] = (img)(_n2##x,_p1##y,z,v), I[34] = (img)(_n3##x,_p1##y,z,v), I[35] = (img)(_n4##x,_p1##y,z,v), \
575 I[36] = (img)(_p4##x,y,z,v), I[37] = (img)(_p3##x,y,z,v), I[38] = (img)(_p2##x,y,z,v), I[39] = (img)(_p1##x,y,z,v), \
576 I[40] = (img)(x,y,z,v), I[41] = (img)(_n1##x,y,z,v), I[42] = (img)(_n2##x,y,z,v), I[43] = (img)(_n3##x,y,z,v), \
577 I[44] = (img)(_n4##x,y,z,v), I[45] = (img)(_p4##x,_n1##y,z,v), I[46] = (img)(_p3##x,_n1##y,z,v), I[47] = (img)(_p2##x,_n1##y,z,v), \
578 I[48] = (img)(_p1##x,_n1##y,z,v), I[49] = (img)(x,_n1##y,z,v), I[50] = (img)(_n1##x,_n1##y,z,v), I[51] = (img)(_n2##x,_n1##y,z,v), \
579 I[52] = (img)(_n3##x,_n1##y,z,v), I[53] = (img)(_n4##x,_n1##y,z,v), I[54] = (img)(_p4##x,_n2##y,z,v), I[55] = (img)(_p3##x,_n2##y,z,v), \
580 I[56] = (img)(_p2##x,_n2##y,z,v), I[57] = (img)(_p1##x,_n2##y,z,v), I[58] = (img)(x,_n2##y,z,v), I[59] = (img)(_n1##x,_n2##y,z,v), \
581 I[60] = (img)(_n2##x,_n2##y,z,v), I[61] = (img)(_n3##x,_n2##y,z,v), I[62] = (img)(_n4##x,_n2##y,z,v), I[63] = (img)(_p4##x,_n3##y,z,v), \
582 I[64] = (img)(_p3##x,_n3##y,z,v), I[65] = (img)(_p2##x,_n3##y,z,v), I[66] = (img)(_p1##x,_n3##y,z,v), I[67] = (img)(x,_n3##y,z,v), \
583 I[68] = (img)(_n1##x,_n3##y,z,v), I[69] = (img)(_n2##x,_n3##y,z,v), I[70] = (img)(_n3##x,_n3##y,z,v), I[71] = (img)(_n4##x,_n3##y,z,v), \
584 I[72] = (img)(_p4##x,_n4##y,z,v), I[73] = (img)(_p3##x,_n4##y,z,v), I[74] = (img)(_p2##x,_n4##y,z,v), I[75] = (img)(_p1##x,_n4##y,z,v), \
585 I[76] = (img)(x,_n4##y,z,v), I[77] = (img)(_n1##x,_n4##y,z,v), I[78] = (img)(_n2##x,_n4##y,z,v), I[79] = (img)(_n3##x,_n4##y,z,v), \
586 I[80] = (img)(_n4##x,_n4##y,z,v)
588 #define cimg_get2x2x2(img,x,y,z,v,I) \
589 I[0] = (img)(x,y,z,v), I[1] = (img)(_n1##x,y,z,v), I[2] = (img)(x,_n1##y,z,v), I[3] = (img)(_n1##x,_n1##y,z,v), \
590 I[4] = (img)(x,y,_n1##z,v), I[5] = (img)(_n1##x,y,_n1##z,v), I[6] = (img)(x,_n1##y,_n1##z,v), I[7] = (img)(_n1##x,_n1##y,_n1##z,v)
592 #define cimg_get3x3x3(img,x,y,z,v,I) \
593 I[0] = (img)(_p1##x,_p1##y,_p1##z,v), I[1] = (img)(x,_p1##y,_p1##z,v), I[2] = (img)(_n1##x,_p1##y,_p1##z,v), \
594 I[3] = (img)(_p1##x,y,_p1##z,v), I[4] = (img)(x,y,_p1##z,v), I[5] = (img)(_n1##x,y,_p1##z,v), \
595 I[6] = (img)(_p1##x,_n1##y,_p1##z,v), I[7] = (img)(x,_n1##y,_p1##z,v), I[8] = (img)(_n1##x,_n1##y,_p1##z,v), \
596 I[9] = (img)(_p1##x,_p1##y,z,v), I[10] = (img)(x,_p1##y,z,v), I[11] = (img)(_n1##x,_p1##y,z,v), \
597 I[12] = (img)(_p1##x,y,z,v), I[13] = (img)(x,y,z,v), I[14] = (img)(_n1##x,y,z,v), \
598 I[15] = (img)(_p1##x,_n1##y,z,v), I[16] = (img)(x,_n1##y,z,v), I[17] = (img)(_n1##x,_n1##y,z,v), \
599 I[18] = (img)(_p1##x,_p1##y,_n1##z,v), I[19] = (img)(x,_p1##y,_n1##z,v), I[20] = (img)(_n1##x,_p1##y,_n1##z,v), \
600 I[21] = (img)(_p1##x,y,_n1##z,v), I[22] = (img)(x,y,_n1##z,v), I[23] = (img)(_n1##x,y,_n1##z,v), \
601 I[24] = (img)(_p1##x,_n1##y,_n1##z,v), I[25] = (img)(x,_n1##y,_n1##z,v), I[26] = (img)(_n1##x,_n1##y,_n1##z,v)
603 // Define various image loops.
604 //
605 // These macros generally avoid the use of iterators, but you are not forced to used them !
606 //
607 #define cimg_for(img,ptr,T_ptr) for (T_ptr *ptr = (img).data + (img).size(); (ptr--)>(img).data; )
608 #define cimg_foroff(img,off) for (unsigned int off = 0, _max##off = (unsigned int)(img).size(); off<_max##off; ++off)
609 #define cimglist_for(list,l) for (unsigned int l=0; l<(list).size; ++l)
610 #define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn
612 #define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i)
613 #define cimg_forX(img,x) cimg_for1((img).width,x)
614 #define cimg_forY(img,y) cimg_for1((img).height,y)
615 #define cimg_forZ(img,z) cimg_for1((img).depth,z)
616 #define cimg_forV(img,v) cimg_for1((img).dim,v)
617 #define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x)
618 #define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x)
619 #define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y)
620 #define cimg_forXV(img,x,v) cimg_forV(img,v) cimg_forX(img,x)
621 #define cimg_forYV(img,y,v) cimg_forV(img,v) cimg_forY(img,y)
622 #define cimg_forZV(img,z,v) cimg_forV(img,v) cimg_forZ(img,z)
623 #define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y)
624 #define cimg_forXYV(img,x,y,v) cimg_forV(img,v) cimg_forXY(img,x,y)
625 #define cimg_forXZV(img,x,z,v) cimg_forV(img,v) cimg_forXZ(img,x,z)
626 #define cimg_forYZV(img,y,z,v) cimg_forV(img,v) cimg_forYZ(img,y,z)
627 #define cimg_forXYZV(img,x,y,z,v) cimg_forV(img,v) cimg_forXYZ(img,x,y,z)
629 #define cimg_for_in1(bound,i0,i1,i) \
630 for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound)-1; i<=_max##i; ++i)
631 #define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img).width,x0,x1,x)
632 #define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img).height,y0,y1,y)
633 #define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img).depth,z0,z1,z)
634 #define cimg_for_inV(img,v0,v1,v) cimg_for_in1((img).dim,v0,v1,v)
635 #define cimg_for_inXY(img,x0,y0,x1,y1,x,y) cimg_for_inY(img,y0,y1,y) cimg_for_inX(img,x0,x1,x)
636 #define cimg_for_inXZ(img,x0,z0,x1,z1,x,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inX(img,x0,x1,x)
637 #define cimg_for_inXV(img,x0,v0,x1,v1,x,v) cimg_for_inV(img,v0,v1,v) cimg_for_inX(img,x0,x1,x)
638 #define cimg_for_inYZ(img,y0,z0,y1,z1,y,z) cimg_for_inZ(img,x0,z1,z) cimg_for_inY(img,y0,y1,y)
639 #define cimg_for_inYV(img,y0,v0,y1,v1,y,v) cimg_for_inV(img,v0,v1,v) cimg_for_inY(img,y0,y1,y)
640 #define cimg_for_inZV(img,z0,v0,z1,v1,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inZ(img,z0,z1,z)
641 #define cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inXY(img,x0,y0,x1,y1,x,y)
642 #define cimg_for_inXYV(img,x0,y0,v0,x1,y1,v1,x,y,v) cimg_for_inV(img,v0,v1,v) cimg_for_inXY(img,x0,y0,x1,y1,x,y)
643 #define cimg_for_inXZV(img,x0,z0,v0,x1,z1,v1,x,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inXZ(img,x0,z0,x1,z1,x,z)
644 #define cimg_for_inYZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inYZ(img,y0,z0,y1,z1,y,z)
645 #define cimg_for_inXYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
646 #define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img).width-1-(n),x)
647 #define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img).height-1-(n),y)
648 #define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img).depth-1-(n),z)
649 #define cimg_for_insideV(img,v,n) cimg_for_inV(img,n,(img).dim-1-(n),v)
650 #define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
651 #define cimg_for_insideXYZ(img,x,y,z,n) cimg_for_inXYZ(img,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),x,y,z)
652 #define cimg_for_insideXYZV(img,x,y,z,v,n) cimg_for_inXYZ(img,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),x,y,z)
654 #define cimg_for_out1(boundi,i0,i1,i) \
655 for (int i = (int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1)+1:i)
656 #define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \
657 for (int j = 0; j<(int)(boundj); ++j) \
658 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
659 ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1)+1:i))
660 #define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \
661 for (int k = 0; k<(int)(boundk); ++k) \
662 for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
663 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
664 ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1)+1:i))
665 #define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \
666 for (int l = 0; l<(int)(boundl); ++l) \
667 for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \
668 for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
669 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k || _n1l?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
670 ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1)+1:i))
671 #define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img).width,x0,x1,x)
672 #define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img).height,y0,y1,y)
673 #define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img).depth,z0,z1,z)
674 #define cimg_for_outV(img,v0,v1,v) cimg_for_out1((img).dim,v0,v1,v)
675 #define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img).width,(img).height,x0,y0,x1,y1,x,y)
676 #define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img).width,(img).depth,x0,z0,x1,z1,x,z)
677 #define cimg_for_outXV(img,x0,v0,x1,v1,x,v) cimg_for_out2((img).width,(img).dim,x0,v0,x1,v1,x,v)
678 #define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img).height,(img).depth,y0,z0,y1,z1,y,z)
679 #define cimg_for_outYV(img,y0,v0,y1,v1,y,v) cimg_for_out2((img).height,(img).dim,y0,v0,y1,v1,y,v)
680 #define cimg_for_outZV(img,z0,v0,z1,v1,z,v) cimg_for_out2((img).depth,(img).dim,z0,v0,z1,v1,z,v)
681 #define cimg_for_outXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_out3((img).width,(img).height,(img).depth,x0,y0,z0,x1,y1,z1,x,y,z)
682 #define cimg_for_outXYV(img,x0,y0,v0,x1,y1,v1,x,y,v) cimg_for_out3((img).width,(img).height,(img).dim,x0,y0,v0,x1,y1,v1,x,y,v)
683 #define cimg_for_outXZV(img,x0,z0,v0,x1,z1,v1,x,z,v) cimg_for_out3((img).width,(img).depth,(img).dim,x0,z0,v0,x1,z1,v1,x,z,v)
684 #define cimg_for_outYZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_out3((img).height,(img).depth,(img).dim,y0,z0,v0,y1,z1,v1,y,z,v)
685 #define cimg_for_outXYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) \
686 cimg_for_out4((img).width,(img).height,(img).depth,(img).dim,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v)
687 #define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img).width-1-(n),x)
688 #define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img).height-1-(n),y)
689 #define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img).depth-1-(n),z)
690 #define cimg_for_borderV(img,v,n) cimg_for_outV(img,n,(img).dim-1-(n),v)
691 #define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
692 #define cimg_for_borderXYZ(img,x,y,z,n) cimg_for_outXYZ(img,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),x,y,z)
693 #define cimg_for_borderXYZV(img,x,y,z,v,n) \
694 cimg_for_outXYZV(img,n,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),(img).dim-1-(n),x,y,z,v)
696 #define cimg_for_spiralXY(img,x,y) \
697 for (int x = 0, y = 0, _n1##x = 1, _n1##y = (int)((img).width*(img).height); _n1##y; \
698 --_n1##y, _n1##x += (_n1##x>>2)-((!(_n1##x&3)?--y:((_n1##x&3)==1?(img).width-1-++x:((_n1##x&3)==2?(img).height-1-++y:--x))))?0:1)
700 #define cimg_for_lineXY(x,y,x0,y0,x1,y1) \
701 for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \
702 _dx=(x1)>(x0)?(int)(x1)-(int)(x0):(_sx=-1,(int)(x0)-(int)(x1)), \
703 _dy=(y1)>(y0)?(int)(y1)-(int)(y0):(_sy=-1,(int)(y0)-(int)(y1)), \
704 _counter = _dx, \
705 _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \
706 _counter>=0; \
707 --_counter, x+=_steep? \
708 (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \
709 (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx))
711 #define cimg_for2(bound,i) \
712 for (int i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1; \
713 _n1##i<(int)(bound) || i==--_n1##i; \
714 ++i, ++_n1##i)
715 #define cimg_for2X(img,x) cimg_for2((img).width,x)
716 #define cimg_for2Y(img,y) cimg_for2((img).height,y)
717 #define cimg_for2Z(img,z) cimg_for2((img).depth,z)
718 #define cimg_for2V(img,v) cimg_for2((img).dim,v)
719 #define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x)
720 #define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x)
721 #define cimg_for2XV(img,x,v) cimg_for2V(img,v) cimg_for2X(img,x)
722 #define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y)
723 #define cimg_for2YV(img,y,v) cimg_for2V(img,v) cimg_for2Y(img,y)
724 #define cimg_for2ZV(img,z,v) cimg_for2V(img,v) cimg_for2Z(img,z)
725 #define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y)
726 #define cimg_for2XZV(img,x,z,v) cimg_for2V(img,v) cimg_for2XZ(img,x,z)
727 #define cimg_for2YZV(img,y,z,v) cimg_for2V(img,v) cimg_for2YZ(img,y,z)
728 #define cimg_for2XYZV(img,x,y,z,v) cimg_for2V(img,v) cimg_for2XYZ(img,x,y,z)
730 #define cimg_for_in2(bound,i0,i1,i) \
731 for (int i = (int)(i0)<0?0:(int)(i0), \
732 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
733 i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
734 ++i, ++_n1##i)
735 #define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img).width,x0,x1,x)
736 #define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img).height,y0,y1,y)
737 #define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img).depth,z0,z1,z)
738 #define cimg_for_in2V(img,v0,v1,v) cimg_for_in2((img).dim,v0,v1,v)
739 #define cimg_for_in2XY(img,x0,y0,x1,y1,x,y) cimg_for_in2Y(img,y0,y1,y) cimg_for_in2X(img,x0,x1,x)
740 #define cimg_for_in2XZ(img,x0,z0,x1,z1,x,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2X(img,x0,x1,x)
741 #define cimg_for_in2XV(img,x0,v0,x1,v1,x,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2X(img,x0,x1,x)
742 #define cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2Y(img,y0,y1,y)
743 #define cimg_for_in2YV(img,y0,v0,y1,v1,y,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2Y(img,y0,y1,y)
744 #define cimg_for_in2ZV(img,z0,v0,z1,v1,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2Z(img,z0,z1,z)
745 #define cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2XY(img,x0,y0,x1,y1,x,y)
746 #define cimg_for_in2XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2XZ(img,x0,y0,x1,y1,x,z)
747 #define cimg_for_in2YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2YZ(img,y0,z0,y1,z1,y,z)
748 #define cimg_for_in2XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
750 #define cimg_for3(bound,i) \
751 for (int i = 0, _p1##i = 0, \
752 _n1##i = 1>=(bound)?(int)(bound)-1:1; \
753 _n1##i<(int)(bound) || i==--_n1##i; \
754 _p1##i = i++, ++_n1##i)
755 #define cimg_for3X(img,x) cimg_for3((img).width,x)
756 #define cimg_for3Y(img,y) cimg_for3((img).height,y)
757 #define cimg_for3Z(img,z) cimg_for3((img).depth,z)
758 #define cimg_for3V(img,v) cimg_for3((img).dim,v)
759 #define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x)
760 #define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x)
761 #define cimg_for3XV(img,x,v) cimg_for3V(img,v) cimg_for3X(img,x)
762 #define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y)
763 #define cimg_for3YV(img,y,v) cimg_for3V(img,v) cimg_for3Y(img,y)
764 #define cimg_for3ZV(img,z,v) cimg_for3V(img,v) cimg_for3Z(img,z)
765 #define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y)
766 #define cimg_for3XZV(img,x,z,v) cimg_for3V(img,v) cimg_for3XZ(img,x,z)
767 #define cimg_for3YZV(img,y,z,v) cimg_for3V(img,v) cimg_for3YZ(img,y,z)
768 #define cimg_for3XYZV(img,x,y,z,v) cimg_for3V(img,v) cimg_for3XYZ(img,x,y,z)
770 #define cimg_for_in3(bound,i0,i1,i) \
771 for (int i = (int)(i0)<0?0:(int)(i0), \
772 _p1##i = i-1<0?0:i-1, \
773 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
774 i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
775 _p1##i = i++, ++_n1##i)
776 #define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img).width,x0,x1,x)
777 #define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img).height,y0,y1,y)
778 #define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img).depth,z0,z1,z)
779 #define cimg_for_in3V(img,v0,v1,v) cimg_for_in3((img).dim,v0,v1,v)
780 #define cimg_for_in3XY(img,x0,y0,x1,y1,x,y) cimg_for_in3Y(img,y0,y1,y) cimg_for_in3X(img,x0,x1,x)
781 #define cimg_for_in3XZ(img,x0,z0,x1,z1,x,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3X(img,x0,x1,x)
782 #define cimg_for_in3XV(img,x0,v0,x1,v1,x,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3X(img,x0,x1,x)
783 #define cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3Y(img,y0,y1,y)
784 #define cimg_for_in3YV(img,y0,v0,y1,v1,y,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3Y(img,y0,y1,y)
785 #define cimg_for_in3ZV(img,z0,v0,z1,v1,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3Z(img,z0,z1,z)
786 #define cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3XY(img,x0,y0,x1,y1,x,y)
787 #define cimg_for_in3XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3XZ(img,x0,y0,x1,y1,x,z)
788 #define cimg_for_in3YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3YZ(img,y0,z0,y1,z1,y,z)
789 #define cimg_for_in3XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
791 #define cimg_for4(bound,i) \
792 for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1, \
793 _n2##i = 2>=(bound)?(int)(bound)-1:2; \
794 _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
795 _p1##i = i++, ++_n1##i, ++_n2##i)
796 #define cimg_for4X(img,x) cimg_for4((img).width,x)
797 #define cimg_for4Y(img,y) cimg_for4((img).height,y)
798 #define cimg_for4Z(img,z) cimg_for4((img).depth,z)
799 #define cimg_for4V(img,v) cimg_for4((img).dim,v)
800 #define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x)
801 #define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x)
802 #define cimg_for4XV(img,x,v) cimg_for4V(img,v) cimg_for4X(img,x)
803 #define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y)
804 #define cimg_for4YV(img,y,v) cimg_for4V(img,v) cimg_for4Y(img,y)
805 #define cimg_for4ZV(img,z,v) cimg_for4V(img,v) cimg_for4Z(img,z)
806 #define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y)
807 #define cimg_for4XZV(img,x,z,v) cimg_for4V(img,v) cimg_for4XZ(img,x,z)
808 #define cimg_for4YZV(img,y,z,v) cimg_for4V(img,v) cimg_for4YZ(img,y,z)
809 #define cimg_for4XYZV(img,x,y,z,v) cimg_for4V(img,v) cimg_for4XYZ(img,x,y,z)
811 #define cimg_for_in4(bound,i0,i1,i) \
812 for (int i = (int)(i0)<0?0:(int)(i0), \
813 _p1##i = i-1<0?0:i-1, \
814 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
815 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
816 i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
817 _p1##i = i++, ++_n1##i, ++_n2##i)
818 #define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img).width,x0,x1,x)
819 #define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img).height,y0,y1,y)
820 #define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img).depth,z0,z1,z)
821 #define cimg_for_in4V(img,v0,v1,v) cimg_for_in4((img).dim,v0,v1,v)
822 #define cimg_for_in4XY(img,x0,y0,x1,y1,x,y) cimg_for_in4Y(img,y0,y1,y) cimg_for_in4X(img,x0,x1,x)
823 #define cimg_for_in4XZ(img,x0,z0,x1,z1,x,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4X(img,x0,x1,x)
824 #define cimg_for_in4XV(img,x0,v0,x1,v1,x,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4X(img,x0,x1,x)
825 #define cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4Y(img,y0,y1,y)
826 #define cimg_for_in4YV(img,y0,v0,y1,v1,y,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4Y(img,y0,y1,y)
827 #define cimg_for_in4ZV(img,z0,v0,z1,v1,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4Z(img,z0,z1,z)
828 #define cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4XY(img,x0,y0,x1,y1,x,y)
829 #define cimg_for_in4XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4XZ(img,x0,y0,x1,y1,x,z)
830 #define cimg_for_in4YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4YZ(img,y0,z0,y1,z1,y,z)
831 #define cimg_for_in4XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
833 #define cimg_for5(bound,i) \
834 for (int i = 0, _p2##i = 0, _p1##i = 0, \
835 _n1##i = 1>=(bound)?(int)(bound)-1:1, \
836 _n2##i = 2>=(bound)?(int)(bound)-1:2; \
837 _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
838 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
839 #define cimg_for5X(img,x) cimg_for5((img).width,x)
840 #define cimg_for5Y(img,y) cimg_for5((img).height,y)
841 #define cimg_for5Z(img,z) cimg_for5((img).depth,z)
842 #define cimg_for5V(img,v) cimg_for5((img).dim,v)
843 #define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x)
844 #define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x)
845 #define cimg_for5XV(img,x,v) cimg_for5V(img,v) cimg_for5X(img,x)
846 #define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y)
847 #define cimg_for5YV(img,y,v) cimg_for5V(img,v) cimg_for5Y(img,y)
848 #define cimg_for5ZV(img,z,v) cimg_for5V(img,v) cimg_for5Z(img,z)
849 #define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y)
850 #define cimg_for5XZV(img,x,z,v) cimg_for5V(img,v) cimg_for5XZ(img,x,z)
851 #define cimg_for5YZV(img,y,z,v) cimg_for5V(img,v) cimg_for5YZ(img,y,z)
852 #define cimg_for5XYZV(img,x,y,z,v) cimg_for5V(img,v) cimg_for5XYZ(img,x,y,z)
854 #define cimg_for_in5(bound,i0,i1,i) \
855 for (int i = (int)(i0)<0?0:(int)(i0), \
856 _p2##i = i-2<0?0:i-2, \
857 _p1##i = i-1<0?0:i-1, \
858 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
859 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
860 i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
861 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
862 #define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img).width,x0,x1,x)
863 #define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img).height,y0,y1,y)
864 #define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img).depth,z0,z1,z)
865 #define cimg_for_in5V(img,v0,v1,v) cimg_for_in5((img).dim,v0,v1,v)
866 #define cimg_for_in5XY(img,x0,y0,x1,y1,x,y) cimg_for_in5Y(img,y0,y1,y) cimg_for_in5X(img,x0,x1,x)
867 #define cimg_for_in5XZ(img,x0,z0,x1,z1,x,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5X(img,x0,x1,x)
868 #define cimg_for_in5XV(img,x0,v0,x1,v1,x,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5X(img,x0,x1,x)
869 #define cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5Y(img,y0,y1,y)
870 #define cimg_for_in5YV(img,y0,v0,y1,v1,y,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5Y(img,y0,y1,y)
871 #define cimg_for_in5ZV(img,z0,v0,z1,v1,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5Z(img,z0,z1,z)
872 #define cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5XY(img,x0,y0,x1,y1,x,y)
873 #define cimg_for_in5XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5XZ(img,x0,y0,x1,y1,x,z)
874 #define cimg_for_in5YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5YZ(img,y0,z0,y1,z1,y,z)
875 #define cimg_for_in5XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
877 #define cimg_for6(bound,i) \
878 for (int i = 0, _p2##i = 0, _p1##i = 0, \
879 _n1##i = 1>=(bound)?(int)(bound)-1:1, \
880 _n2##i = 2>=(bound)?(int)(bound)-1:2, \
881 _n3##i = 3>=(bound)?(int)(bound)-1:3; \
882 _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
883 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
884 #define cimg_for6X(img,x) cimg_for6((img).width,x)
885 #define cimg_for6Y(img,y) cimg_for6((img).height,y)
886 #define cimg_for6Z(img,z) cimg_for6((img).depth,z)
887 #define cimg_for6V(img,v) cimg_for6((img).dim,v)
888 #define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x)
889 #define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x)
890 #define cimg_for6XV(img,x,v) cimg_for6V(img,v) cimg_for6X(img,x)
891 #define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y)
892 #define cimg_for6YV(img,y,v) cimg_for6V(img,v) cimg_for6Y(img,y)
893 #define cimg_for6ZV(img,z,v) cimg_for6V(img,v) cimg_for6Z(img,z)
894 #define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y)
895 #define cimg_for6XZV(img,x,z,v) cimg_for6V(img,v) cimg_for6XZ(img,x,z)
896 #define cimg_for6YZV(img,y,z,v) cimg_for6V(img,v) cimg_for6YZ(img,y,z)
897 #define cimg_for6XYZV(img,x,y,z,v) cimg_for6V(img,v) cimg_for6XYZ(img,x,y,z)
899 #define cimg_for_in6(bound,i0,i1,i) \
900 for (int i = (int)(i0)<0?0:(int)(i0), \
901 _p2##i = i-2<0?0:i-2, \
902 _p1##i = i-1<0?0:i-1, \
903 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
904 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
905 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
906 i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
907 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
908 #define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img).width,x0,x1,x)
909 #define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img).height,y0,y1,y)
910 #define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img).depth,z0,z1,z)
911 #define cimg_for_in6V(img,v0,v1,v) cimg_for_in6((img).dim,v0,v1,v)
912 #define cimg_for_in6XY(img,x0,y0,x1,y1,x,y) cimg_for_in6Y(img,y0,y1,y) cimg_for_in6X(img,x0,x1,x)
913 #define cimg_for_in6XZ(img,x0,z0,x1,z1,x,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6X(img,x0,x1,x)
914 #define cimg_for_in6XV(img,x0,v0,x1,v1,x,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6X(img,x0,x1,x)
915 #define cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6Y(img,y0,y1,y)
916 #define cimg_for_in6YV(img,y0,v0,y1,v1,y,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6Y(img,y0,y1,y)
917 #define cimg_for_in6ZV(img,z0,v0,z1,v1,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6Z(img,z0,z1,z)
918 #define cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6XY(img,x0,y0,x1,y1,x,y)
919 #define cimg_for_in6XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6XZ(img,x0,y0,x1,y1,x,z)
920 #define cimg_for_in6YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6YZ(img,y0,z0,y1,z1,y,z)
921 #define cimg_for_in6XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
923 #define cimg_for7(bound,i) \
924 for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
925 _n1##i = 1>=(bound)?(int)(bound)-1:1, \
926 _n2##i = 2>=(bound)?(int)(bound)-1:2, \
927 _n3##i = 3>=(bound)?(int)(bound)-1:3; \
928 _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
929 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
930 #define cimg_for7X(img,x) cimg_for7((img).width,x)
931 #define cimg_for7Y(img,y) cimg_for7((img).height,y)
932 #define cimg_for7Z(img,z) cimg_for7((img).depth,z)
933 #define cimg_for7V(img,v) cimg_for7((img).dim,v)
934 #define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x)
935 #define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x)
936 #define cimg_for7XV(img,x,v) cimg_for7V(img,v) cimg_for7X(img,x)
937 #define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y)
938 #define cimg_for7YV(img,y,v) cimg_for7V(img,v) cimg_for7Y(img,y)
939 #define cimg_for7ZV(img,z,v) cimg_for7V(img,v) cimg_for7Z(img,z)
940 #define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y)
941 #define cimg_for7XZV(img,x,z,v) cimg_for7V(img,v) cimg_for7XZ(img,x,z)
942 #define cimg_for7YZV(img,y,z,v) cimg_for7V(img,v) cimg_for7YZ(img,y,z)
943 #define cimg_for7XYZV(img,x,y,z,v) cimg_for7V(img,v) cimg_for7XYZ(img,x,y,z)
945 #define cimg_for_in7(bound,i0,i1,i) \
946 for (int i = (int)(i0)<0?0:(int)(i0), \
947 _p3##i = i-3<0?0:i-3, \
948 _p2##i = i-2<0?0:i-2, \
949 _p1##i = i-1<0?0:i-1, \
950 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
951 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
952 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
953 i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
954 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
955 #define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img).width,x0,x1,x)
956 #define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img).height,y0,y1,y)
957 #define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img).depth,z0,z1,z)
958 #define cimg_for_in7V(img,v0,v1,v) cimg_for_in7((img).dim,v0,v1,v)
959 #define cimg_for_in7XY(img,x0,y0,x1,y1,x,y) cimg_for_in7Y(img,y0,y1,y) cimg_for_in7X(img,x0,x1,x)
960 #define cimg_for_in7XZ(img,x0,z0,x1,z1,x,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7X(img,x0,x1,x)
961 #define cimg_for_in7XV(img,x0,v0,x1,v1,x,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7X(img,x0,x1,x)
962 #define cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7Y(img,y0,y1,y)
963 #define cimg_for_in7YV(img,y0,v0,y1,v1,y,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7Y(img,y0,y1,y)
964 #define cimg_for_in7ZV(img,z0,v0,z1,v1,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7Z(img,z0,z1,z)
965 #define cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7XY(img,x0,y0,x1,y1,x,y)
966 #define cimg_for_in7XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7XZ(img,x0,y0,x1,y1,x,z)
967 #define cimg_for_in7YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7YZ(img,y0,z0,y1,z1,y,z)
968 #define cimg_for_in7XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
970 #define cimg_for8(bound,i) \
971 for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
972 _n1##i = 1>=(bound)?(int)(bound)-1:1, \
973 _n2##i = 2>=(bound)?(int)(bound)-1:2, \
974 _n3##i = 3>=(bound)?(int)(bound)-1:3, \
975 _n4##i = 4>=(bound)?(int)(bound)-1:4; \
976 _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
977 i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
978 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
979 #define cimg_for8X(img,x) cimg_for8((img).width,x)
980 #define cimg_for8Y(img,y) cimg_for8((img).height,y)
981 #define cimg_for8Z(img,z) cimg_for8((img).depth,z)
982 #define cimg_for8V(img,v) cimg_for8((img).dim,v)
983 #define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x)
984 #define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x)
985 #define cimg_for8XV(img,x,v) cimg_for8V(img,v) cimg_for8X(img,x)
986 #define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y)
987 #define cimg_for8YV(img,y,v) cimg_for8V(img,v) cimg_for8Y(img,y)
988 #define cimg_for8ZV(img,z,v) cimg_for8V(img,v) cimg_for8Z(img,z)
989 #define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y)
990 #define cimg_for8XZV(img,x,z,v) cimg_for8V(img,v) cimg_for8XZ(img,x,z)
991 #define cimg_for8YZV(img,y,z,v) cimg_for8V(img,v) cimg_for8YZ(img,y,z)
992 #define cimg_for8XYZV(img,x,y,z,v) cimg_for8V(img,v) cimg_for8XYZ(img,x,y,z)
994 #define cimg_for_in8(bound,i0,i1,i) \
995 for (int i = (int)(i0)<0?0:(int)(i0), \
996 _p3##i = i-3<0?0:i-3, \
997 _p2##i = i-2<0?0:i-2, \
998 _p1##i = i-1<0?0:i-1, \
999 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
1000 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
1001 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
1002 _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
1003 i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
1004 i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
1005 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1006 #define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img).width,x0,x1,x)
1007 #define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img).height,y0,y1,y)
1008 #define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img).depth,z0,z1,z)
1009 #define cimg_for_in8V(img,v0,v1,v) cimg_for_in8((img).dim,v0,v1,v)
1010 #define cimg_for_in8XY(img,x0,y0,x1,y1,x,y) cimg_for_in8Y(img,y0,y1,y) cimg_for_in8X(img,x0,x1,x)
1011 #define cimg_for_in8XZ(img,x0,z0,x1,z1,x,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8X(img,x0,x1,x)
1012 #define cimg_for_in8XV(img,x0,v0,x1,v1,x,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8X(img,x0,x1,x)
1013 #define cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8Y(img,y0,y1,y)
1014 #define cimg_for_in8YV(img,y0,v0,y1,v1,y,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8Y(img,y0,y1,y)
1015 #define cimg_for_in8ZV(img,z0,v0,z1,v1,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8Z(img,z0,z1,z)
1016 #define cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8XY(img,x0,y0,x1,y1,x,y)
1017 #define cimg_for_in8XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8XZ(img,x0,y0,x1,y1,x,z)
1018 #define cimg_for_in8YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8YZ(img,y0,z0,y1,z1,y,z)
1019 #define cimg_for_in8XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
1021 #define cimg_for9(bound,i) \
1022 for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
1023 _n1##i = 1>=(int)(bound)?(int)(bound)-1:1, \
1024 _n2##i = 2>=(int)(bound)?(int)(bound)-1:2, \
1025 _n3##i = 3>=(int)(bound)?(int)(bound)-1:3, \
1026 _n4##i = 4>=(int)(bound)?(int)(bound)-1:4; \
1027 _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
1028 i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
1029 _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1030 #define cimg_for9X(img,x) cimg_for9((img).width,x)
1031 #define cimg_for9Y(img,y) cimg_for9((img).height,y)
1032 #define cimg_for9Z(img,z) cimg_for9((img).depth,z)
1033 #define cimg_for9V(img,v) cimg_for9((img).dim,v)
1034 #define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x)
1035 #define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x)
1036 #define cimg_for9XV(img,x,v) cimg_for9V(img,v) cimg_for9X(img,x)
1037 #define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y)
1038 #define cimg_for9YV(img,y,v) cimg_for9V(img,v) cimg_for9Y(img,y)
1039 #define cimg_for9ZV(img,z,v) cimg_for9V(img,v) cimg_for9Z(img,z)
1040 #define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y)
1041 #define cimg_for9XZV(img,x,z,v) cimg_for9V(img,v) cimg_for9XZ(img,x,z)
1042 #define cimg_for9YZV(img,y,z,v) cimg_for9V(img,v) cimg_for9YZ(img,y,z)
1043 #define cimg_for9XYZV(img,x,y,z,v) cimg_for9V(img,v) cimg_for9XYZ(img,x,y,z)
1045 #define cimg_for_in9(bound,i0,i1,i) \
1046 for (int i = (int)(i0)<0?0:(int)(i0), \
1047 _p4##i = i-4<0?0:i-4, \
1048 _p3##i = i-3<0?0:i-3, \
1049 _p2##i = i-2<0?0:i-2, \
1050 _p1##i = i-1<0?0:i-1, \
1051 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
1052 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
1053 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
1054 _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
1055 i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
1056 i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
1057 _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
1058 #define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img).width,x0,x1,x)
1059 #define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img).height,y0,y1,y)
1060 #define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img).depth,z0,z1,z)
1061 #define cimg_for_in9V(img,v0,v1,v) cimg_for_in9((img).dim,v0,v1,v)
1062 #define cimg_for_in9XY(img,x0,y0,x1,y1,x,y) cimg_for_in9Y(img,y0,y1,y) cimg_for_in9X(img,x0,x1,x)
1063 #define cimg_for_in9XZ(img,x0,z0,x1,z1,x,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9X(img,x0,x1,x)
1064 #define cimg_for_in9XV(img,x0,v0,x1,v1,x,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9X(img,x0,x1,x)
1065 #define cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9Y(img,y0,y1,y)
1066 #define cimg_for_in9YV(img,y0,v0,y1,v1,y,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9Y(img,y0,y1,y)
1067 #define cimg_for_in9ZV(img,z0,v0,z1,v1,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9Z(img,z0,z1,z)
1068 #define cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9XY(img,x0,y0,x1,y1,x,y)
1069 #define cimg_for_in9XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9XZ(img,x0,y0,x1,y1,x,z)
1070 #define cimg_for_in9YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9YZ(img,y0,z0,y1,z1,y,z)
1071 #define cimg_for_in9XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
1073 #define cimg_for2x2(img,x,y,z,v,I) \
1074 cimg_for2((img).height,y) for (int x = 0, \
1075 _n1##x = (int)( \
1076 (I[0] = (img)(0,y,z,v)), \
1077 (I[2] = (img)(0,_n1##y,z,v)), \
1078 1>=(img).width?(int)((img).width)-1:1); \
1079 (_n1##x<(int)((img).width) && ( \
1080 (I[1] = (img)(_n1##x,y,z,v)), \
1081 (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1082 x==--_n1##x; \
1083 I[0] = I[1], \
1084 I[2] = I[3], \
1085 ++x, ++_n1##x)
1087 #define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,v,I) \
1088 cimg_for_in2((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1089 _n1##x = (int)( \
1090 (I[0] = (img)(x,y,z,v)), \
1091 (I[2] = (img)(x,_n1##y,z,v)), \
1092 x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1093 x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
1094 (I[1] = (img)(_n1##x,y,z,v)), \
1095 (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1096 x==--_n1##x); \
1097 I[0] = I[1], \
1098 I[2] = I[3], \
1099 ++x, ++_n1##x)
1101 #define cimg_for3x3(img,x,y,z,v,I) \
1102 cimg_for3((img).height,y) for (int x = 0, \
1103 _p1##x = 0, \
1104 _n1##x = (int)( \
1105 (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
1106 (I[3] = I[4] = (img)(0,y,z,v)), \
1107 (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
1108 1>=(img).width?(int)((img).width)-1:1); \
1109 (_n1##x<(int)((img).width) && ( \
1110 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1111 (I[5] = (img)(_n1##x,y,z,v)), \
1112 (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1113 x==--_n1##x; \
1114 I[0] = I[1], I[1] = I[2], \
1115 I[3] = I[4], I[4] = I[5], \
1116 I[6] = I[7], I[7] = I[8], \
1117 _p1##x = x++, ++_n1##x)
1119 #define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,v,I) \
1120 cimg_for_in3((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1121 _p1##x = x-1<0?0:x-1, \
1122 _n1##x = (int)( \
1123 (I[0] = (img)(_p1##x,_p1##y,z,v)), \
1124 (I[3] = (img)(_p1##x,y,z,v)), \
1125 (I[6] = (img)(_p1##x,_n1##y,z,v)), \
1126 (I[1] = (img)(x,_p1##y,z,v)), \
1127 (I[4] = (img)(x,y,z,v)), \
1128 (I[7] = (img)(x,_n1##y,z,v)), \
1129 x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1130 x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
1131 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1132 (I[5] = (img)(_n1##x,y,z,v)), \
1133 (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
1134 x==--_n1##x); \
1135 I[0] = I[1], I[1] = I[2], \
1136 I[3] = I[4], I[4] = I[5], \
1137 I[6] = I[7], I[7] = I[8], \
1138 _p1##x = x++, ++_n1##x)
1140 #define cimg_for4x4(img,x,y,z,v,I) \
1141 cimg_for4((img).height,y) for (int x = 0, \
1142 _p1##x = 0, \
1143 _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1144 _n2##x = (int)( \
1145 (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
1146 (I[4] = I[5] = (img)(0,y,z,v)), \
1147 (I[8] = I[9] = (img)(0,_n1##y,z,v)), \
1148 (I[12] = I[13] = (img)(0,_n2##y,z,v)), \
1149 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1150 (I[6] = (img)(_n1##x,y,z,v)), \
1151 (I[10] = (img)(_n1##x,_n1##y,z,v)), \
1152 (I[14] = (img)(_n1##x,_n2##y,z,v)), \
1153 2>=(img).width?(int)((img).width)-1:2); \
1154 (_n2##x<(int)((img).width) && ( \
1155 (I[3] = (img)(_n2##x,_p1##y,z,v)), \
1156 (I[7] = (img)(_n2##x,y,z,v)), \
1157 (I[11] = (img)(_n2##x,_n1##y,z,v)), \
1158 (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1159 _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
1160 I[0] = I[1], I[1] = I[2], I[2] = I[3], \
1161 I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1162 I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1163 I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1164 _p1##x = x++, ++_n1##x, ++_n2##x)
1166 #define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,v,I) \
1167 cimg_for_in4((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1168 _p1##x = x-1<0?0:x-1, \
1169 _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1170 _n2##x = (int)( \
1171 (I[0] = (img)(_p1##x,_p1##y,z,v)), \
1172 (I[4] = (img)(_p1##x,y,z,v)), \
1173 (I[8] = (img)(_p1##x,_n1##y,z,v)), \
1174 (I[12] = (img)(_p1##x,_n2##y,z,v)), \
1175 (I[1] = (img)(x,_p1##y,z,v)), \
1176 (I[5] = (img)(x,y,z,v)), \
1177 (I[9] = (img)(x,_n1##y,z,v)), \
1178 (I[13] = (img)(x,_n2##y,z,v)), \
1179 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
1180 (I[6] = (img)(_n1##x,y,z,v)), \
1181 (I[10] = (img)(_n1##x,_n1##y,z,v)), \
1182 (I[14] = (img)(_n1##x,_n2##y,z,v)), \
1183 x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
1184 x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
1185 (I[3] = (img)(_n2##x,_p1##y,z,v)), \
1186 (I[7] = (img)(_n2##x,y,z,v)), \
1187 (I[11] = (img)(_n2##x,_n1##y,z,v)), \
1188 (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1189 _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
1190 I[0] = I[1], I[1] = I[2], I[2] = I[3], \
1191 I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1192 I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1193 I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1194 _p1##x = x++, ++_n1##x, ++_n2##x)
1196 #define cimg_for5x5(img,x,y,z,v,I) \
1197 cimg_for5((img).height,y) for (int x = 0, \
1198 _p2##x = 0, _p1##x = 0, \
1199 _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1200 _n2##x = (int)( \
1201 (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
1202 (I[5] = I[6] = I[7] = (img)(0,_p1##y,z,v)), \
1203 (I[10] = I[11] = I[12] = (img)(0,y,z,v)), \
1204 (I[15] = I[16] = I[17] = (img)(0,_n1##y,z,v)), \
1205 (I[20] = I[21] = I[22] = (img)(0,_n2##y,z,v)), \
1206 (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1207 (I[8] = (img)(_n1##x,_p1##y,z,v)), \
1208 (I[13] = (img)(_n1##x,y,z,v)), \
1209 (I[18] = (img)(_n1##x,_n1##y,z,v)), \
1210 (I[23] = (img)(_n1##x,_n2##y,z,v)), \
1211 2>=(img).width?(int)((img).width)-1:2); \
1212 (_n2##x<(int)((img).width) && ( \
1213 (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1214 (I[9] = (img)(_n2##x,_p1##y,z,v)), \
1215 (I[14] = (img)(_n2##x,y,z,v)), \
1216 (I[19] = (img)(_n2##x,_n1##y,z,v)), \
1217 (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1218 _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
1219 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
1220 I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
1221 I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
1222 I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
1223 I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
1224 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
1226 #define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,v,I) \
1227 cimg_for_in5((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1228 _p2##x = x-2<0?0:x-2, \
1229 _p1##x = x-1<0?0:x-1, \
1230 _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1231 _n2##x = (int)( \
1232 (I[0] = (img)(_p2##x,_p2##y,z,v)), \
1233 (I[5] = (img)(_p2##x,_p1##y,z,v)), \
1234 (I[10] = (img)(_p2##x,y,z,v)), \
1235 (I[15] = (img)(_p2##x,_n1##y,z,v)), \
1236 (I[20] = (img)(_p2##x,_n2##y,z,v)), \
1237 (I[1] = (img)(_p1##x,_p2##y,z,v)), \
1238 (I[6] = (img)(_p1##x,_p1##y,z,v)), \
1239 (I[11] = (img)(_p1##x,y,z,v)), \
1240 (I[16] = (img)(_p1##x,_n1##y,z,v)), \
1241 (I[21] = (img)(_p1##x,_n2##y,z,v)), \
1242 (I[2] = (img)(x,_p2##y,z,v)), \
1243 (I[7] = (img)(x,_p1##y,z,v)), \
1244 (I[12] = (img)(x,y,z,v)), \
1245 (I[17] = (img)(x,_n1##y,z,v)), \
1246 (I[22] = (img)(x,_n2##y,z,v)), \
1247 (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1248 (I[8] = (img)(_n1##x,_p1##y,z,v)), \
1249 (I[13] = (img)(_n1##x,y,z,v)), \
1250 (I[18] = (img)(_n1##x,_n1##y,z,v)), \
1251 (I[23] = (img)(_n1##x,_n2##y,z,v)), \
1252 x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
1253 x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
1254 (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1255 (I[9] = (img)(_n2##x,_p1##y,z,v)), \
1256 (I[14] = (img)(_n2##x,y,z,v)), \
1257 (I[19] = (img)(_n2##x,_n1##y,z,v)), \
1258 (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
1259 _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
1260 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
1261 I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
1262 I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
1263 I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
1264 I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
1265 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
1267 #define cimg_for6x6(img,x,y,z,v,I) \
1268 cimg_for6((img).height,y) for (int x = 0, \
1269 _p2##x = 0, _p1##x = 0, \
1270 _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1271 _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
1272 _n3##x = (int)( \
1273 (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
1274 (I[6] = I[7] = I[8] = (img)(0,_p1##y,z,v)), \
1275 (I[12] = I[13] = I[14] = (img)(0,y,z,v)), \
1276 (I[18] = I[19] = I[20] = (img)(0,_n1##y,z,v)), \
1277 (I[24] = I[25] = I[26] = (img)(0,_n2##y,z,v)), \
1278 (I[30] = I[31] = I[32] = (img)(0,_n3##y,z,v)), \
1279 (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1280 (I[9] = (img)(_n1##x,_p1##y,z,v)), \
1281 (I[15] = (img)(_n1##x,y,z,v)), \
1282 (I[21] = (img)(_n1##x,_n1##y,z,v)), \
1283 (I[27] = (img)(_n1##x,_n2##y,z,v)), \
1284 (I[33] = (img)(_n1##x,_n3##y,z,v)), \
1285 (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1286 (I[10] = (img)(_n2##x,_p1##y,z,v)), \
1287 (I[16] = (img)(_n2##x,y,z,v)), \
1288 (I[22] = (img)(_n2##x,_n1##y,z,v)), \
1289 (I[28] = (img)(_n2##x,_n2##y,z,v)), \
1290 (I[34] = (img)(_n2##x,_n3##y,z,v)), \
1291 3>=(img).width?(int)((img).width)-1:3); \
1292 (_n3##x<(int)((img).width) && ( \
1293 (I[5] = (img)(_n3##x,_p2##y,z,v)), \
1294 (I[11] = (img)(_n3##x,_p1##y,z,v)), \
1295 (I[17] = (img)(_n3##x,y,z,v)), \
1296 (I[23] = (img)(_n3##x,_n1##y,z,v)), \
1297 (I[29] = (img)(_n3##x,_n2##y,z,v)), \
1298 (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1299 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \
1300 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
1301 I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1302 I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
1303 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1304 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
1305 I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
1306 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1308 #define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,v,I) \
1309 cimg_for_in6((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \
1310 _p2##x = x-2<0?0:x-2, \
1311 _p1##x = x-1<0?0:x-1, \
1312 _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1313 _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
1314 _n3##x = (int)( \
1315 (I[0] = (img)(_p2##x,_p2##y,z,v)), \
1316 (I[6] = (img)(_p2##x,_p1##y,z,v)), \
1317 (I[12] = (img)(_p2##x,y,z,v)), \
1318 (I[18] = (img)(_p2##x,_n1##y,z,v)), \
1319 (I[24] = (img)(_p2##x,_n2##y,z,v)), \
1320 (I[30] = (img)(_p2##x,_n3##y,z,v)), \
1321 (I[1] = (img)(_p1##x,_p2##y,z,v)), \
1322 (I[7] = (img)(_p1##x,_p1##y,z,v)), \
1323 (I[13] = (img)(_p1##x,y,z,v)), \
1324 (I[19] = (img)(_p1##x,_n1##y,z,v)), \
1325 (I[25] = (img)(_p1##x,_n2##y,z,v)), \
1326 (I[31] = (img)(_p1##x,_n3##y,z,v)), \
1327 (I[2] = (img)(x,_p2##y,z,v)), \
1328 (I[8] = (img)(x,_p1##y,z,v)), \
1329 (I[14] = (img)(x,y,z,v)), \
1330 (I[20] = (img)(x,_n1##y,z,v)), \
1331 (I[26] = (img)(x,_n2##y,z,v)), \
1332 (I[32] = (img)(x,_n3##y,z,v)), \
1333 (I[3] = (img)(_n1##x,_p2##y,z,v)), \
1334 (I[9] = (img)(_n1##x,_p1##y,z,v)), \
1335 (I[15] = (img)(_n1##x,y,z,v)), \
1336 (I[21] = (img)(_n1##x,_n1##y,z,v)), \
1337 (I[27] = (img)(_n1##x,_n2##y,z,v)), \
1338 (I[33] = (img)(_n1##x,_n3##y,z,v)), \
1339 (I[4] = (img)(_n2##x,_p2##y,z,v)), \
1340 (I[10] = (img)(_n2##x,_p1##y,z,v)), \
1341 (I[16] = (img)(_n2##x,y,z,v)), \
1342 (I[22] = (img)(_n2##x,_n1##y,z,v)), \
1343 (I[28] = (img)(_n2##x,_n2##y,z,v)), \
1344 (I[34] = (img)(_n2##x,_n3##y,z,v)), \
1345 x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
1346 x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
1347 (I[5] = (img)(_n3##x,_p2##y,z,v)), \
1348 (I[11] = (img)(_n3##x,_p1##y,z,v)), \
1349 (I[17] = (img)(_n3##x,y,z,v)), \
1350 (I[23] = (img)(_n3##x,_n1##y,z,v)), \
1351 (I[29] = (img)(_n3##x,_n2##y,z,v)), \
1352 (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1353 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \
1354 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
1355 I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
1356 I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
1357 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1358 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
1359 I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
1360 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1362 #define cimg_for7x7(img,x,y,z,v,I) \
1363 cimg_for7((img).height,y) for (int x = 0, \
1364 _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1365 _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
1366 _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
1367 _n3##x = (int)( \
1368 (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
1369 (I[7] = I[8] = I[9] = I[10] = (img)(0,_p2##y,z,v)), \
1370 (I[14] = I[15] = I[16] = I[17] = (img)(0,_p1##y,z,v)), \
1371 (I[21] = I[22] = I[23] = I[24] = (img)(0,y,z,v)), \
1372 (I[28] = I[29] = I[30] = I[31] = (img)(0,_n1##y,z,v)), \
1373 (I[35] = I[36] = I[37] = I[38] = (img)(0,_n2##y,z,v)), \
1374 (I[42] = I[43] = I[44] = I[45] = (img)(0,_n3##y,z,v)), \
1375 (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1376 (I[11] = (img)(_n1##x,_p2##y,z,v)), \
1377 (I[18] = (img)(_n1##x,_p1##y,z,v)), \
1378 (I[25] = (img)(_n1##x,y,z,v)), \
1379 (I[32] = (img)(_n1##x,_n1##y,z,v)), \
1380 (I[39] = (img)(_n1##x,_n2##y,z,v)), \
1381 (I[46] = (img)(_n1##x,_n3##y,z,v)), \
1382 (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1383 (I[12] = (img)(_n2##x,_p2##y,z,v)), \
1384 (I[19] = (img)(_n2##x,_p1##y,z,v)), \
1385 (I[26] = (img)(_n2##x,y,z,v)), \
1386 (I[33] = (img)(_n2##x,_n1##y,z,v)), \
1387 (I[40] = (img)(_n2##x,_n2##y,z,v)), \
1388 (I[47] = (img)(_n2##x,_n3##y,z,v)), \
1389 3>=(img).width?(int)((img).width)-1:3); \
1390 (_n3##x<(int)((img).width) && ( \
1391 (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1392 (I[13] = (img)(_n3##x,_p2##y,z,v)), \
1393 (I[20] = (img)(_n3##x,_p1##y,z,v)), \
1394 (I[27] = (img)(_n3##x,y,z,v)), \
1395 (I[34] = (img)(_n3##x,_n1##y,z,v)), \
1396 (I[41] = (img)(_n3##x,_n2##y,z,v)), \
1397 (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1398 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \
1399 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
1400 I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
1401 I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
1402 I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
1403 I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
1404 I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
1405 I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
1406 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1408 #define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,v,I) \
1409 cimg_for_in7((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1410 _p3##x = x-3<0?0:x-3, \
1411 _p2##x = x-2<0?0:x-2, \
1412 _p1##x = x-1<0?0:x-1, \
1413 _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
1414 _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
1415 _n3##x = (int)( \
1416 (I[0] = (img)(_p3##x,_p3##y,z,v)), \
1417 (I[7] = (img)(_p3##x,_p2##y,z,v)), \
1418 (I[14] = (img)(_p3##x,_p1##y,z,v)), \
1419 (I[21] = (img)(_p3##x,y,z,v)), \
1420 (I[28] = (img)(_p3##x,_n1##y,z,v)), \
1421 (I[35] = (img)(_p3##x,_n2##y,z,v)), \
1422 (I[42] = (img)(_p3##x,_n3##y,z,v)), \
1423 (I[1] = (img)(_p2##x,_p3##y,z,v)), \
1424 (I[8] = (img)(_p2##x,_p2##y,z,v)), \
1425 (I[15] = (img)(_p2##x,_p1##y,z,v)), \
1426 (I[22] = (img)(_p2##x,y,z,v)), \
1427 (I[29] = (img)(_p2##x,_n1##y,z,v)), \
1428 (I[36] = (img)(_p2##x,_n2##y,z,v)), \
1429 (I[43] = (img)(_p2##x,_n3##y,z,v)), \
1430 (I[2] = (img)(_p1##x,_p3##y,z,v)), \
1431 (I[9] = (img)(_p1##x,_p2##y,z,v)), \
1432 (I[16] = (img)(_p1##x,_p1##y,z,v)), \
1433 (I[23] = (img)(_p1##x,y,z,v)), \
1434 (I[30] = (img)(_p1##x,_n1##y,z,v)), \
1435 (I[37] = (img)(_p1##x,_n2##y,z,v)), \
1436 (I[44] = (img)(_p1##x,_n3##y,z,v)), \
1437 (I[3] = (img)(x,_p3##y,z,v)), \
1438 (I[10] = (img)(x,_p2##y,z,v)), \
1439 (I[17] = (img)(x,_p1##y,z,v)), \
1440 (I[24] = (img)(x,y,z,v)), \
1441 (I[31] = (img)(x,_n1##y,z,v)), \
1442 (I[38] = (img)(x,_n2##y,z,v)), \
1443 (I[45] = (img)(x,_n3##y,z,v)), \
1444 (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1445 (I[11] = (img)(_n1##x,_p2##y,z,v)), \
1446 (I[18] = (img)(_n1##x,_p1##y,z,v)), \
1447 (I[25] = (img)(_n1##x,y,z,v)), \
1448 (I[32] = (img)(_n1##x,_n1##y,z,v)), \
1449 (I[39] = (img)(_n1##x,_n2##y,z,v)), \
1450 (I[46] = (img)(_n1##x,_n3##y,z,v)), \
1451 (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1452 (I[12] = (img)(_n2##x,_p2##y,z,v)), \
1453 (I[19] = (img)(_n2##x,_p1##y,z,v)), \
1454 (I[26] = (img)(_n2##x,y,z,v)), \
1455 (I[33] = (img)(_n2##x,_n1##y,z,v)), \
1456 (I[40] = (img)(_n2##x,_n2##y,z,v)), \
1457 (I[47] = (img)(_n2##x,_n3##y,z,v)), \
1458 x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
1459 x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
1460 (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1461 (I[13] = (img)(_n3##x,_p2##y,z,v)), \
1462 (I[20] = (img)(_n3##x,_p1##y,z,v)), \
1463 (I[27] = (img)(_n3##x,y,z,v)), \
1464 (I[34] = (img)(_n3##x,_n1##y,z,v)), \
1465 (I[41] = (img)(_n3##x,_n2##y,z,v)), \
1466 (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
1467 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \
1468 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
1469 I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
1470 I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
1471 I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
1472 I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
1473 I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
1474 I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
1475 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
1477 #define cimg_for8x8(img,x,y,z,v,I) \
1478 cimg_for8((img).height,y) for (int x = 0, \
1479 _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1480 _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
1481 _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
1482 _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
1483 _n4##x = (int)( \
1484 (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
1485 (I[8] = I[9] = I[10] = I[11] = (img)(0,_p2##y,z,v)), \
1486 (I[16] = I[17] = I[18] = I[19] = (img)(0,_p1##y,z,v)), \
1487 (I[24] = I[25] = I[26] = I[27] = (img)(0,y,z,v)), \
1488 (I[32] = I[33] = I[34] = I[35] = (img)(0,_n1##y,z,v)), \
1489 (I[40] = I[41] = I[42] = I[43] = (img)(0,_n2##y,z,v)), \
1490 (I[48] = I[49] = I[50] = I[51] = (img)(0,_n3##y,z,v)), \
1491 (I[56] = I[57] = I[58] = I[59] = (img)(0,_n4##y,z,v)), \
1492 (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1493 (I[12] = (img)(_n1##x,_p2##y,z,v)), \
1494 (I[20] = (img)(_n1##x,_p1##y,z,v)), \
1495 (I[28] = (img)(_n1##x,y,z,v)), \
1496 (I[36] = (img)(_n1##x,_n1##y,z,v)), \
1497 (I[44] = (img)(_n1##x,_n2##y,z,v)), \
1498 (I[52] = (img)(_n1##x,_n3##y,z,v)), \
1499 (I[60] = (img)(_n1##x,_n4##y,z,v)), \
1500 (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1501 (I[13] = (img)(_n2##x,_p2##y,z,v)), \
1502 (I[21] = (img)(_n2##x,_p1##y,z,v)), \
1503 (I[29] = (img)(_n2##x,y,z,v)), \
1504 (I[37] = (img)(_n2##x,_n1##y,z,v)), \
1505 (I[45] = (img)(_n2##x,_n2##y,z,v)), \
1506 (I[53] = (img)(_n2##x,_n3##y,z,v)), \
1507 (I[61] = (img)(_n2##x,_n4##y,z,v)), \
1508 (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1509 (I[14] = (img)(_n3##x,_p2##y,z,v)), \
1510 (I[22] = (img)(_n3##x,_p1##y,z,v)), \
1511 (I[30] = (img)(_n3##x,y,z,v)), \
1512 (I[38] = (img)(_n3##x,_n1##y,z,v)), \
1513 (I[46] = (img)(_n3##x,_n2##y,z,v)), \
1514 (I[54] = (img)(_n3##x,_n3##y,z,v)), \
1515 (I[62] = (img)(_n3##x,_n4##y,z,v)), \
1516 4>=((img).width)?(int)((img).width)-1:4); \
1517 (_n4##x<(int)((img).width) && ( \
1518 (I[7] = (img)(_n4##x,_p3##y,z,v)), \
1519 (I[15] = (img)(_n4##x,_p2##y,z,v)), \
1520 (I[23] = (img)(_n4##x,_p1##y,z,v)), \
1521 (I[31] = (img)(_n4##x,y,z,v)), \
1522 (I[39] = (img)(_n4##x,_n1##y,z,v)), \
1523 (I[47] = (img)(_n4##x,_n2##y,z,v)), \
1524 (I[55] = (img)(_n4##x,_n3##y,z,v)), \
1525 (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1526 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
1527 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1528 I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1529 I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1530 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \
1531 I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \
1532 I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \
1533 I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \
1534 I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \
1535 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1537 #define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,v,I) \
1538 cimg_for_in8((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1539 _p3##x = x-3<0?0:x-3, \
1540 _p2##x = x-2<0?0:x-2, \
1541 _p1##x = x-1<0?0:x-1, \
1542 _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
1543 _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
1544 _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
1545 _n4##x = (int)( \
1546 (I[0] = (img)(_p3##x,_p3##y,z,v)), \
1547 (I[8] = (img)(_p3##x,_p2##y,z,v)), \
1548 (I[16] = (img)(_p3##x,_p1##y,z,v)), \
1549 (I[24] = (img)(_p3##x,y,z,v)), \
1550 (I[32] = (img)(_p3##x,_n1##y,z,v)), \
1551 (I[40] = (img)(_p3##x,_n2##y,z,v)), \
1552 (I[48] = (img)(_p3##x,_n3##y,z,v)), \
1553 (I[56] = (img)(_p3##x,_n4##y,z,v)), \
1554 (I[1] = (img)(_p2##x,_p3##y,z,v)), \
1555 (I[9] = (img)(_p2##x,_p2##y,z,v)), \
1556 (I[17] = (img)(_p2##x,_p1##y,z,v)), \
1557 (I[25] = (img)(_p2##x,y,z,v)), \
1558 (I[33] = (img)(_p2##x,_n1##y,z,v)), \
1559 (I[41] = (img)(_p2##x,_n2##y,z,v)), \
1560 (I[49] = (img)(_p2##x,_n3##y,z,v)), \
1561 (I[57] = (img)(_p2##x,_n4##y,z,v)), \
1562 (I[2] = (img)(_p1##x,_p3##y,z,v)), \
1563 (I[10] = (img)(_p1##x,_p2##y,z,v)), \
1564 (I[18] = (img)(_p1##x,_p1##y,z,v)), \
1565 (I[26] = (img)(_p1##x,y,z,v)), \
1566 (I[34] = (img)(_p1##x,_n1##y,z,v)), \
1567 (I[42] = (img)(_p1##x,_n2##y,z,v)), \
1568 (I[50] = (img)(_p1##x,_n3##y,z,v)), \
1569 (I[58] = (img)(_p1##x,_n4##y,z,v)), \
1570 (I[3] = (img)(x,_p3##y,z,v)), \
1571 (I[11] = (img)(x,_p2##y,z,v)), \
1572 (I[19] = (img)(x,_p1##y,z,v)), \
1573 (I[27] = (img)(x,y,z,v)), \
1574 (I[35] = (img)(x,_n1##y,z,v)), \
1575 (I[43] = (img)(x,_n2##y,z,v)), \
1576 (I[51] = (img)(x,_n3##y,z,v)), \
1577 (I[59] = (img)(x,_n4##y,z,v)), \
1578 (I[4] = (img)(_n1##x,_p3##y,z,v)), \
1579 (I[12] = (img)(_n1##x,_p2##y,z,v)), \
1580 (I[20] = (img)(_n1##x,_p1##y,z,v)), \
1581 (I[28] = (img)(_n1##x,y,z,v)), \
1582 (I[36] = (img)(_n1##x,_n1##y,z,v)), \
1583 (I[44] = (img)(_n1##x,_n2##y,z,v)), \
1584 (I[52] = (img)(_n1##x,_n3##y,z,v)), \
1585 (I[60] = (img)(_n1##x,_n4##y,z,v)), \
1586 (I[5] = (img)(_n2##x,_p3##y,z,v)), \
1587 (I[13] = (img)(_n2##x,_p2##y,z,v)), \
1588 (I[21] = (img)(_n2##x,_p1##y,z,v)), \
1589 (I[29] = (img)(_n2##x,y,z,v)), \
1590 (I[37] = (img)(_n2##x,_n1##y,z,v)), \
1591 (I[45] = (img)(_n2##x,_n2##y,z,v)), \
1592 (I[53] = (img)(_n2##x,_n3##y,z,v)), \
1593 (I[61] = (img)(_n2##x,_n4##y,z,v)), \
1594 (I[6] = (img)(_n3##x,_p3##y,z,v)), \
1595 (I[14] = (img)(_n3##x,_p2##y,z,v)), \
1596 (I[22] = (img)(_n3##x,_p1##y,z,v)), \
1597 (I[30] = (img)(_n3##x,y,z,v)), \
1598 (I[38] = (img)(_n3##x,_n1##y,z,v)), \
1599 (I[46] = (img)(_n3##x,_n2##y,z,v)), \
1600 (I[54] = (img)(_n3##x,_n3##y,z,v)), \
1601 (I[62] = (img)(_n3##x,_n4##y,z,v)), \
1602 x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
1603 x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
1604 (I[7] = (img)(_n4##x,_p3##y,z,v)), \
1605 (I[15] = (img)(_n4##x,_p2##y,z,v)), \
1606 (I[23] = (img)(_n4##x,_p1##y,z,v)), \
1607 (I[31] = (img)(_n4##x,y,z,v)), \
1608 (I[39] = (img)(_n4##x,_n1##y,z,v)), \
1609 (I[47] = (img)(_n4##x,_n2##y,z,v)), \
1610 (I[55] = (img)(_n4##x,_n3##y,z,v)), \
1611 (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1612 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
1613 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \
1614 I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \
1615 I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
1616 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \
1617 I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \
1618 I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \
1619 I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \
1620 I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \
1621 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1623 #define cimg_for9x9(img,x,y,z,v,I) \
1624 cimg_for9((img).height,y) for (int x = 0, \
1625 _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \
1626 _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
1627 _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
1628 _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
1629 _n4##x = (int)( \
1630 (I[0] = I[1] = I[2] = I[3] = I[4] = (img)(0,_p4##y,z,v)), \
1631 (I[9] = I[10] = I[11] = I[12] = I[13] = (img)(0,_p3##y,z,v)), \
1632 (I[18] = I[19] = I[20] = I[21] = I[22] = (img)(0,_p2##y,z,v)), \
1633 (I[27] = I[28] = I[29] = I[30] = I[31] = (img)(0,_p1##y,z,v)), \
1634 (I[36] = I[37] = I[38] = I[39] = I[40] = (img)(0,y,z,v)), \
1635 (I[45] = I[46] = I[47] = I[48] = I[49] = (img)(0,_n1##y,z,v)), \
1636 (I[54] = I[55] = I[56] = I[57] = I[58] = (img)(0,_n2##y,z,v)), \
1637 (I[63] = I[64] = I[65] = I[66] = I[67] = (img)(0,_n3##y,z,v)), \
1638 (I[72] = I[73] = I[74] = I[75] = I[76] = (img)(0,_n4##y,z,v)), \
1639 (I[5] = (img)(_n1##x,_p4##y,z,v)), \
1640 (I[14] = (img)(_n1##x,_p3##y,z,v)), \
1641 (I[23] = (img)(_n1##x,_p2##y,z,v)), \
1642 (I[32] = (img)(_n1##x,_p1##y,z,v)), \
1643 (I[41] = (img)(_n1##x,y,z,v)), \
1644 (I[50] = (img)(_n1##x,_n1##y,z,v)), \
1645 (I[59] = (img)(_n1##x,_n2##y,z,v)), \
1646 (I[68] = (img)(_n1##x,_n3##y,z,v)), \
1647 (I[77] = (img)(_n1##x,_n4##y,z,v)), \
1648 (I[6] = (img)(_n2##x,_p4##y,z,v)), \
1649 (I[15] = (img)(_n2##x,_p3##y,z,v)), \
1650 (I[24] = (img)(_n2##x,_p2##y,z,v)), \
1651 (I[33] = (img)(_n2##x,_p1##y,z,v)), \
1652 (I[42] = (img)(_n2##x,y,z,v)), \
1653 (I[51] = (img)(_n2##x,_n1##y,z,v)), \
1654 (I[60] = (img)(_n2##x,_n2##y,z,v)), \
1655 (I[69] = (img)(_n2##x,_n3##y,z,v)), \
1656 (I[78] = (img)(_n2##x,_n4##y,z,v)), \
1657 (I[7] = (img)(_n3##x,_p4##y,z,v)), \
1658 (I[16] = (img)(_n3##x,_p3##y,z,v)), \
1659 (I[25] = (img)(_n3##x,_p2##y,z,v)), \
1660 (I[34] = (img)(_n3##x,_p1##y,z,v)), \
1661 (I[43] = (img)(_n3##x,y,z,v)), \
1662 (I[52] = (img)(_n3##x,_n1##y,z,v)), \
1663 (I[61] = (img)(_n3##x,_n2##y,z,v)), \
1664 (I[70] = (img)(_n3##x,_n3##y,z,v)), \
1665 (I[79] = (img)(_n3##x,_n4##y,z,v)), \
1666 4>=((img).width)?(int)((img).width)-1:4); \
1667 (_n4##x<(int)((img).width) && ( \
1668 (I[8] = (img)(_n4##x,_p4##y,z,v)), \
1669 (I[17] = (img)(_n4##x,_p3##y,z,v)), \
1670 (I[26] = (img)(_n4##x,_p2##y,z,v)), \
1671 (I[35] = (img)(_n4##x,_p1##y,z,v)), \
1672 (I[44] = (img)(_n4##x,y,z,v)), \
1673 (I[53] = (img)(_n4##x,_n1##y,z,v)), \
1674 (I[62] = (img)(_n4##x,_n2##y,z,v)), \
1675 (I[71] = (img)(_n4##x,_n3##y,z,v)), \
1676 (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1677 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
1678 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \
1679 I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
1680 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], \
1681 I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
1682 I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], \
1683 I[45] = I[46], I[46] = I[47], I[47] = I[48], I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], \
1684 I[54] = I[55], I[55] = I[56], I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], \
1685 I[63] = I[64], I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \
1686 I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], I[79] = I[80], \
1687 _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1689 #define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,v,I) \
1690 cimg_for_in9((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1691 _p4##x = x-4<0?0:x-4, \
1692 _p3##x = x-3<0?0:x-3, \
1693 _p2##x = x-2<0?0:x-2, \
1694 _p1##x = x-1<0?0:x-1, \
1695 _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
1696 _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
1697 _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
1698 _n4##x = (int)( \
1699 (I[0] = (img)(_p4##x,_p4##y,z,v)), \
1700 (I[9] = (img)(_p4##x,_p3##y,z,v)), \
1701 (I[18] = (img)(_p4##x,_p2##y,z,v)), \
1702 (I[27] = (img)(_p4##x,_p1##y,z,v)), \
1703 (I[36] = (img)(_p4##x,y,z,v)), \
1704 (I[45] = (img)(_p4##x,_n1##y,z,v)), \
1705 (I[54] = (img)(_p4##x,_n2##y,z,v)), \
1706 (I[63] = (img)(_p4##x,_n3##y,z,v)), \
1707 (I[72] = (img)(_p4##x,_n4##y,z,v)), \
1708 (I[1] = (img)(_p3##x,_p4##y,z,v)), \
1709 (I[10] = (img)(_p3##x,_p3##y,z,v)), \
1710 (I[19] = (img)(_p3##x,_p2##y,z,v)), \
1711 (I[28] = (img)(_p3##x,_p1##y,z,v)), \
1712 (I[37] = (img)(_p3##x,y,z,v)), \
1713 (I[46] = (img)(_p3##x,_n1##y,z,v)), \
1714 (I[55] = (img)(_p3##x,_n2##y,z,v)), \
1715 (I[64] = (img)(_p3##x,_n3##y,z,v)), \
1716 (I[73] = (img)(_p3##x,_n4##y,z,v)), \
1717 (I[2] = (img)(_p2##x,_p4##y,z,v)), \
1718 (I[11] = (img)(_p2##x,_p3##y,z,v)), \
1719 (I[20] = (img)(_p2##x,_p2##y,z,v)), \
1720 (I[29] = (img)(_p2##x,_p1##y,z,v)), \
1721 (I[38] = (img)(_p2##x,y,z,v)), \
1722 (I[47] = (img)(_p2##x,_n1##y,z,v)), \
1723 (I[56] = (img)(_p2##x,_n2##y,z,v)), \
1724 (I[65] = (img)(_p2##x,_n3##y,z,v)), \
1725 (I[74] = (img)(_p2##x,_n4##y,z,v)), \
1726 (I[3] = (img)(_p1##x,_p4##y,z,v)), \
1727 (I[12] = (img)(_p1##x,_p3##y,z,v)), \
1728 (I[21] = (img)(_p1##x,_p2##y,z,v)), \
1729 (I[30] = (img)(_p1##x,_p1##y,z,v)), \
1730 (I[39] = (img)(_p1##x,y,z,v)), \
1731 (I[48] = (img)(_p1##x,_n1##y,z,v)), \
1732 (I[57] = (img)(_p1##x,_n2##y,z,v)), \
1733 (I[66] = (img)(_p1##x,_n3##y,z,v)), \
1734 (I[75] = (img)(_p1##x,_n4##y,z,v)), \
1735 (I[4] = (img)(x,_p4##y,z,v)), \
1736 (I[13] = (img)(x,_p3##y,z,v)), \
1737 (I[22] = (img)(x,_p2##y,z,v)), \
1738 (I[31] = (img)(x,_p1##y,z,v)), \
1739 (I[40] = (img)(x,y,z,v)), \
1740 (I[49] = (img)(x,_n1##y,z,v)), \
1741 (I[58] = (img)(x,_n2##y,z,v)), \
1742 (I[67] = (img)(x,_n3##y,z,v)), \
1743 (I[76] = (img)(x,_n4##y,z,v)), \
1744 (I[5] = (img)(_n1##x,_p4##y,z,v)), \
1745 (I[14] = (img)(_n1##x,_p3##y,z,v)), \
1746 (I[23] = (img)(_n1##x,_p2##y,z,v)), \
1747 (I[32] = (img)(_n1##x,_p1##y,z,v)), \
1748 (I[41] = (img)(_n1##x,y,z,v)), \
1749 (I[50] = (img)(_n1##x,_n1##y,z,v)), \
1750 (I[59] = (img)(_n1##x,_n2##y,z,v)), \
1751 (I[68] = (img)(_n1##x,_n3##y,z,v)), \
1752 (I[77] = (img)(_n1##x,_n4##y,z,v)), \
1753 (I[6] = (img)(_n2##x,_p4##y,z,v)), \
1754 (I[15] = (img)(_n2##x,_p3##y,z,v)), \
1755 (I[24] = (img)(_n2##x,_p2##y,z,v)), \
1756 (I[33] = (img)(_n2##x,_p1##y,z,v)), \
1757 (I[42] = (img)(_n2##x,y,z,v)), \
1758 (I[51] = (img)(_n2##x,_n1##y,z,v)), \
1759 (I[60] = (img)(_n2##x,_n2##y,z,v)), \
1760 (I[69] = (img)(_n2##x,_n3##y,z,v)), \
1761 (I[78] = (img)(_n2##x,_n4##y,z,v)), \
1762 (I[7] = (img)(_n3##x,_p4##y,z,v)), \
1763 (I[16] = (img)(_n3##x,_p3##y,z,v)), \
1764 (I[25] = (img)(_n3##x,_p2##y,z,v)), \
1765 (I[34] = (img)(_n3##x,_p1##y,z,v)), \
1766 (I[43] = (img)(_n3##x,y,z,v)), \
1767 (I[52] = (img)(_n3##x,_n1##y,z,v)), \
1768 (I[61] = (img)(_n3##x,_n2##y,z,v)), \
1769 (I[70] = (img)(_n3##x,_n3##y,z,v)), \
1770 (I[79] = (img)(_n3##x,_n4##y,z,v)), \
1771 x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
1772 x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
1773 (I[8] = (img)(_n4##x,_p4##y,z,v)), \
1774 (I[17] = (img)(_n4##x,_p3##y,z,v)), \
1775 (I[26] = (img)(_n4##x,_p2##y,z,v)), \
1776 (I[35] = (img)(_n4##x,_p1##y,z,v)), \
1777 (I[44] = (img)(_n4##x,y,z,v)), \
1778 (I[53] = (img)(_n4##x,_n1##y,z,v)), \
1779 (I[62] = (img)(_n4##x,_n2##y,z,v)), \
1780 (I[71] = (img)(_n4##x,_n3##y,z,v)), \
1781 (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
1782 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
1783 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \
1784 I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
1785 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], \
1786 I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
1787 I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], \
1788 I[45] = I[46], I[46] = I[47], I[47] = I[48], I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], \
1789 I[54] = I[55], I[55] = I[56], I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], \
1790 I[63] = I[64], I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \
1791 I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], I[79] = I[80], \
1792 _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
1794 #define cimg_for2x2x2(img,x,y,z,v,I) \
1795 cimg_for2((img).depth,z) cimg_for2((img).height,y) for (int x = 0, \
1796 _n1##x = (int)( \
1797 (I[0] = (img)(0,y,z,v)), \
1798 (I[2] = (img)(0,_n1##y,z,v)), \
1799 (I[4] = (img)(0,y,_n1##z,v)), \
1800 (I[6] = (img)(0,_n1##y,_n1##z,v)), \
1801 1>=(img).width?(int)((img).width)-1:1); \
1802 (_n1##x<(int)((img).width) && ( \
1803 (I[1] = (img)(_n1##x,y,z,v)), \
1804 (I[3] = (img)(_n1##x,_n1##y,z,v)), \
1805 (I[5] = (img)(_n1##x,y,_n1##z,v)), \
1806 (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1807 x==--_n1##x; \
1808 I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
1809 ++x, ++_n1##x)
1811 #define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
1812 cimg_for_in2((img).depth,z0,z1,z) cimg_for_in2((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1813 _n1##x = (int)( \
1814 (I[0] = (img)(x,y,z,v)), \
1815 (I[2] = (img)(x,_n1##y,z,v)), \
1816 (I[4] = (img)(x,y,_n1##z,v)), \
1817 (I[6] = (img)(x,_n1##y,_n1##z,v)), \
1818 x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1819 x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
1820 (I[1] = (img)(_n1##x,y,z,v)), \
1821 (I[3] = (img)(_n1##x,_n1##y,z,v)), \
1822 (I[5] = (img)(_n1##x,y,_n1##z,v)), \
1823 (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1824 x==--_n1##x); \
1825 I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
1826 ++x, ++_n1##x)
1828 #define cimg_for3x3x3(img,x,y,z,v,I) \
1829 cimg_for3((img).depth,z) cimg_for3((img).height,y) for (int x = 0, \
1830 _p1##x = 0, \
1831 _n1##x = (int)( \
1832 (I[0] = I[1] = (img)(0,_p1##y,_p1##z,v)), \
1833 (I[3] = I[4] = (img)(0,y,_p1##z,v)), \
1834 (I[6] = I[7] = (img)(0,_n1##y,_p1##z,v)), \
1835 (I[9] = I[10] = (img)(0,_p1##y,z,v)), \
1836 (I[12] = I[13] = (img)(0,y,z,v)), \
1837 (I[15] = I[16] = (img)(0,_n1##y,z,v)), \
1838 (I[18] = I[19] = (img)(0,_p1##y,_n1##z,v)), \
1839 (I[21] = I[22] = (img)(0,y,_n1##z,v)), \
1840 (I[24] = I[25] = (img)(0,_n1##y,_n1##z,v)), \
1841 1>=(img).width?(int)((img).width)-1:1); \
1842 (_n1##x<(int)((img).width) && ( \
1843 (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
1844 (I[5] = (img)(_n1##x,y,_p1##z,v)), \
1845 (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
1846 (I[11] = (img)(_n1##x,_p1##y,z,v)), \
1847 (I[14] = (img)(_n1##x,y,z,v)), \
1848 (I[17] = (img)(_n1##x,_n1##y,z,v)), \
1849 (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
1850 (I[23] = (img)(_n1##x,y,_n1##z,v)), \
1851 (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1852 x==--_n1##x; \
1853 I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
1854 I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
1855 I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
1856 _p1##x = x++, ++_n1##x)
1858 #define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
1859 cimg_for_in3((img).depth,z0,z1,z) cimg_for_in3((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
1860 _p1##x = x-1<0?0:x-1, \
1861 _n1##x = (int)( \
1862 (I[0] = (img)(_p1##x,_p1##y,_p1##z,v)), \
1863 (I[3] = (img)(_p1##x,y,_p1##z,v)), \
1864 (I[6] = (img)(_p1##x,_n1##y,_p1##z,v)), \
1865 (I[9] = (img)(_p1##x,_p1##y,z,v)), \
1866 (I[12] = (img)(_p1##x,y,z,v)), \
1867 (I[15] = (img)(_p1##x,_n1##y,z,v)), \
1868 (I[18] = (img)(_p1##x,_p1##y,_n1##z,v)), \
1869 (I[21] = (img)(_p1##x,y,_n1##z,v)), \
1870 (I[24] = (img)(_p1##x,_n1##y,_n1##z,v)), \
1871 (I[1] = (img)(x,_p1##y,_p1##z,v)), \
1872 (I[4] = (img)(x,y,_p1##z,v)), \
1873 (I[7] = (img)(x,_n1##y,_p1##z,v)), \
1874 (I[10] = (img)(x,_p1##y,z,v)), \
1875 (I[13] = (img)(x,y,z,v)), \
1876 (I[16] = (img)(x,_n1##y,z,v)), \
1877 (I[19] = (img)(x,_p1##y,_n1##z,v)), \
1878 (I[22] = (img)(x,y,_n1##z,v)), \
1879 (I[25] = (img)(x,_n1##y,_n1##z,v)), \
1880 x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
1881 x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
1882 (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
1883 (I[5] = (img)(_n1##x,y,_p1##z,v)), \
1884 (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
1885 (I[11] = (img)(_n1##x,_p1##y,z,v)), \
1886 (I[14] = (img)(_n1##x,y,z,v)), \
1887 (I[17] = (img)(_n1##x,_n1##y,z,v)), \
1888 (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
1889 (I[23] = (img)(_n1##x,y,_n1##z,v)), \
1890 (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
1891 x==--_n1##x); \
1892 I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
1893 I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
1894 I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
1895 _p1##x = x++, ++_n1##x)
1897 /*------------------------------------------------
1898 #
1899 #
1900 # Definition of the cimg_library:: namespace
1901 #
1902 #
1903 -------------------------------------------------*/
1904 //! This namespace encompasses all classes and functions of the %CImg library.
1905 /**
1906 This namespace is defined to avoid functions and class names collisions
1907 that could happen with the include of other C++ header files.
1908 Anyway, it should not happen often and you should reasonnably start most of your
1909 %CImg-based programs with
1910 \code
1911 #include "CImg.h"
1912 using namespace cimg_library;
1913 \endcode
1914 to simplify the declaration of %CImg Library variables afterwards.
1915 **/
1916 namespace cimg_library {
1918 // Declare the only four classes of the CImg Library.
1919 //
1920 template<typename T=float> struct CImg;
1921 template<typename T=float> struct CImgList;
1922 struct CImgDisplay;
1923 struct CImgException;
1925 // (Pre)declare the cimg namespace.
1926 // This is not the complete namespace declaration. It only contains some
1927 // necessary stuffs to ensure a correct declaration order of classes and functions
1928 // defined afterwards.
1929 //
1930 namespace cimg {
1932 #ifdef cimg_use_vt100
1933 const char t_normal[] = { 0x1b,'[','0',';','0',';','0','m','\0' };
1934 const char t_red[] = { 0x1b,'[','4',';','3','1',';','5','9','m','\0' };
1935 const char t_bold[] = { 0x1b,'[','1','m','\0' };
1936 const char t_purple[] = { 0x1b,'[','0',';','3','5',';','5','9','m','\0' };
1937 const char t_green[] = { 0x1b,'[','0',';','3','2',';','5','9','m','\0' };
1938 #else
1939 const char t_normal[] = { '\0' };
1940 const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal,
1941 *const t_purple = cimg::t_normal, *const t_green = cimg::t_normal;
1942 #endif
1944 inline void info();
1946 //! Get/set the current CImg exception mode.
1947 /**
1948 The way error messages are handled by CImg can be changed dynamically, using this function.
1949 Possible values are :
1950 - 0 to hide debug messages (quiet mode, but exceptions are still thrown).
1951 - 1 to display debug messages on standard error (console).
1952 - 2 to display debug messages in modal windows (default behavior).
1953 - 3 to do as 1 + add extra warnings (may slow down the code !).
1954 - 4 to do as 2 + add extra warnings (may slow down the code !).
1955 **/
1956 inline unsigned int& exception_mode() { static unsigned int mode = cimg_debug; return mode; }
1958 inline int dialog(const char *title, const char *msg, const char *button1_txt="OK",
1959 const char *button2_txt=0, const char *button3_txt=0,
1960 const char *button4_txt=0, const char *button5_txt=0,
1961 const char *button6_txt=0, const bool centering=false);
1962 }
1964 /*----------------------------------------------
1965 #
1966 # Definition of the CImgException structures
1967 #
1968 ----------------------------------------------*/
1969 //! Instances of this class are thrown when errors occur during a %CImg library function call.
1970 /**
1971 \section ex1 Overview
1973 CImgException is the base class of %CImg exceptions.
1974 Exceptions are thrown by the %CImg Library when an error occured in a %CImg library function call.
1975 CImgException is seldom thrown itself. Children classes that specify the kind of error encountered
1976 are generally used instead. These sub-classes are :
1978 - \b CImgInstanceException : Thrown when the instance associated to the called %CImg function is not
1979 correctly defined. Generally, this exception is thrown when one tries to process \a empty images. The example
1980 below will throw a \a CImgInstanceException.
1981 \code
1982 CImg<float> img; // Construct an empty image.
1983 img.blur(10); // Try to blur the image.
1984 \endcode
1986 - \b CImgArgumentException : Thrown when one of the arguments given to the called %CImg function is not correct.
1987 Generally, this exception is thrown when arguments passed to the function are outside an admissible range of values.
1988 The example below will throw a \a CImgArgumentException.
1989 \code
1990 CImg<float> img(100,100,1,3); // Define a 100x100 color image with float pixels.
1991 img = 0; // Try to fill pixels from the 0 pointer (invalid argument to operator=() ).
1992 \endcode
1994 - \b CImgIOException : Thrown when an error occured when trying to load or save image files.
1995 The example below will throw a \a CImgIOException.
1996 \code
1997 CImg<float> img("file_doesnt_exist.jpg"); // Try to load a file that doesn't exist.
1998 \endcode
2000 - \b CImgDisplayException : Thrown when an error occured when trying to display an image in a window.
2001 This exception is thrown when image display request cannot be satisfied.
2003 The parent class CImgException may be thrown itself when errors that cannot be classified in one of
2004 the above type occur. It is recommended not to throw CImgExceptions yourself, since there are normally
2005 reserved to %CImg Library functions.
2006 \b CImgInstanceException, \b CImgArgumentException, \b CImgIOException and \b CImgDisplayException are simple
2007 subclasses of CImgException and are thus not detailled more in this reference documentation.
2009 \section ex2 Exception handling
2011 When an error occurs, the %CImg Library first displays the error in a modal window.
2012 Then, it throws an instance of the corresponding exception class, generally leading the program to stop
2013 (this is the default behavior).
2014 You can bypass this default behavior by handling the exceptions yourself,
2015 using a code block <tt>try { ... } catch() { ... }</tt>.
2016 In this case, you can avoid the apparition of the modal window, by
2017 defining the environment variable <tt>cimg_debug</tt> to 0 before including the %CImg header file.
2018 The example below shows how to cleanly handle %CImg Library exceptions :
2019 \code
2020 #define cimg_debug 0 // Disable modal window in CImg exceptions.
2021 #define "CImg.h"
2022 int main() {
2023 try {
2024 ...; // Here, do what you want.
2025 }
2026 catch (CImgInstanceException &e) {
2027 std::fprintf(stderr,"CImg Library Error : %s",e.message); // Display your own error message
2028 ... // Do what you want now.
2029 }
2030 }
2031 \endcode
2032 **/
2033 struct CImgException {
2034 #define _cimg_exception_err(etype,disp_flag) \
2035 cimg_std::va_list ap; va_start(ap,format); cimg_std::vsprintf(message,format,ap); va_end(ap); \
2036 switch (cimg::exception_mode()) { \
2037 case 0 : break; \
2038 case 2 : case 4 : try { cimg::dialog(etype,message,"Abort"); } catch (CImgException&) { \
2039 cimg_std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
2040 } break; \
2041 default : cimg_std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
2042 } \
2043 if (cimg::exception_mode()>=3) cimg_library::cimg::info();
2045 char message[1024]; //!< Message associated with the error that thrown the exception.
2046 CImgException() { message[0]='\0'; }
2047 CImgException(const char *format, ...) { _cimg_exception_err("CImgException",true); }
2048 };
2050 // The \ref CImgInstanceException class is used to throw an exception related
2051 // to a non suitable instance encountered in a library function call.
2052 struct CImgInstanceException: public CImgException {
2053 CImgInstanceException(const char *format, ...) { _cimg_exception_err("CImgInstanceException",true); }
2054 };
2056 // The \ref CImgArgumentException class is used to throw an exception related
2057 // to invalid arguments encountered in a library function call.
2058 struct CImgArgumentException: public CImgException {
2059 CImgArgumentException(const char *format, ...) { _cimg_exception_err("CImgArgumentException",true); }
2060 };
2062 // The \ref CImgIOException class is used to throw an exception related
2063 // to Input/Output file problems encountered in a library function call.
2064 struct CImgIOException: public CImgException {
2065 CImgIOException(const char *format, ...) { _cimg_exception_err("CImgIOException",true); }
2066 };
2068 // The CImgDisplayException class is used to throw an exception related to display problems
2069 // encountered in a library function call.
2070 struct CImgDisplayException: public CImgException {
2071 CImgDisplayException(const char *format, ...) { _cimg_exception_err("CImgDisplayException",false); }
2072 };
2074 // The CImgWarningException class is used to throw an exception for warnings
2075 // encountered in a library function call.
2076 struct CImgWarningException: public CImgException {
2077 CImgWarningException(const char *format, ...) { _cimg_exception_err("CImgWarningException",false); }
2078 };
2080 /*-------------------------------------
2081 #
2082 # Definition of the namespace 'cimg'
2083 #
2084 --------------------------------------*/
2085 //! Namespace that encompasses \a low-level functions and variables of the %CImg Library.
2086 /**
2087 Most of the functions and variables within this namespace are used by the library for low-level processing.
2088 Nevertheless, documented variables and functions of this namespace may be used safely in your own source code.
2090 \warning Never write <tt>using namespace cimg_library::cimg;</tt> in your source code, since a lot of functions of the
2091 <tt>cimg::</tt> namespace have prototypes similar to standard C functions that could defined in the global namespace <tt>::</tt>.
2092 **/
2093 namespace cimg {
2095 // Define the traits that will be used to determine the best data type to work with.
2096 //
2097 template<typename T> struct type {
2098 static const char* string() {
2099 static const char* s[] = { "unknown", "unknown8", "unknown16", "unknown24",
2100 "unknown32", "unknown40", "unknown48", "unknown56",
2101 "unknown64", "unknown72", "unknown80", "unknown88",
2102 "unknown96", "unknown104", "unknown112", "unknown120",
2103 "unknown128" };
2104 return s[(sizeof(T)<17)?sizeof(T):0];
2105 }
2106 static bool is_float() { return false; }
2107 static T min() { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); }
2108 static T max() { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); }
2109 static const char* format() { return "%s"; }
2110 static const char* format(const T val) { static const char *s = "unknown"; return s; }
2111 };
2113 template<> struct type<bool> {
2114 static const char* string() { static const char *const s = "bool"; return s; }
2115 static bool is_float() { return false; }
2116 static bool min() { return false; }
2117 static bool max() { return true; }
2118 static const char* format() { return "%s"; }
2119 static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; }
2120 };
2122 template<> struct type<unsigned char> {
2123 static const char* string() { static const char *const s = "unsigned char"; return s; }
2124 static bool is_float() { return false; }
2125 static unsigned char min() { return 0; }
2126 static unsigned char max() { return (unsigned char)~0U; }
2127 static const char* format() { return "%u"; }
2128 static unsigned int format(const unsigned char val) { return (unsigned int)val; }
2129 };
2131 template<> struct type<char> {
2132 static const char* string() { static const char *const s = "char"; return s; }
2133 static bool is_float() { return false; }
2134 static char min() { return (char)(-1L<<(8*sizeof(char)-1)); }
2135 static char max() { return ~((char)(-1L<<(8*sizeof(char)-1))); }
2136 static const char* format() { return "%d"; }
2137 static int format(const char val) { return (int)val; }
2138 };
2140 template<> struct type<signed char> {
2141 static const char* string() { static const char *const s = "signed char"; return s; }
2142 static bool is_float() { return false; }
2143 static signed char min() { return (signed char)(-1L<<(8*sizeof(signed char)-1)); }
2144 static signed char max() { return ~((signed char)(-1L<<(8*sizeof(signed char)-1))); }
2145 static const char* format() { return "%d"; }
2146 static unsigned int format(const signed char val) { return (int)val; }
2147 };
2149 template<> struct type<unsigned short> {
2150 static const char* string() { static const char *const s = "unsigned short"; return s; }
2151 static bool is_float() { return false; }
2152 static unsigned short min() { return 0; }
2153 static unsigned short max() { return (unsigned short)~0U; }
2154 static const char* format() { return "%u"; }
2155 static unsigned int format(const unsigned short val) { return (unsigned int)val; }
2156 };
2158 template<> struct type<short> {
2159 static const char* string() { static const char *const s = "short"; return s; }
2160 static bool is_float() { return false; }
2161 static short min() { return (short)(-1L<<(8*sizeof(short)-1)); }
2162 static short max() { return ~((short)(-1L<<(8*sizeof(short)-1))); }
2163 static const char* format() { return "%d"; }
2164 static int format(const short val) { return (int)val; }
2165 };
2167 template<> struct type<unsigned int> {
2168 static const char* string() { static const char *const s = "unsigned int"; return s; }
2169 static bool is_float() { return false; }
2170 static unsigned int min() { return 0; }
2171 static unsigned int max() { return (unsigned int)~0U; }
2172 static const char* format() { return "%u"; }
2173 static unsigned int format(const unsigned int val) { return val; }
2174 };
2176 template<> struct type<int> {
2177 static const char* string() { static const char *const s = "int"; return s; }
2178 static bool is_float() { return false; }
2179 static int min() { return (int)(-1L<<(8*sizeof(int)-1)); }
2180 static int max() { return ~((int)(-1L<<(8*sizeof(int)-1))); }
2181 static const char* format() { return "%d"; }
2182 static int format(const int val) { return val; }
2183 };
2185 template<> struct type<unsigned long> {
2186 static const char* string() { static const char *const s = "unsigned long"; return s; }
2187 static bool is_float() { return false; }
2188 static unsigned long min() { return 0; }
2189 static unsigned long max() { return (unsigned long)~0UL; }
2190 static const char* format() { return "%lu"; }
2191 static unsigned long format(const unsigned long val) { return val; }
2192 };
2194 template<> struct type<long> {
2195 static const char* string() { static const char *const s = "long"; return s; }
2196 static bool is_float() { return false; }
2197 static long min() { return (long)(-1L<<(8*sizeof(long)-1)); }
2198 static long max() { return ~((long)(-1L<<(8*sizeof(long)-1))); }
2199 static const char* format() { return "%ld"; }
2200 static long format(const long val) { return val; }
2201 };
2203 template<> struct type<float> {
2204 static const char* string() { static const char *const s = "float"; return s; }
2205 static bool is_float() { return true; }
2206 static float min() { return -3.4E38f; }
2207 static float max() { return 3.4E38f; }
2208 static const char* format() { return "%g"; }
2209 static double format(const float val) { return (double)val; }
2210 };
2212 template<> struct type<double> {
2213 static const char* string() { static const char *const s = "double"; return s; }
2214 static bool is_float() { return true; }
2215 static double min() { return -1.7E308; }
2216 static double max() { return 1.7E308; }
2217 static const char* format() { return "%g"; }
2218 static double format(const double val) { return val; }
2219 };
2221 template<typename T, typename t> struct superset { typedef T type; };
2222 template<> struct superset<bool,unsigned char> { typedef unsigned char type; };
2223 template<> struct superset<bool,char> { typedef char type; };
2224 template<> struct superset<bool,signed char> { typedef signed char type; };
2225 template<> struct superset<bool,unsigned short> { typedef unsigned short type; };
2226 template<> struct superset<bool,short> { typedef short type; };
2227 template<> struct superset<bool,unsigned int> { typedef unsigned int type; };
2228 template<> struct superset<bool,int> { typedef int type; };
2229 template<> struct superset<bool,unsigned long> { typedef unsigned long type; };
2230 template<> struct superset<bool,long> { typedef long type; };
2231 template<> struct superset<bool,float> { typedef float type; };
2232 template<> struct superset<bool,double> { typedef double type; };
2233 template<> struct superset<unsigned char,char> { typedef short type; };
2234 template<> struct superset<unsigned char,signed char> { typedef short type; };
2235 template<> struct superset<unsigned char,unsigned short> { typedef unsigned short type; };
2236 template<> struct superset<unsigned char,short> { typedef short type; };
2237 template<> struct superset<unsigned char,unsigned int> { typedef unsigned int type; };
2238 template<> struct superset<unsigned char,int> { typedef int type; };
2239 template<> struct superset<unsigned char,unsigned long> { typedef unsigned long type; };
2240 template<> struct superset<unsigned char,long> { typedef long type; };
2241 template<> struct superset<unsigned char,float> { typedef float type; };
2242 template<> struct superset<unsigned char,double> { typedef double type; };
2243 template<> struct superset<signed char,unsigned char> { typedef short type; };
2244 template<> struct superset<signed char,char> { typedef short type; };
2245 template<> struct superset<signed char,unsigned short> { typedef int type; };
2246 template<> struct superset<signed char,short> { typedef short type; };
2247 template<> struct superset<signed char,unsigned int> { typedef long type; };
2248 template<> struct superset<signed char,int> { typedef int type; };
2249 template<> struct superset<signed char,unsigned long> { typedef long type; };
2250 template<> struct superset<signed char,long> { typedef long type; };
2251 template<> struct superset<signed char,float> { typedef float type; };
2252 template<> struct superset<signed char,double> { typedef double type; };
2253 template<> struct superset<char,unsigned char> { typedef short type; };
2254 template<> struct superset<char,signed char> { typedef short type; };
2255 template<> struct superset<char,unsigned short> { typedef int type; };
2256 template<> struct superset<char,short> { typedef short type; };
2257 template<> struct superset<char,unsigned int> { typedef long type; };
2258 template<> struct superset<char,int> { typedef int type; };
2259 template<> struct superset<char,unsigned long> { typedef long type; };
2260 template<> struct superset<char,long> { typedef long type; };
2261 template<> struct superset<char,float> { typedef float type; };
2262 template<> struct superset<char,double> { typedef double type; };
2263 template<> struct superset<unsigned short,char> { typedef int type; };
2264 template<> struct superset<unsigned short,signed char> { typedef int type; };
2265 template<> struct superset<unsigned short,short> { typedef int type; };
2266 template<> struct superset<unsigned short,unsigned int> { typedef unsigned int type; };
2267 template<> struct superset<unsigned short,int> { typedef int type; };
2268 template<> struct superset<unsigned short,unsigned long> { typedef unsigned long type; };
2269 template<> struct superset<unsigned short,long> { typedef long type; };
2270 template<> struct superset<unsigned short,float> { typedef float type; };
2271 template<> struct superset<unsigned short,double> { typedef double type; };
2272 template<> struct superset<short,unsigned short> { typedef int type; };
2273 template<> struct superset<short,unsigned int> { typedef long type; };
2274 template<> struct superset<short,int> { typedef int type; };
2275 template<> struct superset<short,unsigned long> { typedef long type; };
2276 template<> struct superset<short,long> { typedef long type; };
2277 template<> struct superset<short,float> { typedef float type; };
2278 template<> struct superset<short,double> { typedef double type; };
2279 template<> struct superset<unsigned int,char> { typedef long type; };
2280 template<> struct superset<unsigned int,signed char> { typedef long type; };
2281 template<> struct superset<unsigned int,short> { typedef long type; };
2282 template<> struct superset<unsigned int,int> { typedef long type; };
2283 template<> struct superset<unsigned int,unsigned long> { typedef unsigned long type; };
2284 template<> struct superset<unsigned int,long> { typedef long type; };
2285 template<> struct superset<unsigned int,float> { typedef float type; };
2286 template<> struct superset<unsigned int,double> { typedef double type; };
2287 template<> struct superset<int,unsigned int> { typedef long type; };
2288 template<> struct superset<int,unsigned long> { typedef long type; };
2289 template<> struct superset<int,long> { typedef long type; };
2290 template<> struct superset<int,float> { typedef float type; };
2291 template<> struct superset<int,double> { typedef double type; };
2292 template<> struct superset<unsigned long,char> { typedef long type; };
2293 template<> struct superset<unsigned long,signed char> { typedef long type; };
2294 template<> struct superset<unsigned long,short> { typedef long type; };
2295 template<> struct superset<unsigned long,int> { typedef long type; };
2296 template<> struct superset<unsigned long,long> { typedef long type; };
2297 template<> struct superset<unsigned long,float> { typedef float type; };
2298 template<> struct superset<unsigned long,double> { typedef double type; };
2299 template<> struct superset<long,float> { typedef float type; };
2300 template<> struct superset<long,double> { typedef double type; };
2301 template<> struct superset<float,double> { typedef double type; };
2303 template<typename t1, typename t2, typename t3> struct superset2 {
2304 typedef typename superset<t1, typename superset<t2,t3>::type>::type type;
2305 };
2307 template<typename t1, typename t2, typename t3, typename t4> struct superset3 {
2308 typedef typename superset<t1, typename superset2<t2,t3,t4>::type>::type type;
2309 };
2311 template<typename t1, typename t2> struct last { typedef t2 type; };
2313 #define _cimg_Tuchar typename cimg::superset<T,unsigned char>::type
2314 #define _cimg_Tint typename cimg::superset<T,int>::type
2315 #define _cimg_Tfloat typename cimg::superset<T,float>::type
2316 #define _cimg_Tdouble typename cimg::superset<T,double>::type
2317 #define _cimg_Tt typename cimg::superset<T,t>::type
2319 // Define internal library variables.
2320 //
2321 #if cimg_display==1
2322 struct X11info {
2323 volatile unsigned int nb_wins;
2324 pthread_t* event_thread;
2325 CImgDisplay* wins[1024];
2326 Display* display;
2327 unsigned int nb_bits;
2328 GC* gc;
2329 bool blue_first;
2330 bool byte_order;
2331 bool shm_enabled;
2332 #ifdef cimg_use_xrandr
2333 XRRScreenSize *resolutions;
2334 Rotation curr_rotation;
2335 unsigned int curr_resolution;
2336 unsigned int nb_resolutions;
2337 #endif
2338 X11info():nb_wins(0),event_thread(0),display(0),
2339 nb_bits(0),gc(0),blue_first(false),byte_order(false),shm_enabled(false) {
2340 #ifdef cimg_use_xrandr
2341 resolutions = 0;
2342 curr_rotation = 0;
2343 curr_resolution = nb_resolutions = 0;
2344 #endif
2345 }
2346 };
2347 #if defined(cimg_module)
2348 X11info& X11attr();
2349 #elif defined(cimg_main)
2350 X11info& X11attr() { static X11info val; return val; }
2351 #else
2352 inline X11info& X11attr() { static X11info val; return val; }
2353 #endif
2355 #elif cimg_display==2
2356 struct Win32info {
2357 HANDLE wait_event;
2358 Win32info() { wait_event = CreateEvent(0,FALSE,FALSE,0); }
2359 };
2360 #if defined(cimg_module)
2361 Win32info& Win32attr();
2362 #elif defined(cimg_main)
2363 Win32info& Win32attr() { static Win32info val; return val; }
2364 #else
2365 inline Win32info& Win32attr() { static Win32info val; return val; }
2366 #endif
2368 #elif cimg_display==3
2369 struct CarbonInfo {
2370 MPCriticalRegionID windowListCR; // Protects access to the list of windows
2371 int windowCount; // Count of displays used on the screen
2372 pthread_t event_thread; // The background event thread
2373 MPSemaphoreID sync_event; // Event used to perform tasks synchronizations
2374 MPSemaphoreID wait_event; // Event used to notify that new events occured on the display
2375 MPQueueID com_queue; // The message queue
2376 CarbonInfo(): windowCount(0),event_thread(0),sync_event(0),com_queue(0) {
2377 if (MPCreateCriticalRegion(&windowListCR) != noErr) // Create the critical region
2378 throw CImgDisplayException("MPCreateCriticalRegion failed.");
2379 if (MPCreateSemaphore(1, 0, &sync_event) != noErr) // Create the inter-thread sync object
2380 throw CImgDisplayException("MPCreateSemaphore failed.");
2381 if (MPCreateSemaphore(1, 0, &wait_event) != noErr) // Create the event sync object
2382 throw CImgDisplayException("MPCreateSemaphore failed.");
2383 if (MPCreateQueue(&com_queue) != noErr) // Create the shared queue
2384 throw CImgDisplayException("MPCreateQueue failed.");
2385 }
2386 ~CarbonInfo() {
2387 if (event_thread != 0) { // Terminates the resident thread, if needed
2388 pthread_cancel(event_thread);
2389 pthread_join(event_thread, NULL);
2390 event_thread = 0;
2391 }
2392 if (MPDeleteCriticalRegion(windowListCR) != noErr) // Delete the critical region
2393 throw CImgDisplayException("MPDeleteCriticalRegion failed.");
2394 if (MPDeleteSemaphore(wait_event) != noErr) // Delete the event sync event
2395 throw CImgDisplayException("MPDeleteEvent failed.");
2396 if (MPDeleteSemaphore(sync_event) != noErr) // Delete the inter-thread sync event
2397 throw CImgDisplayException("MPDeleteEvent failed.");
2398 if (MPDeleteQueue(com_queue) != noErr) // Delete the shared queue
2399 throw CImgDisplayException("MPDeleteQueue failed.");
2400 }
2401 };
2402 #if defined(cimg_module)
2403 CarbonInfo& CarbonAttr();
2404 #elif defined(cimg_main)
2405 CarbonInfo CarbonAttr() { static CarbonInfo val; return val; }
2406 #else
2407 inline CarbonInfo& CarbonAttr() { static CarbonInfo val; return val; }
2408 #endif
2409 #endif
2411 #if cimg_display==1
2412 // Keycodes for X11-based graphical systems.
2413 //
2414 const unsigned int keyESC = XK_Escape;
2415 const unsigned int keyF1 = XK_F1;
2416 const unsigned int keyF2 = XK_F2;
2417 const unsigned int keyF3 = XK_F3;
2418 const unsigned int keyF4 = XK_F4;
2419 const unsigned int keyF5 = XK_F5;
2420 const unsigned int keyF6 = XK_F6;
2421 const unsigned int keyF7 = XK_F7;
2422 const unsigned int keyF8 = XK_F8;
2423 const unsigned int keyF9 = XK_F9;
2424 const unsigned int keyF10 = XK_F10;
2425 const unsigned int keyF11 = XK_F11;
2426 const unsigned int keyF12 = XK_F12;
2427 const unsigned int keyPAUSE = XK_Pause;
2428 const unsigned int key1 = XK_1;
2429 const unsigned int key2 = XK_2;
2430 const unsigned int key3 = XK_3;
2431 const unsigned int key4 = XK_4;
2432 const unsigned int key5 = XK_5;
2433 const unsigned int key6 = XK_6;
2434 const unsigned int key7 = XK_7;
2435 const unsigned int key8 = XK_8;
2436 const unsigned int key9 = XK_9;
2437 const unsigned int key0 = XK_0;
2438 const unsigned int keyBACKSPACE = XK_BackSpace;
2439 const unsigned int keyINSERT = XK_Insert;
2440 const unsigned int keyHOME = XK_Home;
2441 const unsigned int keyPAGEUP = XK_Page_Up;
2442 const unsigned int keyTAB = XK_Tab;
2443 const unsigned int keyQ = XK_q;
2444 const unsigned int keyW = XK_w;
2445 const unsigned int keyE = XK_e;
2446 const unsigned int keyR = XK_r;
2447 const unsigned int keyT = XK_t;
2448 const unsigned int keyY = XK_y;
2449 const unsigned int keyU = XK_u;
2450 const unsigned int keyI = XK_i;
2451 const unsigned int keyO = XK_o;
2452 const unsigned int keyP = XK_p;
2453 const unsigned int keyDELETE = XK_Delete;
2454 const unsigned int keyEND = XK_End;
2455 const unsigned int keyPAGEDOWN = XK_Page_Down;
2456 const unsigned int keyCAPSLOCK = XK_Caps_Lock;
2457 const unsigned int keyA = XK_a;
2458 const unsigned int keyS = XK_s;
2459 const unsigned int keyD = XK_d;
2460 const unsigned int keyF = XK_f;
2461 const unsigned int keyG = XK_g;
2462 const unsigned int keyH = XK_h;
2463 const unsigned int keyJ = XK_j;
2464 const unsigned int keyK = XK_k;
2465 const unsigned int keyL = XK_l;
2466 const unsigned int keyENTER = XK_Return;
2467 const unsigned int keySHIFTLEFT = XK_Shift_L;
2468 const unsigned int keyZ = XK_z;
2469 const unsigned int keyX = XK_x;
2470 const unsigned int keyC = XK_c;
2471 const unsigned int keyV = XK_v;
2472 const unsigned int keyB = XK_b;
2473 const unsigned int keyN = XK_n;
2474 const unsigned int keyM = XK_m;
2475 const unsigned int keySHIFTRIGHT = XK_Shift_R;
2476 const unsigned int keyARROWUP = XK_Up;
2477 const unsigned int keyCTRLLEFT = XK_Control_L;
2478 const unsigned int keyAPPLEFT = XK_Super_L;
2479 const unsigned int keyALT = XK_Alt_L;
2480 const unsigned int keySPACE = XK_space;
2481 const unsigned int keyALTGR = XK_Alt_R;
2482 const unsigned int keyAPPRIGHT = XK_Super_R;
2483 const unsigned int keyMENU = XK_Menu;
2484 const unsigned int keyCTRLRIGHT = XK_Control_R;
2485 const unsigned int keyARROWLEFT = XK_Left;
2486 const unsigned int keyARROWDOWN = XK_Down;
2487 const unsigned int keyARROWRIGHT = XK_Right;
2488 const unsigned int keyPAD0 = XK_KP_0;
2489 const unsigned int keyPAD1 = XK_KP_1;
2490 const unsigned int keyPAD2 = XK_KP_2;
2491 const unsigned int keyPAD3 = XK_KP_3;
2492 const unsigned int keyPAD4 = XK_KP_4;
2493 const unsigned int keyPAD5 = XK_KP_5;
2494 const unsigned int keyPAD6 = XK_KP_6;
2495 const unsigned int keyPAD7 = XK_KP_7;
2496 const unsigned int keyPAD8 = XK_KP_8;
2497 const unsigned int keyPAD9 = XK_KP_9;
2498 const unsigned int keyPADADD = XK_KP_Add;
2499 const unsigned int keyPADSUB = XK_KP_Subtract;
2500 const unsigned int keyPADMUL = XK_KP_Multiply;
2501 const unsigned int keyPADDIV = XK_KP_Divide;
2503 #elif cimg_display==2
2504 // Keycodes for Windows.
2505 //
2506 const unsigned int keyESC = VK_ESCAPE;
2507 const unsigned int keyF1 = VK_F1;
2508 const unsigned int keyF2 = VK_F2;
2509 const unsigned int keyF3 = VK_F3;
2510 const unsigned int keyF4 = VK_F4;
2511 const unsigned int keyF5 = VK_F5;
2512 const unsigned int keyF6 = VK_F6;
2513 const unsigned int keyF7 = VK_F7;
2514 const unsigned int keyF8 = VK_F8;
2515 const unsigned int keyF9 = VK_F9;
2516 const unsigned int keyF10 = VK_F10;
2517 const unsigned int keyF11 = VK_F11;
2518 const unsigned int keyF12 = VK_F12;
2519 const unsigned int keyPAUSE = VK_PAUSE;
2520 const unsigned int key1 = '1';
2521 const unsigned int key2 = '2';
2522 const unsigned int key3 = '3';
2523 const unsigned int key4 = '4';
2524 const unsigned int key5 = '5';
2525 const unsigned int key6 = '6';
2526 const unsigned int key7 = '7';
2527 const unsigned int key8 = '8';
2528 const unsigned int key9 = '9';
2529 const unsigned int key0 = '0';
2530 const unsigned int keyBACKSPACE = VK_BACK;
2531 const unsigned int keyINSERT = VK_INSERT;
2532 const unsigned int keyHOME = VK_HOME;
2533 const unsigned int keyPAGEUP = VK_PRIOR;
2534 const unsigned int keyTAB = VK_TAB;
2535 const unsigned int keyQ = 'Q';
2536 const unsigned int keyW = 'W';
2537 const unsigned int keyE = 'E';
2538 const unsigned int keyR = 'R';
2539 const unsigned int keyT = 'T';
2540 const unsigned int keyY = 'Y';
2541 const unsigned int keyU = 'U';
2542 const unsigned int keyI = 'I';
2543 const unsigned int keyO = 'O';
2544 const unsigned int keyP = 'P';
2545 const unsigned int keyDELETE = VK_DELETE;
2546 const unsigned int keyEND = VK_END;
2547 const unsigned int keyPAGEDOWN = VK_NEXT;
2548 const unsigned int keyCAPSLOCK = VK_CAPITAL;
2549 const unsigned int keyA = 'A';
2550 const unsigned int keyS = 'S';
2551 const unsigned int keyD = 'D';
2552 const unsigned int keyF = 'F';
2553 const unsigned int keyG = 'G';
2554 const unsigned int keyH = 'H';
2555 const unsigned int keyJ = 'J';
2556 const unsigned int keyK = 'K';
2557 const unsigned int keyL = 'L';
2558 const unsigned int keyENTER = VK_RETURN;
2559 const unsigned int keySHIFTLEFT = VK_SHIFT;
2560 const unsigned int keyZ = 'Z';
2561 const unsigned int keyX = 'X';
2562 const unsigned int keyC = 'C';
2563 const unsigned int keyV = 'V';
2564 const unsigned int keyB = 'B';
2565 const unsigned int keyN = 'N';
2566 const unsigned int keyM = 'M';
2567 const unsigned int keySHIFTRIGHT = VK_SHIFT;
2568 const unsigned int keyARROWUP = VK_UP;
2569 const unsigned int keyCTRLLEFT = VK_CONTROL;
2570 const unsigned int keyAPPLEFT = VK_LWIN;
2571 const unsigned int keyALT = VK_LMENU;
2572 const unsigned int keySPACE = VK_SPACE;
2573 const unsigned int keyALTGR = VK_CONTROL;
2574 const unsigned int keyAPPRIGHT = VK_RWIN;
2575 const unsigned int keyMENU = VK_APPS;
2576 const unsigned int keyCTRLRIGHT = VK_CONTROL;
2577 const unsigned int keyARROWLEFT = VK_LEFT;
2578 const unsigned int keyARROWDOWN = VK_DOWN;
2579 const unsigned int keyARROWRIGHT = VK_RIGHT;
2580 const unsigned int keyPAD0 = 0x60;
2581 const unsigned int keyPAD1 = 0x61;
2582 const unsigned int keyPAD2 = 0x62;
2583 const unsigned int keyPAD3 = 0x63;
2584 const unsigned int keyPAD4 = 0x64;
2585 const unsigned int keyPAD5 = 0x65;
2586 const unsigned int keyPAD6 = 0x66;
2587 const unsigned int keyPAD7 = 0x67;
2588 const unsigned int keyPAD8 = 0x68;
2589 const unsigned int keyPAD9 = 0x69;
2590 const unsigned int keyPADADD = VK_ADD;
2591 const unsigned int keyPADSUB = VK_SUBTRACT;
2592 const unsigned int keyPADMUL = VK_MULTIPLY;
2593 const unsigned int keyPADDIV = VK_DIVIDE;
2595 #elif cimg_display==3
2596 // Keycodes for MacOSX, when using the Carbon framework.
2597 //
2598 const unsigned int keyESC = kEscapeCharCode;
2599 const unsigned int keyF1 = 2U;
2600 const unsigned int keyF2 = 3U;
2601 const unsigned int keyF3 = 4U;
2602 const unsigned int keyF4 = 5U;
2603 const unsigned int keyF5 = 6U;
2604 const unsigned int keyF6 = 7U;
2605 const unsigned int keyF7 = 8U;
2606 const unsigned int keyF8 = 9U;
2607 const unsigned int keyF9 = 10U;
2608 const unsigned int keyF10 = 11U;
2609 const unsigned int keyF11 = 12U;
2610 const unsigned int keyF12 = 13U;
2611 const unsigned int keyPAUSE = 14U;
2612 const unsigned int key1 = '1';
2613 const unsigned int key2 = '2';
2614 const unsigned int key3 = '3';
2615 const unsigned int key4 = '4';
2616 const unsigned int key5 = '5';
2617 const unsigned int key6 = '6';
2618 const unsigned int key7 = '7';
2619 const unsigned int key8 = '8';
2620 const unsigned int key9 = '9';
2621 const unsigned int key0 = '0';
2622 const unsigned int keyBACKSPACE = kBackspaceCharCode;
2623 const unsigned int keyINSERT = 26U;
2624 const unsigned int keyHOME = kHomeCharCode;
2625 const unsigned int keyPAGEUP = kPageUpCharCode;
2626 const unsigned int keyTAB = kTabCharCode;
2627 const unsigned int keyQ = 'q';
2628 const unsigned int keyW = 'w';
2629 const unsigned int keyE = 'e';
2630 const unsigned int keyR = 'r';
2631 const unsigned int keyT = 't';
2632 const unsigned int keyY = 'y';
2633 const unsigned int keyU = 'u';
2634 const unsigned int keyI = 'i';
2635 const unsigned int keyO = 'o';
2636 const unsigned int keyP = 'p';
2637 const unsigned int keyDELETE = kDeleteCharCode;
2638 const unsigned int keyEND = kEndCharCode;
2639 const unsigned int keyPAGEDOWN = kPageDownCharCode;
2640 const unsigned int keyCAPSLOCK = 43U;
2641 const unsigned int keyA = 'a';
2642 const unsigned int keyS = 's';
2643 const unsigned int keyD = 'd';
2644 const unsigned int keyF = 'f';
2645 const unsigned int keyG = 'g';
2646 const unsigned int keyH = 'h';
2647 const unsigned int keyJ = 'j';
2648 const unsigned int keyK = 'k';
2649 const unsigned int keyL = 'l';
2650 const unsigned int keyENTER = kEnterCharCode;
2651 const unsigned int keySHIFTLEFT = 54U; //Macintosh modifier key, emulated
2652 const unsigned int keyZ = 'z';
2653 const unsigned int keyX = 'x';
2654 const unsigned int keyC = 'c';
2655 const unsigned int keyV = 'v';
2656 const unsigned int keyB = 'b';
2657 const unsigned int keyN = 'n';
2658 const unsigned int keyM = 'm';
2659 const unsigned int keySHIFTRIGHT = 62U; //Macintosh modifier key, emulated
2660 const unsigned int keyARROWUP = kUpArrowCharCode;
2661 const unsigned int keyCTRLLEFT = 64U; //Macintosh modifier key, emulated
2662 const unsigned int keyAPPLEFT = 65U; //Macintosh modifier key, emulated
2663 const unsigned int keyALT = 66U;
2664 const unsigned int keySPACE = kSpaceCharCode;
2665 const unsigned int keyALTGR = 67U; //Macintosh modifier key, emulated
2666 const unsigned int keyAPPRIGHT = 68U; //Aliased on keyAPPLEFT
2667 const unsigned int keyMENU = 69U;
2668 const unsigned int keyCTRLRIGHT = 70U; //Macintosh modifier key, emulated
2669 const unsigned int keyARROWLEFT = kLeftArrowCharCode;
2670 const unsigned int keyARROWDOWN = kDownArrowCharCode;
2671 const unsigned int keyARROWRIGHT = kRightArrowCharCode;
2672 const unsigned int keyPAD0 = 74U;
2673 const unsigned int keyPAD1 = 75U;
2674 const unsigned int keyPAD2 = 76U;
2675 const unsigned int keyPAD3 = 77U;
2676 const unsigned int keyPAD4 = 78U;
2677 const unsigned int keyPAD5 = 79U;
2678 const unsigned int keyPAD6 = 80U;
2679 const unsigned int keyPAD7 = 81U;
2680 const unsigned int keyPAD8 = 82U;
2681 const unsigned int keyPAD9 = 83U;
2682 const unsigned int keyPADADD = 84U;
2683 const unsigned int keyPADSUB = 85U;
2684 const unsigned int keyPADMUL = 86U;
2685 const unsigned int keyPADDIV = 87U;
2687 #else
2688 // Define unknow keycodes when no display are available.
2689 // (should rarely be used then !).
2690 //
2691 const unsigned int keyESC = 1U;
2692 const unsigned int keyF1 = 2U;
2693 const unsigned int keyF2 = 3U;
2694 const unsigned int keyF3 = 4U;
2695 const unsigned int keyF4 = 5U;
2696 const unsigned int keyF5 = 6U;
2697 const unsigned int keyF6 = 7U;
2698 const unsigned int keyF7 = 8U;
2699 const unsigned int keyF8 = 9U;
2700 const unsigned int keyF9 = 10U;
2701 const unsigned int keyF10 = 11U;
2702 const unsigned int keyF11 = 12U;
2703 const unsigned int keyF12 = 13U;
2704 const unsigned int keyPAUSE = 14U;
2705 const unsigned int key1 = 15U;
2706 const unsigned int key2 = 16U;
2707 const unsigned int key3 = 17U;
2708 const unsigned int key4 = 18U;
2709 const unsigned int key5 = 19U;
2710 const unsigned int key6 = 20U;
2711 const unsigned int key7 = 21U;
2712 const unsigned int key8 = 22U;
2713 const unsigned int key9 = 23U;
2714 const unsigned int key0 = 24U;
2715 const unsigned int keyBACKSPACE = 25U;
2716 const unsigned int keyINSERT = 26U;
2717 const unsigned int keyHOME = 27U;
2718 const unsigned int keyPAGEUP = 28U;
2719 const unsigned int keyTAB = 29U;
2720 const unsigned int keyQ = 30U;
2721 const unsigned int keyW = 31U;
2722 const unsigned int keyE = 32U;
2723 const unsigned int keyR = 33U;
2724 const unsigned int keyT = 34U;
2725 const unsigned int keyY = 35U;
2726 const unsigned int keyU = 36U;
2727 const unsigned int keyI = 37U;
2728 const unsigned int keyO = 38U;
2729 const unsigned int keyP = 39U;
2730 const unsigned int keyDELETE = 40U;
2731 const unsigned int keyEND = 41U;
2732 const unsigned int keyPAGEDOWN = 42U;
2733 const unsigned int keyCAPSLOCK = 43U;
2734 const unsigned int keyA = 44U;
2735 const unsigned int keyS = 45U;
2736 const unsigned int keyD = 46U;
2737 const unsigned int keyF = 47U;
2738 const unsigned int keyG = 48U;
2739 const unsigned int keyH = 49U;
2740 const unsigned int keyJ = 50U;
2741 const unsigned int keyK = 51U;
2742 const unsigned int keyL = 52U;
2743 const unsigned int keyENTER = 53U;
2744 const unsigned int keySHIFTLEFT = 54U;
2745 const unsigned int keyZ = 55U;
2746 const unsigned int keyX = 56U;
2747 const unsigned int keyC = 57U;
2748 const unsigned int keyV = 58U;
2749 const unsigned int keyB = 59U;
2750 const unsigned int keyN = 60U;
2751 const unsigned int keyM = 61U;
2752 const unsigned int keySHIFTRIGHT = 62U;
2753 const unsigned int keyARROWUP = 63U;
2754 const unsigned int keyCTRLLEFT = 64U;
2755 const unsigned int keyAPPLEFT = 65U;
2756 const unsigned int keyALT = 66U;
2757 const unsigned int keySPACE = 67U;
2758 const unsigned int keyALTGR = 68U;
2759 const unsigned int keyAPPRIGHT = 69U;
2760 const unsigned int keyMENU = 70U;
2761 const unsigned int keyCTRLRIGHT = 71U;
2762 const unsigned int keyARROWLEFT = 72U;
2763 const unsigned int keyARROWDOWN = 73U;
2764 const unsigned int keyARROWRIGHT = 74U;
2765 const unsigned int keyPAD0 = 75U;
2766 const unsigned int keyPAD1 = 76U;
2767 const unsigned int keyPAD2 = 77U;
2768 const unsigned int keyPAD3 = 78U;
2769 const unsigned int keyPAD4 = 79U;
2770 const unsigned int keyPAD5 = 80U;
2771 const unsigned int keyPAD6 = 81U;
2772 const unsigned int keyPAD7 = 82U;
2773 const unsigned int keyPAD8 = 83U;
2774 const unsigned int keyPAD9 = 84U;
2775 const unsigned int keyPADADD = 85U;
2776 const unsigned int keyPADSUB = 86U;
2777 const unsigned int keyPADMUL = 87U;
2778 const unsigned int keyPADDIV = 88U;
2779 #endif
2781 const double valuePI = 3.14159265358979323846; //!< Definition of the mathematical constant PI
2783 // Definition of a 7x11 font, used to return a default font for drawing text.
2784 const unsigned int font7x11[7*11*256/32] = {
2785 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2786 0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x7f0000,0x40000,0x0,0x0,0x4010c0a4,0x82000040,0x11848402,0x18480050,0x80430292,0x8023,0x9008000,
2787 0x40218140,0x4000040,0x21800402,0x18000051,0x1060500,0x8083,0x10000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x24002,0x4031,0x80000000,0x10000,
2788 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c0400,0x40020000,0x80070080,0x40440e00,0x0,0x0,0x1,0x88180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2789 0x0,0x200000,0x0,0x0,0x80000,0x0,0x0,0x20212140,0x5000020,0x22400204,0x240000a0,0x40848500,0x4044,0x80010038,0x20424285,0xa000020,
2790 0x42428204,0x2428e0a0,0x82090a14,0x4104,0x85022014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10240a7,0x88484040,0x40800000,0x270c3,0x87811e0e,
2791 0x7c70e000,0x78,0x3c23c1ef,0x1f3e1e89,0xf1c44819,0xa23cf0f3,0xc3cff120,0xc18307f4,0x4040400,0x20000,0x80080080,0x40200,0x0,
2792 0x40000,0x2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8188,0x50603800,0xf3c00000,0x1c004003,0xc700003e,0x18180,0xc993880,0x10204081,
2793 0x2071ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x7d1224,0x48906048,0x0,0x4000000,0x0,0x9000,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,
2794 0x0,0x10240aa,0x14944080,0x23610000,0x68940,0x40831010,0x8891306,0x802044,0x44522208,0x90202088,0x40448819,0xb242890a,0x24011111,
2795 0x49448814,0x4040a00,0xe2c3c7,0x8e3f3cb9,0xc1c44216,0xee38b0f2,0xe78f9120,0xc18507e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2796 0x101c207,0x88a04001,0x9c00000,0x2200a041,0x8200113a,0x8240,0x50a3110,0x2850a142,0x850c2081,0x2040204,0x8104592,0x142850a1,
2797 0x42cd1224,0x4888bc48,0x70e1c387,0xe3b3c70,0xe1c38e1c,0x38707171,0xc3870e1c,0x10791224,0x48906c41,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2798 0x10003ee,0x15140080,0x21810000,0x48840,0x40851020,0x8911306,0x31fd804,0x9c522408,0x90204088,0x4045081a,0xba42890a,0x24011111,
2799 0x49285024,0x2041b00,0x132408,0x910844c8,0x4044821b,0x7244c913,0x24041111,0x49488822,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2800 0x28204,0x85006001,0x6a414000,0x3a004043,0xc700113a,0x8245,0x50a3a00,0x2850a142,0x850c4081,0x2040204,0x81045d2,0x142850a1,
2801 0x24951224,0x48852250,0x8102040,0x81054089,0x12244204,0x8108992,0x24489122,0x991224,0x4888b222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2802 0x1000143,0xa988080,0x2147c01f,0x88840,0x83091c2c,0x1070f000,0xc000608,0xa48bc408,0x9e3c46f8,0x40460816,0xaa42f10b,0xc3811111,
2803 0x35102044,0x1041100,0xf22408,0x9f084488,0x40470212,0x62448912,0x6041111,0x55308846,0x8061c80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2804 0x1028704,0x8f805801,0x4be28fdf,0x220001f0,0x111a,0x60000182,0x82c5c710,0x44891224,0x489640f1,0xe3c78204,0x810e552,0x142850a1,
2805 0x18a51224,0x48822250,0x78f1e3c7,0x8f1f40f9,0xf3e7c204,0x8108912,0x24489122,0x7ea91224,0x4888a222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2806 0x10007e2,0x85648080,0x20010000,0x88841,0x8f8232,0x20881000,0xc1fc610,0xbefa2408,0x90204288,0x40450816,0xa642810a,0x4041110a,
2807 0x36282084,0x1042080,0x1122408,0x90084488,0x40450212,0x62448912,0x184110a,0x55305082,0x8042700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2808 0x1028207,0x82004801,0x68050040,0x1c000040,0x110a,0x60000001,0x45484d10,0x7cf9f3e7,0xcf944081,0x2040204,0x8104532,0x142850a1,
2809 0x18a51224,0x48822248,0x89122448,0x91244081,0x2040204,0x8108912,0x24489122,0xc91224,0x48852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x282,
2810 0x89630080,0x20010c00,0x30108842,0x810222,0x20882306,0x3001800,0x408a2208,0x90202288,0x40448814,0xa642810a,0x2041110a,0x26442104,
2811 0x840000,0x1122408,0x90084488,0x40448212,0x62448912,0x84130a,0x36485102,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x101c208,0x4f802801,
2812 0x8028040,0x40,0x130a,0x2,0x85e897a0,0x44891224,0x489c2081,0x2040204,0x8104532,0x142850a1,0x24cd1224,0x48823c44,0x89122448,
2813 0x91244081,0x2040204,0x8108912,0x24489122,0xc93264,0xc9852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100028f,0x109f0080,0x20010c00,
2814 0x303071f3,0xc7011c1c,0x4071c306,0x802010,0x3907c1ef,0x1f201e89,0xf3844f90,0xa23c80f2,0x17810e04,0x228223f4,0x840000,0xfbc3c7,
2815 0x8f083c88,0x40444212,0x6238f0f2,0x7039d04,0x228423e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1008780,0x2201800,0xf0014000,0x1f0,
2816 0x1d0a,0x5,0x851e140,0x83060c18,0x30671ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x42f8e1c3,0x8702205c,0x7cf9f3e7,0xcf9b3c78,0xf1e3c204,
2817 0x8107111,0xc3870e1c,0x10f1d3a7,0x4e823c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x40,0x40000400,0x200000,0x0,0x2,0x0,0x0,0x0,0x0,0x18,
2818 0x0,0x4,0x44007f,0x0,0x400,0x400000,0x8010,0x0,0x6002,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x200800,0x0,0x0,0x100a,
2819 0x400000,0x44,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x0,0x62018,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x31,0x80000800,
2820 0x400000,0x0,0x4,0x0,0x0,0x0,0x0,0xc,0x0,0x7,0x3c0000,0x0,0x3800,0x3800000,0x8010,0x0,0x1c001,0x881c0000,0x0,0x0,0x0,0x0,0x0,0x0,
2821 0x0,0x0,0x207000,0x0,0x0,0x100a,0xc00000,0x3c,0x0,0xc00,0x0,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x0,0x1c2070
2822 };
2824 // Definition of a 10x13 font (used in dialog boxes).
2825 const unsigned int font10x13[256*10*13/32] = {
2826 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2827 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80100c0,
2828 0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2829 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2830 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x0,0x0,0x0,0x0,0x0,0x4020120,
2831 0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2832 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x140,0x80000,0x200402,0x800000,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2833 0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2834 0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001,
2835 0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801,
2836 0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0,
2837 0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0,
2838 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010,
2839 0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480,
2840 0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,
2841 0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010,
2842 0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008,
2843 0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006,
2844 0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088,
2845 0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000,
2846 0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220,
2847 0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208,
2848 0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040,
2849 0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508,
2850 0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088,
2851 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018,
2852 0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220,
2853 0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2854 0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484,
2855 0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808,
2856 0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264,
2857 0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010,
2858 0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100,
2859 0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800,
2860 0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,
2861 0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822,
2862 0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200,
2863 0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000,
2864 0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2865 0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8,
2866 0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008,
2867 0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000,
2868 0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220,
2869 0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402,
2870 0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980,
2871 0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421,
2872 0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0,
2873 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020,
2874 0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701,
2875 0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,
2876 0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c,
2877 0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0,
2878 0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000,
2879 0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000,
2880 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0,
2881 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100000,0x0,0x0,0x0,0x0,0x2000,0x0,0x4020040,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,
2882 0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000,
2883 0x0,0x4,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x80f00000,0x0,0x0,0x0,0x800,0xa0001800,0x0,0x0,0x0,0x0,
2884 0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040
2885 };
2887 // Definition of a 8x17 font.
2888 const unsigned int font8x17[8*17*256/32] = {
2889 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2890 0x0,0x0,0x0,0x2400,0x2400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20081834,0x1c0000,0x20081800,0x20081800,0x342008,
2891 0x18340000,0x200818,0x80000,0x0,0x180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4200000,0x0,0x0,
2892 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x380000,0x4000,0x2000c00,0x40100840,0x70000000,0x0,0x0,0x1c,0x10700000,0x7,0x0,
2893 0x1800,0x1800,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1010242c,0x14140000,0x10102414,0x10102414,0x2c1010,0x242c1400,
2894 0x101024,0x14100038,0x0,0x240000,0x0,0x0,0x30000000,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x8100000,0x0,
2895 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x80000,0x10004000,0x2001000,0x40000040,0x10000000,0x0,0x0,0x10,0x10100000,0x4,
2896 0x0,0x18000000,0x0,0x0,0x0,0x34002400,0x2400,0x0,0x0,0x0,0x3c,0x0,0x8000000,0x0,0x60607800,0x0,0x140000,0x0,0x0,0x0,0x0,0x0,
2897 0x44,0x10081834,0x240000,0x10081800,0x10081800,0x1c341008,0x18340000,0x100818,0x84000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102812,
2898 0x8601c10,0x8100800,0x2,0x1c383e3e,0x67e1e7f,0x3e3c0000,0x38,0x1e087e1e,0x7c7f7f1e,0x417c1c42,0x4063611c,0x7e1c7e3e,0xfe414181,
2899 0x63827f10,0x40081000,0x8004000,0x2001000,0x40000040,0x10000000,0x0,0x10000000,0x10,0x10100000,0x3c000008,0x0,0x24003e00,
2900 0x3f007f00,0x0,0x0,0x2ce91800,0x1882,0x10101c,0xc2103c,0x143c3c00,0x3c00,0x18003c3c,0x10001f00,0x181c00,0x20200810,0x8080808,
2901 0x8083e1e,0x7f7f7f7f,0x7c7c7c7c,0x7c611c1c,0x1c1c1c00,0x1e414141,0x41824044,0x810242c,0x14180000,0x8102414,0x8102414,0x382c0810,
2902 0x242c1400,0x81024,0x14104014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102816,0x3e902010,0x10084910,0x4,0x22084343,0xa402102,0x41620000,
2903 0x44,0x33144121,0x42404021,0x41100444,0x40636122,0x43224361,0x10416381,0x22440310,0x20082800,0x4000,0x2001000,0x40000040,
2904 0x10000000,0x0,0x10000000,0x10,0x10100000,0x24000008,0x0,0x606100,0x68000300,0x8106c,0x34000000,0x4f0000,0x44,0x101020,0x441040,
2905 0x420200,0x4200,0x24000404,0x7d00,0x82200,0x20203010,0x14141414,0x14082821,0x40404040,0x10101010,0x42612222,0x22222200,0x23414141,
2906 0x41447e48,0x0,0x0,0x0,0x0,0x4000000,0x18,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10287f,0x49902010,0x10083e10,0x4,0x41080101,
2907 0x1a404002,0x41411818,0x1004004,0x21144140,0x41404040,0x41100448,0x40555141,0x41414140,0x10412281,0x14280610,0x20084400,0x1c7c1c,
2908 0x3e3c7c3a,0x5c703844,0x107f5c3c,0x7c3e3c3c,0x7e424281,0x66427e10,0x10100000,0x40100008,0x1010,0xa04000,0x48100610,0x100c3024,
2909 0x24000000,0x4f3c00,0x2c107e28,0x3820,0x42281060,0x9d1e12,0xbd00,0x24100818,0x427d00,0x82248,0x20200800,0x14141414,0x14142840,
2910 0x40404040,0x10101010,0x41514141,0x41414142,0x43414141,0x41284350,0x1c1c1c1c,0x1c1c6c1c,0x3c3c3c3c,0x70707070,0x3c5c3c3c,
2911 0x3c3c3c18,0x3e424242,0x42427c42,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102824,0x48623010,0x10081c10,0x8,0x41080103,0x127c5e04,
2912 0x41411818,0xe7f3808,0x4f144140,0x41404040,0x41100450,0x40555141,0x41414160,0x1041225a,0x1c280410,0x1008c600,0x226622,0x66661066,
2913 0x62100848,0x10496266,0x66663242,0x10426681,0x24220260,0x100c0000,0xf8280008,0x1010,0x606000,0x48280428,0x28042014,0x48000000,
2914 0x494200,0x52280228,0x105420,0x3cee1058,0xa12236,0xa500,0x18101004,0x427d00,0x8226c,0x76767e10,0x14141414,0x14142840,0x40404040,
2915 0x10101010,0x41514141,0x41414124,0x45414141,0x41284150,0x22222222,0x22221222,0x66666666,0x10101010,0x66626666,0x66666600,
2916 0x66424242,0x42226622,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100024,0x381c4900,0x10086bfe,0x8,0x4908021c,0x22036304,0x3e630000,
2917 0x70000710,0x51227e40,0x417f7f43,0x7f100470,0x40554941,0x43417e3e,0x1041225a,0x8100810,0x10080000,0x24240,0x42421042,0x42100850,
2918 0x10494242,0x42422040,0x1042245a,0x18240410,0x10103900,0x407c003e,0x1818,0x1c3e10,0x4f7c087c,0x7c002010,0x48000000,0x4008,
2919 0x527c0410,0x105078,0x2410104c,0xa13e6c,0x7f00b900,0xfe3c3c,0x421d18,0x1c1c36,0x38383810,0x22222222,0x22144e40,0x7f7f7f7f,
2920 0x10101010,0xf1494141,0x41414118,0x49414141,0x4110435c,0x2020202,0x2021240,0x42424242,0x10101010,0x42424242,0x424242ff,0x4e424242,
2921 0x42244224,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000fe,0xe664d00,0x10080810,0x380010,0x41080c03,0x42014108,0x633d0000,0x70000710,
2922 0x51224140,0x41404041,0x41100448,0x40494541,0x7e414203,0x1041145a,0x14101010,0x10080000,0x3e4240,0x427e1042,0x42100870,0x10494242,
2923 0x4242203c,0x1042245a,0x18241810,0x10104600,0xf8f60008,0x1010,0x600320,0x48f610f6,0xf6000000,0x187eff,0x3c04,0x5ef61810,0x105020,
2924 0x24fe0064,0x9d006c,0x138ad00,0x100000,0x420518,0x36,0xc0c0c020,0x22222222,0x22224840,0x40404040,0x10101010,0x41454141,0x41414118,
2925 0x51414141,0x41107e46,0x3e3e3e3e,0x3e3e7e40,0x7e7e7e7e,0x10101010,0x42424242,0x42424200,0x5a424242,0x42244224,0x0,0x0,0x0,
2926 0x0,0x0,0x0,0x0,0x0,0x28,0x9094500,0x10080010,0x10,0x41081801,0x7f014118,0x41010000,0xe7f3800,0x513e4140,0x41404041,0x41100444,
2927 0x40414541,0x40414101,0x10411466,0x36103010,0x8080000,0x424240,0x42401042,0x42100848,0x10494242,0x42422002,0x10423c5a,0x18142010,
2928 0x10100000,0x407c0010,0x1010,0x260140,0x487c307c,0x7c000000,0x180000,0x202,0x507c2010,0x105020,0x3c10003c,0x423e36,0x1004200,
2929 0x100000,0x420500,0x3e6c,0x41e0440,0x3e3e3e3e,0x3e3e7840,0x40404040,0x10101010,0x41454141,0x41414124,0x61414141,0x41104042,
2930 0x42424242,0x42425040,0x40404040,0x10101010,0x42424242,0x42424218,0x72424242,0x42144214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,
2931 0x49096200,0x8100010,0x18001810,0x22082043,0x2432310,0x61421818,0x1004010,0x4f634121,0x42404021,0x41104444,0x40414322,0x40234143,
2932 0x10411466,0x22106010,0x8080000,0x466622,0x66621066,0x42100844,0x10494266,0x66662042,0x10461824,0x24184010,0x10100000,0x24381010,
2933 0x34001018,0xda4320,0x68386038,0x38000000,0x0,0x4204,0x50384010,0x105420,0x4210100c,0x3c0012,0x3c00,0x0,0x460500,0x48,0xc020c44,
2934 0x63636363,0x63228821,0x40404040,0x10101010,0x42432222,0x22222242,0x62414141,0x41104042,0x46464646,0x46465022,0x62626262,
2935 0x10101010,0x66426666,0x66666618,0x66464646,0x46186618,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,0x3e063d00,0x8100000,0x18001820,
2936 0x1c3e7f3e,0x23c1e20,0x3e3c1818,0x10,0x20417e1e,0x7c7f401e,0x417c3842,0x7f41431c,0x401e40be,0x103e0866,0x41107f10,0x4080000,
2937 0x3a5c1c,0x3a3c103a,0x427c0842,0xe49423c,0x7c3e203c,0xe3a1824,0x66087e10,0x10100000,0x3c103010,0x245a1010,0x5a3e10,0x3f107f10,
2938 0x10000000,0x0,0x3c08,0x2e107e10,0x1038fc,0x101004,0x0,0x0,0xfe0000,0x7f0500,0x0,0x14041438,0x41414141,0x41418e1e,0x7f7f7f7f,
2939 0x7c7c7c7c,0x7c431c1c,0x1c1c1c00,0xbc3e3e3e,0x3e10405c,0x3a3a3a3a,0x3a3a6e1c,0x3c3c3c3c,0x7c7c7c7c,0x3c423c3c,0x3c3c3c00,
2940 0x7c3a3a3a,0x3a087c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x4200000,0x10000020,0x0,0x0,0x10,0x0,0x30000000,0x0,
2941 0x0,0x0,0x60000,0x0,0x1c,0x4380000,0x0,0x2,0x800,0x0,0x40020000,0x0,0x8000c,0x10600000,0x2010,0x48000000,0x240000,0x0,0x0,
2942 0x0,0x0,0x0,0x1000,0x1078,0x0,0x0,0x0,0x400500,0x0,0x1e081e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2943 0x84008,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x20000040,0x0,0x0,0x20,0x0,0x1e000000,0x0,0x0,0x0,0x20000,0x0,
2944 0x0,0x2000000,0x0,0x26,0x800,0x0,0x40020000,0x0,0x100000,0x10000000,0x2030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x1000,0x0,
2945 0x0,0x0,0x400000,0x8000000,0x41e0400,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x104010,0x0,0x0,0x0,0x0,
2946 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe,0x0,0x1c,0x7000,0x0,0x40020000,0x0,0x300000,
2947 0x0,0xe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x0,0x0,0x0,0x400000,0x38000000,0x0,0x0,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2948 0x1c,0x0,0x0,0x0,0x0,0x0,0x304030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2949 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2950 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2951 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2952 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
2954 // Definition of a 10x19 font.
2955 const unsigned int font10x19[10*19*256/32] = {
2956 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2957 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3600000,0x36000,0x0,0x0,0x0,0x0,0x6c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2958 0x0,0x180181c0,0xe81b0300,0x1801,0x81c06c18,0x181c06c,0xe8180,0x181c0e81,0xb0000006,0x60701b,0x1800000,0x0,0x0,0x0,0x0,0x0,
2959 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2960 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x1c000,0x0,0x0,0x0,0x0,0x6c,0x0,0x0,0x0,0x0,
2961 0x0,0x0,0x0,0x0,0x0,0x0,0xc030360,0xb81b0480,0xc03,0x3606c0c,0x303606c,0xb80c0,0x30360b81,0xb0000003,0xc0d81b,0x3000000,0x0,
2962 0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2963 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x0,0x0,0x2200000,
2964 0x22000,0x0,0x0,0x0,0x0,0x0,0x0,0x30000,0x0,0xe0,0x38078000,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000c080,0x480,0x3000,
2965 0xc0800030,0xc08000,0x300,0xc080000,0xc,0x302000,0xc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x41c01,0xe020060c,
2966 0x800000,0x4,0x1e0703e0,0xf8060fc1,0xe1fe1e07,0x80000000,0x78,0x307e0,0x3c7c1fe7,0xf83c408f,0x80f10440,0x18660878,0x7e0787e0,
2967 0x78ff9024,0xa0140a0,0x27f83840,0x700e000,0x18000400,0x8000,0x70004002,0x410078,0x0,0x0,0x0,0x0,0x1808,0xc000000,0xf000000,
2968 0xe000000,0x1400,0x1e0001f,0x8007f800,0x0,0x0,0x3a3b,0x61400000,0x14202,0x20000,0x38002020,0x3c1b00,0x3e00000,0xf8,0x1c0001c0,
2969 0x78060001,0xf800000e,0x1e00020,0x8004020,0xc0300c0,0x300c0301,0xf83c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1821e0,0x781e0781,0xe0001f10,
2970 0x24090240,0xa02400f8,0x18018140,0xe81b0480,0x1801,0x81406c18,0x181406c,0x190e8180,0x18140e81,0xb0000006,0x60501b,0x184006c,
2971 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x26042202,0x200c06,0x800000,0x8,0x210d0611,0x40e0803,0x10026188,0x40000000,
2972 0x8c,0xf030418,0xc6431004,0xc64082,0x110840,0x18660884,0x41084410,0x8c081024,0xa012110,0x40082020,0x101b000,0xc000400,0x8000,
2973 0x80004002,0x410008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x18800000,0x10000000,0x2200,0x2300024,0x800,0x0,0x0,0x2e13,0x60800000,
2974 0x8104,0x20040,0x64001040,0x80401b07,0x80100000,0x1e000,0x22000020,0x40c0003,0xc8000002,0x3300020,0x8004020,0xc0300c0,0x300c0301,
2975 0x40c64010,0x4010008,0x2008020,0x43182210,0x84210842,0x10002190,0x24090240,0x9044018c,0xc030220,0xb81b0300,0xc03,0x2206c0c,
2976 0x302206c,0x1e0b80c0,0x30220b81,0xb0000003,0xc0881b,0x304006c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x241f2202,
2977 0x200802,0x4900000,0x8,0x21010408,0x20a0802,0x44090,0x20000000,0x4,0x11878408,0x80411004,0x804082,0x111040,0x1ce50986,0x40986409,
2978 0x81022,0x12012108,0x80102020,0x1031800,0x400,0x8000,0x80004000,0x10008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x10000000,
2979 0x10000000,0x18,0x4000044,0x1000,0x30180,0xd81b0000,0x13,0xe0000000,0x88,0x40,0x400018c0,0x80400018,0x61f00000,0x61800,0x22020020,
2980 0x4000007,0xc8000002,0x2100020,0x8038000,0x1e0781e0,0x781e0301,0x40804010,0x4010008,0x2008020,0x41142619,0x86619866,0x18002190,
2981 0x24090240,0x8887e104,0x0,0x0,0x0,0x0,0x0,0x2000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x2434a202,
2982 0x200802,0x3e00000,0x10,0x40810008,0x21a0804,0x44090,0x20000000,0x80040004,0x20848409,0x409004,0x1004082,0x112040,0x14a50902,
2983 0x40902409,0x81022,0x11321208,0x80202010,0x1060c00,0x7c5e0,0x781e8783,0xf07a5f0e,0x1c10808,0xfc5f078,0x5e07a170,0x7c7e1024,
2984 0xa016190,0x27f82008,0x2000000,0x20000000,0x10000000,0x80200024,0x4000044,0x2000,0x18180,0xc8320000,0x12,0xa1f00037,0x7f888,
2985 0x1e0,0x40410880,0x80600017,0xa2100000,0x5e800,0x22020040,0x38001027,0xc8000002,0x2100020,0x8004020,0x12048120,0x48120482,
2986 0x41004010,0x4010008,0x2008020,0x40942409,0x2409024,0x9044390,0x24090240,0x88841918,0x1f07c1f0,0x7c1f07c3,0x70781e07,0x81e07838,
2987 0xe0380e0,0x1f17c1e0,0x781e0781,0xe0001f90,0x24090240,0x9025e102,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xff241c41,
2988 0x1001,0x1c02000,0x10,0x40810008,0x6120f85,0xe0086190,0x20c03007,0x8007800c,0x27848419,0x409004,0x1004082,0x114040,0x14a48902,
2989 0x40902409,0x81022,0x11321205,0x602010,0x1000000,0x86610,0x84218840,0x80866182,0x411008,0x9261884,0x61086189,0x82101022,0x12012108,
2990 0x40082008,0x2000000,0x20030000,0x20000000,0x80200024,0x4000044,0x3006030,0xc018100,0x4c260000,0x12,0x26080048,0x83000850,
2991 0x20250,0x403e0500,0x8078002c,0x12302200,0x92400,0x1c0200c0,0x4001027,0xc8000002,0x3308820,0x8004020,0x12048120,0x48120482,
2992 0x41004010,0x4010008,0x2008020,0x40922409,0x2409024,0x8884690,0x24090240,0x85040920,0x21886218,0x86218860,0x88842108,0x42108408,
2993 0x2008020,0x21186210,0x84210842,0x10302190,0x24090240,0x88461084,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x4c240182,
2994 0x80001001,0x6b02000,0x20,0x4c810010,0x78220846,0x10081e10,0x20c0301c,0x1fe0e018,0x4d8487e1,0x409fe7,0xf9007f82,0x11a040,
2995 0x13248902,0x41102418,0xe0081022,0x11320c05,0x402008,0x1000000,0x2409,0x409020,0x81024082,0x412008,0x9240902,0x40902101,0x101022,
2996 0x11321208,0x40102008,0x2000000,0x7e0c8000,0xfc000003,0xf0fc0018,0x43802047,0x8c8040c8,0x32008300,0x44240000,0x0,0x4000048,
2997 0x8c801050,0x20440,0x40221dc0,0x808c0028,0x11d0667f,0x8009c400,0x1fc180,0x4001023,0xc8300002,0x1e0ccfb,0x3ec7b020,0x12048120,
2998 0x48120482,0x79007f9f,0xe7f9fe08,0x2008020,0xf0922409,0x2409024,0x8504490,0x24090240,0x85040920,0x802008,0x2008020,0x89004090,
2999 0x24090208,0x2008020,0x40902409,0x2409024,0x8304390,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
3000 0x481c0606,0xc8001001,0x802000,0x20,0x4c810020,0x4220024,0x8102108,0x60000070,0x3820,0x48884419,0x409004,0x10e4082,0x112040,
3001 0x13244902,0x7e1027e0,0x3c081021,0x21320c02,0x802008,0x1000000,0x7e409,0x409020,0x81024082,0x414008,0x9240902,0x40902101,
3002 0x80101022,0x11320c08,0x40202008,0x2038800,0x200bc000,0x20000000,0x80200003,0x80f04044,0xbc080bc,0x2f000200,0x0,0x0,0x6001048,
3003 0x8bc02020,0x20441,0xf8220200,0x80820028,0x1000cc00,0x80094400,0x201e0,0x78001021,0xc830000f,0x8000663c,0xf03c0c0,0x21084210,
3004 0x84210846,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8204890,0x24090240,0x82040930,0x1f87e1f8,0x7e1f87e0,0x89004090,
3005 0x24090208,0x2008020,0x40902409,0x2409024,0x8004690,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
3006 0x480719c4,0x48001001,0x81fc00,0x7800020,0x40810040,0x2420024,0x8104087,0xa0000070,0x3820,0x48884409,0x409004,0x1024082,0x111040,
3007 0x13244902,0x40102410,0x2081021,0x214a1202,0x1802008,0x1000000,0x182409,0x409fe0,0x81024082,0x41a008,0x9240902,0x40902100,
3008 0xf8101021,0x214a0c04,0x80c0c008,0x1847000,0x7c1ee000,0x20000000,0x8020000c,0x8c044,0x1ee181ee,0x7b800000,0x707,0xf3ff0000,
3009 0x3e0084f,0x9ee0c020,0x20440,0x40221fc0,0xc2002c,0x13f11000,0x87892400,0x20000,0x1020,0x48000000,0x3f011c6,0x31cc6180,0x21084210,
3010 0x84210844,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8505090,0x24090240,0x8204191c,0x60982609,0x82609823,0xf9007f9f,
3011 0xe7f9fe08,0x2008020,0x40902409,0x2409024,0x9fe4c90,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xfe048224,
3012 0x28001001,0x2000,0x40,0x40810080,0x27f8024,0x8104080,0x2000001c,0x1fe0e020,0x488fc409,0x409004,0x1024082,0x110840,0x10242902,
3013 0x40102408,0x2081021,0x214a1202,0x1002004,0x1000000,0x102409,0x409000,0x81024082,0x411008,0x9240902,0x40902100,0x6101021,
3014 0x214a0c04,0x81002008,0x2000000,0x201dc000,0x20000000,0x80200000,0x98044,0x1dc101dc,0x77000000,0x700,0x0,0x180448,0x1dc10020,
3015 0x20440,0x403e0200,0x620017,0xa000cc00,0x80052800,0x20000,0x1020,0x48000000,0x6606,0x206100,0x3f0fc3f0,0xfc3f0fc7,0xc1004010,
3016 0x4010008,0x2008020,0x4090a409,0x2409024,0x8886090,0x24090240,0x8207e106,0x40902409,0x2409024,0x81004010,0x4010008,0x2008020,
3017 0x40902409,0x2409024,0x8005890,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98048224,0x30001001,0x2000,
3018 0x40,0x21010100,0x2020024,0x8204080,0x40000007,0x80078000,0x48884408,0x80411004,0x824082,0x110840,0x10242986,0x40086409,0x2081021,
3019 0xe14a2102,0x2002004,0x1000000,0x106409,0x409000,0x81024082,0x410808,0x9240902,0x40902100,0x2101021,0x214a1202,0x82002008,
3020 0x2000000,0x300f8000,0x20000000,0x80fc001d,0xe4088044,0xf8200f8,0x3e000000,0x300,0x0,0x80c48,0xf820020,0x20640,0x40410200,
3021 0x803c0018,0x60006600,0x61800,0x0,0x1020,0x48000000,0xcc0a,0x20a100,0x21084210,0x84210844,0x40804010,0x4010008,0x2008020,
3022 0x4110a619,0x86619866,0x19046110,0x24090240,0x82040102,0x41906419,0x6419064,0x81004010,0x4010008,0x2008020,0x40902409,0x2409024,
3023 0x8307090,0x24090240,0x82840828,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x90248222,0x30000802,0x200c,0xc080,0x21010301,
3024 0x4021042,0x10202108,0xc0c03000,0x80040020,0x4d902418,0xc6431004,0xc24082,0x6210440,0x10241884,0x40084409,0x86080840,0xc0842102,
3025 0x4002002,0x1000000,0x18e610,0x84218820,0x80864082,0x410408,0x9240884,0x61086101,0x6101860,0xc0842103,0x4002008,0x2000000,
3026 0x10850180,0x20330000,0x80200013,0x26184024,0x5040050,0x14000000,0x0,0x0,0x4180848,0x85040020,0x20350,0x40000200,0x800c0007,
3027 0x80002200,0x1e000,0x0,0x1860,0x48000000,0x880a,0x40a188,0x40902409,0x2409028,0x40c64010,0x4010008,0x2008020,0x43106210,0x84210842,
3028 0x10006108,0x42108421,0x2040102,0x6398e639,0x8e6398e4,0x88842088,0x22088208,0x2008020,0x21102210,0x84210842,0x10306118,0x66198661,
3029 0x83061030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0x901f01c1,0xe8000802,0xc,0xc080,0x1e07c7f8,0xf8020f81,0xe0401e07,
3030 0x80c03000,0x20,0x279027e0,0x3c7c1fe4,0x3c408f,0x83c1027f,0x90241878,0x4007c404,0xf8080780,0xc0844082,0x7f82002,0x1000000,
3031 0xfa5e0,0x781e87c0,0x807a409f,0xc0410207,0x9240878,0x5e07a100,0xf80e0fa0,0xc0846183,0x7f82008,0x2000000,0xf020100,0x40321360,
3032 0x80200014,0xa3e0201f,0x8207f820,0x8000000,0x0,0x0,0x3e01037,0x207f820,0x201e1,0xfc000200,0x80040000,0x0,0x0,0x1fc000,0x17b0,
3033 0x48000000,0x12,0xc120f0,0x40902409,0x2409028,0x783c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1061e0,0x781e0781,0xe000be07,0x81e0781e,
3034 0x204017c,0x3e8fa3e8,0xfa3e8fa3,0x70781f07,0xc1f07c7f,0x1fc7f1fc,0x1e1021e0,0x781e0781,0xe0007e0f,0xa3e8fa3e,0x8305e030,0x0,
3035 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000,0xc06,0xc,0x100,0x0,0x0,0x0,0x3000,0x0,0x20000000,0x0,0x0,0x0,0x0,0xc000,
3036 0x0,0x0,0x2001,0x1000000,0x0,0x0,0x20000,0x400000,0x0,0x40002000,0x0,0x1,0x2008,0x2000000,0x100,0x40240000,0x80200008,0x40000000,
3037 0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80040000,0x0,0x0,0x0,0x1000,0x48000000,0x1f,0x181f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3038 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1040010,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000,0x60c,0x18,0x0,
3039 0x0,0x0,0x0,0x6000,0x0,0x10000000,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x3800,0x7000000,0x0,0x0,0x840000,0x400000,0x0,0x40002000,
3040 0x0,0x2,0x2008,0x2000000,0x200,0x40440000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80780000,0x0,0x0,0x0,0x1000,0x48000400,
3041 0x2,0x1e02000,0x0,0x0,0x80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x0,0x0,0x0,0x0,0x0,0x0,0x2040020,0x0,0x0,0x0,0x0,
3042 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x4000,0x0,0xf000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3043 0x780000,0x3800000,0x0,0x40002000,0x0,0xe,0x1808,0xc000000,0x3,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,
3044 0x0,0x0,0x0,0x1000,0x1c00,0x0,0x0,0x0,0x0,0x380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x380000,0x0,0x0,0x0,0x0,0x0,0x0,0xe0400e0,
3045 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3fc,
3046 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3047 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3049 // Definition of a 12x24 font.
3050 const unsigned int font12x24[12*24*256/32] = {
3051 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3052 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x19,0x80000000,0x198000,0x0,0x0,0x0,0x0,
3053 0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc001806,0xc81980,0x60000000,0xc001806,0x1980c00,0x18060198,0xc80c,
3054 0x180600,0xc8198000,0xc001,0x80601980,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3055 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3056 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,
3057 0x0,0x0,0x0,0x0,0x0,0x0,0x600300f,0x1301980,0x90000000,0x600300f,0x1980600,0x300f0198,0x13006,0x300f01,0x30198000,0x6003,
3058 0xf01980,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3059 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3060 0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x60000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7007,0x3c0000,0x3006019,
3061 0x80000000,0x90000000,0x3006019,0x80000300,0x60198000,0x3,0x601980,0x0,0x3006,0x1980000,0x60000000,0x0,0x0,0xe0000000,0x0,
3062 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3063 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000000,
3064 0x0,0x0,0x0,0x0,0x0,0xc800019,0x80000000,0x198000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x1001,0x420000,0x0,0x0,0x90000000,
3065 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000c06,0xc80001,0x10000000,0x18000c06,0x1800,0xc060000,0xc818,0xc0600,0xc8000000,
3066 0x18000,0xc0600000,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80660207,0x800f8060,0x300c004,0x0,0x6,
3067 0xe00703f,0x3f00383,0xf80f07fc,0x1f01f000,0x0,0xf8,0x607f,0x7c7e07,0xfe7fe0f8,0x6063fc1f,0x86066007,0xe7060f0,0x7f80f07f,
3068 0x81f8fff6,0x6606c03,0x70ee077f,0xe0786000,0xf0070000,0xc000060,0xc0,0x3e000,0x60006003,0x600fc00,0x0,0x0,0x0,0x0,0x0,0x3c0603,
3069 0xc0000000,0x7800000,0xf0000,0x0,0xf00001f,0x80001fe0,0x7fe000,0x0,0x0,0x0,0x168fe609,0x0,0x90e07,0x6000,0x3c000e,0x70000f8,
3070 0x1980001f,0x0,0x1f8,0xf00000f,0xf00180,0xfe000,0xe00e,0x1001,0x20060,0x6006006,0x600600,0x600fe07c,0x7fe7fe7f,0xe7fe3fc3,
3071 0xfc3fc3fc,0x7e07060f,0xf00f00,0xf00f0000,0xf360660,0x6606606e,0x76001e0,0xc00180f,0x1681981,0x10000000,0xc00180f,0x1980c00,
3072 0x180f0198,0x3801680c,0x180f01,0x68198000,0xc001,0x80f01980,0x18600198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,
3073 0x8044020c,0xc01f8060,0x2004004,0x0,0xc,0x3f81f07f,0x87f80383,0xf81f87fc,0x3f83f800,0x0,0x1fc,0x780607f,0x81fe7f87,0xfe7fe1fc,
3074 0x6063fc1f,0x860c6007,0xe7061f8,0x7fc1f87f,0xc3fcfff6,0x6606c03,0x30c6067f,0xe0783000,0xf00d8000,0x6000060,0xc0,0x7e000,0x60006003,
3075 0x600fc00,0x0,0x0,0xc00,0x0,0x0,0x7c0603,0xe0000000,0xfc00000,0x1f0000,0x0,0x900003f,0xc0003fe0,0x7fe000,0x0,0x0,0x0,0x1302660f,
3076 0x0,0xf0606,0x6004,0x7e0006,0x60601f8,0x19800001,0x80000000,0x1f8,0x19800010,0x81080300,0x3f2000,0x2011,0x1001,0x1c0060,0x6006006,
3077 0x600600,0x601fe1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f87061f,0x81f81f81,0xf81f8000,0x3fa60660,0x66066066,0x66003f0,0x6003009,
3078 0x1301981,0x10000000,0x6003009,0x1980600,0x30090198,0x1f013006,0x300901,0x30198000,0x6003,0x901980,0x30600198,0x0,0x0,0x0,
3079 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc0f8c,0xc0180060,0x6006044,0x40000000,0xc,0x3181b041,0xc41c0783,0x388018,
3080 0x71c71800,0x0,0x106,0x18c0f061,0xc38261c6,0x600384,0x60606001,0x86186007,0xe78630c,0x60e30c60,0xe7040606,0x630cc03,0x39c30c00,
3081 0xc0603000,0x3018c000,0x3000060,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,0x60000000,0x18400000,0x180000,
3082 0x0,0x19800070,0x40003600,0xc000,0x0,0x0,0x0,0x25a06,0x0,0x6030c,0x4,0xe20007,0xe060180,0xf000,0x80000000,0xf0000,0x10800000,
3083 0x80080600,0x7f2000,0x2020,0x80001001,0x20000,0xf00f00f,0xf00f00,0x601b0382,0x60060060,0x6000600,0x60060060,0x61c78630,0xc30c30c3,
3084 0xc30c000,0x30e60660,0x66066063,0xc600738,0x3006019,0x80000000,0xe0000000,0x3006019,0x80000300,0x60198000,0x3e000003,0x601980,
3085 0x0,0x3006,0x1980000,0x60600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc1fcc,0xc0180060,0x6006035,0x80000000,
3086 0x18,0x71c03000,0xc00c0583,0x300018,0x60c60c00,0x0,0x6,0x3060f060,0xc30060c6,0x600300,0x60606001,0x86306007,0x9e78670e,0x60670e60,
3087 0x66000606,0x630c606,0x19830c01,0xc0601800,0x30306000,0x60,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,
3088 0x60000000,0x18000000,0x300000,0x0,0x78060,0x6600,0x1c000,0x300c,0x39819c0,0x0,0x25a00,0x0,0x30c,0x4,0xc00003,0xc060180,0x30c1f,
3089 0x80000000,0x30c000,0x10800001,0x80700000,0x7f2000,0x2020,0x80001001,0x20060,0xf00f00f,0xf00f00,0xf01b0300,0x60060060,0x6000600,
3090 0x60060060,0x60c78670,0xe70e70e7,0xe70e000,0x70c60660,0x66066063,0xc7f8618,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0,
3091 0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x87ff3a4c,0xc0180060,0x400600e,0x600000,0x18,0x60c03000,
3092 0xc00c0d83,0x700018,0x60c60c00,0x20,0x400006,0x3060f060,0xc6006066,0x600600,0x60606001,0x86606006,0x966c6606,0x60660660,0x66000606,
3093 0x630c666,0xf019801,0x80601800,0x30603000,0x1f06f,0xf01ec0,0xf03fe1ec,0x6703e01f,0x61c0c06,0xdc6701f0,0x6f01ec0c,0xe1f87fc6,
3094 0xc60cc03,0x71c60c7f,0xc0600600,0x60000000,0x30000000,0x300000,0x40040,0x88060,0x6600,0x18000,0x300c,0x1981980,0x0,0x2421f,
3095 0x80003ce0,0x7fc198,0x601f,0xc02021,0x980600c0,0x40230,0x80000000,0x402000,0x19806003,0x80006,0xc7f2000,0x2020,0x80001001,
3096 0x420060,0xf00f00f,0xf00f00,0xf01b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x6606208,0x60e60660,0x66066061,
3097 0x987fc670,0x1f01f01f,0x1f01f01,0xf039c0f0,0xf00f00f,0xf03e03,0xe03e03e0,0x1f06701f,0x1f01f01,0xf01f0060,0x1e660c60,0xc60c60c6,
3098 0xc6f060c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x7ff3207,0x8c0c0000,0xc00300e,0x600000,0x30,0x60c03000,
3099 0xc01c0983,0xf0600030,0x31860c06,0x6001e0,0x78000e,0x23e1f861,0xc6006066,0x600600,0x60606001,0x86c06006,0x966c6606,0x60660660,
3100 0xe7000606,0x630c666,0xf01f803,0x600c00,0x30000000,0x3f87f,0x83f83fc3,0xf83fe3fc,0x7f83e01f,0x6380c07,0xfe7f83f8,0x7f83fc0d,
3101 0xf3fc7fc6,0xc71cc03,0x3183187f,0xc0600600,0x60000000,0xff806000,0x300000,0x40040,0x88070,0x6600,0x60030060,0x6001818,0x1883180,
3102 0x0,0x2423f,0xc0007ff0,0x607fc1f8,0x603f,0x80c01fc1,0xf80601e0,0x5f220,0x80420000,0x5f2000,0xf006006,0x80006,0xc7f2000,0x2020,
3103 0x82107c07,0xc03c0060,0x1f81f81f,0x81f81f80,0xf03b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x660671c,0x61660660,
3104 0x66066061,0xf860e6c0,0x3f83f83f,0x83f83f83,0xf87fe3f8,0x3f83f83f,0x83f83e03,0xe03e03e0,0x3f87f83f,0x83f83f83,0xf83f8060,
3105 0x3fc60c60,0xc60c60c3,0x187f8318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x883200,0x300c0000,0xc003035,0x80600000,
3106 0x30,0x66c03001,0xc0f81983,0xf86f0030,0x1f071c06,0x600787,0xfe1e001c,0x6261987f,0x86006067,0xfe7fc600,0x7fe06001,0x87c06006,
3107 0xf6646606,0x60e6067f,0xc3e00606,0x61986f6,0x600f007,0x600c00,0x30000000,0x21c71,0x830831c3,0x1c06031c,0x71c06003,0x6700c06,
3108 0x6671c318,0x71831c0f,0x16040c06,0xc318606,0x1b031803,0x80600600,0x60000000,0x30009000,0x300000,0x40040,0x7003e,0x67e0,0x90070090,
3109 0x9001818,0x8c3100,0x0,0x60,0x4000e730,0x900380f0,0x6034,0x80c018c7,0xfe060338,0xb0121,0x80c60000,0x909000,0x6008,0x1080006,
3110 0xc3f2000,0x2011,0x3180060,0x60060e0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0x60664660,0x66066066,
3111 0x66063b8,0x62660660,0x66066060,0xf06066c0,0x21c21c21,0xc21c21c2,0x1c466308,0x31c31c31,0xc31c0600,0x60060060,0x31871c31,0x83183183,
3112 0x18318000,0x71860c60,0xc60c60c3,0x18718318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1981a00,0xe03e0000,0xc003044,
3113 0x40600000,0x60,0x66c03001,0x80f03182,0x1c7f8030,0x3f83fc06,0x601e07,0xfe078038,0x6661987f,0x86006067,0xfe7fc61e,0x7fe06001,
3114 0x87e06006,0x66666606,0x7fc6067f,0x81f80606,0x61986f6,0x6006006,0x600600,0x30000000,0xc60,0xc60060c6,0xc06060c,0x60c06003,
3115 0x6e00c06,0x6660c60c,0x60c60c0e,0x6000c06,0xc318666,0x1f031803,0x600600,0x603c2000,0x30016800,0x1fe0000,0x1f81f8,0x1c1f,0x804067e1,
3116 0x68060168,0x16800810,0xc42300,0x0,0x60,0x20c331,0x68030060,0x6064,0x3fc1040,0xf006031c,0xa011e,0x818c7fe0,0x909000,0x7fe1f,
3117 0x80f00006,0xc0f2060,0xf80e,0x18c0780,0x780781c0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0xfc666660,
3118 0x66066066,0x66061f0,0x66660660,0x66066060,0x606066e0,0xc00c00,0xc00c00c0,0xc066600,0x60c60c60,0xc60c0600,0x60060060,0x60c60c60,
3119 0xc60c60c6,0xc60c000,0x61c60c60,0xc60c60c3,0x1860c318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1980f81,0x80373000,
3120 0xc003004,0x7fe0001,0xf0000060,0x60c03003,0x183180,0xc71c060,0x3181ec00,0x7000,0xe070,0x66619860,0xc6006066,0x60061e,0x60606001,
3121 0x87606006,0x66626606,0x7f860661,0xc01c0606,0x6198696,0xf00600e,0x600600,0x30000000,0x1fc60,0xc60060c7,0xfc06060c,0x60c06003,
3122 0x7c00c06,0x6660c60c,0x60c60c0c,0x7f00c06,0xc3b8666,0xe01b007,0x3c00600,0x3c7fe000,0xff03ec00,0x1fe0000,0x40040,0xe001,0xc0806603,
3123 0xec0e03ec,0x3ec00010,0x0,0x60000000,0x7f,0x10c3f3,0xec070060,0x6064,0x3fc1040,0x6000030c,0xa0100,0x3187fe1,0xf09f1000,0x7fe00,
3124 0x6,0xc012060,0x0,0xc63c03,0xc03c0380,0x19819819,0x81981981,0x98330600,0x60060060,0x6000600,0x60060060,0xfc662660,0x66066066,
3125 0x66060e0,0x6c660660,0x66066060,0x6060e630,0x1fc1fc1f,0xc1fc1fc1,0xfc3fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
3126 0xc60c7fe,0x62c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe02c6,0x3c633000,0xc003004,
3127 0x7fe0001,0xf00000c0,0x60c03006,0xc6180,0xc60c060,0x60c00c00,0x7000,0xe060,0x66639c60,0x66006066,0x600606,0x60606001,0x86306006,
3128 0x66636606,0x60060660,0xc0060606,0x61f8696,0xf00600c,0x600300,0x30000000,0x3fc60,0xc60060c7,0xfc06060c,0x60c06003,0x7c00c06,
3129 0x6660c60c,0x60c60c0c,0x1f80c06,0xc1b0666,0xe01b00e,0x3c00600,0x3c43c000,0x3007de00,0x600000,0x40040,0x30000,0x61006607,0xde0c07de,
3130 0x7de00000,0x0,0xf07fefff,0x1f,0x8008c3f7,0xde0e0060,0x6064,0xc01047,0xfe00018c,0xb013f,0x86300061,0xf0911000,0x6000,0x6,
3131 0xc012060,0x3f,0x8063c0cc,0x3cc0c700,0x39c39c39,0xc39c39c1,0x98630600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,
3132 0x66061f0,0x78660660,0x66066060,0x607fc618,0x3fc3fc3f,0xc3fc3fc3,0xfc7fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
3133 0xc60c7fe,0x64c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe0260,0x6661b000,0xc003000,
3134 0x600000,0xc0,0x60c0300c,0xc7fe0,0xc60c060,0x60c01c00,0x1e07,0xfe078060,0x6663fc60,0x66006066,0x600606,0x60606001,0x86386006,
3135 0x6636606,0x60060660,0xe0060606,0x60f039c,0x1b806018,0x600300,0x30000000,0x70c60,0xc60060c6,0x6060c,0x60c06003,0x7600c06,
3136 0x6660c60c,0x60c60c0c,0x1c0c06,0xc1b03fc,0xe01f01c,0xe00600,0x70000000,0x3007fc00,0x600000,0x40040,0x0,0x62006607,0xfc1807fc,
3137 0x7fc00000,0x0,0xf0000000,0x1,0xc004c307,0xfc1c0060,0x6064,0xc018c0,0x600000d8,0x5f200,0x3180060,0x50a000,0x6000,0x6,0xc012000,
3138 0x0,0xc601c0,0x4201c600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,0x66063b8,
3139 0x70660660,0x66066060,0x607f860c,0x70c70c70,0xc70c70c7,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,
3140 0x68c60c60,0xc60c60c1,0xf060c1f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3300260,0x6661e000,0xc003000,0x600000,
3141 0x180,0x71c03018,0xc7fe0,0xc60c0c0,0x60c01800,0x787,0xfe1e0060,0x6663fc60,0x630060c6,0x600306,0x60606001,0x86186006,0x661e70e,
3142 0x60070c60,0x60060606,0x60f039c,0x19806038,0x600180,0x30000000,0x60c60,0xc60060c6,0x6060c,0x60c06003,0x6700c06,0x6660c60c,
3143 0x60c60c0c,0xc0c06,0xc1b039c,0x1f00e018,0x600600,0x60000000,0x1803f800,0x600000,0x40040,0x39e00,0x63006603,0xf83803f8,0x3f800000,
3144 0x0,0x60000000,0x0,0xc00cc303,0xf8180060,0x6064,0xc01fc0,0x60060070,0x40200,0x18c0060,0x402000,0x6000,0x6,0xc012000,0x0,0x18c0140,
3145 0x2014600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0300,0x60060060,0x6000600,0x60060060,0x60c61e70,0xe70e70e7,0xe70e71c,0x60e60660,0x66066060,
3146 0x6060060c,0x60c60c60,0xc60c60c6,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,0x70c60c60,0xc60c60c0,
3147 0xe060c0e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33022e0,0x6670c000,0xc003000,0x600600,0x60180,0x31803030,
3148 0x41c0184,0x1831c0c0,0x71c23806,0x6001e0,0x780000,0x62630c60,0xe38261c6,0x600386,0x60606043,0x860c6006,0x661e30c,0x60030c60,
3149 0x740e0607,0xe0f039c,0x31c06030,0x600180,0x30000000,0x61c71,0x830831c3,0x406031c,0x60c06003,0x6300c06,0x6660c318,0x71831c0c,
3150 0x41c0c07,0x1c0e039c,0x1b00e030,0x600600,0x60000000,0x1c41b00e,0x601cc0,0x401f8,0x45240,0xe1803601,0xb03001b0,0x1b000000,
3151 0x0,0x0,0x41,0xc008e711,0xb0300060,0x6034,0x80c02020,0x60060030,0x30c00,0xc60000,0x30c000,0x0,0x7,0x1c012000,0x0,0x3180240,
3152 0x6024608,0x30c30c30,0xc30c30c3,0xc630382,0x60060060,0x6000600,0x60060060,0x61c61e30,0xc30c30c3,0xc30c208,0x70c70e70,0xe70e70e0,
3153 0x6060068c,0x61c61c61,0xc61c61c6,0x1cc62308,0x30430430,0x43040600,0x60060060,0x31860c31,0x83183183,0x18318060,0x31c71c71,
3154 0xc71c71c0,0xe07180e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2203fc0,0x663f6000,0x6006000,0x600600,0x60300,
3155 0x3f81fe7f,0xc7f80187,0xf83f80c0,0x3f83f006,0x600020,0x400060,0x33e6067f,0xc1fe7f87,0xfe6001fe,0x6063fc7f,0x60e7fe6,0x660e3f8,
3156 0x6001f860,0x37fc0603,0xfc06030c,0x30c0607f,0xe06000c0,0x30000000,0x7fc7f,0x83f83fc3,0xfc0603fc,0x60c7fe03,0x61807c6,0x6660c3f8,
3157 0x7f83fc0c,0x7f80fc3,0xfc0e039c,0x3180607f,0xc0600600,0x60000000,0xfc0e00c,0x601986,0x66040040,0x4527f,0xc0803fe0,0xe07fe0e0,
3158 0xe000000,0x0,0x0,0x7f,0x80107ff0,0xe07fc060,0x603f,0x83fe0000,0x60060018,0xf000,0x420000,0xf0000,0x7fe00,0x7,0xfe012000,
3159 0x0,0x2100640,0xc0643f8,0x60660660,0x66066067,0xec3e1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f860e3f,0x83f83f83,0xf83f8000,
3160 0x5fc3fc3f,0xc3fc3fc0,0x606006fc,0x7fc7fc7f,0xc7fc7fc7,0xfcffe3f8,0x3fc3fc3f,0xc3fc7fe7,0xfe7fe7fe,0x3f860c3f,0x83f83f83,
3161 0xf83f8060,0x7f83fc3f,0xc3fc3fc0,0x607f8060,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2201f80,0x3c1e7000,0x6006000,
3162 0x600,0x60300,0xe01fe7f,0xc3f00183,0xe01f0180,0x1f01e006,0x600000,0x60,0x3006067f,0x807c7e07,0xfe6000f8,0x6063fc3e,0x6067fe6,
3163 0x660e0f0,0x6000f060,0x3bf80601,0xf806030c,0x60e0607f,0xe06000c0,0x30000000,0x1ec6f,0xf01ec0,0xf80601ec,0x60c7fe03,0x61c03c6,
3164 0x6660c1f0,0x6f01ec0c,0x3f007c1,0xcc0e030c,0x71c0c07f,0xc0600600,0x60000000,0x7804018,0xe01186,0x66040040,0x39e3f,0x80401fe0,
3165 0x407fe040,0x4000000,0x0,0x0,0x3f,0x203ce0,0x407fc060,0x601f,0x3fe0000,0x60060018,0x0,0x0,0x0,0x7fe00,0x6,0xe6012000,0x0,
3166 0x7e0,0x1807e1f0,0x60660660,0x66066066,0x6c3e07c,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7e060e0f,0xf00f00,0xf00f0000,0x8f01f81f,
3167 0x81f81f80,0x60600670,0x1ec1ec1e,0xc1ec1ec1,0xec79c0f0,0xf80f80f,0x80f87fe7,0xfe7fe7fe,0x1f060c1f,0x1f01f01,0xf01f0000,0x4f01cc1c,
3168 0xc1cc1cc0,0xc06f00c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x6006000,0x600,0x600,0x0,0x0,0x0,0x0,
3169 0x600000,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x600060,0x30000000,0x0,0x0,0xc,0x3,0x0,0x0,0x60000c00,0x0,
3170 0x0,0xc000,0x600600,0x60000000,0x18,0xc03100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f8,0x0,0x0,0x0,0x0,0x6,
3171 0x12000,0x2000000,0x40,0x20004000,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3172 0x0,0xc06000c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x2004000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000,
3173 0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0xc00,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x21c,0x3,0x0,0x0,0x60000c00,0x0,0x0,0xc000,
3174 0x7c0603,0xe0000000,0x10,0xc02300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f0,0x0,0x0,0x0,0x0,0x6,0x12000,0x1000000,
3175 0x40,0x7e004000,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc06000c0,0x0,
3176 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x300c000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000,0x0,0x7800000,0x0,
3177 0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x3f8,0x3e,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x3c0603,0xc0000000,
3178 0x10,0xfc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x60000,0x0,0x0,0x0,0x0,0x6,0x0,0x1000000,0x0,0x0,0x0,0x0,
3179 0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3180 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0,
3181 0x0,0x1f0,0x3c,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x600,0x0,0x0,0xf000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3182 0x0,0x0,0x0,0x0,0x0,0x6,0x0,0xe000000,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,
3183 0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3184 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3185 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3186 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3188 // Definition of a 16x32 font.
3189 const unsigned int font16x32[16*32*256/32] = {
3190 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3191 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3192 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3193 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70000e0,0x3c00730,0xe7001c0,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0x730,0x70000e0,0x3c00730,
3194 0xe700000,0x700,0xe003c0,0xe7000e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3195 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3196 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3197 0x0,0x0,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3198 0x0,0x0,0x18001c0,0x6600ff0,0xe7003e0,0x0,0x18001c0,0x6600e70,0x18001c0,0x6600e70,0xff0,0x18001c0,0x6600ff0,0xe700000,0x180,
3199 0x1c00660,0xe7001c0,0x0,0x0,0x0,0x380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3200 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3201 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,
3202 0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00380,
3203 0xc300ce0,0xe700630,0x0,0x1c00380,0xc300e70,0x1c00380,0xc300e70,0xce0,0x1c00380,0xc300ce0,0xe700000,0x1c0,0x3800c30,0xe700380,
3204 0x0,0x0,0x0,0x7c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3205 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3206 0x0,0x0,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,
3207 0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x700000,0x0,0x0,0x0,0x7c007c00,0x3e000000,
3208 0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000070,0x1800000,0xc60,0x0,0xe000070,0x1800000,0xe000070,
3209 0x1800000,0x0,0xe000070,0x1800000,0x0,0xe00,0x700180,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3210 0x0,0x0,0x0,0x800000,0x0,0x600600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3211 0x0,0x0,0x3f0,0xfc0,0x0,0x7000000,0x38000000,0x1c0000,0xfc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,
3212 0x1801f00,0x0,0x0,0x1c,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7300000,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0xe700000,
3213 0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0x0,0xc000c00,0x43800000,0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3214 0xf80,0x70000e0,0x3c00730,0xe700c60,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0xe000730,0x70000e0,0x3c00730,0xe700000,0x700,
3215 0xe003c0,0xe7000e0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300000,0x803c00,0x7c00180,
3216 0xc00300,0x1000000,0x0,0x1c,0x3c007c0,0xfc007e0,0xe01ff8,0x3f03ffc,0x7e007c0,0x0,0x0,0x7c0,0x1c0,0x7f8003f0,0x7f007ff8,0x7ff803f0,
3217 0x70381ffc,0xff0700e,0x7000783c,0x783807c0,0x7fc007c0,0x7fc00fc0,0x7fff7038,0x700ee007,0x780f780f,0x7ffc03f0,0x70000fc0,0x3c00000,
3218 0x3000000,0x38000000,0x1c0000,0x1fc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x1801f80,0x0,0x1f80000,
3219 0x7e,0x0,0x0,0x2400000,0xfc00000,0x7ff0000,0x7ffc0000,0x0,0x0,0x0,0x0,0xf30fb0c,0x2400000,0x0,0x240780f,0x1c0,0xfc,0x780f,
3220 0x18003f0,0xe700000,0x7c00000,0x0,0xff0,0x3c00000,0x78007c0,0xc00000,0xff80000,0xf80,0x7c00000,0xc000c00,0x18001c0,0x1c001c0,
3221 0x1c001c0,0x1c003e0,0x7fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007838,0x7c007c0,0x7c007c0,0x7c00000,0x7c67038,
3222 0x70387038,0x7038780f,0x70001fe0,0x30000c0,0x2400f30,0xe700c60,0x0,0x30000c0,0x2400e70,0x30000c0,0x2400e70,0xf700f30,0x30000c0,
3223 0x2400f30,0xe700000,0x300,0xc00240,0xe7000c0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,
3224 0x630018c,0x807e00,0xfe00180,0xc00300,0x1000000,0x0,0x38,0xff01fc0,0x3ff01ff0,0x1e01ff8,0x7f83ffc,0x1ff80ff0,0x0,0x0,0xff0,
3225 0x1f003e0,0x7fe00ff8,0x7fc07ff8,0x7ff80ff8,0x70381ffc,0xff0701c,0x7000783c,0x78381ff0,0x7fe01ff0,0x7fe01ff0,0x7fff7038,0x781ee007,
3226 0x3c1e380e,0x7ffc0380,0x380001c0,0x3c00000,0x1800000,0x38000000,0x1c0000,0x3c00000,0x380001c0,0xe01c00,0x3800000,0x0,0x0,
3227 0x0,0x7000000,0x0,0x0,0x1e0,0x18003c0,0x0,0x3fc0000,0x70,0x0,0x0,0x6600000,0x1ff00000,0x1fff0000,0x7ffc0000,0x0,0x0,0x0,0x0,
3228 0xcf0239c,0x3c00000,0x0,0x3c0380e,0x1c0,0x2001fe,0x380e,0x18007f8,0xe700000,0x8600000,0x0,0xff0,0x7e00000,0x8c00870,0x1800000,
3229 0x1ff80000,0x180,0xc600000,0xc000c00,0x38001c0,0x3e003e0,0x3e003e0,0x3e001c0,0x7fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,
3230 0x7fc07838,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x1fec7038,0x70387038,0x7038380e,0x70003ce0,0x1800180,0x6600cf0,0xe7007c0,0x0,
3231 0x1800180,0x6600e70,0x1800180,0x6600e70,0x7c00cf0,0x1800180,0x6600cf0,0xe700000,0x180,0x1800660,0xe700180,0x38000e70,0x0,
3232 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630030c,0x3f0e700,0x1e200180,0x1800180,0x21100000,0x0,
3233 0x38,0x1e7819c0,0x38781038,0x1e01c00,0xf080038,0x1c381c38,0x0,0x0,0x1878,0x7fc03e0,0x70e01e18,0x70e07000,0x70001e18,0x703801c0,
3234 0x707038,0x70007c7c,0x7c381c70,0x70701c70,0x70703830,0x1c07038,0x381ce007,0x1c1c3c1e,0x3c0380,0x380001c0,0x7e00000,0xc00000,
3235 0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,0x70c0000,0xe0,
3236 0x0,0x0,0xc300000,0x38300000,0x3c700000,0x3c0000,0x0,0x0,0x0,0x0,0xce022f4,0x1800000,0x0,0x1803c1e,0x1c0,0x2003c2,0x3c1e,
3237 0x1800e08,0x7e0,0x300000,0x0,0x7e00000,0xe700000,0x600030,0x3000000,0x3f980000,0x180,0x18200000,0xc000c00,0x1e0001c0,0x3e003e0,
3238 0x3e003e0,0x3e003e0,0xfe01e18,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70e07c38,0x1c701c70,0x1c701c70,0x1c700000,0x3c787038,
3239 0x70387038,0x70383c1e,0x70003870,0xc00300,0xc300ce0,0x380,0x0,0xc00300,0xc300000,0xc00300,0xc300000,0xfc00ce0,0xc00300,0xc300ce0,
3240 0x0,0xc0,0x3000c30,0x300,0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630031c,0xff8c300,
3241 0x1c000180,0x1800180,0x39380000,0x0,0x70,0x1c3801c0,0x203c001c,0x3e01c00,0x1c000038,0x381c3838,0x0,0x0,0x1038,0xe0e03e0,0x70703c08,
3242 0x70707000,0x70003808,0x703801c0,0x707070,0x70007c7c,0x7c383838,0x70383838,0x70387010,0x1c07038,0x381c700e,0x1e3c1c1c,0x780380,
3243 0x1c0001c0,0xe700000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,
3244 0x0,0xe000000,0xe0,0x0,0x1000100,0x3800,0x70100000,0x38700000,0x780000,0x1c0,0x7801ce0,0xe380000,0x0,0x2264,0x0,0x0,0x1c1c,
3245 0x0,0x200780,0x1c1c,0x1800c00,0x1818,0x7f00000,0x0,0x18180000,0xc300000,0x600070,0x0,0x7f980000,0x180,0x18300000,0xc000c00,
3246 0x3000000,0x3e003e0,0x3e003e0,0x3e003e0,0xee03c08,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,
3247 0x38380000,0x38387038,0x70387038,0x70381c1c,0x7fc03870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbc00000,0x0,0x0,0x0,0x0,0x0,0x0,
3248 0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0xe88c300,0x1c000180,0x38001c0,
3249 0xfe00180,0x0,0x70,0x1c3801c0,0x1c001c,0x6e01c00,0x1c000078,0x381c3818,0x0,0x40000,0x40000038,0x1c0607e0,0x70703800,0x70707000,
3250 0x70003800,0x703801c0,0x7070e0,0x70007c7c,0x7c383838,0x70383838,0x70387000,0x1c07038,0x381c700e,0xf780e38,0x700380,0x1c0001c0,
3251 0x1c380000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,
3252 0xe000000,0xe0,0x0,0x1000100,0x4400,0x70000000,0x38700000,0x700000,0xe0,0x7001c70,0xe380000,0x0,0x2264,0x0,0x0,0xe38,0x0,
3253 0x200700,0xe38,0x1800c00,0x300c,0xc300000,0x0,0x300c0000,0xc300180,0x6003c0,0x0,0x7f980000,0x180,0x18300000,0xc000c00,0x1800000,
3254 0x7e007e0,0x7e007e0,0x7e003e0,0xee03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,0x38380000,
3255 0x38387038,0x70387038,0x70380e38,0x7ff039f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x40000,0x0,0x0,0x38000000,
3256 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0x1c80e700,0x1c000180,0x38001c0,0x3800180,
3257 0x0,0xe0,0x381c01c0,0x1c001c,0x6e01c00,0x38000070,0x381c381c,0x0,0x3c0000,0x78000078,0x38030770,0x70707800,0x70387000,0x70007000,
3258 0x703801c0,0x7071c0,0x7000745c,0x7638701c,0x7038701c,0x70387000,0x1c07038,0x1c38718e,0x7700f78,0xf00380,0xe0001c0,0x381c0000,
3259 0x7e0,0x39e003e0,0x79c03f0,0x3ffc079c,0x39e01fc0,0xfe01c1e,0x3807778,0x39e007e0,0x39e0079c,0x73c07e0,0x7ff83838,0x701ce007,
3260 0x783c701c,0x1ffc01c0,0x18001c0,0x0,0x1c000100,0xe0,0x0,0x1000100,0x4200,0x70000000,0x70700100,0xf00100,0x10000e0,0x7000c70,
3261 0xc700000,0x0,0x2204,0x7e00000,0x1e380100,0x1ffc0f78,0x0,0xf80700,0xf78,0x1800e00,0x63e6,0x18300000,0x0,0x6fe60000,0xe700180,
3262 0xc00060,0x3838,0x7f980000,0x180,0x18300000,0xc000c00,0x18001c0,0x7700770,0x7700770,0x77007f0,0xee07800,0x70007000,0x70007000,
3263 0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1008,0x707c7038,0x70387038,0x70380f78,0x707039c0,0x7e007e0,0x7e007e0,
3264 0x7e007e0,0x1f3c03e0,0x3f003f0,0x3f003f0,0x1fc01fc0,0x1fc01fc0,0x7f039e0,0x7e007e0,0x7e007e0,0x7e00380,0x7ce3838,0x38383838,
3265 0x3838701c,0x39e0701c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6307fff,0x1c807e0c,0xe000180,
3266 0x30000c0,0x3800180,0x0,0xe0,0x381c01c0,0x1c001c,0xce01fe0,0x38000070,0x381c381c,0x3800380,0xfc0000,0x7e0000f0,0x30030770,
3267 0x70707000,0x70387000,0x70007000,0x703801c0,0x707380,0x700076dc,0x7638701c,0x7038701c,0x70387800,0x1c07038,0x1c3873ce,0x7f00770,
3268 0xe00380,0xe0001c0,0x700e0000,0x1ff8,0x3ff00ff0,0xffc0ff8,0x3ffc0ffc,0x3bf01fc0,0xfe01c3c,0x3807f78,0x3bf00ff0,0x3ff00ffc,
3269 0x77e0ff0,0x7ff83838,0x3838e007,0x3c783838,0x1ffc01c0,0x18001c0,0x0,0x7ff00380,0x1e0,0x0,0x1000100,0x4200,0x78000000,0x70700380,
3270 0xe00380,0x3800060,0xe000e30,0x1c600000,0x0,0x2204,0xff00000,0x7f7c0380,0x1ffc0770,0x1c0,0x3fc0700,0x18040770,0x1800780,0x4e12,
3271 0x18300104,0x0,0x4c320000,0x7e00180,0x1c00030,0x3838,0x7f980000,0x180,0x18302080,0xc000c00,0x18001c0,0x7700770,0x7700770,
3272 0x7700770,0x1ee07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c381c,0x705c7038,0x70387038,
3273 0x70380770,0x70383b80,0x1ff81ff8,0x1ff81ff8,0x1ff81ff8,0x3fbe0ff0,0xff80ff8,0xff80ff8,0x1fc01fc0,0x1fc01fc0,0xff83bf0,0xff00ff0,
3274 0xff00ff0,0xff00380,0xffc3838,0x38383838,0x38383838,0x3ff03838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3275 0x0,0x1c0,0x7fff,0x1c803c38,0xf000000,0x70000e0,0xfe00180,0x0,0x1c0,0x381c01c0,0x3c0078,0xce01ff0,0x39e000f0,0x1c38381c,0x3800380,
3276 0x3e07ffc,0xf8001f0,0x307b0770,0x70e07000,0x70387000,0x70007000,0x703801c0,0x707700,0x700076dc,0x7638701c,0x7038701c,0x70387e00,
3277 0x1c07038,0x1c3873ce,0x3e007f0,0x1e00380,0x70001c0,0x0,0x1038,0x3c381e18,0x1c7c1e3c,0x3801e3c,0x3c7801c0,0xe01c78,0x380739c,
3278 0x3c781c38,0x3c381c3c,0x7c21e10,0x7003838,0x3838700e,0x1ef03838,0x3c01c0,0x18001c0,0x0,0x7fe007c0,0x1c0,0x0,0x1000100,0x6400,
3279 0x7e000000,0x707007c0,0x1e007c0,0x7c00070,0xe000638,0x18600000,0x0,0x0,0x1e100000,0x73ce07c0,0x3c07f0,0x1c0,0x7240700,0x1ddc3ffe,
3280 0x1800de0,0x8c01,0x1870030c,0x0,0x8c310000,0x3c00180,0x3800030,0x3838,0x7f980000,0x180,0x183030c0,0xc000c00,0x430001c0,0x7700770,
3281 0x7700770,0x7700770,0x1ce07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1c38,0x70dc7038,
3282 0x70387038,0x703807f0,0x70383b80,0x10381038,0x10381038,0x10381038,0x21e71e18,0x1e3c1e3c,0x1e3c1e3c,0x1c001c0,0x1c001c0,0x1e383c78,
3283 0x1c381c38,0x1c381c38,0x1c380380,0x1c383838,0x38383838,0x38383838,0x3c383838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3284 0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0x1e8000e0,0x1f000000,0x70000e0,0x39380180,0x0,0x1c0,0x3b9c01c0,0x3c07f0,0x18e01078,0x3bf800e0,
3285 0x7e0383c,0x3800380,0x1f807ffc,0x3f001c0,0x61ff0e38,0x7fc07000,0x70387ff0,0x7ff07000,0x7ff801c0,0x707f00,0x7000729c,0x7338701c,
3286 0x7070701c,0x70703fc0,0x1c07038,0x1e7873ce,0x1c003e0,0x3c00380,0x70001c0,0x0,0x1c,0x3c381c00,0x1c3c1c1c,0x3801c3c,0x383801c0,
3287 0xe01cf0,0x380739c,0x38381c38,0x3c381c3c,0x7801c00,0x7003838,0x3838700e,0xfe03c78,0x7801c0,0x18001c0,0x0,0x1c000c20,0xff8,
3288 0x0,0x1ff01ff0,0x3818,0x3fc00100,0x707e0c20,0x3c00c20,0xc200030,0xc000618,0x18c00000,0x0,0x0,0x1c000080,0xe1ce0c20,0x7803e0,
3289 0x1c0,0xe200700,0xff83ffe,0x1801878,0x9801,0x1cf0071c,0x7ffc0000,0x8c310000,0x7ffe,0x7000030,0x3838,0x3f980380,0x180,0xc6038e0,
3290 0x7f9c7f9c,0x3e1c01c0,0xe380e38,0xe380e38,0xe380f78,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,0x1c001c0,0xfe387338,0x701c701c,
3291 0x701c701c,0x701c0e70,0x719c7038,0x70387038,0x703803e0,0x70383b80,0x1c001c,0x1c001c,0x1c001c,0xe71c00,0x1c1c1c1c,0x1c1c1c1c,
3292 0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380000,0x3c383838,0x38383838,0x38383c78,0x3c383c78,0x0,0x0,0x0,0x0,
3293 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0xf800380,0x3f830000,0x70000e0,0x31080180,0x0,0x380,0x3b9c01c0,
3294 0x7807e0,0x38e00038,0x3c3800e0,0xff01c3c,0x3800380,0x7c000000,0x7c03c0,0x61870e38,0x7fc07000,0x70387ff0,0x7ff070fc,0x7ff801c0,
3295 0x707f80,0x7000739c,0x7338701c,0x7ff0701c,0x7fe00ff0,0x1c07038,0xe7073ce,0x1c003e0,0x3800380,0x38001c0,0x0,0x1c,0x381c3800,
3296 0x381c380e,0x380381c,0x383801c0,0xe01de0,0x380739c,0x3838381c,0x381c381c,0x7001e00,0x7003838,0x1c70718e,0x7e01c70,0xf00380,
3297 0x18001e0,0x1e000000,0x1c001bb0,0xff8,0x0,0x1000100,0xe0,0xff00300,0x707e1bb0,0x3801bb0,0x1bb00010,0x8000308,0x30c00000,0x0,
3298 0x0,0x1e0000c0,0xe1ce1bb0,0xf003e0,0x1c0,0x1c203ff8,0x63003e0,0x180181c,0x9801,0xfb00e38,0x7ffc0000,0x8fc10000,0x7ffe,0xe000860,
3299 0x3838,0x1f980380,0x180,0x7c01c70,0x1f001f0,0x1f003c0,0xe380e38,0xe380e38,0xe380e38,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,
3300 0x1c001c0,0xfe387338,0x701c701c,0x701c701c,0x701c07e0,0x731c7038,0x70387038,0x703803e0,0x70383980,0x1c001c,0x1c001c,0x1c001c,
3301 0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x387c3838,0x38383838,0x38381c70,
3302 0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc30,0x7f00e00,0x33c30000,0x70000e0,0x1007ffe,
3303 0x0,0x380,0x3b9c01c0,0xf00078,0x30e0001c,0x3c1c01c0,0x1c381fdc,0x0,0x70000000,0x1c0380,0x63030e38,0x70707000,0x70387000,0x700070fc,
3304 0x703801c0,0x707b80,0x7000739c,0x7338701c,0x7fc0701c,0x7fc001f0,0x1c07038,0xe703e5c,0x3e001c0,0x7800380,0x38001c0,0x0,0x7fc,
3305 0x381c3800,0x381c380e,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7001fc0,0x7003838,0x1c70718e,0x7c01c70,
3306 0xe01f00,0x180007c,0x7f8c0000,0x7fc03fb8,0x1c0,0x0,0x1000100,0x700,0x1f00600,0x70703fb8,0x7803fb8,0x3fb80000,0x8000000,0x180,
3307 0x0,0x0,0x1fc00060,0xe1ce3fb8,0xe001c0,0x1c0,0x1c203ff8,0xc1801c0,0x180c,0x9801,0x1c70,0xc0000,0x8cc10000,0x180,0xfe007c0,
3308 0x3838,0x7980380,0xff0,0xe38,0x3e003e00,0x3e000380,0xe380e38,0xe380e38,0xe380e38,0x38e07000,0x70007000,0x70007000,0x1c001c0,
3309 0x1c001c0,0x70387338,0x701c701c,0x701c701c,0x701c03c0,0x731c7038,0x70387038,0x703801c0,0x703838e0,0x7fc07fc,0x7fc07fc,0x7fc07fc,
3310 0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x38dc3838,0x38383838,0x38381c70,
3311 0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc60,0xf83878,0x71e30000,0x70000e0,0x1007ffe,
3312 0x7f0,0x380,0x381c01c0,0x1e0003c,0x60e0001c,0x381c01c0,0x381c079c,0x0,0x7c000000,0x7c0380,0x63031c1c,0x70307000,0x70387000,
3313 0x7000701c,0x703801c0,0x7071c0,0x7000739c,0x71b8701c,0x7000701c,0x71e00078,0x1c07038,0xe703e7c,0x7e001c0,0xf000380,0x38001c0,
3314 0x0,0x1ffc,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fc0,0x380739c,0x3838381c,0x381c381c,0x7000ff0,0x7003838,0x1ef03bdc,
3315 0x3800ee0,0x1e01f00,0x180007c,0x61fc0000,0x7fc07f3c,0x1c0,0x0,0x1000100,0x1800,0x780c00,0x70707f3c,0xf007f3c,0x7f3c0000,0x0,
3316 0x3c0,0x3ffcffff,0x0,0xff00030,0xe1fe7f3c,0x1e001c0,0x1c0,0x1c200700,0xc183ffe,0xe0c,0x9801,0x1ff038e0,0xc07f0,0x8c610000,
3317 0x180,0x0,0x3838,0x1980380,0x0,0x1ff0071c,0xe000e000,0xe0000f80,0x1c1c1c1c,0x1c1c1c1c,0x1c1c1e38,0x38e07000,0x70007000,0x70007000,
3318 0x1c001c0,0x1c001c0,0x703871b8,0x701c701c,0x701c701c,0x701c03c0,0x761c7038,0x70387038,0x703801c0,0x70703870,0x1ffc1ffc,0x1ffc1ffc,
3319 0x1ffc1ffc,0xfff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x389c3838,0x38383838,
3320 0x38380ee0,0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xfffc,0xbc60fc,0x70e30000,0x70000e0,
3321 0x180,0x7f0,0x700,0x381c01c0,0x3e0001c,0x7ffc001c,0x381c03c0,0x381c001c,0x0,0x1f807ffc,0x3f00380,0x63031ffc,0x70387000,0x70387000,
3322 0x7000701c,0x703801c0,0x7071e0,0x7000701c,0x71b8701c,0x7000701c,0x70f00038,0x1c07038,0x7e03e7c,0x77001c0,0xe000380,0x1c001c0,
3323 0x0,0x3c1c,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x70003f8,0x7003838,0xee03bdc,
3324 0x3c00ee0,0x3c00380,0x18000e0,0xf00000,0x1c007e7c,0x3c0,0x0,0x1000100,0x0,0x381800,0x70707e7c,0xe007e7c,0x7e7c0000,0x0,0x7c0,
3325 0x0,0x0,0x3f80018,0xe1fe7e7c,0x3c001c0,0x1c0,0x1c200700,0xc183ffe,0xf0c,0x8c01,0x38e0,0xc07f0,0x8c710000,0x180,0x0,0x3838,
3326 0x1980000,0x0,0x71c,0x7000f0,0x700f00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x3fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
3327 0x703871b8,0x701c701c,0x701c701c,0x701c07e0,0x7c1c7038,0x70387038,0x703801c0,0x7ff03838,0x3c1c3c1c,0x3c1c3c1c,0x3c1c3c1c,
3328 0x3fff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x391c3838,0x38383838,0x38380ee0,
3329 0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffc,0x9c01ce,0x70f60000,0x70000e0,0x180,
3330 0x0,0x700,0x381c01c0,0x780001c,0x7ffc001c,0x381c0380,0x381c003c,0x0,0x3e07ffc,0xf800380,0x63031ffc,0x70387000,0x70387000,
3331 0x7000701c,0x703801c0,0x7070f0,0x7000701c,0x71b8701c,0x7000701c,0x70700038,0x1c07038,0x7e03e7c,0xf7801c0,0x1e000380,0x1c001c0,
3332 0x0,0x381c,0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7000078,0x7003838,0xee03a5c,
3333 0x7c00fe0,0x78001c0,0x18001c0,0x0,0x1c003ef8,0x380,0x0,0x1000100,0x810,0x383000,0x70703ef8,0x1e003ef8,0x3ef80000,0x0,0x7c0,
3334 0x0,0x0,0x78000c,0xe1c03ef8,0x78001c0,0x1c0,0x1c200700,0x63001c0,0x18003f8,0x4e12,0x1c70,0xc0000,0x4c320000,0x180,0x0,0x3838,
3335 0x1980000,0x0,0xe38,0x700118,0x701e00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x7fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
3336 0x703871b8,0x701c701c,0x701c701c,0x701c0e70,0x7c1c7038,0x70387038,0x703801c0,0x7fc0381c,0x381c381c,0x381c381c,0x381c381c,
3337 0x78e03800,0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x3b1c3838,0x38383838,0x38380fe0,
3338 0x381c0fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1860,0x9c0186,0x707e0000,0x30000c0,0x180,
3339 0x0,0xe00,0x183801c0,0xf00001c,0xe0001c,0x181c0380,0x381c0038,0x0,0xfc0000,0x7e000000,0x61873c1e,0x70383800,0x70707000,0x7000381c,
3340 0x703801c0,0x707070,0x7000701c,0x70f83838,0x70003838,0x70780038,0x1c07038,0x7e03c3c,0xe3801c0,0x1c000380,0xe001c0,0x0,0x381c,
3341 0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01ef0,0x380739c,0x3838381c,0x381c381c,0x7000038,0x7003838,0xfe03e7c,0xfe007c0,
3342 0x70001c0,0x18001c0,0x0,0xe001ff0,0x380,0x0,0x1000100,0x162c,0x381800,0x30701ff0,0x1c001ff0,0x1ff00000,0x0,0x3c0,0x0,0x0,
3343 0x380018,0xe1c01ff0,0x70001c0,0x1c0,0x1c200700,0xff801c0,0x18000f0,0x63e6,0xe38,0x0,0x6c3e0000,0x0,0x0,0x3838,0x1980000,0x0,
3344 0x1c70,0xf0000c,0xf01c00,0x3c1e3c1e,0x3c1e3c1e,0x3c1e3c1c,0x70e03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x707070f8,
3345 0x38383838,0x38383838,0x38381c38,0x38387038,0x70387038,0x703801c0,0x7000381c,0x381c381c,0x381c381c,0x381c381c,0x70e03800,
3346 0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0380,0x3e1c3838,0x38383838,0x383807c0,0x381c07c0,
3347 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18c0,0x9c0186,0x783c0000,0x38001c0,0x180,0x3800000,
3348 0x3800e00,0x1c3801c0,0x1e00003c,0xe00038,0x1c1c0780,0x381c0038,0x3800380,0x3c0000,0x78000000,0x61ff380e,0x70383808,0x70707000,
3349 0x7000381c,0x703801c0,0x40707078,0x7000701c,0x70f83838,0x70003838,0x70384038,0x1c07038,0x7e03c3c,0x1e3c01c0,0x3c000380,0xe001c0,
3350 0x0,0x383c,0x3c381c00,0x1c3c1c00,0x3801c3c,0x383801c0,0xe01c78,0x380739c,0x38381c38,0x3c381c3c,0x7000038,0x7003878,0x7c01e78,
3351 0x1ef007c0,0xf0001c0,0x18001c0,0x0,0xe000ee0,0x7800380,0xe380000,0x1001ff0,0x2242,0x40380c00,0x38700ee0,0x3c000ee0,0xee00000,
3352 0x0,0x0,0x0,0x0,0x380030,0xe1c00ee0,0xf0001c0,0x1c0,0xe200700,0xdd801c0,0x1800038,0x300c,0x71c,0x0,0x300c0000,0x0,0x0,0x3838,
3353 0x1980000,0x0,0x38e0,0xb0000c,0xb01c08,0x380e380e,0x380e380e,0x380e380e,0x70e03808,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
3354 0x707070f8,0x38383838,0x38383838,0x3838381c,0x38387038,0x70387038,0x703801c0,0x7000381c,0x383c383c,0x383c383c,0x383c383c,
3355 0x70e01c00,0x1c001c00,0x1c001c00,0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383878,0x38783878,0x387807c0,
3356 0x3c3807c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x18c0,0x10b801ce,0x3c3e0000,0x38001c0,0x180,
3357 0x3800000,0x3801c00,0x1e7801c0,0x3c002078,0xe02078,0x1c380700,0x1c3810f0,0x3800380,0x40000,0x40000380,0x307b380e,0x70701e18,
3358 0x70e07000,0x70001c1c,0x703801c0,0x60e0703c,0x7000701c,0x70f83c78,0x70003c70,0x703c70f0,0x1c03870,0x3c01c3c,0x3c1c01c0,0x78000380,
3359 0x7001c0,0x0,0x3c7c,0x3c381e18,0x1c7c1e0c,0x3801c3c,0x383801c0,0xe01c38,0x3c0739c,0x38381c38,0x3c381c3c,0x7001078,0x7803c78,
3360 0x7c01c38,0x1c780380,0x1e0001c0,0x18001c0,0x0,0x70c06c0,0x7000380,0xe300000,0x1000100,0x2142,0x70f00600,0x3c7006c0,0x780006c0,
3361 0x6c00000,0x0,0x0,0x0,0x0,0x10780060,0x73e206c0,0x1e0001c0,0x1c0,0x7240700,0x180c01c0,0x1800018,0x1818,0x30c,0x0,0x18180000,
3362 0x0,0x0,0x3c78,0x1980000,0x0,0x30c0,0x130000c,0x1301c18,0x380e380e,0x380e380e,0x380e380e,0x70e01e18,0x70007000,0x70007000,
3363 0x1c001c0,0x1c001c0,0x70e070f8,0x3c783c78,0x3c783c78,0x3c781008,0x7c783870,0x38703870,0x387001c0,0x70003a3c,0x3c7c3c7c,0x3c7c3c7c,
3364 0x3c7c3c7c,0x79f11e18,0x1e0c1e0c,0x1e0c1e0c,0x1c001c0,0x1c001c0,0x1c783838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383c78,0x3c783c78,
3365 0x3c780380,0x3c380380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x38c0,0x1ff800fc,0x1fee0000,
3366 0x1800180,0x180,0x3800000,0x3801c00,0xff01ffc,0x3ffc3ff0,0xe03ff0,0xff00700,0x1ff81fe0,0x3800380,0x0,0x380,0x3000780f,0x7ff00ff8,
3367 0x7fc07ff8,0x70000ffc,0x70381ffc,0x7fe0701c,0x7ff8701c,0x70781ff0,0x70001ff0,0x701c7ff0,0x1c01fe0,0x3c01c38,0x380e01c0,0x7ffc0380,
3368 0x7001c0,0x0,0x1fdc,0x3ff00ff0,0xffc0ffc,0x3800fdc,0x38383ffe,0xe01c3c,0x1fc739c,0x38380ff0,0x3ff00ffc,0x7001ff0,0x3f81fb8,
3369 0x7c01c38,0x3c3c0380,0x1ffc01c0,0x18001c0,0x0,0x3fc0380,0x7000380,0xc70718c,0x1000100,0x2244,0x7ff00200,0x1fff0380,0x7ffc0380,
3370 0x3800000,0x0,0x0,0x0,0x0,0x1ff000c0,0x7f7e0380,0x1ffc01c0,0x1c0,0x3fc3ffe,0x1c0,0x1800018,0x7e0,0x104,0x0,0x7e00000,0x7ffe,
3371 0x0,0x3fde,0x1980000,0x0,0x2080,0x3300018,0x3300ff0,0x780f780f,0x780f780f,0x780f780e,0xf0fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,
3372 0x1ffc1ffc,0x7fc07078,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x7ff01fe0,0x1fe01fe0,0x1fe001c0,0x70003bf8,0x1fdc1fdc,0x1fdc1fdc,
3373 0x1fdc1fdc,0x3fbf0ff0,0xffc0ffc,0xffc0ffc,0x3ffe3ffe,0x3ffe3ffe,0xff03838,0xff00ff0,0xff00ff0,0xff00000,0x3ff01fb8,0x1fb81fb8,
3374 0x1fb80380,0x3ff00380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x31c0,0x7e00078,0x7cf0000,0x1800180,
3375 0x0,0x3800000,0x3803800,0x3c01ffc,0x3ffc0fe0,0xe01fc0,0x3e00e00,0x7e00f80,0x3800380,0x0,0x380,0x18007007,0x7fc003f0,0x7f007ff8,
3376 0x700003f0,0x70381ffc,0x3f80701e,0x7ff8701c,0x707807c0,0x700007c0,0x701e1fc0,0x1c00fc0,0x3c01818,0x780f01c0,0x7ffc0380,0x3801c0,
3377 0x0,0xf9c,0x39e003e0,0x79c03f0,0x380079c,0x38383ffe,0xe01c1e,0x7c739c,0x383807e0,0x39e0079c,0x7000fc0,0x1f80f38,0x3801c38,
3378 0x781e0380,0x1ffc01c0,0x18001c0,0x0,0x1f80100,0xe000700,0x1c60718c,0x1000100,0x1e3c,0x1fc00100,0x7ff0100,0x7ffc0100,0x1000000,
3379 0x0,0x0,0x0,0x0,0xfc00080,0x3e3c0100,0x1ffc01c0,0x1c0,0xf83ffe,0x1c0,0x1800838,0x0,0x0,0x0,0x0,0x7ffe,0x0,0x3b9e,0x1980000,
3380 0x0,0x0,0x2300038,0x23003e0,0x70077007,0x70077007,0x70077007,0xe0fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007078,
3381 0x7c007c0,0x7c007c0,0x7c00000,0xc7c00fc0,0xfc00fc0,0xfc001c0,0x700039f0,0xf9c0f9c,0xf9c0f9c,0xf9c0f9c,0x1f1e03e0,0x3f003f0,
3382 0x3f003f0,0x3ffe3ffe,0x3ffe3ffe,0x7e03838,0x7e007e0,0x7e007e0,0x7e00000,0x63e00f38,0xf380f38,0xf380380,0x39e00380,0x0,0x0,
3383 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x3000000,0x3800,0x0,0x0,0x0,0x0,
3384 0x0,0x300,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x0,0x0,0x0,0x0,0x380,0x3801c0,0x0,0x0,0x0,0x0,0x1c,0x0,0xe00000,
3385 0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1c0,0x18001c0,0x0,0x0,0xe000700,0x18600000,0x1000100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3386 0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800ff0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0x1800000,0x0,0x6300070,0x6300000,0x0,
3387 0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000000,
3388 0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x7000000,
3389 0x7000,0x0,0x0,0x0,0x0,0x0,0x700,0x0,0x0,0xf040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x3f0,0x1c0fc0,0x0,0x0,
3390 0x0,0x0,0x1c,0x0,0xe00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1e0,0x18003c0,0x0,0x0,0xc000700,0x18c00000,0x1000000,0x0,
3391 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x18007e0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000,
3392 0x0,0x7f800e0,0x7f80000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,
3393 0x0,0x0,0x0,0x0,0x0,0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,
3394 0x0,0x600600,0x0,0x6000000,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,
3395 0x3f0,0xfc0,0x0,0x0,0x0,0x0,0x838,0x0,0x1e00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0xf00,0xfc,0x1801f80,0x0,0x0,0x8008e00,0x30c00000,
3396 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000,
3397 0x0,0x3001c0,0x300000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,
3398 0x0,0x0,0x0,0x0,0x0,0xf00,0x38000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,
3399 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3400 0x0,0x0,0xff0,0x0,0x1fc00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3e00,0x7c,0x1801f00,0x0,0x0,0x800fe00,0x0,0x0,0x0,0x0,0x0,0x0,
3401 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7c00000,0x0,0x3001fc,0x300000,
3402 0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3403 0x3e00,0x38003e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3404 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x7e0,0x0,0x1f000000,
3405 0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3c00,0x0,0x1800000,0x0,0x0,0x7800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3406 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3407 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00,0x38003c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3408 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3409 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,0x0,
3410 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3411 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3412 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3413 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3414 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3415 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3416 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3417 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3418 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3419 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3420 0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3422 // Definition of a 19x38 font.
3423 const unsigned int font19x38[19*38*256/32] = {
3424 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3425 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3426 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c380000,0x0,0x1c380,0x0,0x0,0x0,0x0,0x0,
3427 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800007,0x3c003,0x86000000,
3428 0x1e00000,0x3,0x80000700,0x3c00000,0x380000,0x70003c00,0x0,0xe1800e,0x1c00,0xf000e18,0x0,0x0,0x700000e0,0x780000,0x7000,0x0,
3429 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3430 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3431 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3432 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe700000,0x0,0xe700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3433 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0000e,0x7e003,0xe60071c0,0x7f80000,0x1,0xc0000e00,0x7e0038e,0x1c0000,
3434 0xe0007e00,0x38e00000,0xf98007,0x3800,0x1f800f98,0x1c70000,0x0,0x380001c0,0xfc0071,0xc000e000,0x0,0x0,0x0,0x0,0x3e00000,0x0,
3435 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3436 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3437 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3438 0x0,0x0,0x0,0x7e00000,0x0,0x7e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3439 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0001c,0xe7006,0x7c0071c0,0xe180000,0x0,0xe0001c00,0xe70038e,0xe0001,0xc000e700,0x38e00000,
3440 0x19f0003,0x80007000,0x39c019f0,0x1c70000,0x0,0x1c000380,0x1ce0071,0xc001c000,0x0,0x0,0x0,0x0,0x7f00000,0x0,0x0,0x0,0x0,0x0,
3441 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3442 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3443 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,
3444 0x0,0x3c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3445 0x0,0x0,0x700038,0x1c3806,0x3c0071c0,0xc0c0000,0x0,0x70003800,0x1c38038e,0x70003,0x8001c380,0x38e00000,0x18f0001,0xc000e000,
3446 0x70e018f0,0x1c70000,0x0,0xe000700,0x3870071,0xc0038000,0x0,0x0,0x0,0x0,0xe380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3447 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3448 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3449 0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60000000,0x0,0x0,
3450 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c38,0x0,0x1,0xc3800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x0,
3451 0x0,0x0,0x0,0x0,0x0,0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000003,0x80018000,0x0,0xc180000,
3452 0xe,0x380,0x1800000,0xe00000,0x38001800,0x0,0x38,0xe00,0x6000000,0x0,0x1,0xc0000070,0x300000,0x3800,0x0,0x0,0x0,0x0,0x0,0x0,
3453 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3454 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0,0x0,0x0,0x0,
3455 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78c00,0xc30,
3456 0x0,0x0,0xc3000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800000,0x0,0x0,0x0,0xe0,0x1c000f,0xc0000000,0x0,0x0,
3457 0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000007,0x3c003,0xc6000000,0xc180000,0x7,0x700,
3458 0x3c00000,0x700000,0x70003c00,0x0,0xf1801c,0x1c00,0xf000f18,0x0,0x0,0xe00000e0,0x780000,0x7000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3459 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x1c007000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3460 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x3800000,0x700000,0x38,
3461 0x7,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf800e,0x3e0000,0x0,0x0,0x0,0x1e00000,0x0,0x1,
3462 0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7cc00,0x660,0x0,0x0,0x66000000,0x0,0x0,0x0,0x0,0x7,0x1c000000,0x0,0x0,0x0,0x3fe00000,
3463 0x0,0x0,0x7000000,0x0,0x0,0x0,0x3e0,0x7c001f,0xe0000000,0x0,0x0,0x0,0xe1c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3464 0x0,0x0,0x0,0x1f80,0x380000e,0x7e007,0xe60071c0,0xc180000,0x3,0x80000e00,0x7e0038e,0x380000,0xe0007e00,0x38e00f00,0x1f9800e,
3465 0x3800,0x1f801f98,0x1c70000,0x0,0x700001c0,0xfc0071,0xc000e007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3466 0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61c00600,0x1e00007e,0x70000,0x18003000,0x1800000,0x0,0x0,0x1c01f0,0x7e003f,0xc003f800,
3467 0x1e03ffc,0x7f01ff,0xfc03f000,0x7e000000,0x0,0x0,0xfc0,0x1e,0x7fe000,0x7e03fe00,0x3fff07ff,0xe007e038,0x383ffe0,0xff81c01,
3468 0xe1c000f8,0xf8f00e0,0xfc01ffc,0x3f00ff,0xc000fe07,0xfffc7007,0x1c007700,0x73c01ef,0x78ffff,0xfe0380,0xfe000,0x38000000,0x1800000,
3469 0x700000,0x38,0x1f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0xfc0000,
3470 0x0,0x7f00000,0x0,0x1,0x98000000,0x7f00000,0x3ffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0xcf81f,0xee3807e0,0x0,0x0,0x7e03c01e,0x1c,
3471 0x0,0x1f800000,0xf0078038,0xfc007,0x1c000000,0xfe00000,0x0,0x0,0x3fe000f0,0xf,0xc001f800,0x6000000,0xffc000,0x0,0x1c0007e0,
3472 0x360,0x6c0010,0x70000700,0xf0001e,0x3c000,0x78000f00,0x7f800ff,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,
3473 0x7807007,0xe000fc00,0x1f8003f0,0x7e0000,0x1f867,0x70e00e,0x1c01c380,0x38f00787,0x3fe0,0x180000c,0x66006,0x7c0071c0,0xe380000,
3474 0x1,0x80000c00,0x660038e,0x180000,0xc0006600,0x38e0078e,0x19f0006,0x3000,0x198019f0,0x1c70000,0x0,0x30000180,0xcc0071,0xc000c007,
3475 0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61800600,0x7f8001ff,0x70000,
3476 0x38003800,0x1800000,0x0,0x0,0x3807fc,0x1fe00ff,0xf00ffe00,0x3e03ffc,0xff81ff,0xfc07fc01,0xff800000,0x0,0x0,0x3fe0,0xfe001e,
3477 0x7ff801,0xff83ff80,0x3fff07ff,0xe01ff838,0x383ffe0,0xff81c03,0xc1c000f8,0xf8f80e0,0x3ff01fff,0xffc0ff,0xf003ff87,0xfffc7007,
3478 0x1e00f700,0x71c03c7,0x70ffff,0xfe01c0,0xfe000,0x7c000000,0xc00000,0x700000,0x38,0x3f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,
3479 0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0x3fe0000,0x0,0xff00000,0x0,0x3,0xc000000,0x1ffc0000,0xfffe00,
3480 0xffff0,0x0,0x0,0x0,0x0,0x0,0xc781f,0xee3803c0,0x0,0x0,0x3c01c01c,0x1c,0xc000,0x7fc00000,0x70070038,0x3fe007,0x1c000000,0x1ff80000,
3481 0x0,0x0,0x3fe003fc,0x1f,0xe003fc00,0xc000000,0x3ffc000,0x0,0x7c000ff0,0x60,0xc0000,0x30000700,0xf0001e,0x3c000,0x78000f00,
3482 0x3f000ff,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x7c0701f,0xf803ff00,0x7fe00ffc,0x1ff8000,0x7fe67,
3483 0x70e00e,0x1c01c380,0x38700707,0x7ff0,0xc00018,0xc3006,0x3c0071c0,0x7f00000,0x0,0xc0001800,0xc30038e,0xc0001,0x8000c300,0x38e003fc,
3484 0x18f0003,0x6000,0x30c018f0,0x1c70000,0x0,0x18000300,0x1860071,0xc0018007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3485 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe1801fc0,0x618001ff,0x70000,0x30001800,0x21840000,0x0,0x0,0x380ffe,0x1fe00ff,
3486 0xfc0fff00,0x3e03ffc,0x1ff81ff,0xfc0ffe03,0xffc00000,0x0,0x0,0x7ff0,0x3ff803f,0x7ffc03,0xffc3ffc0,0x3fff07ff,0xe03ffc38,0x383ffe0,
3487 0xff81c07,0x81c000f8,0xf8f80e0,0x7ff81fff,0x81ffe0ff,0xf80fff87,0xfffc7007,0xe00e700,0x70e0387,0x80f0ffff,0xe001c0,0xe000,
3488 0xfe000000,0xe00000,0x700000,0x38,0x3c,0x1c,0x1c00,0x1c00700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x78000e,0x3c000,
3489 0x0,0x7ff0000,0x0,0xf100000,0x0,0x7,0xe000000,0x7ffc0000,0x1fffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0x3,0xf780180,0x0,0x0,0x1801e03c,
3490 0x1c,0xc000,0xffc00000,0x780f0038,0x786000,0x7f00,0x18380000,0x0,0xfe00,0x30c,0x10,0x70020e00,0x1c000000,0x7f8c000,0x0,0x6c001c38,
3491 0x60,0xc0000,0x70000700,0x1f8003f,0x7e000,0xfc001f80,0x3f000ff,0xf03ffc1f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,
3492 0x7c0703f,0xfc07ff80,0xfff01ffe,0x3ffc000,0xffec7,0x70e00e,0x1c01c380,0x38780f07,0xf070,0xe00038,0x1c3800,0x0,0x3e00000,0x0,
3493 0xe0003800,0x1c380000,0xe0003,0x8001c380,0x3e0,0x3,0x8000e000,0x70e00000,0x0,0x0,0x1c000700,0x3870000,0x38007,0x0,0x0,0x0,
3494 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe3807ff0,0xc0c003c1,0x70000,0x70001c00,
3495 0x718e0000,0x0,0x0,0x700f1e,0x1ce00c0,0x3c0c0f80,0x7e03800,0x3e08000,0x381e0f03,0xc1e00000,0x0,0x0,0x7078,0x783c03f,0x701e07,
3496 0xc1c383e0,0x38000700,0x7c1c38,0x3801c00,0x381c0f,0x1c000fc,0x1f8f80e0,0x78781c07,0x81e1e0e0,0x780f0180,0xe007007,0xe00e380,
3497 0xe0f0783,0x80e0000e,0xe000e0,0xe001,0xef000000,0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,
3498 0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xf830000,0x0,0x1e000000,0x0,0x0,0x10000,0x780c0000,0x3e38000,0xe0,0x0,0x0,0x0,0x0,0x0,0x3,
3499 0xd580000,0x0,0x0,0xe038,0x1c,0xc000,0xf0400000,0x380e0038,0x702000,0x1ffc0,0xc0000,0x0,0x3ff80,0x606,0x0,0x30000600,0x0,
3500 0x7f8c000,0x0,0xc001818,0x60,0xc0003,0xe0000700,0x1f8003f,0x7e000,0xfc001f80,0x73801ee,0x7c1c1c,0x38000,0x70000e00,0xe0001,
3501 0xc0003800,0x700383e,0x7c0703c,0x3c078780,0xf0f01e1e,0x3c3c000,0xf0f87,0x70e00e,0x1c01c380,0x38380e07,0xe038,0x0,0x0,0x0,
3502 0x0,0x0,0x0,0x0,0x0,0x0,0xff0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3503 0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xc380fff0,0xc0c00380,0x70000,0x70001c00,0x3dbc0070,0x0,0x0,0x701e0f,0xe0000,0x1e000380,
3504 0x6e03800,0x7800000,0x781c0707,0x80e00000,0x0,0x0,0x4038,0xe00c03f,0x700e07,0x4380f0,0x38000700,0x700438,0x3801c00,0x381c0e,
3505 0x1c000ec,0x1b8fc0e0,0xf03c1c03,0xc3c0f0e0,0x3c1e0000,0xe007007,0xe00e380,0xe070703,0xc1e0001e,0xe000e0,0xe001,0xc7000000,
3506 0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xe010000,0x0,
3507 0x1c000000,0x10,0x20000,0x6c000,0xf0000000,0x3838000,0x1e0,0x0,0xf000f,0xf1e00,0x78f00000,0x0,0x3,0xdd80000,0x0,0x0,0xf078,
3508 0x0,0xc001,0xe0000000,0x1c1c0038,0x700000,0x3c1e0,0xc0000,0x0,0x783c0,0x606,0x0,0x30000e00,0x0,0xff8c000,0x0,0xc00300c,0x60,
3509 0xc0003,0xe0000000,0x1f8003f,0x7e000,0xfc001f80,0x73801ce,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x7e07078,
3510 0x1e0f03c1,0xe0783c0f,0x781e000,0x1c0787,0x70e00e,0x1c01c380,0x383c1e07,0xff00e038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x878,
3511 0x0,0x0,0x0,0x7,0x80000080,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,
3512 0x1c7000,0xc301e630,0xc0c00380,0x70000,0xe0000e00,0xff00070,0x0,0x0,0xe01c07,0xe0000,0xe000380,0xce03800,0x7000000,0x701c0707,
3513 0x600000,0x0,0x4000010,0x38,0x1c00e07f,0x80700e0e,0x38070,0x38000700,0xe00038,0x3801c00,0x381c1c,0x1c000ec,0x1b8ec0e0,0xe01c1c01,
3514 0xc38070e0,0x1c1c0000,0xe007007,0x701c380,0xe078e01,0xc1c0003c,0xe00070,0xe003,0x83800000,0x7f,0x71f000,0x3e003e38,0x3f007ff,
3515 0xe01f1c1c,0x7801fc00,0x3fc00701,0xe01c0077,0x8f071e00,0xf801c7c,0x7c700e,0x3e01fc03,0xfff8380e,0xe007700,0x73c0787,0x387ffc,
3516 0x70000e,0x1c000,0x0,0xe000000,0x0,0x1c000000,0x10,0x20000,0xc2000,0xe0000000,0x3838000,0x3c0,0x0,0xf000f,0x78e00,0x70e00000,
3517 0x0,0x3,0xc980fe0,0x1f0,0xf8000007,0xffc07070,0x0,0x3f801,0xc0000000,0x1e3c0038,0x700000,0x70070,0x7fc0000,0x0,0xe00e0,0x606,
3518 0x1c0000,0x70007c00,0x380e,0xff8c000,0x0,0xc00300c,0x60,0xc0000,0x70000000,0x3fc007f,0x800ff001,0xfe003fc0,0x73801ce,0xe0001c,
3519 0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,0x7607070,0xe0e01c1,0xc0383807,0x700e000,0x1c0387,0x70e00e,0x1c01c380,0x381c1c07,
3520 0xffc0e0f8,0x3f8007f,0xfe001,0xfc003f80,0x7f007e3,0xe003e001,0xf8003f00,0x7e000fc,0xfe001f,0xc003f800,0x7f00003c,0x38f0007,
3521 0xc000f800,0x1f0003e0,0x7c0007,0x8003f0c3,0x80e0701c,0xe0381c0,0x70700387,0x1f01c00e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3522 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0xc0c00380,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03c07,
3523 0x800e0000,0xe000380,0x1ce03800,0x7000000,0x701c0707,0x7003c0,0x780000,0x3c00001e,0x38,0x18006073,0x80700e0e,0x38070,0x38000700,
3524 0xe00038,0x3801c00,0x381c38,0x1c000ee,0x3b8ee0e1,0xe01e1c01,0xc78078e0,0x1c1c0000,0xe007007,0x701c387,0xe03de00,0xe3800038,
3525 0xe00070,0xe007,0x1c00000,0x1ff,0xc077f801,0xff807fb8,0xff807ff,0xe03fdc1d,0xfc01fc00,0x3fc00703,0xc01c007f,0xdf877f00,0x3fe01dfe,
3526 0xff700e,0xff07ff03,0xfff8380e,0x700f700,0x71e0f03,0x80707ffc,0x70000e,0x1c000,0x0,0x1c000008,0x0,0x1c000000,0x10,0x20000,
3527 0x82000,0xe0000000,0x7038000,0x80000380,0x2000040,0x7000e,0x38700,0xf1e00000,0x0,0x3,0xc183ff8,0x3fd,0xfc008007,0xffc038e0,
3528 0x0,0xffc01,0xc0008008,0xe380038,0x380000,0xe3e38,0x1ffc0040,0x80000000,0x1cfc70,0x606,0x1c0000,0xe0007c00,0x380e,0xff8c000,
3529 0x0,0xc00300c,0x8100060,0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0x73801ce,0xe0001c,0x38000,0x70000e00,0xe0001,
3530 0xc0003800,0x7003807,0x77070f0,0xf1e01e3,0xc03c7807,0x8f00f080,0x83c0787,0x70e00e,0x1c01c380,0x380e3807,0xffe0e1c0,0xffe01ff,
3531 0xc03ff807,0xff00ffe0,0x1ffc0ff7,0xf01ff807,0xfc00ff80,0x1ff003fe,0xfe001f,0xc003f800,0x7f0003fc,0x3bf801f,0xf003fe00,0x7fc00ff8,
3532 0x1ff0007,0x8007fd83,0x80e0701c,0xe0381c0,0x70380707,0x7f80e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3533 0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0x618081c0,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03803,0x800e0000,0xe000380,0x18e03800,
3534 0xf000000,0xf01c0707,0x7003c0,0x780000,0xfc00001f,0x80000078,0x301e6073,0x80700e1c,0x38038,0x38000700,0x1c00038,0x3801c00,
3535 0x381c70,0x1c000e6,0x338ee0e1,0xc00e1c01,0xc70038e0,0x1c1c0000,0xe007007,0x701c387,0xe01dc00,0xf7800078,0xe00070,0xe00e,0xe00000,
3536 0x3ff,0xe07ffc03,0xffc0fff8,0x1ffc07ff,0xe07ffc1d,0xfe01fc00,0x3fc00707,0x801c007f,0xdf877f80,0x7ff01fff,0x1fff00e,0xff07ff03,
3537 0xfff8380e,0x700e380,0xe0e0e03,0x80707ffc,0x70000e,0x1c000,0x0,0x7ffc001c,0x0,0x1c000000,0x10,0x20000,0x82000,0xe0000000,
3538 0x7038001,0xc0000780,0x70000e0,0x3800e,0x38700,0xe1c00000,0x0,0x3,0xc183ff8,0x7ff,0xfc01c007,0xffc03de0,0x0,0x1ffc01,0xc001c01c,
3539 0xf780038,0x3c0000,0xcff18,0x380c00c1,0x80000000,0x18fe30,0x30c,0x1c0001,0xc0000e00,0x380e,0xff8c000,0x0,0xc00300c,0xc180060,
3540 0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x877070e0,
3541 0x71c00e3,0x801c7003,0x8e0071c0,0x1c380fc7,0x70e00e,0x1c01c380,0x380f7807,0x1e0e380,0x1fff03ff,0xe07ffc0f,0xff81fff0,0x3ffe0fff,
3542 0xf03ffc0f,0xfe01ffc0,0x3ff807ff,0xfe001f,0xc003f800,0x7f0007fe,0x3bfc03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x800fff83,0x80e0701c,
3543 0xe0381c0,0x70380707,0xffc0e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,
3544 0xfff1c600,0x7f8381e0,0x70000,0xc0000600,0xff00070,0x0,0x0,0x1c03803,0x800e0000,0xe000f00,0x38e03fe0,0xe000000,0xe00e0e07,
3545 0x7003c0,0x780007,0xf0ffff87,0xf00000f0,0x307fe0f3,0xc0703c1c,0x38038,0x38000700,0x1c00038,0x3801c00,0x381ce0,0x1c000e6,0x338e70e1,
3546 0xc00e1c01,0xc70038e0,0x3c1e0000,0xe007007,0x783c38f,0x8e01fc00,0x770000f0,0xe00038,0xe01c,0x700000,0x381,0xe07c1e07,0xc0c1e0f8,
3547 0x3c1e0038,0xf07c1f,0xe001c00,0x1c0070f,0x1c0079,0xf3c7c380,0xf0781f07,0x83c1f00f,0xc10f0300,0x1c00380e,0x700e380,0xe0f1e03,
3548 0xc0f00078,0x70000e,0x1c000,0x0,0xfff8003e,0x0,0x3c000000,0x10,0x20000,0xc6000,0xf0000000,0x7038003,0xe0000f00,0xf8001f0,
3549 0x3801c,0x18300,0xe1800000,0x0,0x3,0xc187818,0x70f,0x9e03e000,0x7801dc0,0x1c,0x3cc401,0xc000efb8,0x7f7f0038,0x3f0000,0x1ce11c,
3550 0x300c01c3,0x80000000,0x38c638,0x3fc,0x1c0003,0x80000600,0x380e,0xff8c000,0x0,0xc00300c,0xe1c0060,0xc0010,0x70000700,0x79e00f3,
3551 0xc01e7803,0xcf0079e0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,
3552 0x8e0070e0,0x38381dc7,0x70e00e,0x1c01c380,0x38077007,0xf0e700,0x1c0f0381,0xe0703c0e,0x781c0f0,0x381e083e,0x787c0c1e,0xf03c1e0,
3553 0x783c0f07,0x800e0001,0xc0003800,0x7000fff,0x3e1c078,0x3c0f0781,0xe0f03c1e,0x783c000,0x1e0f03,0x80e0701c,0xe0381c0,0x70380f07,
3554 0xc1e0e03c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1,0x8701c600,0x1e0f01e0,0x1,
3555 0xc0000700,0x3dbc0070,0x0,0x0,0x1c03803,0x800e0000,0x1e01fe00,0x70e03ff8,0xe3e0001,0xe007fc07,0x80f003c0,0x78001f,0xc0ffff81,
3556 0xfc0001e0,0x30e1e0e1,0xc07ff81c,0x38038,0x3ffe07ff,0xc1c0003f,0xff801c00,0x381de0,0x1c000e7,0x738e70e1,0xc00e1c03,0xc70038e0,
3557 0x780f8000,0xe007007,0x383838d,0x8e00f800,0x7f0000e0,0xe00038,0xe000,0x0,0x200,0xf0780e07,0x8041c078,0x380e0038,0xe03c1e,
3558 0xf001c00,0x1c0071e,0x1c0070,0xe1c783c0,0xe0381e03,0x8380f00f,0xe0000,0x1c00380e,0x381c380,0xe07bc01,0xc0e00078,0x70000e,
3559 0x1c000,0x0,0x1c000061,0x0,0x38000000,0x10,0x20000,0x7c000,0x7c000000,0x703fc06,0x10000e00,0x18400308,0x1801c,0x1c381,0xc3800000,
3560 0x0,0x0,0x7000,0xe0f,0xe061000,0x7801fc0,0x1c,0x38c001,0xc0007ff0,0x7fff0038,0x77c000,0x19c00c,0x301c0387,0x0,0x30c618,0xf0,
3561 0x1c0007,0x600,0x380e,0x7f8c007,0x80000000,0xc001818,0x70e03fc,0x387f871f,0xe0e00700,0x70e00e1,0xc01c3803,0x870070e0,0xe1c038f,
3562 0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,0x8e007070,0x703839c7,0x70e00e,
3563 0x1c01c380,0x3807f007,0x70e700,0x10078200,0xf0401e08,0x3c10078,0x200f001c,0x3878041c,0x70380e0,0x701c0e03,0x800e0001,0xc0003800,
3564 0x7001e0f,0x3c1e070,0x1c0e0381,0xc070380e,0x701c000,0x1c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80e07038,0x0,0x0,0x0,0x0,0x0,
3565 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600e600,0x7803f0,0x1,0xc0000700,0x718e0070,0x0,0x0,0x38038c3,
3566 0x800e0000,0x3c01f800,0x60e03ffc,0xeff8001,0xc001f003,0xc1f003c0,0x7800fe,0xffff80,0x3f8003c0,0x60c0e0e1,0xc07fe01c,0x38038,
3567 0x3ffe07ff,0xc1c07e3f,0xff801c00,0x381fe0,0x1c000e3,0x638e30e1,0xc00e1c07,0x870038ff,0xf00ff800,0xe007007,0x38381cd,0x9c007000,
3568 0x3e0001e0,0xe0001c,0xe000,0x0,0x0,0x70780f0f,0x3c078,0x70070038,0x1e03c1c,0x7001c00,0x1c0073c,0x1c0070,0xe1c701c1,0xe03c1e03,
3569 0xc780f00f,0xe0000,0x1c00380e,0x381c387,0xe03f801,0xc0e000f0,0x70000e,0x1c007,0xe0100000,0x1c0000cd,0x80000003,0xffc00000,
3570 0x3ff,0x807ff000,0xe0,0x7fc00060,0x703fc0c,0xd8001e00,0x3360066c,0x1c018,0xc181,0x83000000,0x0,0x0,0x7000,0x300e07,0xe0cd800,
3571 0xf000f80,0x1c,0x78c00f,0xff0038e0,0x3e00038,0xe1e000,0x19800c,0x383c070e,0x7fffc00,0x30fc18,0x0,0xffff80e,0x20e00,0x380e,
3572 0x7f8c007,0x80000000,0xc001c38,0x38703ff,0xf87fff0f,0xcfe00f00,0x70e00e1,0xc01c3803,0x870070e0,0x1e1e078f,0xe1c0001f,0xff03ffe0,
3573 0x7ffc0fff,0x800e0001,0xc0003800,0x700ff83,0x871870e0,0x71c00e3,0x801c7003,0x8e007038,0xe03871c7,0x70e00e,0x1c01c380,0x3803e007,
3574 0x70e700,0x38000,0x70000e00,0x1c00038,0x7001c,0x38f00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7001c07,0x380e0f0,0x1e1e03c3,
3575 0xc078780f,0xf01e000,0x3c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80f07038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3576 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600ff00,0x1e00778,0x38000001,0xc0000700,0x21843fff,0xe0000000,0x0,0x38039e3,0x800e0000,
3577 0x7c01fe00,0xe0e0203e,0xeffc001,0xc00ffe03,0xff700000,0x7f0,0x0,0x7f00380,0x618060e1,0xc07ffc1c,0x38038,0x3ffe07ff,0xc1c07e3f,
3578 0xff801c00,0x381ff0,0x1c000e3,0x638e38e1,0xc00e1fff,0x870038ff,0xc003fe00,0xe007007,0x38381cd,0x9c00f800,0x3e0003c0,0xe0001c,
3579 0xe000,0x0,0x0,0x7070070e,0x38038,0x70070038,0x1c01c1c,0x7001c00,0x1c00778,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0xfc000,
3580 0x1c00380e,0x381c3c7,0x1e01f001,0xe1e001e0,0xf0000e,0x1e01f,0xf8300000,0x1c00019c,0xc0000003,0xffc00000,0x10,0x20000,0x700,
3581 0x1ff000c0,0x703fc19,0xcc003c00,0x67300ce6,0xc038,0xc181,0x83000000,0x0,0x0,0x7e00,0x180e07,0xe19cc00,0x1e000f80,0x1c,0x70c00f,
3582 0xff007070,0x3e00038,0xe0f000,0x19800c,0x1fec0e1c,0x7fffc00,0x30f818,0x0,0xffff81f,0xf003fc00,0x380e,0x3f8c007,0x80000000,
3583 0x7f800ff0,0x1c3803f,0xe007fc00,0xff800e00,0x70e00e1,0xc01c3803,0x870070e0,0x1c0e070f,0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,
3584 0xc0003800,0x700ff83,0x871c70e0,0x71c00e3,0x801c7003,0x8e00701d,0xc038e1c7,0x70e00e,0x1c01c380,0x3803e007,0x70e3c0,0x38000,
3585 0x70000e00,0x1c00038,0x7001c,0x38e00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7003c07,0x8380e0e0,0xe1c01c3,0x80387007,
3586 0xe00e1ff,0xfe381b83,0x80e0701c,0xe0381c0,0x701e1e07,0x707878,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3587 0x0,0x0,0x0,0x0,0x1c,0x3,0xe007fe0,0x7800e3c,0x38000001,0xc0000700,0x1803fff,0xe0000000,0x0,0x70039c3,0x800e0000,0xf8000f80,
3588 0xc0e0000e,0xf83c003,0xc01e0f01,0xff700000,0x7c0,0x0,0x1f00780,0x618061c0,0xe0701e1c,0x38038,0x38000700,0x1c07e38,0x3801c00,
3589 0x381e78,0x1c000e3,0xe38e18e1,0xc00e1fff,0x70038ff,0xe0007f80,0xe007007,0x1c701dd,0x9c00f800,0x1c000780,0xe0000e,0xe000,0x0,
3590 0x7f,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x7fc00,0x1c00380e,
3591 0x1c381c7,0x1c01f000,0xe1c001c0,0xfe0000e,0xfe1f,0xfff00000,0x7ff003fc,0xe0000003,0xffc00000,0x10,0x20000,0x3800,0x3fc0180,
3592 0x703803f,0xce007800,0xff381fe7,0x30,0x0,0xc0,0x0,0x0,0x3fe0,0xc0e07,0xfe3fce00,0x1c000700,0x1c,0x70c00f,0xff006030,0x1c00000,
3593 0xe07800,0x19800c,0xfcc1c38,0x7fffc00,0x30d818,0x0,0xffff81f,0xf001f800,0x380e,0xf8c007,0x80000000,0x7f8007e0,0xe1c3fe,0x7fc00f,
3594 0xf8001e00,0xe0701c0,0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700ff83,0x870c70e0,
3595 0x71c00e3,0x801c7003,0x8e00700f,0x8038c1c7,0x70e00e,0x1c01c380,0x3801c007,0xf0e3e0,0x3ff807f,0xf00ffe01,0xffc03ff8,0x7ff03ff,
3596 0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe383383,0x80e0701c,
3597 0xe0381c0,0x700e1c07,0x703870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0xc000ff0,
3598 0x3c1e1c1c,0x38000001,0xc0000700,0x1803fff,0xe0000007,0xf8000000,0x7003803,0x800e0001,0xf0000381,0xc0e00007,0xf01e003,0x801c0700,
3599 0x7c700000,0x7c0,0x0,0x1f00700,0x618061c0,0xe0700e1c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381e38,0x1c000e1,0xc38e1ce1,
3600 0xc00e1ffc,0x70038e0,0xf0000780,0xe007007,0x1c701dd,0xdc01fc00,0x1c000780,0xe0000e,0xe000,0x0,0x1ff,0xf070070e,0x38038,0x7fff0038,
3601 0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3ff00,0x1c00380e,0x1c381cd,0x9c00e000,0xe1c003c0,
3602 0xf80000e,0x3e18,0x3ff00000,0xffe007fd,0xf0000000,0x38000000,0x10,0x20000,0x1c000,0x3c0300,0x703807f,0xdf007801,0xff7c3fef,
3603 0x80000000,0x0,0x3e0,0x7ffe7ff,0xff000000,0x1ff8,0x60e07,0xfe7fdf00,0x3c000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0xf03800,
3604 0x19800c,0x1c38,0x1c07,0xf830cc18,0x0,0x1c0000,0x0,0x380e,0x18c007,0x80000000,0x0,0xe1cfe0,0x1fc003f,0x80003c00,0xe0701c0,
3605 0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,
3606 0x8e007007,0x3981c7,0x70e00e,0x1c01c380,0x3801c007,0x1e0e0f8,0xfff81ff,0xf03ffe07,0xffc0fff8,0x1fff07ff,0xf8e0003f,0xff87fff0,
3607 0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe386383,0x80e0701c,0xe0381c0,0x700e1c07,
3608 0x703870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x7f,0xffc00678,0x707f9c1e,0x38000001,
3609 0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0003,0xe00001c3,0x80e00007,0xe00e007,0x80380380,0x700000,0x7f0,0x0,0x7f00700,
3610 0x618061ff,0xe070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381c3c,0x1c000e1,0xc38e1ce1,0xc00e1c00,0x70038e0,0x700003c0,
3611 0xe007007,0x1c701d8,0xdc03dc00,0x1c000f00,0xe00007,0xe000,0x0,0x3ff,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007fc,
3612 0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3f00,0x1c00380e,0x1c381cd,0x9c01f000,0x73800780,0xfe0000e,0xfe10,0x7c00000,0x1c000ffb,
3613 0xf8000000,0x38000000,0x10,0x20000,0x20000,0x1e0700,0x70380ff,0xbf80f003,0xfefe7fdf,0xc0000000,0x0,0x3f0,0x7ffe7ff,0xff000000,
3614 0x1f8,0x30e07,0xfeffbf80,0x78000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0x783800,0x1ce11c,0xe1c,0x1c07,0xf838ce38,0x0,0x1c0000,
3615 0x0,0x380e,0x18c000,0x0,0x0,0x1c38c00,0x1800030,0x7800,0xfff01ff,0xe03ffc07,0xff80fff0,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,
3616 0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,0x8e00700f,0x803b81c7,0x70e00e,0x1c01c380,0x3801c007,0xffe0e03c,
3617 0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0fff,0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,
3618 0x80387007,0xe00e000,0x38c383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3619 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0063c,0x40619c0f,0x30000001,0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0007,0xc00001c3,
3620 0xfffc0007,0xe00e007,0x380380,0xf00000,0xfe,0xffff80,0x3f800700,0x618063ff,0xf070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,
3621 0x381c1e,0x1c000e0,0x38e0ee1,0xc00e1c00,0x70038e0,0x380001c0,0xe007007,0x1ef01d8,0xdc038e00,0x1c001e00,0xe00007,0xe000,0x0,
3622 0x7c0,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0079e,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x780,0x1c00380e,
3623 0xe701cd,0x9c01f000,0x73800f00,0xe0000e,0xe000,0x0,0x1c0007f7,0xf0000000,0x70000000,0x10,0x20000,0x0,0xe0e00,0x703807f,0x7f01e001,
3624 0xfdfc3fbf,0x80000000,0x0,0x7f0,0x0,0x0,0x3c,0x18e07,0x7f7f00,0xf0000700,0x1c,0x70c001,0xc0007070,0x1c00000,0x3e7000,0xcff18,
3625 0x3ffc070e,0x1c07,0xf818c630,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x3870000,0xe000fc00,0x380f000,0x1fff83ff,0xf07ffe0f,
3626 0xffc1fff8,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870770e0,0x71c00e3,0x801c7003,0x8e00701d,
3627 0xc03f01c7,0x70e00e,0x1c01c380,0x3801c007,0xffc0e01c,0x3e0387c0,0x70f80e1f,0x1c3e038,0x7c071e1c,0xe00038,0x70000,0xe0001c00,
3628 0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x398383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,
3629 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0061c,0xc0dc07,0xf0000001,0xc0000700,
3630 0x70,0x0,0x0,0x1c003c07,0x800e000f,0x1c3,0xfffc0007,0xe00e007,0x380380,0xe00000,0x1f,0xc0ffff81,0xfc000700,0x618063ff,0xf070070e,
3631 0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0e,0x1c000e0,0x38e0ee1,0xe01e1c00,0x78078e0,0x380001c0,0xe007007,0xee01f8,0xfc078f00,
3632 0x1c001c00,0xe00003,0x8000e000,0x0,0x700,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0070e,0x1c0070,0xe1c701c1,
3633 0xc01c1c01,0xc700700e,0x380,0x1c00380e,0xe700ed,0xb803f800,0x77800f00,0x70000e,0x1c000,0x0,0xe0003f7,0xe0000000,0x70000000,
3634 0x10,0x20000,0x1c0e0,0xe1c00,0x703803f,0x7e01c000,0xfdf81fbf,0x0,0x0,0x3f0,0x0,0x0,0x1c,0x1ce07,0x3f7e00,0xf0000700,0x1c,
3635 0x70c001,0xc00038e0,0x1c00038,0xf7000,0xe3e38,0x3ffc0387,0x1c00,0x1cc770,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x70e0001,
3636 0xe001fe00,0x780e000,0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0ffe,0xe0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,
3637 0x70770f0,0xf1e01e3,0xc03c7807,0x8f00f038,0xe03e03c7,0x70e00e,0x1c01c380,0x3801c007,0xff00e00e,0x38038700,0x70e00e1c,0x1c38038,
3638 0x70071c1c,0xe00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x3b0383,0x80e0701c,
3639 0xe0381c0,0x70077807,0x701de0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x1c00061c,
3640 0xc0de03,0xe0000001,0xc0000700,0x70,0x0,0x0,0x1c001c07,0xe001e,0x1c3,0xfffc0007,0x600e00e,0x380380,0xe00000,0x7,0xf0ffff87,
3641 0xf0000000,0x60c0e380,0x7070070e,0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0f,0x1c000e0,0x38e06e0,0xe01c1c00,0x38070e0,
3642 0x1c0001c0,0xe007007,0xee00f8,0xf80f0700,0x1c003c00,0xe00003,0x8000e000,0x0,0x700,0x70780f0f,0x3c078,0x70000038,0x1e03c1c,
3643 0x7001c00,0x1c0070f,0x1c0070,0xe1c701c1,0xe03c1e03,0xc780f00e,0x380,0x1c00380e,0xe700f8,0xf807bc00,0x3f001e00,0x70000e,0x1c000,
3644 0x0,0xe0001ff,0xc0000000,0x70000000,0x10,0x20000,0x33110,0xe0e00,0x383801f,0xfc03c000,0x7ff00ffe,0x0,0x0,0x3e0,0x0,0x0,0x1c,
3645 0x38e07,0x1ffc01,0xe0000700,0x1c,0x78c001,0xc0007ff0,0x1c00038,0x7c000,0x70070,0x1c3,0x80001c00,0xe00e0,0x0,0x1c0000,0x0,
3646 0x380e,0x18c000,0x0,0x0,0xe1c0001,0xe0010700,0x780e000,0x1c038380,0x70700e0e,0x1c1c038,0x78070e0e,0xe0001c,0x38000,0x70000e00,
3647 0xe0001,0xc0003800,0x7003807,0x7037070,0xe0e01c1,0xc0383807,0x700e070,0x701c0387,0x70e00e,0x1c01c380,0x3801c007,0xe00e,0x38038700,
3648 0x70e00e1c,0x1c38038,0x70071c1c,0xf00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003c07,0x8380e0f0,0x1e1e03c3,0xc078780f,
3649 0xf01e007,0x803e0783,0x80e0701c,0xe0381c0,0x7003f007,0x80f00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3650 0x0,0x0,0x0,0x0,0x0,0x6,0x1800061c,0xc0de01,0xc0000000,0xc0000e00,0x70,0xf0000,0x3c00,0x38001c0f,0xe003c,0x3c0,0xe0000e,0x701e00e,
3651 0x3c0780,0x1e003c0,0x780000,0xfc00001f,0x80000000,0x60e1e780,0x78700f07,0x4380f0,0x38000700,0xf00e38,0x3801c00,0xc0781c07,
3652 0x81c000e0,0x38e07e0,0xe03c1c00,0x380f0e0,0x1e0003c0,0xe00780f,0xee00f0,0x780e0780,0x1c007800,0xe00001,0xc000e000,0x0,0x700,
3653 0xf0780e07,0x8041c078,0x38020038,0xe03c1c,0x7001c00,0x1c00707,0x801c0070,0xe1c701c0,0xe0381e03,0x8380f00e,0x80380,0x1c003c1e,
3654 0x7e00f8,0xf80f1e00,0x3f003c00,0x70000e,0x1c000,0x0,0xf0100f7,0x80078000,0x700078f0,0x10,0x7ff000,0x61208,0x1e0700,0x383800f,
3655 0x78078000,0x3de007bc,0x0,0x0,0x0,0x0,0x0,0x401c,0x70e0f,0xf7803,0xc0000700,0x1c,0x38c001,0xc000efb8,0x1c00038,0x1e000,0x3c1e0,
3656 0xc1,0x80000000,0x783c0,0x0,0x0,0x0,0x3c1e,0x18c000,0x0,0x0,0xc180003,0x60000300,0xd80e010,0x3c03c780,0x78f00f1e,0x1e3c03c,
3657 0x70039c0e,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x703f070,0x1e0e03c1,0xc078380f,0x701e0e0,0x381c0787,
3658 0x80f0f01e,0x1e03c3c0,0x7801c007,0xe00e,0x38078700,0xf0e01e1c,0x3c38078,0x700f1c1c,0x78041c,0x1038020,0x70040e00,0x800e0001,
3659 0xc0003800,0x7001c07,0x380e070,0x1c0e0381,0xc070380e,0x701c007,0x801e0703,0xc1e0783c,0xf0781e0,0xf003f007,0x80e00fc0,0x0,
3660 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xe,0x1801867c,0xc0cf83,0xe0000000,0xe0000e00,
3661 0x70,0xf0000,0x3c00,0x38000f1e,0xe0070,0x180780,0xe0603e,0x783c01e,0x1e0f01,0x7c003c0,0x780000,0x3c00001e,0x700,0x307fe700,
3662 0x38701e07,0xc1c383e0,0x38000700,0x7c1e38,0x3801c00,0xe0f01c03,0x81c000e0,0x38e03e0,0x78781c00,0x1e1e0e0,0xe180780,0xe003c1e,
3663 0x7c00f0,0x781e03c0,0x1c007000,0xe00001,0xc000e000,0x0,0x783,0xf07c1e07,0xc0c1e0f8,0x3e0e0038,0xf07c1c,0x7001c00,0x1c00703,
3664 0xc01e0070,0xe1c701c0,0xf0781f07,0x83c1f00e,0xe0f80,0x1e003c3e,0x7e00f8,0xf80e0e00,0x3f003800,0x70000e,0x1c000,0x0,0x7830077,
3665 0xf0000,0x700078f0,0x10,0x20000,0x41208,0xc03c0380,0x3c38007,0x70070000,0x1dc003b8,0x0,0x0,0x0,0x0,0x0,0x707c,0x6070f,0x86077003,
3666 0x80000700,0x1c,0x3ec401,0xc001c01c,0x1c00038,0xf000,0x1ffc0,0x40,0x80000000,0x3ff80,0x0,0x0,0x0,0x3e3e,0x18c000,0x0,0x0,
3667 0x8100006,0x60000300,0x1980f070,0x3801c700,0x38e0071c,0xe3801c,0x70039c0e,0x7c1c1c,0x38000,0x70000e00,0xe0001,0xc0003800,
3668 0x700383e,0x701f03c,0x3c078780,0xf0f01e1e,0x3c3c1c0,0x1c3f0f03,0xc1e0783c,0xf0781e0,0xf001c007,0xe81e,0x3c1f8783,0xf0f07e1e,
3669 0xfc3c1f8,0x783f1e3e,0x187c0c1f,0x703e0e0,0x7c1c0f83,0x800e0001,0xc0003800,0x7001e0f,0x380e078,0x3c0f0781,0xe0f03c1e,0x783c007,
3670 0x801e0f03,0xc3e0787c,0xf0f81e1,0xf003f007,0xc1e00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3671 0x0,0x0,0x1c,0xe,0x3801fff8,0x6187ff,0xe0000000,0xe0000e00,0x70,0xf0000,0x3c00,0x38000ffe,0x1fff0ff,0xfe1fff80,0xe07ffc,0x3ffc01c,
3672 0x1fff01,0xff8003c0,0x780000,0x4000010,0x700,0x301e6700,0x387ffe03,0xffc3ffc0,0x3fff0700,0x3ffe38,0x383ffe0,0xfff01c03,0xc1fff8e0,
3673 0x38e03e0,0x7ff81c00,0x1ffe0e0,0xf1fff80,0xe003ffe,0x7c00f0,0x781c01c0,0x1c00ffff,0xe00001,0xc000e000,0x0,0x3ff,0x707ffc03,
3674 0xffc0fff8,0x1ffe0038,0x7ffc1c,0x707fff0,0x1c00701,0xc00ff070,0xe1c701c0,0x7ff01fff,0x1fff00e,0xfff00,0xff81fee,0x7e00f0,
3675 0x781e0f00,0x1e007ffc,0x70000e,0x1c000,0x0,0x3ff003e,0xf0000,0xe00070e0,0x60830010,0x20000,0x41208,0xfffc01c0,0x1fffe03,0xe00ffff0,
3676 0xf8001f0,0x0,0x0,0x0,0x0,0x0,0x7ff8,0xc07fd,0xfe03e007,0xffc00700,0x1c,0x1ffc1f,0xffc08008,0x1c00038,0x7000,0x7f00,0x0,0x0,
3677 0xfe00,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0x6,0x60000700,0x19807ff0,0x3801c700,0x38e0071c,0xe3801c,0x70039c0f,0xf03ffc1f,
3678 0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,0x701f03f,0xfc07ff80,0xfff01ffe,0x3ffc080,0x83fff03,0xffe07ffc,0xfff81ff,
3679 0xf001c007,0xeffc,0x1ffb83ff,0x707fee0f,0xfdc1ffb8,0x3ff70ff7,0xf83ffc0f,0xff01ffe0,0x3ffc07ff,0x83fff87f,0xff0fffe1,0xfffc0ffe,
3680 0x380e03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x803ffe01,0xfee03fdc,0x7fb80ff,0x7001e007,0xffc00780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3681 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x3801fff0,0x7f83fe,0x70000000,0xe0000e00,0x0,0xf0000,0x3c00,0x700007fc,
3682 0x1fff0ff,0xfe1ffe00,0xe07ff8,0x1ff801c,0xffe01,0xff0003c0,0x780000,0x0,0x700,0x38000f00,0x3c7ffc01,0xff83ff80,0x3fff0700,
3683 0x1ffc38,0x383ffe0,0x7fe01c01,0xe1fff8e0,0x38e03e0,0x3ff01c00,0xffc0e0,0x71fff00,0xe001ffc,0x7c00f0,0x783c01e0,0x1c00ffff,
3684 0xe00000,0xe000e000,0x0,0x1ff,0x7077f801,0xff807fb8,0xffc0038,0x3fdc1c,0x707fff0,0x1c00701,0xe007f070,0xe1c701c0,0x3fe01dfe,
3685 0xff700e,0x7fe00,0xff80fee,0x3c0070,0x703c0780,0x1e007ffc,0x70000e,0x1c000,0x0,0x1fe001c,0xe0000,0xe000e1c0,0x71c78010,0x20000,
3686 0x21318,0xfff800c0,0xfffe01,0xc00ffff0,0x70000e0,0x0,0x0,0x0,0x0,0x0,0x3ff0,0x1803fd,0xfe01c007,0xffc00700,0x1c,0xffc1f,0xffc00000,
3687 0x1c00038,0x7000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0xc,0x60000e00,0x31803fe0,0x7801ef00,0x3de007bc,
3688 0xf7801e,0xf003fc0f,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x701f01f,0xf803ff00,0x7fe00ffc,0x1ff8000,
3689 0x67fe01,0xffc03ff8,0x7ff00ff,0xe001c007,0xeff8,0xffb81ff,0x703fee07,0xfdc0ffb8,0x1ff70ff7,0xf81ff807,0xfe00ffc0,0x1ff803ff,
3690 0x3fff87f,0xff0fffe1,0xfffc07fc,0x380e01f,0xf003fe00,0x7fc00ff8,0x1ff0000,0x37fc00,0xfee01fdc,0x3fb807f,0x7001e007,0x7f800780,
3691 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x30007fc0,0x1e00f8,0x78000000,0x70001c00,
3692 0x0,0xe0000,0x3c00,0x700001f0,0x1fff0ff,0xfe07f800,0xe01fe0,0x7e0038,0x3f800,0xfc0003c0,0x700000,0x0,0x700,0x18000e00,0x1c7ff000,
3693 0x7e03fe00,0x3fff0700,0x7f038,0x383ffe0,0x1f801c00,0xf1fff8e0,0x38e01e0,0xfc01c00,0x3f80e0,0x787fc00,0xe0007f0,0x7c00f0,0x387800f0,
3694 0x1c00ffff,0xe00000,0xe000e000,0x0,0xfc,0x7071f000,0x3f003e38,0x3f00038,0x1f1c1c,0x707fff0,0x1c00700,0xf003f070,0xe1c701c0,
3695 0x1f801c7c,0x7c700e,0x1f800,0x3f8078e,0x3c0070,0x707803c0,0x1c007ffc,0x70000e,0x1c000,0x0,0x7c0008,0x1e0000,0xe000e1c0,0x71c30010,
3696 0x20000,0x1e1f0,0x3fe00020,0x3ffe00,0x800ffff0,0x2000040,0x0,0x0,0x0,0x0,0x0,0xfc0,0x3001f0,0x78008007,0xffc00700,0x1c,0x3f81f,
3697 0xffc00000,0x1c00038,0x407000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x39c7,0x18c000,0x0,0x0,0x18,0x60001c00,0x61801f80,0x7000ee00,
3698 0x1dc003b8,0x77000e,0xe001f80f,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,0x700f007,0xe000fc00,0x1f8003f0,
3699 0x7e0000,0xe1f800,0x7f000fe0,0x1fc003f,0x8001c007,0xe7f0,0x7e380fc,0x701f8e03,0xf1c07e38,0xfc703c1,0xe003f001,0xf8003f00,
3700 0x7e000fc,0x3fff87f,0xff0fffe1,0xfffc03f8,0x380e00f,0xc001f800,0x3f0007e0,0xfc0000,0x61f800,0x78e00f1c,0x1e3803c,0x7001c007,
3701 0x1f000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x70001c00,0x0,
3702 0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
3703 0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
3704 0x70000e,0x1c000,0x0,0x0,0x1c0000,0xe000c180,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
3705 0x0,0x38,0x70e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x2000,0x0,0x1f,0xf8003800,0x7fe00000,0x0,0x0,0x0,0x0,0x4000,
3706 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400000,
3707 0x0,0x0,0x1c007,0x700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x30001800,
3708 0x0,0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e000,
3709 0x0,0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
3710 0x70000e,0x1c000,0x0,0x0,0x1c0001,0xe001c380,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
3711 0x0,0x38,0x7fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x3000,0x0,0x1f,0xf8007000,0x7fe00000,0x0,0x0,0x0,0x0,0x6000,
3712 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3713 0x0,0x1c007,0x700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x38003800,
3714 0x0,0x380000,0x1,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x3c18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf000,
3715 0x0,0x0,0x0,0x0,0x0,0xfe0000,0x380fe000,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x38000000,
3716 0x78000e,0x3c000,0x0,0x0,0x180001,0xc0018300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,
3717 0x38,0x1f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x1800,0x0,0x0,0x6000e000,0x1800000,0x0,0x0,0x0,0x0,0x3000,0x0,
3718 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3719 0x38007,0xe00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x18003000,
3720 0x0,0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x1ff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,
3721 0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x0,0x0,0x0,0x0,0x607800,0x0,0x3c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x78000000,
3722 0x3f800e,0x3f8000,0x0,0x0,0x300043,0xc0018200,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
3723 0x0,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x11800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x23000,0x0,0x0,
3724 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x23000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78007,
3725 0x1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x1c007000,0x0,0x0,
3726 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe0000,
3727 0xfe000,0x0,0x0,0x0,0x0,0x0,0x7ff000,0x0,0x7f800000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf8000000,0x3f800e,0x3f8000,0x0,
3728 0x0,0x10007f,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x38,0x0,0x0,0x0,0x0,
3729 0x0,0x0,0x0,0x0,0x3800,0x0,0x1f800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x3f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3730 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f8007,0xfe00,0x0,0x0,0x0,0x0,
3731 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3732 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x7fe000,0x0,
3733 0x7f000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf0000000,0xf800e,0x3e0000,0x0,0x0,0x7f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3734 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1f000,0x0,0x0,0x0,0x0,0x0,
3735 0x0,0x0,0x0,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,
3736 0x0,0x0,0x0,0x0,0x0,0x0,0x3f0007,0xfc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3737 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3738 0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x1fc000,0x0,0x7e000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xc0000000,0xe,0x0,
3739 0x0,0x0,0x3e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3740 0x0,0x0,0x3800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3741 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0007,0xf000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3742 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3743 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3744 0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3745 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3746 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
3748 // Definition of a 29x57 font.
3749 const unsigned int font29x57[29*57*256/32] = {
3750 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3751 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3752 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3753 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3754 0x0,0x781e00,0x0,0x0,0x7,0x81e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3755 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0000,0xf8000,0x7e00000,0x0,0x7,
3756 0xc0000000,0x0,0x7c00,0xf80,0x7e000,0x0,0x7c00000,0xf80000,0x7e000000,0x0,0x0,0x1f00,0x3e0,0x1f800,0x0,0x0,0x0,0x3,0xe0000000,
3757 0x7c00003f,0x0,0xf8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3758 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3759 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3760 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3761 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3762 0x0,0x0,0x0,0x0,0x0,0x0,0x3c3c00,0x0,0x0,0x3,0xc3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,
3763 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,
3764 0x1f0000,0x7e00000,0xf838001f,0xf80001f,0xf0000000,0x0,0x3e00,0x1f00,0x7e000,0x3e1f000,0x3e00000,0x1f00000,0x7e00003e,0x1f000000,
3765 0x3e0,0xe0000f80,0x7c0,0x1f800,0x3e0e00,0x7c3e000,0x0,0x1,0xf0000000,0xf800003f,0x1f0f,0x800001f0,0x0,0x0,0x0,0x0,0x0,0x0,
3766 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3767 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3768 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3769 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3770 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e7800,0x0,0x0,
3771 0x1,0xe7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3772 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x1e0000,0xff00001,0xfe38001f,0xf80003f,
3773 0xf8000000,0x0,0x1e00,0x1e00,0xff000,0x3e1f000,0x1e00000,0x1e00000,0xff00003e,0x1f000000,0x7f8,0xe0000780,0x780,0x3fc00,0x7f8e00,
3774 0x7c3e000,0x0,0x0,0xf0000000,0xf000007f,0x80001f0f,0x800001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3775 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3776 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3777 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3778 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3779 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xef000,0x0,0x0,0x0,0xef000000,0x0,0x0,0x0,0x0,0x0,0x0,
3780 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3781 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000,0x3c0000,0x1e780003,0xfff8001f,0xf80003c,0x78000000,0x0,0xf00,0x3c00,0x1e7800,
3782 0x3e1f000,0xf00000,0x3c00001,0xe780003e,0x1f000000,0xfff,0xe00003c0,0xf00,0x79e00,0xfffe00,0x7c3e000,0x0,0x0,0x78000001,0xe00000f3,
3783 0xc0001f0f,0x800003c0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3784 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3785 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3786 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3787 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3788 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3789 0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3790 0x0,0x78000,0x780000,0x3c3c0003,0x8ff0001f,0xf800078,0x3c000000,0x0,0x780,0x7800,0x3c3c00,0x3e1f000,0x780000,0x7800003,0xc3c0003e,
3791 0x1f000000,0xe3f,0xc00001e0,0x1e00,0xf0f00,0xe3fc00,0x7c3e000,0x0,0x0,0x3c000003,0xc00001e1,0xe0001f0f,0x80000780,0x0,0x0,
3792 0x0,0x0,0x0,0x0,0x1f,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3793 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3794 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3795 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3796 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3797 0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,
3798 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc00,0x7e000,0xfe000,0x0,0x3c000,0xf00000,0x781e0003,
3799 0x83e0001f,0xf800070,0x1c000000,0x0,0x3c0,0xf000,0x781e00,0x3e1f000,0x3c0000,0xf000007,0x81e0003e,0x1f000000,0xe0f,0x800000f0,
3800 0x3c00,0x1e0780,0xe0f800,0x7c3e000,0x0,0x0,0x1e000007,0x800003c0,0xf0001f0f,0x80000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf8000000,
3801 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3802 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3803 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3804 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3805 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3806 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3807 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ff800,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3808 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3809 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3810 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3811 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3812 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3813 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3814 0x0,0x0,0x78,0xf000000,0x0,0x0,0x780f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0,
3815 0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ffc00,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3816 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x3e000,0x3e00000,0x0,0x78,0x3c000000,0x0,0x1f000,0x3e0,
3817 0x3e000,0x0,0x1f000000,0x3e0000,0x3e000000,0x0,0x0,0x7c00,0xf8,0xf800,0x0,0x0,0x0,0xf,0x80000000,0x1f00001f,0x0,0x3e,0x0,
3818 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3819 0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3820 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80000,
3821 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3822 0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x781c0000,0x38,0xe000000,0x0,0x0,0x380e0,0x0,
3823 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x39c00,0x1ce000,0x303e00,
3824 0x0,0x0,0x0,0x0,0x0,0x78,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,
3825 0x0,0x0,0xf80000,0x7c000,0x3e00000,0xf0380000,0x70,0x1c000000,0x0,0xf800,0x7c0,0x3e000,0x0,0xf800000,0x7c0000,0x3e000000,
3826 0x0,0x3c0,0xe0003e00,0x1f0,0xf800,0x3c0e00,0x0,0x0,0x7,0xc0000000,0x3e00001f,0x0,0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3827 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0xff,0x0,
3828 0xf8,0xf8000,0x1c000,0x0,0x0,0x0,0x0,0x1f,0xc0000000,0x1ff8,0xff00,0x0,0x0,0x3fe000,0x0,0x1fc00001,0xfe000000,0x0,0x0,0x0,
3829 0x0,0x7f800,0x0,0x0,0x0,0xff00000,0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf8000000,0xfe,0x0,0x7f80,0x0,0x0,0x0,0x0,0x0,
3830 0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x780000,0x1,0xe0000000,0x0,0x780000,0x3,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,
3831 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x3fc00,0x0,0x0,0x1fc000,0x0,0x0,0x0,0x1fc0,
3832 0x0,0xff000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe1c0000,0x1c,0x1c000000,0x0,0x0,0x1c1c0,0x0,0x0,0x0,0x0,0x1fe0000,
3833 0x0,0x0,0x1ff,0x1f0f8,0x0,0xff000,0x0,0x0,0x0,0x3f,0xff00000f,0x80000000,0xfe0,0x3f80,0xf00,0x0,0x0,0x0,0x1,0xf8000003,0xe0000000,
3834 0x1c00,0xe000,0xe00,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,
3835 0x7f0000,0x0,0x1fc07000,0x0,0x0,0x0,0x0,0x0,0x3f800,0x780000,0x78000,0x7f00001,0xfc38001f,0xf800070,0x1c000000,0x0,0x7800,
3836 0x780,0x7f000,0x3e1f000,0x7800000,0x780000,0x7f00003e,0x1f0003f0,0x7f0,0xe0001e00,0x1e0,0x1fc00,0x7f0e00,0x7c3e000,0x0,0x3,
3837 0xc0000000,0x3c00003f,0x80001f0f,0x80000078,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3838 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x1e078000,0x30000000,0x3ff,0xc00001e0,0xf0,
3839 0x78000,0x1c000,0x0,0x0,0x0,0x0,0x1e0007f,0xf000007e,0x1ffff,0x7ffe0,0x1f80,0x3ffff80,0xfff803,0xfffff800,0xfff80007,0xff800000,
3840 0x0,0x0,0x0,0x0,0x1ffe00,0x0,0xfe0003,0xfff80000,0x3ffe01ff,0xe00003ff,0xffe01fff,0xff0003ff,0xe01e0007,0x803ffff0,0xfff80,
3841 0x3c000fc0,0x7800001f,0x8003f07e,0x1e000f,0xfe0007ff,0xf00003ff,0x8007ffe0,0x1fff8,0x7fffffe,0xf0003c1,0xe000079e,0xf1f,0x1f3e0,
3842 0x1f01ff,0xfff8003f,0xf003c000,0x7fe0,0x3f00,0x0,0x3c0000,0x1,0xe0000000,0x0,0x780000,0xf,0xfe000000,0x78000,0x3c00,0xf000,
3843 0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xfc0000f0,0x3fe00,0x0,0x0,0xfff00,0x0,0x0,0x3fe000,
3844 0x0,0x0,0x0,0x1dc0,0x0,0x3fff00,0x0,0x3ffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff1c07ff,0x3c0f001e,0x3c000000,
3845 0x0,0x0,0x1e3c0,0xf80007c,0x0,0x780000,0x0,0xfff8000,0x3e00,0x1f00000,0x7ff,0xc001f0f8,0x0,0x3ffc00,0x0,0x0,0x0,0x3f,0xff00003f,
3846 0xe0000000,0x3ff8,0xffe0,0x1e00,0x0,0xfffc00,0x0,0x7,0xf800000f,0xf8000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,
3847 0x3f800001,0xfc00003f,0xf80000ff,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,
3848 0xfc00,0x3c001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x0,0x7ff8f0f0,0x3c0780,0x1e03c00,0xf01e000,0x783e0001,0xf01e0000,0xffe00,
3849 0x3c0000,0xf0000,0x7700001,0xfe38001f,0xf800070,0x1c000000,0x0,0x3c00,0xf00,0x77000,0x3e1f000,0x3c00000,0xf00000,0x7700003e,
3850 0x1f0000f8,0xc0007f8,0xe0000f00,0x3c0,0x1dc00,0x7f8e00,0x7c3e000,0x0,0x1,0xe0000000,0x7800003b,0x80001f0f,0x800000f0,0x1e0000,
3851 0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3852 0x0,0x0,0x780000,0x3c1e0000,0x1e070000,0x300001f0,0x7ff,0xc00001e0,0x1e0,0x7c000,0x1c000,0x0,0x0,0x0,0x0,0x3c000ff,0xf80007fe,
3853 0x3ffff,0x801ffff8,0x1f80,0x3ffff80,0x3fff803,0xfffff801,0xfffc000f,0xffc00000,0x0,0x0,0x0,0x0,0x7fff80,0x0,0xfe0003,0xffff0000,
3854 0xffff01ff,0xfc0003ff,0xffe01fff,0xff000fff,0xf01e0007,0x803ffff0,0xfff80,0x3c001f80,0x7800001f,0xc007f07e,0x1e001f,0xff0007ff,
3855 0xfc0007ff,0xc007fffc,0x3fffc,0x7fffffe,0xf0003c1,0xf0000f9e,0xf0f,0x8003e1e0,0x1e01ff,0xfff8003f,0xf001e000,0x7fe0,0x3f00,
3856 0x0,0x1e0000,0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,
3857 0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x1fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x3de0,0x0,0x7fff80,0x0,0xfffff80,
3858 0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe7bc07ff,0x3e1f000f,0x78000000,0x0,0x0,0xf780,0x7800078,0x0,0x780000,0x180000,
3859 0x1fff8000,0x1e00,0x1e0003c,0xfff,0xc001f0f8,0x0,0x7ffe00,0x0,0x0,0x0,0x3f,0xff00007f,0xf0000000,0x3ffc,0xfff0,0x3c00,0x0,
3860 0x7fffc00,0x0,0x7,0xf800003f,0xfe000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xe00001ff,
3861 0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000fc00,0x3c003ffe,0x1fff0,
3862 0xfff80,0x7ffc00,0x3ffe000,0x0,0xfffce0f0,0x3c0780,0x1e03c00,0xf01e000,0x781e0001,0xe01e0000,0x3fff00,0x1e0000,0x1e0000,0xf780003,
3863 0xcf78001f,0xf800078,0x3c000000,0x0,0x1e00,0x1e00,0xf7800,0x3e1f000,0x1e00000,0x1e00000,0xf780003e,0x1f0000fc,0x7c000f3d,
3864 0xe0000780,0x780,0x3de00,0xf3de00,0x7c3e000,0x0,0x0,0xf0000000,0xf000007b,0xc0001f0f,0x800001e0,0x1e0000,0x3e1f00,0x0,0x0,
3865 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
3866 0x3c1e0000,0x1e0f0000,0x300007fc,0xfff,0xc00001e0,0x1e0,0x3c000,0x1c000,0x0,0x0,0x0,0x0,0x3c001ff,0xfc001ffe,0x3ffff,0xc01ffffc,
3867 0x3f80,0x3ffff80,0x7fff803,0xfffff803,0xfffe001f,0xffe00000,0x0,0x0,0x0,0x0,0xffff80,0x7f800,0xfe0003,0xffff8001,0xffff01ff,
3868 0xff0003ff,0xffe01fff,0xff001fff,0xf01e0007,0x803ffff0,0xfff80,0x3c003f00,0x7800001f,0xc007f07f,0x1e003f,0xff8007ff,0xff000fff,
3869 0xe007ffff,0x7fffc,0x7fffffe,0xf0003c0,0xf0000f1e,0xf07,0x8003c1f0,0x3e01ff,0xfff8003f,0xf001e000,0x7fe0,0x7f80,0x0,0xe0000,
3870 0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
3871 0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x3fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x78f0,0x0,0xffff80,0x0,0x3fffff80,0x1f,
3872 0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc7f80070,0x3e1f0007,0x70000000,0x0,0x0,0x7700,0x7c000f8,0x0,0x780000,0x180000,
3873 0x3fff8000,0x1f00,0x3e0003c,0x1f03,0xc001f0f8,0x0,0x703f00,0x0,0x0,0x0,0x3f,0xff0000f0,0xf8000000,0x303e,0xc0f8,0x7800,0x0,
3874 0xffffc00,0x0,0x7,0x3800003e,0x3e000000,0x1c00,0xe000,0x3c00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00000f,0xe00001ff,
3875 0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000fe00,0x3c007fff,0x3fff8,
3876 0x1fffc0,0xfffe00,0x7fff000,0x1,0xffffc0f0,0x3c0780,0x1e03c00,0xf01e000,0x781f0003,0xe01e0000,0x3fff80,0xe0000,0x3c0000,0x1e3c0003,
3877 0x8ff0001f,0xf80003c,0x78000000,0x0,0xe00,0x3c00,0x1e3c00,0x3e1f000,0xe00000,0x3c00001,0xe3c0003e,0x1f00007f,0xf8000e3f,0xc0000380,
3878 0xf00,0x78f00,0xe3fc00,0x7c3e000,0x0,0x0,0x70000001,0xe00000f1,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,
3879 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0000,
3880 0x30000ffe,0xf80,0xc00001e0,0x3c0,0x1e000,0x101c040,0x0,0x0,0x0,0x0,0x78003f0,0x7e001ffe,0x3f807,0xe01f00fe,0x3f80,0x3ffff80,
3881 0x7e01803,0xfffff007,0xe03f003f,0x3f00000,0x0,0x0,0x0,0x0,0xfc0fc0,0x3ffe00,0xfe0003,0xffffc003,0xf81f01ff,0xff8003ff,0xffe01fff,
3882 0xff003f01,0xf01e0007,0x803ffff0,0xfff80,0x3c007e00,0x7800001f,0xc007f07f,0x1e007e,0xfc007ff,0xff801f83,0xf007ffff,0x800fc07c,
3883 0x7fffffe,0xf0003c0,0xf0000f0f,0x1e07,0xc007c0f8,0x7c01ff,0xfff8003c,0xf000,0x1e0,0xffc0,0x0,0xf0000,0x1,0xe0000000,0x0,0x780000,
3884 0x3e,0x0,0x78000,0x3c00,0xf000,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0x800000f0,0x1f80,
3885 0x0,0x0,0x7e0780,0x0,0x0,0x1f82000,0x0,0x0,0x0,0x7070,0x0,0x1f80f80,0x0,0x7fffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,
3886 0x0,0x1,0xc3f80070,0x3f3f0007,0xf0000000,0x0,0x0,0x7f00,0x3e001f0,0x0,0x780000,0x180000,0x7f018000,0xf80,0x7c0003c,0x3e00,
3887 0x4001f0f8,0xfe00,0x400f00,0x0,0x0,0x0,0x7f000000,0xe0,0x38000000,0x1e,0x38,0x7800,0x0,0x1ffe1c00,0x0,0x0,0x38000078,0xf000000,
3888 0x1c00,0xe000,0x7f800,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xf00001ff,0xffc03f81,0xf007ffff,0xc03ffffe,
3889 0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf800fe00,0x3c00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,
3890 0x3,0xf07fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x780f8007,0xc01e0000,0x7e0fc0,0xf0000,0x3c0000,0x1c1c0003,0x87f0001f,0xf80003f,
3891 0xf8000000,0x0,0xf00,0x3c00,0x1c1c00,0x3e1f000,0xf00000,0x3c00001,0xc1c0003e,0x1f00003f,0xc0000e1f,0xc00003c0,0xf00,0x70700,
3892 0xe1fc00,0x7c3e000,0x0,0x0,0x78000001,0xe00000e0,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3893 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0001,0xff801e0f,
3894 0x1f00,0x1e0,0x3c0,0x1e000,0x3c1c1e0,0x0,0x0,0x0,0x0,0x78007c0,0x1f001f9e,0x3c001,0xf010003e,0x7780,0x3c00000,0xf800000,0xf007,
3895 0xc01f007c,0x1f80000,0x0,0x0,0x0,0x0,0xe003e0,0x7fff00,0x1ef0003,0xc007e007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x301e0007,
3896 0x80007800,0x780,0x3c00fc00,0x7800001f,0xe00ff07f,0x1e00f8,0x3e00780,0x1fc03e00,0xf807801f,0xc01f001c,0xf000,0xf0003c0,0xf0000f0f,
3897 0x1e03,0xc00f8078,0x780000,0xf0003c,0xf000,0x1e0,0x1f3e0,0x0,0x78000,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,
3898 0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0xf0,0xf80,0x0,0x0,0xf80180,0x0,0x0,0x1e00000,
3899 0x0,0x0,0x0,0xe038,0x0,0x3e00380,0x0,0xfe0f0000,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc0f00070,0x3b370003,0xe0000000,
3900 0x0,0x0,0x3e00,0x1e001e0,0x0,0x780000,0x180000,0x7c000000,0x780,0x780003c,0x3c00,0x0,0x7ffc0,0x780,0x0,0x0,0x3,0xffe00000,
3901 0x1c0,0x3c000000,0xe,0x38,0xf000,0x0,0x3ffe1c00,0x0,0x0,0x38000078,0xf000000,0x1c00,0xe000,0x7f000,0xf000,0x3de000,0x1ef0000,
3902 0xf780000,0x7bc00003,0xde00001e,0xf00003e7,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
3903 0xe0001e03,0xfc00fe00,0x3c01f007,0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x7,0xc01f80f0,0x3c0780,0x1e03c00,0xf01e000,0x78078007,
3904 0x801e0000,0x7803c0,0x78000,0x780000,0x380e0003,0x81e00000,0x1f,0xf0000000,0x0,0x780,0x7800,0x380e00,0x0,0x780000,0x7800003,
3905 0x80e00000,0x1ff,0x80000e07,0x800001e0,0x1e00,0xe0380,0xe07800,0x0,0x0,0x0,0x3c000003,0xc00001c0,0x70000000,0x780,0x1e0000,
3906 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3907 0x780000,0x3c1e0000,0x3c0e0007,0xfff01c07,0x1e00,0x1e0,0x780,0xf000,0x3e1c3e0,0x0,0x0,0x0,0x0,0xf0007c0,0x1f00181e,0x20000,
3908 0xf000001f,0xf780,0x3c00000,0x1f000000,0x1f00f,0x800f8078,0xf80000,0x0,0x0,0x0,0x0,0x8003e0,0x1fc0f80,0x1ef0003,0xc001e007,
3909 0x800101e0,0x7e003c0,0x1e00,0x7800,0x101e0007,0x80007800,0x780,0x3c00f800,0x7800001e,0xe00ef07f,0x801e00f0,0x1e00780,0x7c03c00,
3910 0x78078007,0xc01e0004,0xf000,0xf0003c0,0x78001e0f,0x1e03,0xe00f807c,0xf80000,0x1f0003c,0x7800,0x1e0,0x3e1f0,0x0,0x3c000,0x1,
3911 0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,
3912 0x1e,0xf0,0x780,0x0,0x0,0x1f00080,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x1e03c,0x0,0x3c00080,0x0,0xf80f0000,0x0,0x1f0000,0x0,0x0,
3913 0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x3bf70003,0xe0000000,0x0,0x0,0x3e00,0x1f003e0,0x0,0x780000,0x180000,0x78000000,0x7c0,0xf80003c,
3914 0x3c00,0x0,0x1f01f0,0x780,0x0,0x0,0xf,0x80f80000,0x1c0,0x1c000000,0xe,0x38,0x1e000,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,0x7800000,
3915 0x1c00,0xe000,0x7fc00,0xf000,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x80007800,0x10078000,0x3c0000,
3916 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00ff00,0x3c01e003,0xc00f001e,0x7800f0,0x3c00780,0x1e003c00,
3917 0x7,0x800f00f0,0x3c0780,0x1e03c00,0xf01e000,0x7807c00f,0x801e0000,0xf803c0,0x3c000,0xf00000,0x780f0000,0x0,0x7,0xc0000000,
3918 0x0,0x3c0,0xf000,0x780f00,0x0,0x3c0000,0xf000007,0x80f00000,0x7ff,0xc0000000,0xf0,0x3c00,0x1e03c0,0x0,0x0,0x0,0x0,0x1e000007,
3919 0x800003c0,0x78000000,0xf00,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3920 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c1e001f,0xfff03803,0x80001e00,0x1e0,0x780,0xf000,0xf9cf80,
3921 0x0,0x0,0x0,0x0,0xf000780,0xf00001e,0x0,0xf800000f,0xe780,0x3c00000,0x1e000000,0x1e00f,0x78078,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,
3922 0x3f003c0,0x1ef0003,0xc000f00f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,0x3c01f000,0x7800001e,0xe00ef07f,
3923 0x801e01f0,0x1e00780,0x3c07c00,0x78078003,0xc03e0000,0xf000,0xf0003c0,0x78001e0f,0x1e01,0xf01f003c,0xf00000,0x3e0003c,0x7800,
3924 0x1e0,0x7c0f8,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,
3925 0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x8,0x40,0x0,0x7e0000,0x7c00000,0x1,0xf00f0000,
3926 0x0,0x3e0000,0x0,0x3f,0xfc0,0xfc3f0,0xfc3f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,0xf003c0,0x0,0x0,0x180000,0xf8000000,
3927 0x3c0,0xf00003c,0x3c00,0x0,0x3c0078,0x7ff80,0x0,0x0,0x1e,0x3c0000,0x1c0,0x1c000000,0xe,0xf0,0x0,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,
3928 0x7800000,0x1c00,0xe000,0x3c00,0x0,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x8000f800,0x78000,0x3c0000,
3929 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00ff00,0x3c03e003,0xc01f001e,0xf800f0,0x7c00780,0x3e003c00,
3930 0xf,0x800f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803c00f,0x1fffc0,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3931 0x0,0x0,0x307,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3932 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x781e003f,0xfff03803,
3933 0x80001e00,0x1e0,0xf80,0xf000,0x3dde00,0x0,0x0,0x0,0x0,0xf000f00,0x780001e,0x0,0x7800000f,0x1e780,0x3c00000,0x3e000000,0x3e00f,
3934 0x780f0,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,0x7c001e0,0x3ef8003,0xc000f00f,0x1e0,0xf003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,
3935 0x3c03e000,0x7800001e,0xf01ef07b,0xc01e01e0,0xf00780,0x3e07800,0x3c078003,0xe03c0000,0xf000,0xf0003c0,0x78001e0f,0x1e00,0xf01e003e,
3936 0x1f00000,0x3c0003c,0x7800,0x1e0,0x78078,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,
3937 0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,
3938 0xe70000,0x7800000,0x1,0xe00f0000,0x0,0x3c0000,0x0,0x3f,0xfc0,0xfc1f0,0x1f83f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,
3939 0xf807c0,0x0,0x0,0x180000,0xf0000000,0x3e0,0x1f00003c,0x3e00,0x0,0x70001c,0x3fff80,0x0,0x0,0x38,0xe0000,0x1c0,0x1c000078,
3940 0x1c,0x1fe0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x7df000,0x3ef8000,0x1f7c0000,0xfbe00007,
3941 0xdf00003c,0x780003c7,0x8000f000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f780,
3942 0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0xf80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803e01f,0x1ffff8,0xf001e0,
3943 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x0,0x0,0x1e0000,
3944 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3945 0x780000,0x3c1e0000,0x781e003e,0x30703803,0x80001e00,0x1e0,0xf00,0x7800,0xff800,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,
3946 0x0,0x7800000f,0x3c780,0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x2000000,0x800000,0x1e0,0x78000e0,0x3c78003,
3947 0xc000f01e,0x1e0,0xf803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x701cf07b,0xc01e01e0,0xf00780,0x1e07800,
3948 0x3c078001,0xe03c0000,0xf000,0xf0003c0,0x7c003e0f,0x1e00,0xf83e001e,0x1e00000,0x7c0003c,0x3c00,0x1e0,0xf807c,0x0,0x0,0x1fe0001,
3949 0xe1fc0000,0x7f00003,0xf8780007,0xf000003c,0x7f0,0x783f0,0x0,0x0,0x7800000,0x1e00000,0x3e0f8000,0xfc00007,0xf8000007,0xf00001fc,
3950 0xf,0xc0003fc0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,0x1818000,
3951 0x7800000,0x1,0xe00f0000,0x0,0x7c0000,0x0,0x1f,0x80001f80,0x7c1f8,0x1f83e0,0x0,0x0,0x0,0x70,0x38c70007,0xf8000000,0x7f03,
3952 0xf0000000,0x0,0x780780,0x0,0x0,0xfe0000,0xf0000000,0x1e0,0x1e00003c,0x3f00,0x0,0xe07f0e,0x7fff80,0x0,0x0,0x70,0x70000,0x1c0,
3953 0x1c000078,0x3c,0x1fc0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x78f000,0x3c78000,0x1e3c0000,
3954 0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
3955 0xf80f780,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0x1f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801e01e,0x1ffffc,
3956 0xf007e0,0x3fc000,0x1fe0000,0xff00000,0x7f800003,0xfc00001f,0xe0000fc0,0xfc00007f,0xfe0,0x7f00,0x3f800,0x1fc000,0x0,0x0,0x0,
3957 0x1,0xf000001f,0x80000ff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x1f80000,0x1fc1e000,0x0,0x0,0x0,0x0,0x1e1fc0,0x0,0x0,0x0,0x0,
3958 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,
3959 0x781c007c,0x30003803,0x80001f00,0x1e0,0xf00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,0x0,0x7800000f,0x3c780,
3960 0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x1e000000,0xf00000,0x3e0,0xf0000e0,0x3c78003,0xc000f01e,0x1e0,0x7803c0,
3961 0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c0f8000,0x7800001e,0x701cf079,0xe01e01e0,0xf00780,0x1e07800,0x3c078001,0xe03c0000,
3962 0xf000,0xf0003c0,0x3c003c0f,0x3e00,0x787c001f,0x3e00000,0xf80003c,0x3c00,0x1e0,0x1f003e,0x0,0x0,0x1fffc001,0xe7ff0000,0x3ffe000f,
3963 0xfe78003f,0xfc001fff,0xfe001ffc,0xf0078ffc,0x1ffc00,0x7ff000,0x7800f80,0x1e0000f,0x7f1fc01e,0x3ff0001f,0xfe00079f,0xfc0007ff,
3964 0x3c003c7f,0xf001fff8,0x1fffff0,0x3c003c0,0xf0000f1e,0xf1f,0x7c1f0,0x1f00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3c00000,0x100000,
3965 0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7800000,0x1,0xe00f0000,0x1000000,0xf80000,0x40000002,0xf,0x80001f00,0x7e0f8,0x1f07c0,
3966 0x0,0x0,0x0,0x70,0x38c7003f,0xff000000,0xff8f,0xf8000100,0xffffe,0x7c0f80,0x0,0x0,0x3ffc000,0xf0000020,0x1001f0,0x3c00003c,
3967 0x1f80,0x0,0x1c3ffc7,0x7c0780,0x0,0x0,0xe3,0xff038000,0xe0,0x38000078,0x78,0x1ff0,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,
3968 0x7800000,0x1c00,0xe000,0xe00,0xf000,0x78f000,0x3c78000,0x1e3c0000,0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,
3969 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,
3970 0x4000200f,0x3f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801f03e,0x1ffffe,0xf01fe0,0x3fff800,0x1fffc000,0xfffe0007,0xfff0003f,
3971 0xff8001ff,0xfc003ff3,0xfe0003ff,0xe0007ff8,0x3ffc0,0x1ffe00,0xfff000,0x3ff80001,0xffc0000f,0xfe00007f,0xf000003f,0xf8003c7f,
3972 0xe0003ffc,0x1ffe0,0xfff00,0x7ff800,0x3ffc000,0x1f80000,0xfff1c03c,0x3c01e0,0x1e00f00,0xf007800,0x781f0001,0xf01e7ff0,0x7c0007c,
3973 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
3974 0x3c1e003f,0xfffff078,0x30003803,0x80000f00,0x1e0,0x1f00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x3c000f00,0x780001e,0x0,0x7800000f,
3975 0x78780,0x3c00000,0x3c000000,0x7c00f,0x780f0,0x3c0007,0xe000003f,0x0,0xfe000000,0xfe0000,0x3c0,0x1f000070,0x7c7c003,0xc000f01e,
3976 0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c1f0000,0x7800001e,0x783cf079,0xe01e03c0,0xf00780,0x1e0f000,0x3c078001,
3977 0xe03c0000,0xf000,0xf0003c0,0x3c003c07,0x81f03c00,0x7c7c000f,0x87c00000,0xf00003c,0x1e00,0x1e0,0x3e001f,0x0,0x0,0x3fffe001,
3978 0xefff8000,0x7fff001f,0xff78007f,0xfe001fff,0xfe003ffe,0xf0079ffe,0x1ffc00,0x7ff000,0x7801f00,0x1e0000f,0xffbfe01e,0x7ff8003f,
3979 0xff0007bf,0xfe000fff,0xbc003cff,0xf803fffc,0x1fffff0,0x3c003c0,0x78001e1e,0xf0f,0x800f80f0,0x1e00ff,0xffe0001e,0xf0,0x780,
3980 0x0,0x0,0x3c00000,0x380000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1008000,0x7800000,0x3,0xe00f0000,0x3800000,0xf00000,0xe0000007,
3981 0xf,0x80001f00,0x3e0f8,0x1e07c0,0x0,0x0,0x0,0x70,0x3807007f,0xff800000,0x1ffdf,0xfc000380,0xffffe,0x3e1f00,0x0,0x0,0xfffe000,
3982 0xf0000030,0x3800f8,0x7c00003c,0xfc0,0x0,0x18780c3,0xf00780,0x80100,0x0,0xc3,0xffc18000,0xf0,0x78000078,0xf0,0xf0,0x0,0x3c003c0,
3983 0xfffe1c00,0x0,0x0,0x380000f0,0x7800801,0x1c00,0xe000,0x1e00,0xf000,0xf8f800,0x7c7c000,0x3e3e0001,0xf1f0000f,0x8f80007c,0x7c000787,
3984 0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078001,0xe03c000f,
3985 0x1e00078,0xf0003c0,0x78001e00,0xe000701f,0x3fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x7800f87c,0x1e007f,0xf07e00,0x7fffc00,0x3fffe001,
3986 0xffff000f,0xfff8007f,0xffc003ff,0xfe007ff7,0xff0007ff,0xf000fffc,0x7ffe0,0x3fff00,0x1fff800,0x3ff80001,0xffc0000f,0xfe00007f,
3987 0xf00000ff,0xf8003cff,0xf0007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x1f80001,0xfffb803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,
3988 0xe01efff8,0x3c00078,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
3989 0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e003f,0xfffff078,0x30001c07,0xf80,0x1e0,0x1e00,0x3c00,0xff800,0x1e0000,0x0,0x0,0x0,0x3c001e00,
3990 0x3c0001e,0x0,0x7800001e,0x70780,0x3c00000,0x78000000,0x78007,0x800f00f0,0x3e0007,0xe000003f,0x3,0xfe000000,0xff8000,0x7c0,
3991 0x1e000070,0x783c003,0xc001f01e,0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c3e0000,0x7800001e,0x3838f079,
3992 0xe01e03c0,0x780780,0x1e0f000,0x1e078001,0xe03c0000,0xf000,0xf0003c0,0x3c007c07,0x81f03c00,0x3ef80007,0x87800000,0x1f00003c,
3993 0x1e00,0x1e0,0x7c000f,0x80000000,0x0,0x3ffff001,0xffffc000,0xffff003f,0xff7800ff,0xff001fff,0xfe007ffe,0xf007bffe,0x1ffc00,
3994 0x7ff000,0x7803e00,0x1e0000f,0xffffe01e,0xfff8007f,0xff8007ff,0xff001fff,0xbc003dff,0xf807fffc,0x1fffff0,0x3c003c0,0x78001e0f,
3995 0x1e07,0xc01f00f0,0x1e00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7c00000,0x7c0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1018000,0x7800000,
3996 0x3,0xc00f0000,0x7c00000,0x1f00001,0xf000000f,0x80000007,0xc0003e00,0x1e07c,0x3e0780,0x0,0x0,0x0,0x70,0x380700ff,0xff800000,
3997 0x3ffff,0xfe0007c0,0xffffe,0x1e1e00,0x0,0x780000,0x1fffe000,0xf0000078,0x7c0078,0x7800003c,0xff0,0x0,0x38e0003,0x80f00780,
3998 0x180300,0x0,0x1c3,0x81e1c000,0x7f,0xf0000078,0x1e0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800c01,0x80001c00,
3999 0xe000,0x603e00,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x7800078,0x3c000f87,0x8001e000,0x78000,0x3c0000,0x1e00000,
4000 0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f01,0xf000f81e,
4001 0x7bc0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007878,0x1e001f,0xf0f800,0x7fffe00,0x3ffff001,0xffff800f,0xfffc007f,0xffe003ff,
4002 0xff007fff,0xff800fff,0xf001fffe,0xffff0,0x7fff80,0x3fffc00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00001ff,0xfc003dff,0xf000ffff,
4003 0x7fff8,0x3fffc0,0x1fffe00,0xffff000,0x1f80003,0xffff803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,0xe01ffffc,0x3c00078,0x0,
4004 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
4005 0x3c1e003f,0xfffff078,0x30001e0f,0x300780,0x1e0,0x1e00,0x3c00,0x3dde00,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf800003e,
4006 0xf0780,0x3dfc000,0x783f8000,0xf8007,0xc01f00f0,0x3e0007,0xe000003f,0x1f,0xfc000000,0x7ff000,0xf80,0x3e007c70,0x783c003,0xc001e03c,
4007 0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,0x80007800,0x780,0x3c7c0000,0x7800001e,0x3878f078,0xf01e03c0,0x780780,0x1e0f000,0x1e078001,
4008 0xe03e0000,0xf000,0xf0003c0,0x1e007807,0x83f03c00,0x3ef00007,0xcf800000,0x3e00003c,0xf00,0x1e0,0xf80007,0xc0000000,0x0,0x3e01f801,
4009 0xfe07e001,0xf80f007e,0x7f801f8,0x1f801fff,0xfe00fc0f,0xf007f83f,0x1ffc00,0x7ff000,0x7807c00,0x1e0000f,0x87e1e01f,0xe0fc00fc,
4010 0xfc007f8,0x1f803f03,0xfc003df0,0x3807e03c,0x1fffff0,0x3c003c0,0x78003e0f,0x1e03,0xe03e00f8,0x3e00ff,0xffe0001e,0xf0,0x780,
4011 0x0,0x0,0x7800000,0xfe0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7c00000,0x3,0xc00f0000,0xfe00000,0x3e00003,0xf800001f,
4012 0xc0000007,0xc0003e00,0x1e03c,0x3c0f80,0x0,0x0,0x0,0x70,0x380700fc,0x7800000,0x7c1fe,0x3e000fe0,0xffffe,0x1f3e00,0x0,0x780000,
4013 0x3f98e000,0xf000003c,0xfcf8007c,0xf800003c,0x3ffc,0x0,0x31c0001,0x80f00f80,0x380700,0x0,0x183,0x80e0c000,0x3f,0xe0000078,
4014 0x3c0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x38000078,0xf000e01,0xc003ffe0,0x1fff00,0x7ffc00,0xf000,0xf07800,0x783c000,0x3c1e0001,
4015 0xe0f0000f,0x7800078,0x3c000f07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
4016 0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf801f01e,0xf3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007cf8,
4017 0x1e000f,0x80f0f000,0x7c03f00,0x3e01f801,0xf00fc00f,0x807e007c,0x3f003e0,0x1f80707f,0x8f801f80,0xf003f03f,0x1f81f8,0xfc0fc0,
4018 0x7e07e00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00003ff,0xfc003fc1,0xf801f81f,0x800fc0fc,0x7e07e0,0x3f03f00,0x1f81f800,0x1f80007,
4019 0xe07f003c,0x3c01e0,0x1e00f00,0xf007800,0x780f8003,0xe01fe07e,0x3e000f8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4020 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3f,0xfffff078,0x30000ffe,0x1f007c0,0x0,0x1e00,
4021 0x3c00,0xf9cf80,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf00000fc,0x1e0780,0x3fff800,0x78ffe000,0xf0003,0xe03e00f0,
4022 0x3e0007,0xe000003f,0x7f,0xe01fffff,0xf00ffc00,0x1f80,0x3c01ff70,0x783c003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,
4023 0x80007800,0x780,0x3cfc0000,0x7800001e,0x3c78f078,0xf01e03c0,0x780780,0x3e0f000,0x1e078003,0xc01f0000,0xf000,0xf0003c0,0x1e007807,
4024 0x83f83c00,0x1ff00003,0xcf000000,0x3e00003c,0xf00,0x1e0,0x0,0x0,0x0,0x20007801,0xfc03e003,0xe003007c,0x3f803e0,0x7c0003c,
4025 0xf807,0xf007e00f,0x3c00,0xf000,0x780f800,0x1e0000f,0x87e1f01f,0x803c00f8,0x7c007f0,0xf803e01,0xfc003f80,0x80f8004,0x3c000,
4026 0x3c003c0,0x3c003c0f,0x1e03,0xe03e0078,0x3c0000,0x7c0001e,0xf0,0x780,0x0,0x0,0x3ffff800,0x1ff0000,0x0,0x7800000,0x0,0x18,
4027 0xc0,0x0,0x1818000,0x3e00000,0x3,0xc00f0000,0x1ff00000,0x3e00007,0xfc00003f,0xe0000003,0xc0003c00,0xf03c,0x3c0f00,0x0,0x0,
4028 0x0,0x70,0x380701f0,0x800000,0x780fc,0x1e001ff0,0x7c,0xf3c00,0x0,0x780000,0x7e182000,0xf000001f,0xfff00ffc,0xffc0003c,0x3cfe,
4029 0x0,0x31c0001,0x80f01f80,0x780f00,0x0,0x183,0x80e0c000,0xf,0x80000078,0x780,0x38,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x38000078,
4030 0xf000f01,0xe003ffe0,0x1fff00,0x7ff800,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x78000f8,0x3e000f07,0x8003c000,0x78000,
4031 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
4032 0x78000f00,0x7c03e01e,0x1e3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78003cf0,0x1e0007,0x80f1e000,0x4000f00,0x20007801,0x3c008,
4033 0x1e0040,0xf00200,0x780403f,0x7803e00,0x3007c00f,0x803e007c,0x1f003e0,0xf801f00,0x780000,0x3c00000,0x1e000000,0xf00007f0,
4034 0x3e003f00,0x7801f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e003c,0x3c01e0,0x1e00f00,0xf007800,0x78078003,
4035 0xc01fc03e,0x1e000f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4036 0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xf078007c,0x300007fc,0x7e00fe0,0x0,0x1e00,0x3c00,0x3e1c3e0,0x1e0000,0x0,0x0,0x0,0xf0001e00,
4037 0x3c0001e,0x1,0xf000fff8,0x1e0780,0x3fffe00,0x79fff000,0x1f0001,0xfffc00f0,0x7e0007,0xe000003f,0x3ff,0x801fffff,0xf003ff80,
4038 0x3f00,0x3c03fff0,0xf01e003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3df80000,0x7800001e,
4039 0x1c70f078,0x781e03c0,0x780780,0x3c0f000,0x1e078007,0xc01f8000,0xf000,0xf0003c0,0x1e007807,0x83f83c00,0xfe00003,0xff000000,
4040 0x7c00003c,0x780,0x1e0,0x0,0x0,0x0,0x7c01,0xf801f007,0xc00100f8,0x1f803c0,0x3c0003c,0x1f003,0xf007c00f,0x80003c00,0xf000,
4041 0x783f000,0x1e0000f,0x3c0f01f,0x3e01f0,0x3e007e0,0x7c07c00,0xfc003f00,0xf0000,0x3c000,0x3c003c0,0x3c003c0f,0x1e01,0xf07c007c,
4042 0x7c0000,0xfc0001e,0xf0,0x780,0x0,0x0,0x3ffff000,0x3838000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0xff0000,0x3f00000,0x3,0xc00fff00,
4043 0x38380000,0x7c0000e,0xe000070,0x70000001,0xe0003c00,0xf01e,0x780e00,0x0,0x0,0x0,0x0,0x1e0,0x0,0x780f8,0xf003838,0xfc,0xffc00,
4044 0x0,0x780000,0x7c180000,0xf000000f,0xffe00fff,0xffc0003c,0x783f,0x80000000,0x6380000,0xc0f83f80,0xf81f00,0x0,0x303,0x80e06000,
4045 0x0,0x78,0xf00,0x78,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x3800003c,0x3e000f81,0xf003ffe0,0x1fff00,0x1fc000,0xf000,0x1e03c00,
4046 0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e000f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,
4047 0x3c000001,0xe0001e00,0x3c0f0f0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3e07c01e,0x1e3c0f0,0x3c0780,0x1e03c00,
4048 0xf01e000,0x78003ff0,0x1e0007,0x80f1e000,0xf80,0x7c00,0x3e000,0x1f0000,0xf80000,0x7c0001e,0x3c07c00,0x10078007,0x803c003c,
4049 0x1e001e0,0xf000f00,0x780000,0x3c00000,0x1e000000,0xf00007c0,0x1e003e00,0x7c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,
4050 0xf,0x801f003c,0x3c01e0,0x1e00f00,0xf007800,0x7807c007,0xc01f801f,0x1f001f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4051 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xe078003c,0x300001f0,0x3f801ff0,0x0,
4052 0x3c00,0x1e00,0x3c1c1e0,0x1e0000,0x0,0x0,0x0,0xf0001e0f,0x3c0001e,0x3,0xe000fff0,0x3c0780,0x3ffff00,0x7bfff800,0x1e0000,0x7ff00078,
4053 0x7e0007,0xe000003f,0x1ffc,0x1fffff,0xf0007ff0,0x7e00,0x3c07c3f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,
4054 0x1fffff,0x80007800,0x780,0x3ffc0000,0x7800001e,0x1ef0f078,0x781e03c0,0x780780,0x7c0f000,0x1e07801f,0x800ff000,0xf000,0xf0003c0,
4055 0xf00f807,0x83b83c00,0xfc00001,0xfe000000,0xf800003c,0x780,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0xc00000f0,0xf80780,0x3c0003c,
4056 0x1e001,0xf007c007,0x80003c00,0xf000,0x787e000,0x1e0000f,0x3c0f01f,0x1e01e0,0x1e007c0,0x3c07800,0x7c003f00,0xf0000,0x3c000,
4057 0x3c003c0,0x3e007c07,0x80003c00,0xf8f8003c,0x780000,0xf80001e,0xf0,0x780,0x0,0x0,0x7ffff000,0x601c000,0x3,0xffff0000,0x0,
4058 0xfff,0xf8007fff,0xc0000000,0x7e003c,0x1fe0000,0xc0003,0xc00fff00,0x601c0000,0xf800018,0x70000c0,0x38000001,0xe0007800,0x701e,
4059 0x701e00,0x0,0x0,0x0,0x0,0x1e0,0x6,0x700f8,0xf00601c,0xf8,0x7f800,0x0,0x780000,0xf8180000,0xf000000f,0x87c00fff,0xffc0003c,
4060 0xf01f,0xc0000000,0x6380000,0xc07ff780,0x1f03e03,0xfffffe00,0x303,0x81c06000,0x0,0x1ffff,0xfe001e00,0x180f8,0x0,0x3c003c0,
4061 0x3ffe1c00,0x3f00000,0x0,0x3800003f,0xfe0007c0,0xf8000000,0x18000000,0xc0000006,0x1f000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,
4062 0x3c000f0,0x1e001f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f0f0,
4063 0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f0f801e,0x3c3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,
4064 0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07c00,0xf0007,0x8078003c,0x3c001e0,0x1e000f00,0x780000,0x3c00000,
4065 0x1e000000,0xf0000f80,0x1f003e00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0xf,0x3f003c,0x3c01e0,0x1e00f00,0xf007800,
4066 0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4067 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe078003f,0xb0000000,0xfc003cf0,0x0,0x3c00,0x1e00,0x101c040,0x1e0000,0x0,0x0,0x1,
4068 0xe0001e1f,0x83c0001e,0x7,0xe000fff0,0x3c0780,0x3c03f80,0x7fc0fc00,0x1e0000,0xfff80078,0xfe0007,0xe000003f,0x7fe0,0x1fffff,
4069 0xf0000ffc,0xfc00,0x780f81f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3ffc0000,
4070 0x7800001e,0x1ef0f078,0x3c1e03c0,0x780780,0x1fc0f000,0x1e07ffff,0x7ff00,0xf000,0xf0003c0,0xf00f007,0xc3b87c00,0x7c00001,0xfe000000,
4071 0xf800003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0x800000f0,0xf80780,0x1e0003c,0x1e001,0xf0078007,0x80003c00,0xf000,0x78fc000,
4072 0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,0x3c07800,0x7c003e00,0xf0000,0x3c000,0x3c003c0,0x1e007807,0x80003c00,0x7df0003c,0x780000,
4073 0x1f00001e,0xf0,0x780,0x0,0x0,0x7800000,0xe7ce000,0x3,0xffff0000,0x0,0xfff,0xf8007fff,0xc0000000,0x1f0,0xffe000,0x1c0003,
4074 0xc00fff00,0xe7ce0000,0xf800039,0xf38001cf,0x9c000000,0xe0007800,0x780e,0x701c00,0x0,0x0,0x0,0x0,0x1e0,0x7,0xf0078,0xf00e7ce,
4075 0x1f0,0x7f800,0x0,0x780000,0xf0180000,0xf000000e,0x1c0001f,0xe000003c,0xf007,0xe0000000,0x6380000,0xc03fe780,0x3e07c03,0xfffffe00,
4076 0x303,0xffc06000,0x0,0x1ffff,0xfe003ffe,0x1fff0,0x0,0x3c003c0,0x1ffe1c00,0x3f00000,0x7,0xffc0001f,0xfc0003e0,0x7c000001,0xfc00000f,
4077 0xe000007f,0x1e000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,
4078 0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,
4079 0x783c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07800,
4080 0xf0003,0xc078001e,0x3c000f0,0x1e000780,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,
4081 0x7800780,0x3c003c00,0xf,0x7f003c,0x3c01e0,0x1e00f00,0xf007800,0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4082 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe070001f,0xf8000007,
4083 0xf0007cf8,0x7800000,0x3c00,0x1e00,0x1c000,0x1e0000,0x0,0x0,0x1,0xe0001e1f,0x83c0001e,0xf,0xc000fff8,0x780780,0x2000f80,0x7f803e00,
4084 0x3e0003,0xfffe007c,0x1fe0000,0x0,0x3ff00,0x0,0x1ff,0x8001f000,0x780f00f0,0x1f00f003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,
4085 0xfe03c00f,0xf81fffff,0x80007800,0x780,0x3ffe0000,0x7800001e,0xee0f078,0x3c1e03c0,0x7807ff,0xff80f000,0x1e07fffe,0x3ffe0,
4086 0xf000,0xf0003c0,0xf00f003,0xc7bc7800,0xfc00000,0xfc000001,0xf000003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xe000f80f,0x800001e0,
4087 0xf80f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x79f8000,0x1e0000f,0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003e00,
4088 0xf0000,0x3c000,0x3c003c0,0x1e007807,0x81e03c00,0x7df0003e,0xf80000,0x3e00003e,0xf0,0x7c0,0xfc000,0x80000000,0x7800000,0x1e7cf000,
4089 0x3,0xffff0000,0x0,0x18,0xc0,0x0,0xf80,0x7ffc00,0x380003,0xc00fff01,0xe7cf0000,0x1f000079,0xf3c003cf,0x9e000000,0xe0007000,
4090 0x380e,0xe01c00,0x0,0x0,0x0,0x0,0x1e0,0x3,0x800f0078,0xf01e7cf,0x3e0,0x3f000,0x0,0x780000,0xf018001f,0xfff8001e,0x1e0000f,
4091 0xc000003c,0xf003,0xe0000000,0x6380000,0xc00fc780,0x7c0f803,0xfffffe00,0x303,0xfe006000,0x0,0x1ffff,0xfe003ffe,0x1ffe0,0x0,
4092 0x3c003c0,0xffe1c00,0x3f00000,0x7,0xffc00007,0xf00001f0,0x3e00001f,0xfc0000ff,0xe00007ff,0x3e000,0x3e01e00,0x1f00f000,0xf8078007,
4093 0xc03c003e,0x1e001e0,0xf001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,
4094 0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000fc0,
4095 0x1e0007,0x80f1f000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c0f800,0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,
4096 0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1e,0xf7803c,0x3c01e0,0x1e00f00,
4097 0xf007800,0x7803e00f,0x801e000f,0x80f803e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4098 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe0f0000f,0xff00001f,0x8000f87c,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,
4099 0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x1f,0x800000fe,0xf00780,0x7c0,0x7f001e00,0x3c0007,0xe03f003f,0x3fe0000,0x0,0x3fc00,0x0,
4100 0x7f,0x8001e000,0x781f00f0,0x1e00f003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3f9f0000,0x7800001e,
4101 0xfe0f078,0x3c1e03c0,0x7807ff,0xff00f000,0x1e07fff8,0xfff8,0xf000,0xf0003c0,0xf81f003,0xc7bc7800,0xfe00000,0x78000003,0xe000003c,
4102 0x1e0,0x1e0,0x0,0x0,0x0,0x1fffc01,0xe000780f,0x1e0,0x780f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7bf0000,0x1e0000f,
4103 0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xf8000,0x3c000,0x3c003c0,0x1f00f807,0x81f03c00,0x3fe0001e,0xf00000,0x7c00007c,
4104 0xf0,0x3e0,0x3ff801,0x80000000,0x7800000,0x3cfcf800,0x3,0xffff0000,0x0,0x18,0xc0,0x0,0x7c00,0x1fff00,0x700003,0xc00f0003,
4105 0xcfcf8000,0x3e0000f3,0xf3e0079f,0x9f000000,0xf000,0x1000,0x0,0x0,0x0,0x0,0x0,0x1f0,0x1,0xc00f0078,0xf03cfcf,0x800007c0,0x1e000,
4106 0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x8000003c,0xf001,0xf0000000,0x6380000,0xc0000000,0xf81f003,0xfffffe00,0x303,
4107 0x87006000,0x0,0x1ffff,0xfe003ffe,0x7f00,0x0,0x3c003c0,0x3fe1c00,0x3f00000,0x7,0xffc00000,0xf8,0x1f0001ff,0xf0000fff,0x80007ffc,
4108 0xfc000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf001e07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,
4109 0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3fc001e,0x1e03c0f0,0x3c0780,
4110 0x1e03c00,0xf01e000,0x78000780,0x1e0007,0x80f0fc00,0x3fff80,0x1fffc00,0xfffe000,0x7fff0003,0xfff8001f,0xffc0001e,0x3c0f000,
4111 0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,0x3c00000,0x1e000000,0xf0001e00,0xf803c00,0x3c078001,0xe03c000f,0x1e00078,
4112 0xf0003c0,0x78001e07,0xfffffe1e,0x1e7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801e00f,0x1e0007,0x807803c0,0x0,0x0,0x0,0x0,0x0,
4113 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00007,
4114 0xffc0007e,0xf03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x3f,0x3e,0xf00780,0x3c0,0x7e001e00,
4115 0x7c000f,0x800f001f,0xffde0000,0x0,0x3e000,0x0,0xf,0x8003e000,0x781e0070,0x1e00f003,0xc001f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,
4116 0xf81e0007,0x80007800,0x780,0x3f1f0000,0x7800001e,0x7c0f078,0x1e1e03c0,0x7807ff,0xfc00f000,0x1e07fffe,0xffc,0xf000,0xf0003c0,
4117 0x781e003,0xc71c7800,0x1ff00000,0x78000003,0xe000003c,0x1e0,0x1e0,0x0,0x0,0x0,0xffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,
4118 0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7f000,0x3c000,
4119 0x3c003c0,0xf00f007,0xc1f07c00,0x1fc0001f,0x1f00000,0xfc000ff8,0xf0,0x1ff,0xfffe07,0x80000000,0x7800000,0x7ffcfc00,0x0,0xf000000,
4120 0x0,0x18,0xc0,0x0,0x3e000,0x1ff80,0xe00003,0xc00f0007,0xffcfc000,0x3e0001ff,0xf3f00fff,0x9f800000,0x6000,0x0,0x0,0x7c000,
4121 0x0,0x0,0x0,0xfe,0x0,0xe00f007f,0xff07ffcf,0xc0000fc0,0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x80000000,0xf800,
4122 0xf0000000,0x6380000,0xc0000000,0x1f03c000,0x1e00,0x303,0x83806000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xfe1c00,0x3f00000,0x0,
4123 0x0,0x3c,0xf801fff,0xfff8,0x7ffc0,0x1f8000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf003c07,0x8003c000,0x78000,
4124 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
4125 0x78000f00,0x1f8001e,0x1e03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e000f,0x80f0ff00,0x1ffff80,0xffffc00,0x7fffe003,
4126 0xffff001f,0xfff800ff,0xffc007ff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,
4127 0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x3c7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801f01f,
4128 0x1e0007,0x807c07c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4129 0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00000,0xfff003f0,0x1f00f03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x7ff80000,0x3,
4130 0xc0001e0f,0x3c0001e,0x7e,0x1f,0x1e00780,0x3e0,0x7e000f00,0x78000f,0x7800f,0xff9e0000,0x0,0x3fc00,0x0,0x7f,0x8003c000,0x781e0070,
4131 0x3e00f803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3e0f8000,0x7800001e,0x7c0f078,0x1e1e03c0,
4132 0x7807ff,0xf000f000,0x1e07807f,0xfe,0xf000,0xf0003c0,0x781e003,0xc71c7800,0x3ef00000,0x78000007,0xc000003c,0x1e0,0x1e0,0x0,
4133 0x0,0x0,0x1ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,
4134 0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7ff80,0x3c000,0x3c003c0,0xf00f003,0xc1f07800,0x1fc0000f,0x1e00000,0xf8000ff0,0xf0,
4135 0xff,0xffffff,0x80000000,0x3fffc000,0xfff9fe00,0x0,0xf000000,0x0,0x18,0xc0,0x0,0x1f0000,0x1fc0,0x1c00003,0xc00f000f,0xff9fe000,
4136 0x7c0003ff,0xe7f81fff,0x3fc00000,0x0,0x0,0x0,0xfe000,0x1ffffc0f,0xfffffc00,0x0,0xff,0xf0000000,0x700f007f,0xff0fff9f,0xe0000f80,
4137 0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00fff,0xffc00000,0xf800,0xf0000000,0x6380000,0xc0ffff80,0x3e078000,0x1e00,0x7ff80303,
4138 0x83c06000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,0x0,0x7f,0xff00001e,0x7c1fff0,0xfff80,0x7ffc00,0x3f0000,0x7c01f00,
4139 0x3e00f801,0xf007c00f,0x803e007c,0x1f003e0,0xf803c07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
4140 0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f8001e,0x3c03c0f0,0x3c0780,0x1e03c00,0xf01e000,
4141 0x78000780,0x1e001f,0xf07f80,0x3ffff80,0x1ffffc00,0xffffe007,0xffff003f,0xfff801ff,0xffc03fff,0xffc0f000,0x1fffff,0xc0fffffe,
4142 0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,
4143 0xfffffe1e,0x787803c,0x3c01e0,0x1e00f00,0xf007800,0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4144 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x3ff80fc0,0x7fc1e01f,
4145 0x7800000,0x3c00,0x1e00,0x0,0x7fffff80,0x0,0x7ff80000,0x7,0x80001e00,0x3c0001e,0xfc,0xf,0x1e00780,0x1e0,0x7c000f00,0x78000f,
4146 0x78007,0xff1e0000,0x0,0x3ff00,0x0,0x1ff,0x8003c000,0x781e0070,0x3c007803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,
4147 0x80007800,0x780,0x3c07c000,0x7800001e,0x7c0f078,0xf1e03c0,0x780780,0xf000,0x1e07801f,0x3e,0xf000,0xf0003c0,0x781e003,0xcf1c7800,
4148 0x3cf80000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,0x0,0x0,0x3ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,
4149 0x80003c00,0xf000,0x7ff8000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3fff0,0x3c000,0x3c003c0,0xf81f003,
4150 0xc3b87800,0xf80000f,0x1e00001,0xf0000ff0,0xf0,0xff,0xf03fff,0x80000000,0x3fff8001,0xfff1ff00,0x0,0xf000000,0x0,0x18,0xc0,
4151 0x0,0x380000,0x7c0,0x3c00003,0xc00f001f,0xff1ff000,0xf80007ff,0xc7fc3ffe,0x3fe00000,0x0,0x0,0x0,0x1ff000,0x7ffffe1f,0xffffff00,
4152 0x0,0x7f,0xfe000000,0x780f007f,0xff1fff1f,0xf0001f00,0x1e000,0x0,0x780001,0xe0180000,0xf000001c,0xe00fff,0xffc00000,0x7c00,
4153 0xf0000000,0x31c0001,0x80ffff80,0x3e078000,0x1e00,0x7ff80183,0x81c0c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,
4154 0x0,0x7f,0xff00001e,0x7c7ff03,0xc03ff8fe,0x1ffc0f0,0x7e0000,0x7800f00,0x3c007801,0xe003c00f,0x1e0078,0xf003c0,0x7803c07,0x8003c000,
4155 0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,
4156 0xf0001e0,0x78000f00,0x3fc001e,0x7803c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e007f,0xf03fe0,0x7ffff80,0x3ffffc01,
4157 0xffffe00f,0xffff007f,0xfff803ff,0xffc07fff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,
4158 0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x707803c,0x3c01e0,0x1e00f00,0xf007800,
4159 0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4160 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x30f81f00,0xffe1e00f,0x87800000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,
4161 0x7,0x80001e00,0x3c0001e,0x1f8,0x7,0x83c00780,0x1e0,0x7c000f00,0xf8001e,0x3c001,0xfc1e0000,0x0,0x7fe0,0x0,0xffc,0x3c000,0x781e0070,
4162 0x3ffff803,0xc000783c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x380f078,0xf1e03c0,
4163 0x780780,0xf000,0x1e07800f,0x8000001e,0xf000,0xf0003c0,0x3c3c003,0xcf1e7800,0x7c780000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,
4164 0x0,0x0,0x7f003c01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7f7c000,0x1e0000f,0x3c0f01e,
4165 0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfff8,0x3c000,0x3c003c0,0x781e003,0xc3b87800,0x1fc00007,0x83e00003,0xe0000ff8,0xf0,
4166 0x1ff,0xc007fe,0x0,0x7fff8001,0xffe3ff00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x3c0,0x7800003,0xc00f001f,0xfe3ff000,0xf80007ff,
4167 0x8ffc3ffc,0x7fe00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x1f,0xff000000,0x3c0f007f,0xff1ffe3f,0xf0003e00,0x1e000,0x0,0x780001,
4168 0xe0180000,0xf000001e,0x1e00fff,0xffc00000,0x3f00,0xf0000000,0x31c0001,0x80ffff80,0x1f03c000,0x1e00,0x7ff80183,0x81c0c000,
4169 0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x7f,0xff00003c,0xf87f007,0xc03f83ff,0x81fc01f0,0x7c0000,0x7ffff00,0x3ffff801,
4170 0xffffc00f,0xfffe007f,0xfff003ff,0xff807fff,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
4171 0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf003c0f0,0x3c0780,0x1e03c00,0xf01e000,
4172 0x78000780,0x1ffffe,0xf00ff0,0xfe00780,0x7f003c03,0xf801e01f,0xc00f00fe,0x7807f0,0x3c0ffff,0xffc0f000,0x1fffff,0xc0fffffe,
4173 0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
4174 0x1e,0xf07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783e,0x1e0007,0x801e0f80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4175 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x307c0801,0xe1f1e00f,0x87000000,
4176 0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,0xf,0x1e00,0x3c0001e,0x3f0,0x7,0x83fffffc,0x1e0,0x7c000f00,0xf0001e,0x3c000,0x3e0000,
4177 0x0,0x1ffc,0x1fffff,0xf0007ff0,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x3c000,0x781e0007,0x80007800,
4178 0x780,0x3c03e000,0x7800001e,0xf078,0x79e03c0,0x780780,0xf000,0x1e078007,0x8000000f,0xf000,0xf0003c0,0x3c3c001,0xee0ef000,
4179 0xf87c0000,0x7800001f,0x3c,0x78,0x1e0,0x0,0x0,0x0,0x7c003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
4180 0xf000,0x7e3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x1ffc,0x3c000,0x3c003c0,0x781e003,0xe3b8f800,
4181 0x1fc00007,0x83c00007,0xc00000fc,0xf0,0x3e0,0x8001f8,0x0,0x7800000,0xffc7fe00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,
4182 0xf000003,0xc00f000f,0xfc7fe001,0xf00003ff,0x1ff81ff8,0xffc00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x3,0xff800000,0x1e0f0078,
4183 0xffc7f,0xe0007c00,0x1e000,0x0,0x780001,0xe0180000,0xf000000e,0x1c00007,0x80000000,0x1f81,0xe0000000,0x38e0003,0x80000000,
4184 0xf81f000,0x1e00,0x7ff801c3,0x80e1c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf8,0x1f070007,0xc03803ff,0xc1c001f0,
4185 0xf80000,0xfffff00,0x7ffff803,0xffffc01f,0xfffe00ff,0xfff007ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,
4186 0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f00f,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,0xf003c0f0,
4187 0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1ffffc,0xf003f8,0xf800780,0x7c003c03,0xe001e01f,0xf00f8,0x7807c0,0x3c0fc1e,0xf000,
4188 0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,
4189 0xf0003c0,0x78001e00,0x1e,0x1e07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783c,0x1e0007,0x801e0f00,0x0,0x0,0x0,0x0,0x0,0x0,
4190 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xffff8000,0x303c0001,
4191 0xc071e007,0xcf000000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0xf,0xf00,0x780001e,0x7e0,0x7,0x83fffffc,0x1e0,0x7c000f00,0x1f0001e,
4192 0x3c000,0x3c0000,0x0,0x3ff,0x801fffff,0xf003ff80,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,
4193 0x80007800,0x780,0x3c01f000,0x7800001e,0xf078,0x79e03c0,0xf00780,0xf000,0x3e078007,0xc000000f,0xf000,0xf0003c0,0x3c3c001,
4194 0xee0ef000,0xf03e0000,0x7800003e,0x3c,0x78,0x1e0,0x0,0x0,0x0,0xf8003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,
4195 0x80003c00,0xf000,0x7c3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfc,0x3c000,0x3c003c0,0x3c3e001,0xe7b8f000,
4196 0x3fe00007,0xc7c0000f,0xc000003e,0xf0,0x7c0,0x0,0x0,0x7c00000,0x7fcffc00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,0x1e000003,
4197 0xc00f0007,0xfcffc003,0xe00001ff,0x3ff00ff9,0xff800000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x1f800000,0xf0f0078,0x7fcff,
4198 0xc000fc00,0x1e000,0x0,0x780001,0xe0180000,0xf000000f,0x87c00007,0x80000000,0xfe3,0xe0000000,0x18780c3,0x0,0x7c0f800,0x1e00,
4199 0xc3,0x80e18000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x1f0,0x3e00000f,0xc0000303,0xe00003f0,0xf00000,0xfffff80,
4200 0x7ffffc03,0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,
4201 0x3c000001,0xe0001e00,0x780f00f,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1f0f801f,0xe00780f0,0x3c0780,0x1e03c00,
4202 0xf01e000,0x78000780,0x1ffff8,0xf000f8,0x1f000780,0xf8003c07,0xc001e03e,0xf01f0,0x780f80,0x3c1f01e,0xf000,0x1e0000,0xf00000,
4203 0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
4204 0x1e,0x3c07803c,0x3c01e0,0x1e00f00,0xf007800,0x78007c7c,0x1e0007,0x801f1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4205 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c00000,0x303c0003,0x8039e003,0xef000000,
4206 0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0xfc0,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,
4207 0x0,0x7f,0xe01fffff,0xf00ffc00,0x3c000,0x781f00f0,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,0x80007800,
4208 0x780,0x3c01f000,0x7800001e,0xf078,0x7de01e0,0xf00780,0x7800,0x3c078003,0xc000000f,0xf000,0xf0003c0,0x3e7c001,0xee0ef001,
4209 0xf01e0000,0x7800003e,0x3c,0x3c,0x1e0,0x0,0x0,0x0,0xf0003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
4210 0xf000,0x781f000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0x7df00003,
4211 0xc780000f,0x8000003e,0xf0,0x780,0x0,0x0,0x3c00000,0x3fcff800,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x1f00fc,0x1e0,0x1e000001,
4212 0xe00f0003,0xfcff8003,0xe00000ff,0x3fe007f9,0xff000000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x7c00000,0xf0f0078,0x3fcff,0x8000f800,
4213 0x1e000,0x0,0x780001,0xe0180000,0xf000001f,0xffe00007,0x8000003c,0x7ff,0xc0000000,0x1c3ffc7,0x0,0x3e07c00,0x1e00,0xe3,0x80738000,
4214 0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x3e0,0x7c00001d,0xc0000001,0xe0000770,0x1f00000,0xfffff80,0x7ffffc03,
4215 0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
4216 0xe0001e00,0x780f00f,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0x3e07c01f,0xc00780f0,0x3c0780,0x1e03c00,0xf01e000,
4217 0x78000780,0x1fffc0,0xf0007c,0x1e000780,0xf0003c07,0x8001e03c,0xf01e0,0x780f00,0x3c1e01e,0xf000,0x1e0000,0xf00000,0x7800000,
4218 0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1e,0x7807803c,
4219 0x3c01e0,0x1e00f00,0xf007800,0x78003c78,0x1e0007,0x800f1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4220 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x83c00000,0x303c0003,0x8039e001,0xee000000,0x1e00,0x3c00,
4221 0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0x1f80,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,0x0,0x1f,0xfc1fffff,
4222 0xf07ff000,0x0,0x780f00f0,0x78003c03,0xc000781e,0x1e0,0xf803c0,0x1e00,0x1e000,0x781e0007,0x80007800,0x780,0x3c00f800,0x7800001e,
4223 0xf078,0x3de01e0,0xf00780,0x7800,0x3c078003,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfe0ff003,0xe01f0000,0x7800007c,0x3c,0x3c,
4224 0x1e0,0x0,0x0,0x0,0xf0007c01,0xe000f80f,0x800001e0,0xf80f00,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x780f800,0x1e0000f,
4225 0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003c00,0x1e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0xf8f80003,0xe780001f,0x1e,
4226 0xf0,0x780,0x0,0x0,0x3c00000,0x1ffff000,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x3bc1de,0x1e0,0xf000001,0xe00f0001,0xffff0007,0xc000007f,
4227 0xffc003ff,0xfe000000,0x0,0x0,0x0,0xfe000,0x0,0x0,0x0,0x0,0x3c00000,0x1e0f0078,0x1ffff,0x1f000,0x1e000,0x0,0x780000,0xf0180000,
4228 0xf000001f,0xfff00007,0x8000003c,0x1ff,0x80000000,0xe0ff0e,0x0,0x1f03e00,0x1e00,0x70,0x70000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,
4229 0xe1c00,0x0,0x0,0x0,0x7c0,0xf8000019,0xc0000000,0xe0000670,0x1e00000,0xf000780,0x78003c03,0xc001e01e,0xf00f0,0x780780,0x3c0f807,
4230 0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf80f007,0xbc03c001,0xe01e000f,
4231 0xf00078,0x78003c0,0x3c001e00,0x7c03e00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,
4232 0xf0007c07,0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0xf800,0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,
4233 0xf0001e00,0x7803c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1f8001f,0xf00f803c,0x3c01e0,0x1e00f00,0xf007800,
4234 0x78003e78,0x1e000f,0x800f9e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4235 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x3c00000,0x303c0003,0x8039f001,0xfe000000,0x1e00,0x3c00,0x0,0x1e0000,0x0,0x0,0x3c,0xf00,
4236 0x780001e,0x3f00,0x7,0x80000780,0x3e0,0x3e000f00,0x3c0001e,0x3c000,0x7c0000,0x0,0x3,0xfe000000,0xff8000,0x0,0x3c0f81f0,0xf0001e03,
4237 0xc000780f,0x1e0,0xf003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x780,0x3c007c00,0x7800001e,0xf078,0x3de01e0,0xf00780,0x7800,
4238 0x3c078001,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfc07f003,0xe00f0000,0x78000078,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
4239 0xf000f007,0x800000f0,0xf80780,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
4240 0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78001,0xe71df000,0xf8f80001,0xef80003e,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,
4241 0xfffe000,0x0,0x3e000000,0x0,0x18,0x7fff,0xc0000000,0x60c306,0x1e0,0x7800001,0xe00f0000,0xfffe0007,0x8000003f,0xff8001ff,
4242 0xfc000000,0x0,0x0,0x0,0x7c000,0x0,0x0,0x0,0x0,0x3c00000,0x3c0f0078,0xfffe,0x3e000,0x1e000,0x0,0x780000,0xf0180000,0xf000003c,
4243 0xfcf80007,0x8000003c,0x7f,0x0,0x70001c,0x0,0xf81f00,0x0,0x38,0xe0000,0x0,0x0,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf81,
4244 0xf0000039,0xc0000000,0xe0000e70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,0x8000f000,0x78000,
4245 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f007,0xbc03c001,0xe01e000f,0xf00078,0x78003c0,
4246 0x3c001e00,0xf801f00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,0x8003e03c,
4247 0x1f01e0,0xf80f00,0x7c1e01e,0x7800,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,
4248 0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xe00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef8,0x1f000f,
4249 0x7be00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4250 0x0,0x0,0xf,0x3c00000,0x307c0003,0x8038f000,0xfc000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e00003c,0x780,0xf00001e,
4251 0x7e00,0xf,0x80000780,0x3c0,0x3e001e00,0x3c0001f,0x7c000,0x780007,0xe000003f,0x0,0xfe000000,0xfe0000,0x0,0x3c07c3f0,0xf0001e03,
4252 0xc000f80f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x4000f80,0x3c003c00,0x7800001e,0xf078,0x1fe01f0,0x1f00780,
4253 0x7c00,0x7c078001,0xf000001f,0xf000,0xf0003c0,0x1e78001,0xfc07f007,0xc00f8000,0x780000f8,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
4254 0xf000f007,0xc00000f0,0xf80780,0x3c,0x1f003,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
4255 0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78000,0xfe0fe001,0xf07c0001,0xef00007c,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,
4256 0x7cfc000,0xfc00000,0x3c00000f,0xc3f00000,0x18,0x7fff,0xc0000000,0x406303,0x3e0,0x3c00001,0xf00f0000,0x7cfc000f,0x8000001f,
4257 0x3f0000f9,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x780700f8,0x7cfc,0x7c000,0x1e000,0x0,0x780000,0xf8180000,
4258 0xf0000070,0x3c0007,0x8000003c,0x3f,0x80000000,0x3c0078,0x0,0x780f00,0x0,0x1e,0x3c0000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,0xe1c00,
4259 0x0,0x0,0x0,0xf01,0xe0000071,0xc0000000,0xe0001c70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
4260 0x8000f800,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00f003,0xfc03e003,0xe01f001f,
4261 0xf800f8,0x7c007c0,0x3e003e01,0xf000f80f,0xf00f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,
4262 0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0x7c00,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,
4263 0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xc00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef0,
4264 0x1f000f,0x7bc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4265 0x0,0x0,0x0,0x0,0x780000,0xf,0x3800040,0x30780003,0x8038f800,0x78000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
4266 0x780,0x1f00001e,0xfc00,0x20001f,0x780,0x80007c0,0x1f001e00,0x7c0000f,0x78000,0xf80007,0xe000003f,0x0,0x1e000000,0xf00000,
4267 0x3c000,0x3c03fff0,0xf0001e03,0xc001f007,0x800101e0,0x7e003c0,0x1e00,0x7800,0x781e0007,0x80007800,0x6000f00,0x3c003e00,0x7800001e,
4268 0xf078,0x1fe00f0,0x1e00780,0x3c00,0x78078000,0xf020001e,0xf000,0x7800780,0xff0001,0xfc07f00f,0x8007c000,0x780001f0,0x3c,0xf,
4269 0x1e0,0x0,0x0,0x0,0xf800fc01,0xf801f007,0xc00100f8,0x1f807c0,0x40003c,0xf807,0xf0078007,0x80003c00,0xf000,0x7803e00,0x1f0000f,
4270 0x3c0f01e,0x1e01f0,0x3e007e0,0x7c07c00,0xfc003c00,0x1e,0x3e000,0x3e007c0,0x1ff8000,0xfe0fe003,0xe03e0001,0xff0000fc,0x1e,
4271 0xf0,0x780,0x0,0x0,0x1f00080,0x3cf8000,0xfc00000,0x3c00001f,0x83f00000,0x18,0xc0,0x0,0xc06203,0x40003c0,0x1c00000,0xf80f0000,
4272 0x3cf8001f,0xf,0x3e000079,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x700780fc,0x3cf8,0xfc000,0x1e000,0x0,0x780000,
4273 0x7c180000,0xf0000020,0x100007,0x8000003c,0xf,0x80000000,0x1f01f0,0x0,0x380700,0x0,0xf,0x80f80000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,
4274 0xe1c00,0x0,0x0,0x0,0xe01,0xc0000071,0xc0000001,0xc0001c70,0x1e00040,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
4275 0x80007800,0x10078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00f003,0xfc01e003,0xc00f001e,
4276 0x7800f0,0x3c00780,0x1e003c00,0xe000700f,0x800f0078,0x7803c0,0x3c01e00,0x1e00f000,0xf0000780,0x1e0000,0xf0003c,0x1f001f80,
4277 0xf800fc07,0xc007e03e,0x3f01f0,0x1f80f80,0xfc1e01f,0x7c00,0x100f8000,0x807c0004,0x3e00020,0x1f000100,0x780000,0x3c00000,0x1e000000,
4278 0xf0000f80,0x1f003c00,0x3c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,0x1f8000f,0x801f003e,0x7c01f0,0x3e00f80,0x1f007c00,
4279 0xf8001ff0,0x1f801f,0x7fc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4280 0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0xf,0x7800078,0x31f80001,0xc070fc00,0xfc000000,0x1e00,0x7c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
4281 0x7c0,0x1f00001e,0x1f000,0x38003f,0x780,0xe000f80,0x1f803e00,0x780000f,0x800f8000,0x1f00007,0xe000003f,0x0,0x2000000,0x800000,
4282 0x3c000,0x3e01ff71,0xf0001f03,0xc007f007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x781e0007,0x80007800,0x7801f00,0x3c001f00,0x7800001e,
4283 0xf078,0xfe00f8,0x3e00780,0x3e00,0xf8078000,0xf838003e,0xf000,0x7c00f80,0xff0000,0xfc07e00f,0x8003c000,0x780001e0,0x3c,0xf,
4284 0x1e0,0x0,0x0,0x0,0xf801fc01,0xfc03e003,0xe003007c,0x3f803e0,0x1c0003c,0xfc0f,0xf0078007,0x80003c00,0xf000,0x7801f00,0xf8000f,
4285 0x3c0f01e,0x1e00f8,0x7c007f0,0xf803e01,0xfc003c00,0x8003e,0x1f000,0x1e00fc0,0xff0000,0xfe0fe007,0xc01f0000,0xfe0000f8,0x1e,
4286 0xf0,0x780,0x0,0x0,0xf80180,0x1cf0000,0x1f800000,0x3c00001f,0x83e00000,0x18,0xc0,0x0,0xc06203,0x70007c0,0xe00000,0x7e0f0000,
4287 0x1cf0001e,0x7,0x3c000039,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x7c00000,0xe00780fc,0x2001cf0,0xf8000,0x1e000,0x0,
4288 0x780000,0x7e182000,0xf0000000,0x7,0x8000003c,0x7,0xc0000000,0x7ffc0,0x0,0x180300,0x0,0x3,0xffe00000,0x0,0x0,0x0,0x0,0x0,
4289 0x3f00fc0,0xe1c00,0x0,0x0,0x0,0xc01,0x800000e1,0xc0000003,0xc0003870,0x1f001c0,0x3e0003e1,0xf0001f0f,0x8000f87c,0x7c3e0,0x3e1f00,
4290 0x1f1e007,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e03,0xfc00f001,0xfc01f007,
4291 0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x4000201f,0xc01f007c,0xf803e0,0x7c01f00,0x3e00f801,0xf0000780,0x1e0000,0xf0007c,
4292 0x1f003f80,0xf801fc07,0xc00fe03e,0x7f01f0,0x3f80f80,0x1fc1f03f,0x803e00,0x3007c003,0x803e001c,0x1f000e0,0xf800700,0x780000,
4293 0x3c00000,0x1e000000,0xf00007c0,0x3e003c00,0x3c01f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e001e,0xfc00f0,
4294 0x7e00780,0x3f003c01,0xf8000fe0,0x1fc03e,0x3f800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4295 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,0xfff00001,0xe0f07f03,0xfe000000,0xf00,0x7800,0x0,
4296 0x1e0000,0xfc0000,0x0,0x7e0000f0,0x3f0,0x7e000fff,0xfc03ffff,0xf83f00fe,0x780,0xfc03f80,0xfc0fc00,0xf800007,0xe03f0018,0x7e00007,
4297 0xe000003f,0x0,0x0,0x0,0x3c000,0x1e007c71,0xe0000f03,0xffffe003,0xf01f01ff,0xff8003ff,0xffe01e00,0x3f01,0xf81e0007,0x803ffff0,
4298 0x7e03f00,0x3c000f00,0x7ffffe1e,0xf078,0xfe007e,0xfc00780,0x1f83,0xf0078000,0x783f00fe,0xf000,0x3f03f00,0xff0000,0xfc07e01f,
4299 0x3e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7e07fc01,0xfe07e001,0xf80f007e,0x7f801f8,0xfc0003c,0x7ffe,0xf0078007,
4300 0x807ffffe,0xf000,0x7801f00,0xfff00f,0x3c0f01e,0x1e00fc,0xfc007f8,0x1f803f03,0xfc003c00,0xf80fc,0x1fff0,0x1f83fc0,0xff0000,
4301 0xfc07e007,0xc01f0000,0xfe0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfe0780,0xfe0000,0x1f000000,0x3c00001f,0x7c00e03,0x81c00018,
4302 0xc0,0x0,0x406203,0x7e01fc0,0x700000,0x7fffff80,0xfe0003f,0xffffc003,0xf800001f,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f0,
4303 0x1f800001,0xc007c1fe,0x6000fe0,0x1ffffe,0x1e000,0x0,0x780000,0x3f98e03f,0xffff8000,0x7,0x8000003c,0x7,0xc0000000,0xfe00,
4304 0x0,0x80100,0x0,0x0,0x7f000000,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3f83fe8,0xe1c00,0x0,0x0,0x0,0x801,0xc1,0xc0000007,0x80003070,
4305 0xfc0fc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc03f01,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,
4306 0xffff001f,0xfff800ff,0xffc01fff,0xf800f001,0xfc00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,0x1f,0xf07e003f,0x3f001f8,
4307 0x1f800fc0,0xfc007e07,0xe0000780,0x1e0000,0xf301f8,0xfc0ff80,0x7e07fc03,0xf03fe01f,0x81ff00fc,0xff807e0,0x7fc0f87f,0x81801f80,
4308 0xf003f01f,0x801f80fc,0xfc07e0,0x7e03f00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff807e0,0x7e003c00,0x3c01f81f,0x800fc0fc,0x7e07e0,
4309 0x3f03f00,0x1f81f800,0x1f8000f,0xe07e001f,0x83fc00fc,0x1fe007e0,0xff003f07,0xf8000fe0,0x1fe07e,0x3f800,0x0,0x0,0x0,0x0,0x0,
4310 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,
4311 0xffe00000,0xffe03fff,0xdf000000,0xf00,0x7800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0x1ff,0xfc000fff,0xfc03ffff,0xf83ffffc,0x780,
4312 0xfffff00,0x7fff800,0xf000007,0xffff001f,0xffe00007,0xe000003f,0x0,0x0,0x0,0x3c000,0x1e000001,0xe0000f03,0xffffc001,0xffff01ff,
4313 0xff0003ff,0xffe01e00,0x1fff,0xf81e0007,0x803ffff0,0x7fffe00,0x3c000f80,0x7ffffe1e,0xf078,0xfe003f,0xff800780,0xfff,0xf0078000,
4314 0x7c3ffffc,0xf000,0x3ffff00,0xff0000,0xf803e01e,0x1e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7fffbc01,0xffffc000,
4315 0xffff003f,0xfff800ff,0xffc0003c,0x3ffe,0xf0078007,0x807ffffe,0xf000,0x7800f80,0x7ff00f,0x3c0f01e,0x1e007f,0xff8007ff,0xff001fff,
4316 0xbc003c00,0xffffc,0x1fff0,0x1fffbc0,0xff0000,0x7c07c00f,0x800f8000,0x7e0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7fff80,0x7c0000,
4317 0x1f000000,0x3c00001e,0x7c00f07,0xc1e00018,0xc0,0x0,0x60e303,0x7ffff80,0x380000,0x3fffff80,0x7c0003f,0xffffc001,0xf000000f,
4318 0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff800003,0x8003ffff,0xfe0007c0,0x1ffffe,0x1e000,0x0,0x780000,0x1fffe03f,0xffff8000,
4319 0x7,0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3fffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x1c1,
4320 0xc000000f,0x7070,0x7fffc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,
4321 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000f001,0xfc007fff,0x3fff8,0x1fffc0,0xfffe00,0x7fff000,0x3b,0xfffc003f,
4322 0xfff001ff,0xff800fff,0xfc007fff,0xe0000780,0x1e0000,0xf3fff8,0xffff780,0x7fffbc03,0xfffde01f,0xffef00ff,0xff7807ff,0xfbc0ffff,
4323 0xff800fff,0xf001ffff,0x800ffffc,0x7fffe0,0x3ffff00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff803ff,0xfc003c00,0x3c00ffff,0x7fff8,
4324 0x3fffc0,0x1fffe00,0xffff000,0x1f,0xfffc001f,0xffbc00ff,0xfde007ff,0xef003fff,0x780007e0,0x1ffffc,0x1f800,0x0,0x0,0x0,0x0,
4325 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x700003f,
4326 0xffc00000,0x7fc01fff,0x9f800000,0xf80,0xf800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0xff,0xf8000fff,0xfc03ffff,0xf83ffff8,0x780,
4327 0xffffe00,0x7fff000,0xf000003,0xfffe001f,0xffc00007,0xe000003f,0x0,0x0,0x0,0x3c000,0xf000003,0xe0000f83,0xffff0000,0xffff01ff,
4328 0xfc0003ff,0xffe01e00,0xfff,0xf01e0007,0x803ffff0,0x7fffc00,0x3c0007c0,0x7ffffe1e,0xf078,0x7e003f,0xff000780,0x7ff,0xe0078000,
4329 0x3c3ffff8,0xf000,0x1fffe00,0x7e0000,0xf803e03e,0x1f000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x3fff3c01,0xefff8000,
4330 0x7ffe001f,0xff78007f,0xff80003c,0x1ffc,0xf0078007,0x807ffffe,0xf000,0x78007c0,0x3ff00f,0x3c0f01e,0x1e003f,0xff0007bf,0xfe000fff,
4331 0xbc003c00,0xffff8,0xfff0,0xfff3c0,0x7e0000,0x7c07c01f,0x7c000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3fff80,0x380000,
4332 0x3e000000,0x7c00003e,0x7801f07,0xc1e00018,0xc0,0x0,0x39c1ce,0x7ffff00,0x1c0000,0xfffff80,0x380003f,0xffffc000,0xe0000007,
4333 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff000007,0x1ffcf,0xfe000380,0x1ffffe,0x1e000,0x0,0x780000,0xfffe03f,0xffff8000,0x7,
4334 0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x381,
4335 0xc000001e,0xe070,0x7fff80,0x7c0001f3,0xe0000f9f,0x7cf8,0x3e7c0,0x1f3e00,0xfbe007,0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,
4336 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000f000,0xfc007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x79,0xfff8001f,
4337 0xffe000ff,0xff0007ff,0xf8003fff,0xc0000780,0x1e0000,0xf3fff0,0x7ffe780,0x3fff3c01,0xfff9e00f,0xffcf007f,0xfe7803ff,0xf3c07ff3,
4338 0xff8007ff,0xe000ffff,0x7fff8,0x3fffc0,0x1fffe00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff801ff,0xf8003c00,0x3c007ffe,0x3fff0,
4339 0x1fff80,0xfffc00,0x7ffe000,0x1d,0xfff8000f,0xff3c007f,0xf9e003ff,0xcf001ffe,0x780007c0,0x1efff8,0x1f000,0x0,0x0,0x0,0x0,
4340 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0xf000003,
4341 0xfe000000,0x1f000fff,0xfc00000,0x780,0xf000,0x0,0x0,0xf80000,0x0,0x7e0001e0,0x7f,0xf0000fff,0xfc03ffff,0xf81ffff0,0x780,
4342 0x7fff800,0x1ffe000,0x1f000000,0xfff8001f,0xff000007,0xe000003e,0x0,0x0,0x0,0x3c000,0xf800003,0xc0000783,0xfff80000,0x3ffe01ff,
4343 0xe00003ff,0xffe01e00,0x7ff,0xc01e0007,0x803ffff0,0x3fff800,0x3c0003c0,0x7ffffe1e,0xf078,0x7e000f,0xfe000780,0x3ff,0xc0078000,
4344 0x3e1fffe0,0xf000,0x7ff800,0x7e0000,0xf803e07c,0xf800,0x780003ff,0xfffc003c,0x3,0xc00001e0,0x0,0x0,0x0,0xffe3c01,0xe7ff0000,
4345 0x3ffc000f,0xfe78003f,0xfe00003c,0x7f0,0xf0078007,0x807ffffe,0xf000,0x78003e0,0xff00f,0x3c0f01e,0x1e001f,0xfe00079f,0xfc0007ff,
4346 0x3c003c00,0x7ffe0,0x1ff0,0x7fe3c0,0x7e0000,0x7c07c03e,0x3e000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfff00,0x100000,
4347 0x3e000000,0x7800003c,0xf800f07,0xc1e00018,0xc0,0x0,0x1f80fc,0x3fffc00,0xc0000,0x3ffff80,0x100003f,0xffffc000,0x40000002,
4348 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xfc000006,0xff87,0xfc000100,0x1ffffe,0x1e000,0x0,0x780000,0x3ffc03f,0xffff8000,0x7,
4349 0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dff9f8,0xe1c00,0x0,0x0,0x0,0x0,0x3ff,
4350 0xf800003c,0xfffe,0x1ffe00,0x780000f3,0xc000079e,0x3cf0,0x1e780,0xf3c00,0x7bc007,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,
4351 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,0xf000,0xfc001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x70,0xfff00007,
4352 0xff80003f,0xfc0001ff,0xe0000fff,0x780,0x1e0000,0xf3ffe0,0x1ffc780,0xffe3c00,0x7ff1e003,0xff8f001f,0xfc7800ff,0xe3c03fe1,
4353 0xff0003ff,0xc0007ffc,0x3ffe0,0x1fff00,0xfff800,0xfffffc07,0xffffe03f,0xffff01ff,0xfff800ff,0xf0003c00,0x3c003ffc,0x1ffe0,
4354 0xfff00,0x7ff800,0x3ffc000,0x38,0xfff00007,0xfe3c003f,0xf1e001ff,0x8f000ffc,0x780007c0,0x1e7ff0,0x1f000,0x0,0x0,0x0,0x0,0x0,
4355 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,
4356 0x1fc,0x0,0x780,0xf000,0x0,0x0,0x1f80000,0x0,0x1e0,0x1f,0xc0000000,0x0,0x1ff80,0x0,0xffc000,0x7f8000,0x0,0x3fe00007,0xfc000000,
4357 0x7e,0x0,0x0,0x0,0x0,0x7c00000,0x0,0x0,0xff00000,0x0,0x0,0xfe,0x0,0x0,0x3fc000,0x0,0x0,0x0,0x3,0xf8000000,0xff,0xc0000000,
4358 0x1ff00,0x0,0x1fe000,0x0,0x0,0x0,0x0,0x3c,0x3,0xc00001e0,0x0,0x0,0x0,0x3f80000,0x1fc0000,0x7f00003,0xf8000007,0xf0000000,
4359 0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x7,0xf8000787,0xf00001fc,0x3c000000,0x7f80,0x0,0x1f8000,0x0,0x0,0x0,0x7c000000,0x1e,
4360 0xf0,0x780,0x0,0x0,0x3fc00,0x0,0x3c000000,0x7800003c,0xf000601,0xc00018,0xc0,0x0,0x0,0x3fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4361 0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xf0000000,0x7e03,0xf0000000,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x3c,0x2007,0x80000000,0x0,0x0,
4362 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c7e0f0,0xe1c00,0x0,0x3800000,0x0,0x0,0x3ff,0xf8000078,0xfffe,0x7f800,0x0,0x0,0x0,0x0,
4363 0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,0x7f0000,0x70,0x3fc00001,0xfe00000f,0xf000007f,
4364 0x800003fc,0x0,0x0,0xff00,0x7f0000,0x3f80000,0x1fc00000,0xfe000007,0xf000003f,0x80001f80,0xfc00007f,0xfe0,0x7f00,0x3f800,
4365 0x1fc000,0x0,0x0,0x0,0x3f,0xc0000000,0xff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x78,0x3fc00001,0xf800000f,0xc000007e,0x3f0,0x7c0,
4366 0x1e1fc0,0x1f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4367 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4368 0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xe0000000,0x0,0x0,0x0,
4369 0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,
4370 0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,0x1e,0xf0,0x780,0x0,0x0,0x0,0x0,0x3c000000,0x78000078,0xf000000,0x18,0xc0,0x0,0x0,0x0,
4371 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3c0f,0x80000000,
4372 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0x1800000,0x0,0x0,0x3ff,0xf80000f0,0xfffe,0x0,0x0,0x0,0x0,
4373 0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4374 0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,0x780,0x1e0000,0x1e000,0x0,0x0,0x0,
4375 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,
4376 0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x1f80000,
4377 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0,
4378 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf8000000,
4379 0x1f,0xf0,0xf80,0x0,0x0,0x0,0x0,0x78000000,0xf8000078,0x1e000000,0x8,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4380 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3fff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4381 0x0,0x3c00000,0xe1c00,0x0,0x1c00000,0x0,0x0,0x1,0xc00001e0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4382 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4383 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x1e0000,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4384 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x3c000,0x0,0x0,0x1f00000,
4385 0x0,0x780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0xfe0100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4386 0x0,0x0,0x0,0x0,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0xf0007fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000,
4387 0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x1f,0x800000f0,0x1f80,0x0,0x0,0x0,0x0,
4388 0x78000000,0xf0000070,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4389 0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3ffe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,
4390 0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4391 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4392 0x0,0x0,0x0,0xf00,0x1e0000,0x3c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4393 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x7c000,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4394 0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x7fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,
4395 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4003,0xe0000000,0x0,0x1f000,0x0,0x0,
4396 0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x1,0xf0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0x70000001,0xf00000e0,
4397 0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,
4398 0x0,0x0,0x3c,0xff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,0x0,0x0,0x1,0xc00003ff,
4399 0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4400 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00,0x1e0000,
4401 0x7c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4402 0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0xf0,0x78000,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf8,0x0,
4403 0x0,0x0,0x0,0x1fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,
4404 0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780f,0xc0000000,0x0,0x3e000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
4405 0x0,0x0,0x0,0x0,0x3,0xe0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0xf0000103,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4406 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,
4407 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x21e00000,0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,
4408 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,0x0,
4409 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e00,0x1e0000,0xf8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4410 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,
4411 0xf8,0xf8000,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x1fe00,0x0,0x0,0x0,0x0,
4412 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,
4413 0x0,0x0,0x7fff,0xc0000000,0x0,0x3ffe000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0xe0000000,0x7,0xfc0000f0,
4414 0x3fe00,0x0,0x0,0x0,0x0,0x600001ff,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4415 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,
4416 0x3fe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4417 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4418 0x0,0x0,0x0,0x0,0x7fe00,0x1e0000,0x1ff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4419 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4420 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4421 0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff,0x80000000,0x0,0x3ffc000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
4422 0x0,0x0,0x0,0x0,0x7f,0xc0000000,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x0,0x0,0x1ff,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4423 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4424 0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3fc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0,
4425 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0,0x0,
4426 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fc00,0x1e0000,0x1ff0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4427 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4428 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4429 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x3ffe,0x0,0x0,0x3ff8000,0x0,0x0,0x0,
4430 0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0x80000000,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x80000000,0x0,0x0,0x0,0x0,
4431 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4432 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0,
4433 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0,0x0,
4434 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f800,0x1e0000,0x1fe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4435 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4436 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4437 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8,0x0,0x0,0x3fe0000,
4438 0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7e,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0xfe,0x0,0x0,0x0,0x0,0x0,0x0,
4439 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4440 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4441 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4442 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x1e0000,0x1f80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4443 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4444 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4445 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4446 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4447 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4448 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4449 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4450 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4451 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4452 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4453 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,
4454 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4455 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4456 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
4457 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
4459 // Definition of a 40x38 'danger' color logo.
4460 const unsigned char logo40x38[4576] = {
4461 177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200,
4462 1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0,
4463 0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200,
4464 1,123,123,0,7,255,255,0,1,0,0,0,2,123,123,123,28,200,200,200,1,123,123,0,8,255,255,0,1,189,189,189,1,0,0,0,
4465 2,123,123,123,27,200,200,200,1,123,123,0,9,255,255,0,1,0,0,0,2,123,123,123,26,200,200,200,1,123,123,0,10,255,
4466 255,0,1,189,189,189,1,0,0,0,2,123,123,123,25,200,200,200,1,123,123,0,3,255,255,0,1,189,189,189,3,0,0,0,1,189,
4467 189,189,3,255,255,0,1,0,0,0,2,123,123,123,24,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,3,255,255,0,1,189,
4468 189,189,1,0,0,0,2,123,123,123,23,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,4,255,255,0,1,0,0,0,2,123,123,123,
4469 22,200,200,200,1,123,123,0,5,255,255,0,5,0,0,0,4,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,21,200,200,200,
4470 1,123,123,0,5,255,255,0,5,0,0,0,5,255,255,0,1,0,0,0,2,123,123,123,20,200,200,200,1,123,123,0,6,255,255,0,5,0,0,
4471 0,5,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,19,200,200,200,1,123,123,0,6,255,255,0,1,123,123,0,3,0,0,0,1,
4472 123,123,0,6,255,255,0,1,0,0,0,2,123,123,123,18,200,200,200,1,123,123,0,7,255,255,0,1,189,189,189,3,0,0,0,1,189,
4473 189,189,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,17,200,200,200,1,123,123,0,8,255,255,0,3,0,0,0,8,255,255,
4474 0,1,0,0,0,2,123,123,123,16,200,200,200,1,123,123,0,9,255,255,0,1,123,123,0,1,0,0,0,1,123,123,0,8,255,255,0,1,189,
4475 189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255,255,
4476 0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2,123,
4477 123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0,1,189,
4478 189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11,255,255,
4479 0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0,1,189,189,
4480 189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11,255,255,0,1,
4481 0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123,123,0,26,255,
4482 255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0,0,4,123,123,
4483 123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25,123,123,123,86,
4484 200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0};
4486 //! Display a warning message.
4487 /**
4488 \param format is a C-string describing the format of the message, as in <tt>std::printf()</tt>.
4489 **/
4490 inline void warn(const char *format, ...) {
4491 if (cimg::exception_mode()>=1) {
4492 char message[8192];
4493 cimg_std::va_list ap;
4494 va_start(ap,format);
4495 cimg_std::vsprintf(message,format,ap);
4496 va_end(ap);
4497 #ifdef cimg_strict_warnings
4498 throw CImgWarningException(message);
4499 #else
4500 cimg_std::fprintf(cimg_stdout,"\n%s# CImg Warning%s :\n%s\n",cimg::t_red,cimg::t_normal,message);
4501 #endif
4502 }
4503 }
4505 // Execute an external system command.
4506 /**
4507 \note This function is similar to <tt>std::system()</tt>
4508 and is here because using the <tt>std::</tt> version on
4509 Windows may open undesired consoles.
4510 **/
4511 inline int system(const char *const command, const char *const module_name=0) {
4512 #if cimg_OS==2
4513 PROCESS_INFORMATION pi;
4514 STARTUPINFO si;
4515 cimg_std::memset(&pi,0,sizeof(PROCESS_INFORMATION));
4516 cimg_std::memset(&si,0,sizeof(STARTUPINFO));
4517 GetStartupInfo(&si);
4518 si.cb = sizeof(si);
4519 si.wShowWindow = SW_HIDE;
4520 si.dwFlags |= SW_HIDE;
4521 const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);
4522 if (res) {
4523 WaitForSingleObject(pi.hProcess, INFINITE);
4524 CloseHandle(pi.hThread);
4525 CloseHandle(pi.hProcess);
4526 return 0;
4527 } else
4528 #endif
4529 return cimg_std::system(command);
4530 return module_name?0:1;
4531 }
4533 //! Return a reference to a temporary variable of type T.
4534 template<typename T>
4535 inline T& temporary(const T&) {
4536 static T temp;
4537 return temp;
4538 }
4540 //! Exchange values of variables \p a and \p b.
4541 template<typename T>
4542 inline void swap(T& a, T& b) { T t = a; a = b; b = t; }
4544 //! Exchange values of variables (\p a1,\p a2) and (\p b1,\p b2).
4545 template<typename T1, typename T2>
4546 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) {
4547 cimg::swap(a1,b1); cimg::swap(a2,b2);
4548 }
4550 //! Exchange values of variables (\p a1,\p a2,\p a3) and (\p b1,\p b2,\p b3).
4551 template<typename T1, typename T2, typename T3>
4552 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) {
4553 cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3);
4554 }
4556 //! Exchange values of variables (\p a1,\p a2,...,\p a4) and (\p b1,\p b2,...,\p b4).
4557 template<typename T1, typename T2, typename T3, typename T4>
4558 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) {
4559 cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);
4560 }
4562 //! Exchange values of variables (\p a1,\p a2,...,\p a5) and (\p b1,\p b2,...,\p b5).
4563 template<typename T1, typename T2, typename T3, typename T4, typename T5>
4564 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) {
4565 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);
4566 }
4568 //! Exchange values of variables (\p a1,\p a2,...,\p a6) and (\p b1,\p b2,...,\p b6).
4569 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
4570 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6) {
4571 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
4572 }
4574 //! Exchange values of variables (\p a1,\p a2,...,\p a7) and (\p b1,\p b2,...,\p b7).
4575 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
4576 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
4577 T7& a7, T7& b7) {
4578 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);
4579 }
4581 //! Exchange values of variables (\p a1,\p a2,...,\p a8) and (\p b1,\p b2,...,\p b8).
4582 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
4583 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
4584 T7& a7, T7& b7, T8& a8, T8& b8) {
4585 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);
4586 }
4588 //! Return the current endianness of the CPU.
4589 /**
4590 \return \c false for "Little Endian", \c true for "Big Endian".
4591 **/
4592 inline bool endianness() {
4593 const int x = 1;
4594 return ((unsigned char*)&x)[0]?false:true;
4595 }
4597 //! Invert endianness of a memory buffer.
4598 template<typename T>
4599 inline void invert_endianness(T* const buffer, const unsigned int size) {
4600 if (size) switch (sizeof(T)) {
4601 case 1 : break;
4602 case 2 : { for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer; ) {
4603 const unsigned short val = *(--ptr);
4604 *ptr = (unsigned short)((val>>8)|((val<<8)));
4605 }} break;
4606 case 4 : { for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer; ) {
4607 const unsigned int val = *(--ptr);
4608 *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24);
4609 }} break;
4610 default : { for (T* ptr = buffer+size; ptr>buffer; ) {
4611 unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);
4612 for (int i=0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe));
4613 }}
4614 }
4615 }
4617 //! Invert endianness of a single variable.
4618 template<typename T>
4619 inline T& invert_endianness(T& a) {
4620 invert_endianness(&a,1);
4621 return a;
4622 }
4624 //! Get the value of a system timer with a millisecond precision.
4625 inline unsigned long time() {
4626 #if cimg_OS==1
4627 struct timeval st_time;
4628 gettimeofday(&st_time,0);
4629 return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
4630 #elif cimg_OS==2
4631 static SYSTEMTIME st_time;
4632 GetSystemTime(&st_time);
4633 return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
4634 #else
4635 return 0;
4636 #endif
4637 }
4639 //! Sleep for a certain numbers of milliseconds.
4640 /**
4641 This function frees the CPU ressources during the sleeping time.
4642 It may be used to temporize your program properly, without wasting CPU time.
4643 **/
4644 inline void sleep(const unsigned int milliseconds) {
4645 #if cimg_OS==1
4646 struct timespec tv;
4647 tv.tv_sec = milliseconds/1000;
4648 tv.tv_nsec = (milliseconds%1000)*1000000;
4649 nanosleep(&tv,0);
4650 #elif cimg_OS==2
4651 Sleep(milliseconds);
4652 #endif
4653 }
4655 inline unsigned int _sleep(const unsigned int milliseconds, unsigned long& timer) {
4656 if (!timer) timer = cimg::time();
4657 const unsigned long current_time = cimg::time();
4658 if (current_time>=timer+milliseconds) { timer = current_time; return 0; }
4659 const unsigned long time_diff = timer + milliseconds - current_time;
4660 timer = current_time + time_diff;
4661 cimg::sleep(time_diff);
4662 return (unsigned int)time_diff;
4663 }
4665 //! Wait for a certain number of milliseconds since the last call.
4666 /**
4667 This function is equivalent to sleep() but the waiting time is computed with regard to the last call
4668 of wait(). It may be used to temporize your program properly.
4669 **/
4670 inline unsigned int wait(const unsigned int milliseconds) {
4671 static unsigned long timer = 0;
4672 if (!timer) timer = cimg::time();
4673 return _sleep(milliseconds,timer);
4674 }
4676 // Use a specific srand initialization to avoid multi-threads to have to the
4677 // same series of random numbers (executed only once for a single program).
4678 inline void srand() {
4679 static bool first_time = true;
4680 if (first_time) {
4681 cimg_std::srand(cimg::time());
4682 unsigned char *const rand_ptr = new unsigned char[1+cimg_std::rand()%2048];
4683 cimg_std::srand((unsigned int)cimg_std::rand() + *(unsigned int*)(void*)rand_ptr);
4684 delete[] rand_ptr;
4685 first_time = false;
4686 }
4687 }
4689 //! Return a left bitwise-rotated number.
4690 template<typename T>
4691 inline const T rol(const T a, const unsigned int n=1) {
4692 return n?(T)((a<<n)|(a>>((sizeof(T)<<3)-n))):a;
4693 }
4695 //! Return a right bitwise-rotated number.
4696 template<typename T>
4697 inline const T ror(const T a, const unsigned int n=1) {
4698 return n?(T)((a>>n)|(a<<((sizeof(T)<<3)-n))):a;
4699 }
4701 //! Return the absolute value of a number.
4702 /**
4703 \note This function is different from <tt>std::abs()</tt> or <tt>std::fabs()</tt>
4704 because it is able to consider a variable of any type, without cast needed.
4705 **/
4706 template<typename T>
4707 inline T abs(const T a) {
4708 return a>=0?a:-a;
4709 }
4710 inline bool abs(const bool a) {
4711 return a;
4712 }
4713 inline unsigned char abs(const unsigned char a) {
4714 return a;
4715 }
4716 inline unsigned short abs(const unsigned short a) {
4717 return a;
4718 }
4719 inline unsigned int abs(const unsigned int a) {
4720 return a;
4721 }
4722 inline unsigned long abs(const unsigned long a) {
4723 return a;
4724 }
4725 inline double abs(const double a) {
4726 return cimg_std::fabs(a);
4727 }
4728 inline float abs(const float a) {
4729 return (float)cimg_std::fabs((double)a);
4730 }
4731 inline int abs(const int a) {
4732 return cimg_std::abs(a);
4733 }
4735 //! Return the square of a number.
4736 template<typename T>
4737 inline T sqr(const T val) {
4738 return val*val;
4739 }
4741 //! Return 1 + log_10(x).
4742 inline int xln(const int x) {
4743 return x>0?(int)(1+cimg_std::log10((double)x)):1;
4744 }
4746 //! Return the minimum value between two numbers.
4747 template<typename t1, typename t2>
4748 inline typename cimg::superset<t1,t2>::type min(const t1& a, const t2& b) {
4749 typedef typename cimg::superset<t1,t2>::type t1t2;
4750 return (t1t2)(a<=b?a:b);
4751 }
4753 //! Return the minimum value between three numbers.
4754 template<typename t1, typename t2, typename t3>
4755 inline typename cimg::superset2<t1,t2,t3>::type min(const t1& a, const t2& b, const t3& c) {
4756 typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
4757 return (t1t2t3)cimg::min(cimg::min(a,b),c);
4758 }
4760 //! Return the minimum value between four numbers.
4761 template<typename t1, typename t2, typename t3, typename t4>
4762 inline typename cimg::superset3<t1,t2,t3,t4>::type min(const t1& a, const t2& b, const t3& c, const t4& d) {
4763 typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
4764 return (t1t2t3t4)cimg::min(cimg::min(a,b,c),d);
4765 }
4767 //! Return the maximum value between two numbers.
4768 template<typename t1, typename t2>
4769 inline typename cimg::superset<t1,t2>::type max(const t1& a, const t2& b) {
4770 typedef typename cimg::superset<t1,t2>::type t1t2;
4771 return (t1t2)(a>=b?a:b);
4772 }
4774 //! Return the maximum value between three numbers.
4775 template<typename t1, typename t2, typename t3>
4776 inline typename cimg::superset2<t1,t2,t3>::type max(const t1& a, const t2& b, const t3& c) {
4777 typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
4778 return (t1t2t3)cimg::max(cimg::max(a,b),c);
4779 }
4781 //! Return the maximum value between four numbers.
4782 template<typename t1, typename t2, typename t3, typename t4>
4783 inline typename cimg::superset3<t1,t2,t3,t4>::type max(const t1& a, const t2& b, const t3& c, const t4& d) {
4784 typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
4785 return (t1t2t3t4)cimg::max(cimg::max(a,b,c),d);
4786 }
4788 //! Return the sign of a number.
4789 template<typename T>
4790 inline T sign(const T x) {
4791 return (x<0)?(T)(-1):(x==0?(T)0:(T)1);
4792 }
4794 //! Return the nearest power of 2 higher than a given number.
4795 template<typename T>
4796 inline unsigned long nearest_pow2(const T x) {
4797 unsigned long i = 1;
4798 while (x>i) i<<=1;
4799 return i;
4800 }
4802 //! Return the modulo of a number.
4803 /**
4804 \note This modulo function accepts negative and floating-points modulo numbers, as well as
4805 variable of any type.
4806 **/
4807 template<typename T>
4808 inline T mod(const T& x, const T& m) {
4809 const double dx = (double)x, dm = (double)m;
4810 if (x<0) { return (T)(dm+dx+dm*cimg_std::floor(-dx/dm)); }
4811 return (T)(dx-dm*cimg_std::floor(dx/dm));
4812 }
4813 inline int mod(const bool x, const bool m) {
4814 return m?(x?1:0):0;
4815 }
4816 inline int mod(const char x, const char m) {
4817 return x>=0?x%m:(x%m?m+x%m:0);
4818 }
4819 inline int mod(const short x, const short m) {
4820 return x>=0?x%m:(x%m?m+x%m:0);
4821 }
4822 inline int mod(const int x, const int m) {
4823 return x>=0?x%m:(x%m?m+x%m:0);
4824 }
4825 inline int mod(const long x, const long m) {
4826 return x>=0?x%m:(x%m?m+x%m:0);
4827 }
4828 inline int mod(const unsigned char x, const unsigned char m) {
4829 return x%m;
4830 }
4831 inline int mod(const unsigned short x, const unsigned short m) {
4832 return x%m;
4833 }
4834 inline int mod(const unsigned int x, const unsigned int m) {
4835 return x%m;
4836 }
4837 inline int mod(const unsigned long x, const unsigned long m) {
4838 return x%m;
4839 }
4841 //! Return the minmod of two numbers.
4842 /**
4843 <i>minmod(\p a,\p b)</i> is defined to be :
4844 - <i>minmod(\p a,\p b) = min(\p a,\p b)</i>, if \p a and \p b have the same sign.
4845 - <i>minmod(\p a,\p b) = 0</i>, if \p a and \p b have different signs.
4846 **/
4847 template<typename T>
4848 inline T minmod(const T a, const T b) {
4849 return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));
4850 }
4852 //! Return a random variable between [0,1] with respect to an uniform distribution.
4853 inline double rand() {
4854 static bool first_time = true;
4855 if (first_time) { cimg::srand(); first_time = false; }
4856 return (double)cimg_std::rand()/RAND_MAX;
4857 }
4859 //! Return a random variable between [-1,1] with respect to an uniform distribution.
4860 inline double crand() {
4861 return 1-2*cimg::rand();
4862 }
4864 //! Return a random variable following a gaussian distribution and a standard deviation of 1.
4865 inline double grand() {
4866 double x1, w;
4867 do {
4868 const double x2 = 2*cimg::rand() - 1.0;
4869 x1 = 2*cimg::rand()-1.0;
4870 w = x1*x1 + x2*x2;
4871 } while (w<=0 || w>=1.0);
4872 return x1*cimg_std::sqrt((-2*cimg_std::log(w))/w);
4873 }
4875 //! Return a random variable following a Poisson distribution of parameter z.
4876 inline unsigned int prand(const double z) {
4877 if (z<=1.0e-10) return 0;
4878 if (z>100.0) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z);
4879 unsigned int k = 0;
4880 const double y = std::exp(-z);
4881 for (double s = 1.0; s>=y; ++k) s*=cimg::rand();
4882 return k-1;
4883 }
4885 //! Return a rounded number.
4886 /**
4887 \param x is the number to be rounded.
4888 \param y is the rounding precision.
4889 \param rounding_type defines the type of rounding (0=nearest, -1=backward, 1=forward).
4890 **/
4891 inline double round(const double x, const double y, const int rounding_type=0) {
4892 if (y<=0) return x;
4893 const double delta = cimg::mod(x,y);
4894 if (delta==0.0) return x;
4895 const double
4896 backward = x - delta,
4897 forward = backward + y;
4898 return rounding_type<0?backward:(rounding_type>0?forward:(2*delta<y?backward:forward));
4899 }
4901 inline double _pythagore(double a, double b) {
4902 const double absa = cimg::abs(a), absb = cimg::abs(b);
4903 if (absa>absb) { const double tmp = absb/absa; return absa*cimg_std::sqrt(1.0+tmp*tmp); }
4904 else { const double tmp = absa/absb; return (absb==0?0:absb*cimg_std::sqrt(1.0+tmp*tmp)); }
4905 }
4907 //! Remove the 'case' of an ASCII character.
4908 inline char uncase(const char x) {
4909 return (char)((x<'A'||x>'Z')?x:x-'A'+'a');
4910 }
4912 //! Remove the 'case' of a C string.
4913 /**
4914 Acts in-place.
4915 **/
4916 inline void uncase(char *const string) {
4917 if (string) for (char *ptr = string; *ptr; ++ptr) *ptr = uncase(*ptr);
4918 }
4920 //! Read a float number from a C-string.
4921 /**
4922 \note This function is quite similar to <tt>std::atof()</tt>,
4923 but that it allows the retrieval of fractions as in "1/2".
4924 **/
4925 inline float atof(const char *const str) {
4926 float x = 0,y = 1;
4927 if (!str) return 0; else { cimg_std::sscanf(str,"%g/%g",&x,&y); return x/y; }
4928 }
4930 //! Compute the length of a C-string.
4931 /**
4932 \note This function is similar to <tt>std::strlen()</tt>
4933 and is here because some old compilers do not
4934 define the <tt>std::</tt> version.
4935 **/
4936 inline int strlen(const char *const s) {
4937 if (!s) return -1;
4938 int k = 0;
4939 for (const char *ns = s; *ns; ++ns) ++k;
4940 return k;
4941 }
4943 //! Compare the first \p n characters of two C-strings.
4944 /**
4945 \note This function is similar to <tt>std::strncmp()</tt>
4946 and is here because some old compilers do not
4947 define the <tt>std::</tt> version.
4948 **/
4949 inline int strncmp(const char *const s1, const char *const s2, const int l) {
4950 if (!s1) return s2?-1:0;
4951 const char *ns1 = s1, *ns2 = s2;
4952 int k, diff = 0; for (k = 0; k<l && !(diff = *ns1-*ns2); ++k) { ++ns1; ++ns2; }
4953 return k!=l?diff:0;
4954 }
4956 //! Compare the first \p n characters of two C-strings, ignoring the case.
4957 /**
4958 \note This function is similar to <tt>std::strncasecmp()</tt>
4959 and is here because some old compilers do not
4960 define the <tt>std::</tt> version.
4961 **/
4962 inline int strncasecmp(const char *const s1, const char *const s2, const int l) {
4963 if (!s1) return s2?-1:0;
4964 const char *ns1 = s1, *ns2 = s2;
4965 int k, diff = 0; for (k = 0; k<l && !(diff = uncase(*ns1)-uncase(*ns2)); ++k) { ++ns1; ++ns2; }
4966 return k!=l?diff:0;
4967 }
4969 //! Compare two C-strings.
4970 /**
4971 \note This function is similar to <tt>std::strcmp()</tt>
4972 and is here because some old compilers do not
4973 define the <tt>std::</tt> version.
4974 **/
4975 inline int strcmp(const char *const s1, const char *const s2) {
4976 const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
4977 return cimg::strncmp(s1,s2,1+(l1<l2?l1:l2));
4978 }
4980 //! Compare two C-strings, ignoring the case.
4981 /**
4982 \note This function is similar to <tt>std::strcasecmp()</tt>
4983 and is here because some old compilers do not
4984 define the <tt>std::</tt> version.
4985 **/
4986 inline int strcasecmp(const char *const s1, const char *const s2) {
4987 const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
4988 return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2));
4989 }
4991 //! Find a character in a C-string.
4992 inline int strfind(const char *const s, const char c) {
4993 if (!s) return -1;
4994 int l; for (l = cimg::strlen(s); l>=0 && s[l]!=c; --l) {}
4995 return l;
4996 }
4998 //! Remove useless delimiters on the borders of a C-string
4999 inline bool strpare(char *const s, const char delimiter=' ', const bool symmetric=false) {
5000 if (!s) return false;
5001 const int l = cimg::strlen(s);
5002 int p, q;
5003 if (symmetric) for (p = 0, q = l-1; p<q && s[p]==delimiter && s[q]==delimiter; ++p) --q;
5004 else {
5005 for (p = 0; p<l && s[p]==delimiter; ) ++p;
5006 for (q = l-1; q>p && s[q]==delimiter; ) --q;
5007 }
5008 const int n = q - p + 1;
5009 if (n!=l) { cimg_std::memmove(s,s+p,n); s[n] = '\0'; return true; }
5010 return false;
5011 }
5013 //! Remove useless spaces and symmetric delimiters ', " and ` from a C-string.
5014 inline void strclean(char *const s) {
5015 if (!s) return;
5016 strpare(s,' ',false);
5017 for (bool need_iter = true; need_iter; ) {
5018 need_iter = false;
5019 need_iter |= strpare(s,'\'',true);
5020 need_iter |= strpare(s,'\"',true);
5021 need_iter |= strpare(s,'`',true);
5022 }
5023 }
5025 //! Replace explicit escape sequences '\x' in C-strings (where x in [ntvbrfa?'"0]).
5026 inline void strescape(char *const s) {
5027 #define cimg_strescape(ci,co) case ci: *nd = co; break;
5028 char *ns, *nd;
5029 for (ns = nd = s; *ns; ++ns, ++nd)
5030 if (*ns=='\\') switch (*(++ns)) {
5031 cimg_strescape('n','\n');
5032 cimg_strescape('t','\t');
5033 cimg_strescape('v','\v');
5034 cimg_strescape('b','\b');
5035 cimg_strescape('r','\r');
5036 cimg_strescape('f','\f');
5037 cimg_strescape('a','\a');
5038 cimg_strescape('\\','\\');
5039 cimg_strescape('\?','\?');
5040 cimg_strescape('\'','\'');
5041 cimg_strescape('\"','\"');
5042 cimg_strescape('\0','\0');
5043 }
5044 else *nd = *ns;
5045 *nd = 0;
5046 }
5048 //! Compute the basename of a filename.
5049 inline const char* basename(const char *const s) {
5050 return (cimg_OS!=2)?(s?s+1+cimg::strfind(s,'/'):0):(s?s+1+cimg::strfind(s,'\\'):0);
5051 }
5053 // Generate a random filename.
5054 inline const char* filenamerand() {
5055 static char id[9] = { 0,0,0,0,0,0,0,0,0 };
5056 cimg::srand();
5057 for (unsigned int k=0; k<8; ++k) {
5058 const int v = (int)cimg_std::rand()%3;
5059 id[k] = (char)(v==0?('0'+(cimg_std::rand()%10)):(v==1?('a'+(cimg_std::rand()%26)):('A'+(cimg_std::rand()%26))));
5060 }
5061 return id;
5062 }
5064 // Convert filename into a Windows-style filename.
5065 inline void winformat_string(char *const s) {
5066 if (s && s[0]) {
5067 #if cimg_OS==2
5068 char *const ns = new char[MAX_PATH];
5069 if (GetShortPathNameA(s,ns,MAX_PATH)) cimg_std::strcpy(s,ns);
5070 #endif
5071 }
5072 }
5074 //! Return or set path to store temporary files.
5075 inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false) {
5076 #define _cimg_test_temporary_path(p) \
5077 if (!path_found) { \
5078 cimg_std::sprintf(st_path,"%s",p); \
5079 cimg_std::sprintf(tmp,"%s%s%s",st_path,cimg_OS==2?"\\":"/",filetmp); \
5080 if ((file=cimg_std::fopen(tmp,"wb"))!=0) { cimg_std::fclose(file); cimg_std::remove(tmp); path_found = true; } \
5081 }
5082 static char *st_path = 0;
5083 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5084 if (user_path) {
5085 if (!st_path) st_path = new char[1024];
5086 cimg_std::memset(st_path,0,1024);
5087 cimg_std::strncpy(st_path,user_path,1023);
5088 } else if (!st_path) {
5089 st_path = new char[1024];
5090 cimg_std::memset(st_path,0,1024);
5091 bool path_found = false;
5092 char tmp[1024], filetmp[512];
5093 cimg_std::FILE *file = 0;
5094 cimg_std::sprintf(filetmp,"%s.tmp",cimg::filenamerand());
5095 char *tmpPath = getenv("TMP");
5096 if (!tmpPath) { tmpPath = getenv("TEMP"); winformat_string(tmpPath); }
5097 if (tmpPath) _cimg_test_temporary_path(tmpPath);
5098 #if cimg_OS==2
5099 _cimg_test_temporary_path("C:\\WINNT\\Temp");
5100 _cimg_test_temporary_path("C:\\WINDOWS\\Temp");
5101 _cimg_test_temporary_path("C:\\Temp");
5102 _cimg_test_temporary_path("C:");
5103 _cimg_test_temporary_path("D:\\WINNT\\Temp");
5104 _cimg_test_temporary_path("D:\\WINDOWS\\Temp");
5105 _cimg_test_temporary_path("D:\\Temp");
5106 _cimg_test_temporary_path("D:");
5107 #else
5108 _cimg_test_temporary_path("/tmp");
5109 _cimg_test_temporary_path("/var/tmp");
5110 #endif
5111 if (!path_found) {
5112 st_path[0]='\0';
5113 cimg_std::strcpy(tmp,filetmp);
5114 if ((file=cimg_std::fopen(tmp,"wb"))!=0) { cimg_std::fclose(file); cimg_std::remove(tmp); path_found = true; }
5115 }
5116 if (!path_found)
5117 throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n"
5118 "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n"
5119 "#define cimg_temporary_path \"path\" (before including 'CImg.h')");
5120 }
5121 return st_path;
5122 }
5124 // Return or set path to the "Program files/" directory (windows only).
5125 #if cimg_OS==2
5126 inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false) {
5127 static char *st_path = 0;
5128 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5129 if (user_path) {
5130 if (!st_path) st_path = new char[1024];
5131 cimg_std::memset(st_path,0,1024);
5132 cimg_std::strncpy(st_path,user_path,1023);
5133 } else if (!st_path) {
5134 st_path = new char[MAX_PATH];
5135 cimg_std::memset(st_path,0,MAX_PATH);
5136 // Note : in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler).
5137 #if !defined(__INTEL_COMPILER)
5138 if (!SHGetSpecialFolderPathA(0,st_path,0x0026,false)) {
5139 const char *pfPath = getenv("PROGRAMFILES");
5140 if (pfPath) cimg_std::strncpy(st_path,pfPath,MAX_PATH-1);
5141 else cimg_std::strcpy(st_path,"C:\\PROGRA~1");
5142 }
5143 #else
5144 cimg_std::strcpy(st_path,"C:\\PROGRA~1");
5145 #endif
5146 }
5147 return st_path;
5148 }
5149 #endif
5151 //! Return or set path to the ImageMagick's \c convert tool.
5152 inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false) {
5153 static char *st_path = 0;
5154 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5155 if (user_path) {
5156 if (!st_path) st_path = new char[1024];
5157 cimg_std::memset(st_path,0,1024);
5158 cimg_std::strncpy(st_path,user_path,1023);
5159 } else if (!st_path) {
5160 st_path = new char[1024];
5161 cimg_std::memset(st_path,0,1024);
5162 bool path_found = false;
5163 cimg_std::FILE *file = 0;
5164 #if cimg_OS==2
5165 const char *pf_path = programfiles_path();
5166 if (!path_found) {
5167 cimg_std::sprintf(st_path,".\\convert.exe");
5168 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5169 }
5170 { for (int k=32; k>=10 && !path_found; --k) {
5171 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k);
5172 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5173 }}
5174 { for (int k=9; k>=0 && !path_found; --k) {
5175 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k);
5176 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5177 }}
5178 { for (int k=32; k>=0 && !path_found; --k) {
5179 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k);
5180 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5181 }}
5182 { for (int k=32; k>=10 && !path_found; --k) {
5183 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k);
5184 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5185 }}
5186 { for (int k=9; k>=0 && !path_found; --k) {
5187 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k);
5188 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5189 }}
5190 { for (int k=32; k>=0 && !path_found; --k) {
5191 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k);
5192 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5193 }}
5194 { for (int k=32; k>=10 && !path_found; --k) {
5195 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\convert.exe",k);
5196 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5197 }}
5198 { for (int k=9; k>=0 && !path_found; --k) {
5199 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\convert.exe",k);
5200 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5201 }}
5202 { for (int k=32; k>=0 && !path_found; --k) {
5203 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d\\convert.exe",k);
5204 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5205 }}
5206 { for (int k=32; k>=10 && !path_found; --k) {
5207 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
5208 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5209 }}
5210 { for (int k=9; k>=0 && !path_found; --k) {
5211 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
5212 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5213 }}
5214 { for (int k=32; k>=0 && !path_found; --k) {
5215 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
5216 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5217 }}
5218 { for (int k=32; k>=10 && !path_found; --k) {
5219 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\convert.exe",k);
5220 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5221 }}
5222 { for (int k=9; k>=0 && !path_found; --k) {
5223 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\convert.exe",k);
5224 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5225 }}
5226 { for (int k=32; k>=0 && !path_found; --k) {
5227 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d\\convert.exe",k);
5228 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5229 }}
5230 { for (int k=32; k>=10 && !path_found; --k) {
5231 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
5232 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5233 }}
5234 { for (int k=9; k>=0 && !path_found; --k) {
5235 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
5236 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5237 }}
5238 { for (int k=32; k>=0 && !path_found; --k) {
5239 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
5240 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5241 }}
5242 if (!path_found) cimg_std::strcpy(st_path,"convert.exe");
5243 #else
5244 if (!path_found) {
5245 cimg_std::sprintf(st_path,"./convert");
5246 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5247 }
5248 if (!path_found) cimg_std::strcpy(st_path,"convert");
5249 #endif
5250 winformat_string(st_path);
5251 }
5252 return st_path;
5253 }
5255 //! Return path of the GraphicsMagick's \c gm tool.
5256 inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false) {
5257 static char *st_path = 0;
5258 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5259 if (user_path) {
5260 if (!st_path) st_path = new char[1024];
5261 cimg_std::memset(st_path,0,1024);
5262 cimg_std::strncpy(st_path,user_path,1023);
5263 } else if (!st_path) {
5264 st_path = new char[1024];
5265 cimg_std::memset(st_path,0,1024);
5266 bool path_found = false;
5267 cimg_std::FILE *file = 0;
5268 #if cimg_OS==2
5269 const char* pf_path = programfiles_path();
5270 if (!path_found) {
5271 cimg_std::sprintf(st_path,".\\gm.exe");
5272 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5273 }
5274 { for (int k=32; k>=10 && !path_found; --k) {
5275 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k);
5276 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5277 }}
5278 { for (int k=9; k>=0 && !path_found; --k) {
5279 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k);
5280 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5281 }}
5282 { for (int k=32; k>=0 && !path_found; --k) {
5283 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k);
5284 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5285 }}
5286 { for (int k=32; k>=10 && !path_found; --k) {
5287 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k);
5288 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5289 }}
5290 { for (int k=9; k>=0 && !path_found; --k) {
5291 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k);
5292 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5293 }}
5294 { for (int k=32; k>=0 && !path_found; --k) {
5295 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k);
5296 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5297 }}
5298 { for (int k=32; k>=10 && !path_found; --k) {
5299 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\gm.exe",k);
5300 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5301 }}
5302 { for (int k=9; k>=0 && !path_found; --k) {
5303 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\gm.exe",k);
5304 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5305 }}
5306 { for (int k=32; k>=0 && !path_found; --k) {
5307 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d\\gm.exe",k);
5308 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5309 }}
5310 { for (int k=32; k>=10 && !path_found; --k) {
5311 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
5312 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5313 }}
5314 { for (int k=9; k>=0 && !path_found; --k) {
5315 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
5316 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5317 }}
5318 { for (int k=32; k>=0 && !path_found; --k) {
5319 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
5320 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5321 }}
5322 { for (int k=32; k>=10 && !path_found; --k) {
5323 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\gm.exe",k);
5324 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5325 }}
5326 { for (int k=9; k>=0 && !path_found; --k) {
5327 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\gm.exe",k);
5328 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5329 }}
5330 { for (int k=32; k>=0 && !path_found; --k) {
5331 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d\\gm.exe",k);
5332 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5333 }}
5334 { for (int k=32; k>=10 && !path_found; --k) {
5335 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
5336 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5337 }}
5338 { for (int k=9; k>=0 && !path_found; --k) {
5339 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
5340 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5341 }}
5342 { for (int k=32; k>=0 && !path_found; --k) {
5343 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
5344 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5345 }}
5346 if (!path_found) cimg_std::strcpy(st_path,"gm.exe");
5347 #else
5348 if (!path_found) {
5349 cimg_std::sprintf(st_path,"./gm");
5350 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5351 }
5352 if (!path_found) cimg_std::strcpy(st_path,"gm");
5353 #endif
5354 winformat_string(st_path);
5355 }
5356 return st_path;
5357 }
5359 //! Return or set path of the \c XMedcon tool.
5360 inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false) {
5361 static char *st_path = 0;
5362 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5363 if (user_path) {
5364 if (!st_path) st_path = new char[1024];
5365 cimg_std::memset(st_path,0,1024);
5366 cimg_std::strncpy(st_path,user_path,1023);
5367 } else if (!st_path) {
5368 st_path = new char[1024];
5369 cimg_std::memset(st_path,0,1024);
5370 bool path_found = false;
5371 cimg_std::FILE *file = 0;
5372 #if cimg_OS==2
5373 const char* pf_path = programfiles_path();
5374 if (!path_found) {
5375 cimg_std::sprintf(st_path,".\\medcon.bat");
5376 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5377 }
5378 if (!path_found) {
5379 cimg_std::sprintf(st_path,".\\medcon.exe");
5380 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5381 }
5382 if (!path_found) {
5383 cimg_std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.bat",pf_path);
5384 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5385 }
5386 if (!path_found) {
5387 cimg_std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.exe",pf_path);
5388 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5389 }
5390 if (!path_found) cimg_std::strcpy(st_path,"medcon.bat");
5391 #else
5392 if (!path_found) {
5393 cimg_std::sprintf(st_path,"./medcon");
5394 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5395 }
5396 if (!path_found) cimg_std::strcpy(st_path,"medcon");
5397 #endif
5398 winformat_string(st_path);
5399 }
5400 return st_path;
5401 }
5403 //! Return or set path to the 'ffmpeg' command.
5404 inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false) {
5405 static char *st_path = 0;
5406 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5407 if (user_path) {
5408 if (!st_path) st_path = new char[1024];
5409 cimg_std::memset(st_path,0,1024);
5410 cimg_std::strncpy(st_path,user_path,1023);
5411 } else if (!st_path) {
5412 st_path = new char[1024];
5413 cimg_std::memset(st_path,0,1024);
5414 bool path_found = false;
5415 cimg_std::FILE *file = 0;
5416 #if cimg_OS==2
5417 if (!path_found) {
5418 cimg_std::sprintf(st_path,".\\ffmpeg.exe");
5419 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5420 }
5421 if (!path_found) cimg_std::strcpy(st_path,"ffmpeg.exe");
5422 #else
5423 if (!path_found) {
5424 cimg_std::sprintf(st_path,"./ffmpeg");
5425 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5426 }
5427 if (!path_found) cimg_std::strcpy(st_path,"ffmpeg");
5428 #endif
5429 winformat_string(st_path);
5430 }
5431 return st_path;
5432 }
5434 //! Return or set path to the 'gzip' command.
5435 inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false) {
5436 static char *st_path = 0;
5437 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5438 if (user_path) {
5439 if (!st_path) st_path = new char[1024];
5440 cimg_std::memset(st_path,0,1024);
5441 cimg_std::strncpy(st_path,user_path,1023);
5442 } else if (!st_path) {
5443 st_path = new char[1024];
5444 cimg_std::memset(st_path,0,1024);
5445 bool path_found = false;
5446 cimg_std::FILE *file = 0;
5447 #if cimg_OS==2
5448 if (!path_found) {
5449 cimg_std::sprintf(st_path,".\\gzip.exe");
5450 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5451 }
5452 if (!path_found) cimg_std::strcpy(st_path,"gzip.exe");
5453 #else
5454 if (!path_found) {
5455 cimg_std::sprintf(st_path,"./gzip");
5456 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5457 }
5458 if (!path_found) cimg_std::strcpy(st_path,"gzip");
5459 #endif
5460 winformat_string(st_path);
5461 }
5462 return st_path;
5463 }
5465 //! Return or set path to the 'gunzip' command.
5466 inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false) {
5467 static char *st_path = 0;
5468 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5469 if (user_path) {
5470 if (!st_path) st_path = new char[1024];
5471 cimg_std::memset(st_path,0,1024);
5472 cimg_std::strncpy(st_path,user_path,1023);
5473 } else if (!st_path) {
5474 st_path = new char[1024];
5475 cimg_std::memset(st_path,0,1024);
5476 bool path_found = false;
5477 cimg_std::FILE *file = 0;
5478 #if cimg_OS==2
5479 if (!path_found) {
5480 cimg_std::sprintf(st_path,".\\gunzip.exe");
5481 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5482 }
5483 if (!path_found) cimg_std::strcpy(st_path,"gunzip.exe");
5484 #else
5485 if (!path_found) {
5486 cimg_std::sprintf(st_path,"./gunzip");
5487 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5488 }
5489 if (!path_found) cimg_std::strcpy(st_path,"gunzip");
5490 #endif
5491 winformat_string(st_path);
5492 }
5493 return st_path;
5494 }
5496 //! Return or set path to the 'dcraw' command.
5497 inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false) {
5498 static char *st_path = 0;
5499 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
5500 if (user_path) {
5501 if (!st_path) st_path = new char[1024];
5502 cimg_std::memset(st_path,0,1024);
5503 cimg_std::strncpy(st_path,user_path,1023);
5504 } else if (!st_path) {
5505 st_path = new char[1024];
5506 cimg_std::memset(st_path,0,1024);
5507 bool path_found = false;
5508 cimg_std::FILE *file = 0;
5509 #if cimg_OS==2
5510 if (!path_found) {
5511 cimg_std::sprintf(st_path,".\\dcraw.exe");
5512 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5513 }
5514 if (!path_found) cimg_std::strcpy(st_path,"dcraw.exe");
5515 #else
5516 if (!path_found) {
5517 cimg_std::sprintf(st_path,"./dcraw");
5518 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
5519 }
5520 if (!path_found) cimg_std::strcpy(st_path,"dcraw");
5521 #endif
5522 winformat_string(st_path);
5523 }
5524 return st_path;
5525 }
5527 //! Split a filename into two strings 'body' and 'extension'.
5528 inline const char *split_filename(const char *const filename, char *const body=0) {
5529 if (!filename) { if (body) body[0]='\0'; return 0; }
5530 int l = cimg::strfind(filename,'.');
5531 if (l>=0) { if (body) { cimg_std::strncpy(body,filename,l); body[l]='\0'; }}
5532 else { if (body) cimg_std::strcpy(body,filename); l = (int)cimg::strlen(filename)-1; }
5533 return filename+l+1;
5534 }
5536 //! Create a numbered version of a filename.
5537 inline char* number_filename(const char *const filename, const int number, const unsigned int n, char *const string) {
5538 if (!filename) { if (string) string[0]='\0'; return 0; }
5539 char format[1024],body[1024];
5540 const char *ext = cimg::split_filename(filename,body);
5541 if (n>0) cimg_std::sprintf(format,"%s_%%.%ud.%s",body,n,ext);
5542 else cimg_std::sprintf(format,"%s_%%d.%s",body,ext);
5543 cimg_std::sprintf(string,format,number);
5544 return string;
5545 }
5547 //! Open a file, and check for possible errors.
5548 inline cimg_std::FILE *fopen(const char *const path, const char *const mode) {
5549 if(!path || !mode)
5550 throw CImgArgumentException("cimg::fopen() : File '%s', cannot open with mode '%s'.",
5551 path?path:"(null)",mode?mode:"(null)");
5552 if (path[0]=='-') return (mode[0]=='r')?stdin:stdout;
5553 cimg_std::FILE *dest = cimg_std::fopen(path,mode);
5554 if (!dest)
5555 throw CImgIOException("cimg::fopen() : File '%s', cannot open file %s",
5556 path,mode[0]=='r'?"for reading.":(mode[0]=='w'?"for writing.":"."),path);
5557 return dest;
5558 }
5560 //! Close a file, and check for possible errors.
5561 inline int fclose(cimg_std::FILE *file) {
5562 if (!file) warn("cimg::fclose() : Can't close (null) file");
5563 if (!file || file==stdin || file==stdout) return 0;
5564 const int errn = cimg_std::fclose(file);
5565 if (errn!=0) warn("cimg::fclose() : Error %d during file closing",errn);
5566 return errn;
5567 }
5569 //! Try to guess the image format of a filename, using its magick numbers.
5570 inline const char *file_type(cimg_std::FILE *const file, const char *const filename) {
5571 static const char
5572 *const _pnm = "pnm",
5573 *const _bmp = "bmp",
5574 *const _gif = "gif",
5575 *const _jpeg = "jpeg",
5576 *const _off = "off",
5577 *const _pan = "pan",
5578 *const _png = "png",
5579 *const _tiff = "tiff";
5580 if (!filename && !file) throw CImgArgumentException("cimg::file_type() : Cannot load (null) filename.");
5581 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
5582 const char *ftype = 0, *head;
5583 char header[2048], item[1024];
5584 const unsigned char *const uheader = (unsigned char*)header;
5585 int err;
5586 const unsigned int siz = (unsigned int)cimg_std::fread(header,2048,1,nfile); // Read first 2048 bytes.
5587 if (!file) cimg::fclose(nfile);
5588 if (!ftype) { // Check for BMP format.
5589 if (header[0]=='B' && header[1]=='M') ftype = _bmp;
5590 }
5591 if (!ftype) { // Check for GIF format.
5592 if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' &&
5593 (header[4]=='7' || header[4]=='9')) ftype = _gif;
5594 }
5595 if (!ftype) { // Check for JPEG format.
5596 if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) ftype = _jpeg;
5597 }
5598 if (!ftype) { // Check for OFF format.
5599 if (header[0]=='O' && header[1]=='F' && header[2]=='F' && header[3]=='\n') ftype = _off;
5600 }
5601 if (!ftype) { // Check for PAN format.
5602 if (header[0]=='P' && header[1]=='A' && header[2]=='N' && header[3]=='D' && header[4]=='O' &&
5603 header[5]=='R' && header[6]=='E') ftype = _pan;
5604 }
5605 if (!ftype) { // Check for PNG format.
5606 if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 &&
5607 uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) ftype = _png;
5608 }
5609 if (!ftype) { // Check for PNM format.
5610 head = header;
5611 while (head<header+siz && (err=cimg_std::sscanf(head,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err))
5612 head+=1+(err?cimg::strlen(item):0);
5613 if (cimg_std::sscanf(item," P%d",&err)==1) ftype = _pnm;
5614 }
5615 if (!ftype) { // Check for TIFF format.
5616 if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) ftype = _tiff;
5617 }
5618 return ftype;
5619 }
5621 //! Read file data, and check for possible errors.
5622 template<typename T>
5623 inline int fread(T *const ptr, const unsigned int nmemb, cimg_std::FILE *stream) {
5624 if (!ptr || nmemb<=0 || !stream)
5625 throw CImgArgumentException("cimg::fread() : Can't read %u x %u bytes of file pointer '%p' in buffer '%p'",
5626 nmemb,sizeof(T),stream,ptr);
5627 const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
5628 unsigned int toread = nmemb, alread = 0, ltoread = 0, lalread = 0;
5629 do {
5630 ltoread = (toread*sizeof(T))<wlimitT?toread:wlimit;
5631 lalread = (unsigned int)cimg_std::fread((void*)(ptr+alread),sizeof(T),ltoread,stream);
5632 alread+=lalread;
5633 toread-=lalread;
5634 } while (ltoread==lalread && toread>0);
5635 if (toread>0) warn("cimg::fread() : File reading problems, only %u/%u elements read",alread,nmemb);
5636 return alread;
5637 }
5639 //! Write data to a file, and check for possible errors.
5640 template<typename T>
5641 inline int fwrite(const T *ptr, const unsigned int nmemb, cimg_std::FILE *stream) {
5642 if (!ptr || !stream)
5643 throw CImgArgumentException("cimg::fwrite() : Can't write %u x %u bytes of file pointer '%p' from buffer '%p'",
5644 nmemb,sizeof(T),stream,ptr);
5645 if (nmemb<=0) return 0;
5646 const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
5647 unsigned int towrite = nmemb, alwrite = 0, ltowrite = 0, lalwrite = 0;
5648 do {
5649 ltowrite = (towrite*sizeof(T))<wlimitT?towrite:wlimit;
5650 lalwrite = (unsigned int)cimg_std::fwrite((void*)(ptr+alwrite),sizeof(T),ltowrite,stream);
5651 alwrite+=lalwrite;
5652 towrite-=lalwrite;
5653 } while (ltowrite==lalwrite && towrite>0);
5654 if (towrite>0) warn("cimg::fwrite() : File writing problems, only %u/%u elements written",alwrite,nmemb);
5655 return alwrite;
5656 }
5658 inline const char* option(const char *const name, const int argc, const char *const *const argv,
5659 const char *defaut, const char *const usage=0) {
5660 static bool first = true, visu = false;
5661 const char *res = 0;
5662 if (first) {
5663 first=false;
5664 visu = (cimg::option("-h",argc,argv,(char*)0)!=0);
5665 visu |= (cimg::option("-help",argc,argv,(char*)0)!=0);
5666 visu |= (cimg::option("--help",argc,argv,(char*)0)!=0);
5667 }
5668 if (!name && visu) {
5669 if (usage) {
5670 cimg_std::fprintf(cimg_stdout,"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);
5671 cimg_std::fprintf(cimg_stdout," : %s",usage);
5672 cimg_std::fprintf(cimg_stdout," (%s, %s)\n\n",__DATE__,__TIME__);
5673 }
5674 if (defaut) cimg_std::fprintf(cimg_stdout,"%s\n",defaut);
5675 }
5676 if (name) {
5677 if (argc>0) {
5678 int k = 0;
5679 while (k<argc && cimg::strcmp(argv[k],name)) ++k;
5680 res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
5681 } else res = defaut;
5682 if (visu && usage) cimg_std::fprintf(cimg_stdout," %s%-16s%s %-24s %s%s%s\n",
5683 cimg::t_bold,name,cimg::t_normal,res?res:"0",cimg::t_green,usage,cimg::t_normal);
5684 }
5685 return res;
5686 }
5688 inline bool option(const char *const name, const int argc, const char *const *const argv,
5689 const bool defaut, const char *const usage=0) {
5690 const char *s = cimg::option(name,argc,argv,(char*)0);
5691 const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut;
5692 cimg::option(name,0,0,res?"true":"false",usage);
5693 return res;
5694 }
5696 inline int option(const char *const name, const int argc, const char *const *const argv,
5697 const int defaut, const char *const usage=0) {
5698 const char *s = cimg::option(name,argc,argv,(char*)0);
5699 const int res = s?cimg_std::atoi(s):defaut;
5700 char tmp[256];
5701 cimg_std::sprintf(tmp,"%d",res);
5702 cimg::option(name,0,0,tmp,usage);
5703 return res;
5704 }
5706 inline char option(const char *const name, const int argc, const char *const *const argv,
5707 const char defaut, const char *const usage=0) {
5708 const char *s = cimg::option(name,argc,argv,(char*)0);
5709 const char res = s?s[0]:defaut;
5710 char tmp[8];
5711 tmp[0] = res; tmp[1] ='\0';
5712 cimg::option(name,0,0,tmp,usage);
5713 return res;
5714 }
5716 inline float option(const char *const name, const int argc, const char *const *const argv,
5717 const float defaut, const char *const usage=0) {
5718 const char *s = cimg::option(name,argc,argv,(char*)0);
5719 const float res = s?cimg::atof(s):defaut;
5720 char tmp[256];
5721 cimg_std::sprintf(tmp,"%g",res);
5722 cimg::option(name,0,0,tmp,usage);
5723 return res;
5724 }
5726 inline double option(const char *const name, const int argc, const char *const *const argv,
5727 const double defaut, const char *const usage=0) {
5728 const char *s = cimg::option(name,argc,argv,(char*)0);
5729 const double res = s?cimg::atof(s):defaut;
5730 char tmp[256];
5731 cimg_std::sprintf(tmp,"%g",res);
5732 cimg::option(name,0,0,tmp,usage);
5733 return res;
5734 }
5736 inline const char* argument(const unsigned int nb, const int argc, const char *const *const argv, const unsigned int nb_singles=0, ...) {
5737 for (int k = 1, pos = 0; k<argc;) {
5738 const char *const item = argv[k];
5739 bool option = (*item=='-'), single_option = false;
5740 if (option) {
5741 va_list ap;
5742 va_start(ap,nb_singles);
5743 for (unsigned int i=0; i<nb_singles; ++i) if (!cimg::strcasecmp(item,va_arg(ap,char*))) { single_option = true; break; }
5744 va_end(ap);
5745 }
5746 if (option) { ++k; if (!single_option) ++k; }
5747 else { if (pos++==(int)nb) return item; else ++k; }
5748 }
5749 return 0;
5750 }
5752 //! Print informations about %CImg environement variables.
5753 /**
5754 Printing is done on the standard error output.
5755 **/
5756 inline void info() {
5757 char tmp[1024] = { 0 };
5758 cimg_std::fprintf(cimg_stdout,"\n %sCImg Library %u.%u.%u%s, compiled %s ( %s ) with the following flags :\n\n",
5759 cimg::t_red,cimg_version/100,(cimg_version/10)%10,cimg_version%10,
5760 cimg::t_normal,__DATE__,__TIME__);
5762 cimg_std::fprintf(cimg_stdout," > Operating System : %s%-13s%s %s('cimg_OS'=%d)%s\n",
5763 cimg::t_bold,
5764 cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"),
5765 cimg::t_normal,cimg::t_green,
5766 cimg_OS,
5767 cimg::t_normal);
5769 cimg_std::fprintf(cimg_stdout," > CPU endianness : %s%s Endian%s\n",
5770 cimg::t_bold,
5771 cimg::endianness()?"Big":"Little",
5772 cimg::t_normal);
5774 #ifdef cimg_use_visualcpp6
5775 cimg_std::fprintf(cimg_stdout," > Using Visual C++ 6.0 : %s%-13s%s %s('cimg_use_visualcpp6' defined)%s\n",
5776 cimg::t_bold,"Yes",cimg::t_normal,cimg::t_green,cimg::t_normal);
5777 #endif
5779 cimg_std::fprintf(cimg_stdout," > Debug messages : %s%-13s%s %s('cimg_debug'=%d)%s\n",
5780 cimg::t_bold,
5781 cimg_debug==0?"Quiet":(cimg_debug==1?"Console":(cimg_debug==2?"Dialog":(cimg_debug==3?"Console+Warnings":"Dialog+Warnings"))),
5782 cimg::t_normal,cimg::t_green,
5783 cimg_debug,
5784 cimg::t_normal);
5786 cimg_std::fprintf(cimg_stdout," > Stricts warnings : %s%-13s%s %s('cimg_strict_warnings' %s)%s\n",
5787 cimg::t_bold,
5788 #ifdef cimg_strict_warnings
5789 "Yes",cimg::t_normal,cimg::t_green,"defined",
5790 #else
5791 "No",cimg::t_normal,cimg::t_green,"undefined",
5792 #endif
5793 cimg::t_normal);
5795 cimg_std::fprintf(cimg_stdout," > Using VT100 messages : %s%-13s%s %s('cimg_use_vt100' %s)%s\n",
5796 cimg::t_bold,
5797 #ifdef cimg_use_vt100
5798 "Yes",cimg::t_normal,cimg::t_green,"defined",
5799 #else
5800 "No",cimg::t_normal,cimg::t_green,"undefined",
5801 #endif
5802 cimg::t_normal);
5804 cimg_std::fprintf(cimg_stdout," > Display type : %s%-13s%s %s('cimg_display'=%d)%s\n",
5805 cimg::t_bold,
5806 cimg_display==0?"No display":
5807 (cimg_display==1?"X11":
5808 (cimg_display==2?"Windows GDI":
5809 (cimg_display==3?"Carbon":"Unknow"))),
5810 cimg::t_normal,cimg::t_green,
5811 cimg_display,
5812 cimg::t_normal);
5814 #if cimg_display==1
5815 cimg_std::fprintf(cimg_stdout," > Using XShm for X11 : %s%-13s%s %s('cimg_use_xshm' %s)%s\n",
5816 cimg::t_bold,
5817 #ifdef cimg_use_xshm
5818 "Yes",cimg::t_normal,cimg::t_green,"defined",
5819 #else
5820 "No",cimg::t_normal,cimg::t_green,"undefined",
5821 #endif
5822 cimg::t_normal);
5824 cimg_std::fprintf(cimg_stdout," > Using XRand for X11 : %s%-13s%s %s('cimg_use_xrandr' %s)%s\n",
5825 cimg::t_bold,
5826 #ifdef cimg_use_xrandr
5827 "Yes",cimg::t_normal,cimg::t_green,"defined",
5828 #else
5829 "No",cimg::t_normal,cimg::t_green,"undefined",
5830 #endif
5831 cimg::t_normal);
5832 #endif
5833 cimg_std::fprintf(cimg_stdout," > Using OpenMP : %s%-13s%s %s('cimg_use_openmp' %s)%s\n",
5834 cimg::t_bold,
5835 #ifdef cimg_use_openmp
5836 "Yes",cimg::t_normal,cimg::t_green,"defined",
5837 #else
5838 "No",cimg::t_normal,cimg::t_green,"undefined",
5839 #endif
5840 cimg::t_normal);
5841 cimg_std::fprintf(cimg_stdout," > Using PNG library : %s%-13s%s %s('cimg_use_png' %s)%s\n",
5842 cimg::t_bold,
5843 #ifdef cimg_use_png
5844 "Yes",cimg::t_normal,cimg::t_green,"defined",
5845 #else
5846 "No",cimg::t_normal,cimg::t_green,"undefined",
5847 #endif
5848 cimg::t_normal);
5849 cimg_std::fprintf(cimg_stdout," > Using JPEG library : %s%-13s%s %s('cimg_use_jpeg' %s)%s\n",
5850 cimg::t_bold,
5851 #ifdef cimg_use_jpeg
5852 "Yes",cimg::t_normal,cimg::t_green,"defined",
5853 #else
5854 "No",cimg::t_normal,cimg::t_green,"undefined",
5855 #endif
5856 cimg::t_normal);
5858 cimg_std::fprintf(cimg_stdout," > Using TIFF library : %s%-13s%s %s('cimg_use_tiff' %s)%s\n",
5859 cimg::t_bold,
5860 #ifdef cimg_use_tiff
5861 "Yes",cimg::t_normal,cimg::t_green,"defined",
5862 #else
5863 "No",cimg::t_normal,cimg::t_green,"undefined",
5864 #endif
5865 cimg::t_normal);
5867 cimg_std::fprintf(cimg_stdout," > Using Magick++ library : %s%-13s%s %s('cimg_use_magick' %s)%s\n",
5868 cimg::t_bold,
5869 #ifdef cimg_use_magick
5870 "Yes",cimg::t_normal,cimg::t_green,"defined",
5871 #else
5872 "No",cimg::t_normal,cimg::t_green,"undefined",
5873 #endif
5874 cimg::t_normal);
5876 cimg_std::fprintf(cimg_stdout," > Using FFTW3 library : %s%-13s%s %s('cimg_use_fftw3' %s)%s\n",
5877 cimg::t_bold,
5878 #ifdef cimg_use_fftw3
5879 "Yes",cimg::t_normal,cimg::t_green,"defined",
5880 #else
5881 "No",cimg::t_normal,cimg::t_green,"undefined",
5882 #endif
5883 cimg::t_normal);
5885 cimg_std::fprintf(cimg_stdout," > Using LAPACK library : %s%-13s%s %s('cimg_use_lapack' %s)%s\n",
5886 cimg::t_bold,
5887 #ifdef cimg_use_lapack
5888 "Yes",cimg::t_normal,cimg::t_green,"defined",
5889 #else
5890 "No",cimg::t_normal,cimg::t_green,"undefined",
5891 #endif
5892 cimg::t_normal);
5894 cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::imagemagick_path());
5895 cimg_std::fprintf(cimg_stdout," > Path of ImageMagick : %s%-13s%s\n",
5896 cimg::t_bold,
5897 tmp,
5898 cimg::t_normal);
5900 cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::graphicsmagick_path());
5901 cimg_std::fprintf(cimg_stdout," > Path of GraphicsMagick : %s%-13s%s\n",
5902 cimg::t_bold,
5903 tmp,
5904 cimg::t_normal);
5906 cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::medcon_path());
5907 cimg_std::fprintf(cimg_stdout," > Path of 'medcon' : %s%-13s%s\n",
5908 cimg::t_bold,
5909 tmp,
5910 cimg::t_normal);
5912 cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::temporary_path());
5913 cimg_std::fprintf(cimg_stdout," > Temporary path : %s%-13s%s\n",
5914 cimg::t_bold,
5915 tmp,
5916 cimg::t_normal);
5918 cimg_std::fprintf(cimg_stdout,"\n");
5919 }
5921 // Declare LAPACK function signatures if necessary.
5922 //
5923 #ifdef cimg_use_lapack
5924 template<typename T>
5925 inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) {
5926 dgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
5927 }
5929 inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) {
5930 sgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
5931 }
5933 template<typename T>
5934 inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {
5935 dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
5936 }
5938 inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) {
5939 sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
5940 }
5942 template<typename T>
5943 inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN,
5944 T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) {
5945 dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
5946 }
5948 inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN,
5949 float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) {
5950 sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
5951 }
5953 template<typename T>
5954 inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) {
5955 int one = 1;
5956 dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
5957 }
5959 inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) {
5960 int one = 1;
5961 sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
5962 }
5964 template<typename T>
5965 inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {
5966 dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
5967 }
5969 inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) {
5970 ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
5971 }
5972 #endif
5974 // End of the 'cimg' namespace
5975 }
5977 /*------------------------------------------------
5978 #
5979 #
5980 # Definition of mathematical operators and
5981 # external functions.
5982 #
5983 #
5984 -------------------------------------------------*/
5985 //
5986 // These functions are extern to any classes and can be used for a "functional-style" programming,
5987 // such as writting :
5988 // cos(img);
5989 // instead of img.get_cos();
5990 //
5991 // Note that only the arithmetic operators and functions are implemented here.
5992 //
5994 #ifdef cimg_use_visualcpp6
5995 template<typename t>
5996 inline CImg<t> operator+(const CImg<t>& img, const t val) {
5997 return CImg<t>(img,false)+=val;
5998 }
5999 #else
6000 template<typename t1, typename t2>
6001 inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const t2 val) {
6002 typedef typename cimg::superset<t1,t2>::type t1t2;
6003 return CImg<t1t2>(img,false)+=val;
6004 }
6005 #endif
6007 #ifdef cimg_use_visualcpp6
6008 template<typename t>
6009 inline CImg<t> operator+(const t val, const CImg<t>& img) {
6010 return img + val;
6011 }
6012 #else
6013 template<typename t1, typename t2>
6014 inline CImg<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImg<t2>& img) {
6015 return img + val;
6016 }
6017 #endif
6019 #ifdef cimg_use_visualcpp6
6020 template<typename t>
6021 inline CImgList<t> operator+(const CImgList<t>& list, const t val) {
6022 return CImgList<t>(list)+=val;
6023 }
6024 #else
6025 template<typename t1, typename t2>
6026 inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const t2 val) {
6027 typedef typename cimg::superset<t1,t2>::type t1t2;
6028 return CImgList<t1t2>(list)+=val;
6029 }
6030 #endif
6032 #ifdef cimg_use_visualcpp6
6033 template<typename t>
6034 inline CImgList<t> operator+(const t val, const CImgList<t>& list) {
6035 return list + val;
6036 }
6037 #else
6038 template<typename t1, typename t2>
6039 inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImgList<t2>& list) {
6040 return list + val;
6041 }
6042 #endif
6044 template<typename t1, typename t2>
6045 inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img1, const CImg<t2>& img2) {
6046 typedef typename cimg::superset<t1,t2>::type t1t2;
6047 return CImg<t1t2>(img1,false)+=img2;
6048 }
6050 template<typename t1, typename t2>
6051 inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const CImgList<t2>& list) {
6052 typedef typename cimg::superset<t1,t2>::type t1t2;
6053 return CImgList<t1t2>(list)+=img;
6054 }
6056 template<typename t1, typename t2>
6057 inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const CImg<t2>& img) {
6058 return img + list;
6059 }
6061 template<typename t1, typename t2>
6062 inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list1, const CImgList<t2>& list2) {
6063 typedef typename cimg::superset<t1,t2>::type t1t2;
6064 return CImgList<t1t2>(list1)+=list2;
6065 }
6067 #ifdef cimg_use_visualcpp6
6068 template<typename t>
6069 inline CImg<t> operator-(const CImg<t>& img, const t val) {
6070 return CImg<t>(img,false)-=val;
6071 }
6072 #else
6073 template<typename t1, typename t2>
6074 inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const t2 val) {
6075 typedef typename cimg::superset<t1,t2>::type t1t2;
6076 return CImg<t1t2>(img,false)-=val;
6077 }
6078 #endif
6080 #ifdef cimg_use_visualcpp6
6081 template<typename t>
6082 inline CImg<t> operator-(const t val, const CImg<t>& img) {
6083 return CImg<t>(img.width,img.height,img.depth,img.dim,val)-=img;
6084 }
6085 #else
6086 template<typename t1, typename t2>
6087 inline CImg<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImg<t2>& img) {
6088 typedef typename cimg::superset<t1,t2>::type t1t2;
6089 return CImg<t1t2>(img.width,img.height,img.depth,img.dim,(t1t2)val)-=img;
6090 }
6091 #endif
6093 #ifdef cimg_use_visualcpp6
6094 template<typename t>
6095 inline CImgList<t> operator-(const CImgList<t>& list, const t val) {
6096 return CImgList<t>(list)-=val;
6097 }
6098 #else
6099 template<typename t1, typename t2>
6100 inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const t2 val) {
6101 typedef typename cimg::superset<t1,t2>::type t1t2;
6102 return CImgList<t1t2>(list)-=val;
6103 }
6104 #endif
6106 #ifdef cimg_use_visualcpp6
6107 template<typename t>
6108 inline CImgList<double> operator-(const t val, const CImgList<t>& list) {
6109 CImgList<t> res(list.size);
6110 cimglist_for(res,l) res[l] = val - list[l];
6111 return res;
6112 }
6113 #else
6114 template<typename t1, typename t2>
6115 inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImgList<t2>& list) {
6116 typedef typename cimg::superset<t1,t2>::type t1t2;
6117 CImgList<t1t2> res(list.size);
6118 cimglist_for(res,l) res[l] = val - list[l];
6119 return res;
6120 }
6121 #endif
6123 template<typename t1, typename t2>
6124 inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img1, const CImg<t2>& img2) {
6125 typedef typename cimg::superset<t1,t2>::type t1t2;
6126 return CImg<t1t2>(img1,false)-=img2;
6127 }
6129 template<typename t1, typename t2>
6130 inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const CImgList<t2>& list) {
6131 typedef typename cimg::superset<t1,t2>::type t1t2;
6132 CImgList<t1t2> res(list.size);
6133 cimglist_for(res,l) res[l] = img - list[l];
6134 return res;
6135 }
6137 template<typename t1, typename t2>
6138 inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const CImg<t2>& img) {
6139 typedef typename cimg::superset<t1,t2>::type t1t2;
6140 return CImgList<t1t2>(list)-=img;
6141 }
6143 template<typename t1, typename t2>
6144 inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list1, const CImgList<t2>& list2) {
6145 typedef typename cimg::superset<t1,t2>::type t1t2;
6146 return CImgList<t1t2>(list1)-=list2;
6147 }
6149 #ifdef cimg_use_visualcpp6
6150 template<typename t>
6151 inline CImg<t> operator*(const CImg<t>& img, const double val) {
6152 return CImg<t>(img,false)*=val;
6153 }
6154 #else
6155 template<typename t1, typename t2>
6156 inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const t2 val) {
6157 typedef typename cimg::superset<t1,t2>::type t1t2;
6158 return CImg<t1t2>(img,false)*=val;
6159 }
6160 #endif
6162 #ifdef cimg_use_visualcpp6
6163 template<typename t>
6164 inline CImg<t> operator*(const double val, const CImg<t>& img) {
6165 return img*val;
6166 }
6167 #else
6168 template<typename t1, typename t2>
6169 inline CImg<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImg<t2>& img) {
6170 return img*val;
6171 }
6172 #endif
6174 #ifdef cimg_use_visualcpp6
6175 template<typename t>
6176 inline CImgList<t> operator*(const CImgList<t>& list, const double val) {
6177 return CImgList<t>(list)*=val;
6178 }
6179 #else
6180 template<typename t1, typename t2>
6181 inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const t2 val) {
6182 typedef typename cimg::superset<t1,t2>::type t1t2;
6183 return CImgList<t1t2>(list)*=val;
6184 }
6185 #endif
6187 #ifdef cimg_use_visualcpp6
6188 template<typename t>
6189 inline CImgList<t> operator*(const double val, const CImgList<t>& list) {
6190 return list*val;
6191 }
6192 #else
6193 template<typename t1, typename t2>
6194 inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImgList<t2>& list) {
6195 return list*val;
6196 }
6197 #endif
6199 template<typename t1, typename t2>
6200 inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img1, const CImg<t2>& img2) {
6201 typedef typename cimg::superset<t1,t2>::type t1t2;
6202 if (img1.width!=img2.height)
6203 throw CImgArgumentException("operator*() : can't multiply a matrix (%ux%u) by a matrix (%ux%u)",
6204 img1.width,img1.height,img2.width,img2.height);
6205 CImg<t1t2> res(img2.width,img1.height);
6206 t1t2 val;
6207 #ifdef cimg_use_openmp
6208 #pragma omp parallel for if (img1.size()>=1000 && img2.size()>=1000) private(val)
6209 #endif
6210 cimg_forXY(res,i,j) { val = 0; cimg_forX(img1,k) val+=img1(k,j)*img2(i,k); res(i,j) = val; }
6211 return res;
6212 }
6214 template<typename t1, typename t2>
6215 inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const CImgList<t2>& list) {
6216 typedef typename cimg::superset<t1,t2>::type t1t2;
6217 CImgList<t1t2> res(list.size);
6218 cimglist_for(res,l) res[l] = img*list[l];
6219 return res;
6220 }
6222 template<typename t1, typename t2>
6223 inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const CImg<t2>& img) {
6224 typedef typename cimg::superset<t1,t2>::type t1t2;
6225 CImgList<t1t2> res(list.size);
6226 cimglist_for(res,l) res[l] = list[l]*img;
6227 return res;
6228 }
6230 template<typename t1, typename t2>
6231 inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list1, const CImgList<t2>& list2) {
6232 typedef typename cimg::superset<t1,t2>::type t1t2;
6233 CImgList<t1t2> res(cimg::min(list1.size,list2.size));
6234 cimglist_for(res,l) res[l] = list1[l]*list2[l];
6235 return res;
6236 }
6238 #ifdef cimg_use_visualcpp6
6239 template<typename t>
6240 inline CImg<t> operator/(const CImg<t>& img, const double val) {
6241 return CImg<t>(img,false)/=val;
6242 }
6243 #else
6244 template<typename t1, typename t2>
6245 inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const t2 val) {
6246 typedef typename cimg::superset<t1,t2>::type t1t2;
6247 return CImg<t1t2>(img,false)/=val;
6248 }
6249 #endif
6251 #ifdef cimg_use_visualcpp6
6252 template<typename t>
6253 inline CImg<t> operator/(const double val, CImg<t>& img) {
6254 return val*img.get_invert();
6255 }
6256 #else
6257 template<typename t1, typename t2>
6258 inline CImg<typename cimg::superset<t1,t2>::type> operator/(const t1 val, CImg<t2>& img) {
6259 return val*img.get_invert();
6260 }
6261 #endif
6263 #ifdef cimg_use_visualcpp6
6264 template<typename t>
6265 inline CImgList<t> operator/(const CImgList<t>& list, const double val) {
6266 return CImgList<t>(list)/=val;
6267 }
6268 #else
6269 template<typename t1, typename t2>
6270 inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const t2 val) {
6271 typedef typename cimg::superset<t1,t2>::type t1t2;
6272 return CImgList<t1t2>(list)/=val;
6273 }
6274 #endif
6276 #ifdef cimg_use_visualcpp6
6277 template<typename t>
6278 inline CImgList<t> operator/(const double val, const CImgList<t>& list) {
6279 CImgList<t> res(list.size);
6280 cimglist_for(res,l) res[l] = val/list[l];
6281 return res;
6282 }
6283 #else
6284 template<typename t1, typename t2>
6285 inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const t1 val, const CImgList<t2>& list) {
6286 typedef typename cimg::superset<t1,t2>::type t1t2;
6287 CImgList<t1t2> res(list.size);
6288 cimglist_for(res,l) res[l] = val/list[l];
6289 return res;
6290 }
6291 #endif
6293 template<typename t1, typename t2>
6294 inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img1, const CImg<t2>& img2) {
6295 typedef typename cimg::superset<t1,t2>::type t1t2;
6296 return CImg<t1t2>(img1,false)*=img2.get_invert();
6297 }
6299 template<typename t1, typename t2>
6300 inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const CImgList<t2>& list) {
6301 typedef typename cimg::superset<t1,t2>::type t1t2;
6302 CImgList<t1t2> res(list.size);
6303 cimglist_for(res,l) res[l] = img/list[l];
6304 return res;
6305 }
6307 template<typename t1, typename t2>
6308 inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const CImg<t2>& img) {
6309 typedef typename cimg::superset<t1,t2>::type t1t2;
6310 return CImgList<t1t2>(list)/=img;
6311 }
6313 template<typename t1, typename t2>
6314 inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list1, const CImgList<t2>& list2) {
6315 typedef typename cimg::superset<t1,t2>::type t1t2;
6316 return CImgList<t1t2>(list1)/=list2;
6317 }
6319 template<typename T>
6320 inline CImg<_cimg_Tfloat> sqr(const CImg<T>& instance) {
6321 return instance.get_sqr();
6322 }
6324 template<typename T>
6325 inline CImg<_cimg_Tfloat> sqrt(const CImg<T>& instance) {
6326 return instance.get_sqrt();
6327 }
6329 template<typename T>
6330 inline CImg<_cimg_Tfloat> exp(const CImg<T>& instance) {
6331 return instance.get_exp();
6332 }
6334 template<typename T>
6335 inline CImg<_cimg_Tfloat> log(const CImg<T>& instance) {
6336 return instance.get_log();
6337 }
6339 template<typename T>
6340 inline CImg<_cimg_Tfloat> log10(const CImg<T>& instance) {
6341 return instance.get_log10();
6342 }
6344 template<typename T>
6345 inline CImg<_cimg_Tfloat> abs(const CImg<T>& instance) {
6346 return instance.get_abs();
6347 }
6349 template<typename T>
6350 inline CImg<_cimg_Tfloat> cos(const CImg<T>& instance) {
6351 return instance.get_cos();
6352 }
6354 template<typename T>
6355 inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) {
6356 return instance.get_sin();
6357 }
6359 template<typename T>
6360 inline CImg<_cimg_Tfloat> tan(const CImg<T>& instance) {
6361 return instance.get_tan();
6362 }
6364 template<typename T>
6365 inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) {
6366 return instance.get_acos();
6367 }
6369 template<typename T>
6370 inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) {
6371 return instance.get_asin();
6372 }
6374 template<typename T>
6375 inline CImg<_cimg_Tfloat> atan(const CImg<T>& instance) {
6376 return instance.get_atan();
6377 }
6379 template<typename T>
6380 inline CImg<T> transpose(const CImg<T>& instance) {
6381 return instance.get_transpose();
6382 }
6384 template<typename T>
6385 inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance) {
6386 return instance.get_invert();
6387 }
6389 template<typename T>
6390 inline CImg<_cimg_Tfloat> pseudoinvert(const CImg<T>& instance) {
6391 return instance.get_pseudoinvert();
6392 }
6394 /*-------------------------------------------
6395 #
6396 #
6397 #
6398 # Definition of the CImgDisplay structure
6399 #
6400 #
6401 #
6402 --------------------------------------------*/
6404 //! This class represents a window which can display \ref CImg images and handles mouse and keyboard events.
6405 /**
6406 Creating a \c CImgDisplay instance opens a window that can be used to display a \c CImg<T> image
6407 of a \c CImgList<T> image list inside. When a display is created, associated window events
6408 (such as mouse motion, keyboard and window size changes) are handled and can be easily
6409 detected by testing specific \c CImgDisplay data fields.
6410 See \ref cimg_displays for a complete tutorial on using the \c CImgDisplay class.
6411 **/
6413 struct CImgDisplay {
6415 //! Width of the display
6416 unsigned int width;
6418 //! Height of the display
6419 unsigned int height;
6421 //! Normalization type used for the display
6422 unsigned int normalization;
6424 //! Display title
6425 char* title;
6427 //! X-pos of the display on the screen
6428 volatile int window_x;
6430 //! Y-pos of the display on the screen
6431 volatile int window_y;
6433 //! Width of the underlying window
6434 volatile unsigned int window_width;
6436 //! Height of the underlying window
6437 volatile unsigned int window_height;
6439 //! X-coordinate of the mouse pointer on the display
6440 volatile int mouse_x;
6442 //! Y-coordinate of the mouse pointer on the display
6443 volatile int mouse_y;
6445 //! Button state of the mouse
6446 volatile unsigned int buttons[512];
6447 volatile unsigned int& button;
6449 //! Wheel state of the mouse
6450 volatile int wheel;
6452 //! Key value if pressed
6453 volatile unsigned int& key;
6454 volatile unsigned int keys[512];
6456 //! Key value if released
6457 volatile unsigned int& released_key;
6458 volatile unsigned int released_keys[512];
6460 //! Closed state of the window
6461 volatile bool is_closed;
6463 //! Resized state of the window
6464 volatile bool is_resized;
6466 //! Moved state of the window
6467 volatile bool is_moved;
6469 //! Event state of the window
6470 volatile bool is_event;
6472 //! Current state of the corresponding key (exists for all referenced keys).
6473 volatile bool is_keyESC;
6474 volatile bool is_keyF1;
6475 volatile bool is_keyF2;
6476 volatile bool is_keyF3;
6477 volatile bool is_keyF4;
6478 volatile bool is_keyF5;
6479 volatile bool is_keyF6;
6480 volatile bool is_keyF7;
6481 volatile bool is_keyF8;
6482 volatile bool is_keyF9;
6483 volatile bool is_keyF10;
6484 volatile bool is_keyF11;
6485 volatile bool is_keyF12;
6486 volatile bool is_keyPAUSE;
6487 volatile bool is_key1;
6488 volatile bool is_key2;
6489 volatile bool is_key3;
6490 volatile bool is_key4;
6491 volatile bool is_key5;
6492 volatile bool is_key6;
6493 volatile bool is_key7;
6494 volatile bool is_key8;
6495 volatile bool is_key9;
6496 volatile bool is_key0;
6497 volatile bool is_keyBACKSPACE;
6498 volatile bool is_keyINSERT;
6499 volatile bool is_keyHOME;
6500 volatile bool is_keyPAGEUP;
6501 volatile bool is_keyTAB;
6502 volatile bool is_keyQ;
6503 volatile bool is_keyW;
6504 volatile bool is_keyE;
6505 volatile bool is_keyR;
6506 volatile bool is_keyT;
6507 volatile bool is_keyY;
6508 volatile bool is_keyU;
6509 volatile bool is_keyI;
6510 volatile bool is_keyO;
6511 volatile bool is_keyP;
6512 volatile bool is_keyDELETE;
6513 volatile bool is_keyEND;
6514 volatile bool is_keyPAGEDOWN;
6515 volatile bool is_keyCAPSLOCK;
6516 volatile bool is_keyA;
6517 volatile bool is_keyS;
6518 volatile bool is_keyD;
6519 volatile bool is_keyF;
6520 volatile bool is_keyG;
6521 volatile bool is_keyH;
6522 volatile bool is_keyJ;
6523 volatile bool is_keyK;
6524 volatile bool is_keyL;
6525 volatile bool is_keyENTER;
6526 volatile bool is_keySHIFTLEFT;
6527 volatile bool is_keyZ;
6528 volatile bool is_keyX;
6529 volatile bool is_keyC;
6530 volatile bool is_keyV;
6531 volatile bool is_keyB;
6532 volatile bool is_keyN;
6533 volatile bool is_keyM;
6534 volatile bool is_keySHIFTRIGHT;
6535 volatile bool is_keyARROWUP;
6536 volatile bool is_keyCTRLLEFT;
6537 volatile bool is_keyAPPLEFT;
6538 volatile bool is_keyALT;
6539 volatile bool is_keySPACE;
6540 volatile bool is_keyALTGR;
6541 volatile bool is_keyAPPRIGHT;
6542 volatile bool is_keyMENU;
6543 volatile bool is_keyCTRLRIGHT;
6544 volatile bool is_keyARROWLEFT;
6545 volatile bool is_keyARROWDOWN;
6546 volatile bool is_keyARROWRIGHT;
6547 volatile bool is_keyPAD0;
6548 volatile bool is_keyPAD1;
6549 volatile bool is_keyPAD2;
6550 volatile bool is_keyPAD3;
6551 volatile bool is_keyPAD4;
6552 volatile bool is_keyPAD5;
6553 volatile bool is_keyPAD6;
6554 volatile bool is_keyPAD7;
6555 volatile bool is_keyPAD8;
6556 volatile bool is_keyPAD9;
6557 volatile bool is_keyPADADD;
6558 volatile bool is_keyPADSUB;
6559 volatile bool is_keyPADMUL;
6560 volatile bool is_keyPADDIV;
6562 //! Fullscreen state of the display
6563 bool is_fullscreen;
6565 float fps_fps, min, max;
6566 unsigned long timer, fps_frames, fps_timer;
6568 #ifdef cimgdisplay_plugin
6569 #include cimgdisplay_plugin
6570 #endif
6571 #ifdef cimgdisplay_plugin1
6572 #include cimgdisplay_plugin1
6573 #endif
6574 #ifdef cimgdisplay_plugin2
6575 #include cimgdisplay_plugin2
6576 #endif
6577 #ifdef cimgdisplay_plugin3
6578 #include cimgdisplay_plugin3
6579 #endif
6580 #ifdef cimgdisplay_plugin4
6581 #include cimgdisplay_plugin4
6582 #endif
6583 #ifdef cimgdisplay_plugin5
6584 #include cimgdisplay_plugin5
6585 #endif
6586 #ifdef cimgdisplay_plugin6
6587 #include cimgdisplay_plugin6
6588 #endif
6589 #ifdef cimgdisplay_plugin7
6590 #include cimgdisplay_plugin7
6591 #endif
6592 #ifdef cimgdisplay_plugin8
6593 #include cimgdisplay_plugin8
6594 #endif
6596 //! Create an empty display window.
6597 CImgDisplay():
6598 width(0),height(0),normalization(0),title(0),
6599 window_x(0),window_y(0),window_width(0),window_height(0),
6600 mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
6601 is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
6602 min(0),max(0) {}
6604 //! Create a display window with a specified size \p pwidth x \p height.
6605 /** \param dimw Width of the display window.
6606 \param dimh Height of the display window.
6607 \param title Title of the display window.
6608 \param normalization_type Normalization type of the display window (0=none, 1=always, 2=once).
6609 \param fullscreen_flag : Fullscreen mode.
6610 \param closed_flag : Initially visible mode.
6611 A black image will be initially displayed in the display window.
6612 **/
6613 CImgDisplay(const unsigned int dimw, const unsigned int dimh, const char *title=0,
6614 const unsigned int normalization_type=3,
6615 const bool fullscreen_flag=false, const bool closed_flag=false):
6616 width(0),height(0),normalization(0),title(0),
6617 window_x(0),window_y(0),window_width(0),window_height(0),
6618 mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
6619 is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
6620 min(0),max(0) {
6621 assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
6622 }
6624 //! Create a display window from an image.
6625 /** \param img : Image that will be used to create the display window.
6626 \param title : Title of the display window
6627 \param normalization_type : Normalization type of the display window.
6628 \param fullscreen_flag : Fullscreen mode.
6629 \param closed_flag : Initially visible mode.
6630 **/
6631 template<typename T>
6632 CImgDisplay(const CImg<T>& img, const char *title=0,
6633 const unsigned int normalization_type=3,
6634 const bool fullscreen_flag=false, const bool closed_flag=false):
6635 width(0),height(0),normalization(0),title(0),
6636 window_x(0),window_y(0),window_width(0),window_height(0),
6637 mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
6638 is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
6639 assign(img,title,normalization_type,fullscreen_flag,closed_flag);
6640 }
6642 //! Create a display window from an image list.
6643 /** \param list : The list of images to display.
6644 \param title : Title of the display window
6645 \param normalization_type : Normalization type of the display window.
6646 \param fullscreen_flag : Fullscreen mode.
6647 \param closed_flag : Initially visible mode.
6648 **/
6649 template<typename T>
6650 CImgDisplay(const CImgList<T>& list, const char *title=0,
6651 const unsigned int normalization_type=3,
6652 const bool fullscreen_flag=false, const bool closed_flag=false):
6653 width(0),height(0),normalization(0),title(0),
6654 window_x(0),window_y(0),window_width(0),window_height(0),
6655 mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
6656 is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
6657 assign(list,title,normalization_type,fullscreen_flag,closed_flag);
6658 }
6660 //! Create a display window by copying another one.
6661 /**
6662 \param disp : Display window to copy.
6663 **/
6664 CImgDisplay(const CImgDisplay& disp):
6665 width(0),height(0),normalization(0),title(0),
6666 window_x(0),window_y(0),window_width(0),window_height(0),
6667 mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
6668 is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
6669 assign(disp);
6670 }
6672 //! Destructor.
6673 ~CImgDisplay() {
6674 assign();
6675 }
6677 //! Assignment operator.
6678 CImgDisplay& operator=(const CImgDisplay& disp) {
6679 return assign(disp);
6680 }
6682 //! Return true is display is empty.
6683 bool is_empty() const {
6684 return (!width || !height);
6685 }
6687 //! Return true if display is not empty.
6688 operator bool() const {
6689 return !is_empty();
6690 }
6692 //! Return display width.
6693 int dimx() const {
6694 return (int)width;
6695 }
6697 //! Return display height.
6698 int dimy() const {
6699 return (int)height;
6700 }
6702 //! Return display window width.
6703 int window_dimx() const {
6704 return (int)window_width;
6705 }
6707 //! Return display window height.
6708 int window_dimy() const {
6709 return (int)window_height;
6710 }
6712 //! Return X-coordinate of the window.
6713 int window_posx() const {
6714 return window_x;
6715 }
6717 //! Return Y-coordinate of the window.
6718 int window_posy() const {
6719 return window_y;
6720 }
6722 //! Synchronized waiting function. Same as cimg::wait().
6723 CImgDisplay& wait(const unsigned int milliseconds) {
6724 cimg::_sleep(milliseconds,timer);
6725 return *this;
6726 }
6728 //! Wait for an event occuring on the current display.
6729 CImgDisplay& wait() {
6730 if (!is_empty()) wait(*this);
6731 return *this;
6732 }
6734 //! Wait for any event occuring on the display \c disp1.
6735 static void wait(CImgDisplay& disp1) {
6736 disp1.is_event = 0;
6737 while (!disp1.is_event) wait_all();
6738 }
6740 //! Wait for any event occuring either on the display \c disp1 or \c disp2.
6741 static void wait(CImgDisplay& disp1, CImgDisplay& disp2) {
6742 disp1.is_event = disp2.is_event = 0;
6743 while (!disp1.is_event && !disp2.is_event) wait_all();
6744 }
6746 //! Wait for any event occuring either on the display \c disp1, \c disp2 or \c disp3.
6747 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) {
6748 disp1.is_event = disp2.is_event = disp3.is_event = 0;
6749 while (!disp1.is_event && !disp2.is_event && !disp3.is_event) wait_all();
6750 }
6752 //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3 or \c disp4.
6753 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) {
6754 disp1.is_event = disp2.is_event = disp3.is_event = disp4.is_event = 0;
6755 while (!disp1.is_event && !disp2.is_event && !disp3.is_event && !disp4.is_event) wait_all();
6756 }
6758 //! Return the frame per second rate.
6759 float frames_per_second() {
6760 if (!fps_timer) fps_timer = cimg::time();
6761 const float delta = (cimg::time()-fps_timer)/1000.0f;
6762 ++fps_frames;
6763 if (delta>=1) {
6764 fps_fps = fps_frames/delta;
6765 fps_frames = 0;
6766 fps_timer = cimg::time();
6767 }
6768 return fps_fps;
6769 }
6771 //! Display an image list CImgList<T> into a display window.
6772 /** First, all images of the list are appended into a single image used for visualization,
6773 then this image is displayed in the current display window.
6774 \param list : The list of images to display.
6775 \param axis : The axis used to append the image for visualization. Can be 'x' (default),'y','z' or 'v'.
6776 \param align : Defines the relative alignment of images when displaying images of different sizes.
6777 Can be '\p c' (centered, which is the default), '\p p' (top alignment) and '\p n' (bottom aligment).
6778 **/
6779 template<typename T>
6780 CImgDisplay& display(const CImgList<T>& list, const char axis='x', const char align='p') {
6781 return display(list.get_append(axis,align));
6782 }
6784 //! Display an image CImg<T> into a display window.
6785 template<typename T>
6786 CImgDisplay& operator<<(const CImg<T>& img) {
6787 return display(img);
6788 }
6790 //! Display an image CImg<T> into a display window.
6791 template<typename T>
6792 CImgDisplay& operator<<(const CImgList<T>& list) {
6793 return display(list);
6794 }
6796 //! Resize a display window with the size of an image.
6797 /** \param img : Input image. \p image.width and \p image.height give the new dimensions of the display window.
6798 \param redraw : If \p true (default), the current displayed image in the display window will
6799 be bloc-interpolated to fit the new dimensions. If \p false, a black image will be drawn in the resized window.
6800 **/
6801 template<typename T>
6802 CImgDisplay& resize(const CImg<T>& img, const bool redraw=true) {
6803 return resize(img.width,img.height,redraw);
6804 }
6806 //! Resize a display window using the size of the given display \p disp.
6807 CImgDisplay& resize(const CImgDisplay& disp, const bool redraw=true) {
6808 return resize(disp.width,disp.height,redraw);
6809 }
6811 //! Resize a display window in its current size.
6812 CImgDisplay& resize(const bool redraw=true) {
6813 resize(window_width,window_height,redraw);
6814 return *this;
6815 }
6817 //! Set fullscreen mode.
6818 CImgDisplay& fullscreen(const bool redraw=true) {
6819 if (is_empty() || is_fullscreen) return *this;
6820 return toggle_fullscreen(redraw);
6821 }
6823 //! Set normal screen mode.
6824 CImgDisplay& normalscreen(const bool redraw=true) {
6825 if (is_empty() || !is_fullscreen) return *this;
6826 return toggle_fullscreen(redraw);
6827 }
6829 // Inner routine used for fast resizing of buffer to display size.
6830 template<typename t, typename T>
6831 static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,
6832 t *ptrd, const unsigned int wd, const unsigned int hd) {
6833 unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd+1], *poffx, *poffy;
6834 float s, curr, old;
6835 s = (float)ws/wd;
6836 poffx = offx; curr = 0; for (unsigned int x=0; x<wd; ++x) { old=curr; curr+=s; *(poffx++) = (unsigned int)curr-(unsigned int)old; }
6837 s = (float)hs/hd;
6838 poffy = offy; curr = 0; for (unsigned int y=0; y<hd; ++y) { old=curr; curr+=s; *(poffy++) = ws*((unsigned int)curr-(unsigned int)old); }
6839 *poffy = 0;
6840 poffy = offy;
6841 {for (unsigned int y=0; y<hd; ) {
6842 const T *ptr = ptrs;
6843 poffx = offx;
6844 for (unsigned int x=0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); }
6845 ++y;
6846 unsigned int dy=*(poffy++);
6847 for (;!dy && y<hd; cimg_std::memcpy(ptrd, ptrd-wd, sizeof(t)*wd), ++y, ptrd+=wd, dy=*(poffy++)) {}
6848 ptrs+=dy;
6849 }}
6850 delete[] offx; delete[] offy;
6851 }
6853 //! Clear all events of the current display.
6854 CImgDisplay& flush() {
6855 cimg_std::memset((void*)buttons,0,512*sizeof(unsigned int));
6856 cimg_std::memset((void*)keys,0,512*sizeof(unsigned int));
6857 cimg_std::memset((void*)released_keys,0,512*sizeof(unsigned int));
6858 is_keyESC = is_keyF1 = is_keyF2 = is_keyF3 = is_keyF4 = is_keyF5 = is_keyF6 = is_keyF7 = is_keyF8 = is_keyF9 =
6859 is_keyF10 = is_keyF11 = is_keyF12 = is_keyPAUSE = is_key1 = is_key2 = is_key3 = is_key4 = is_key5 = is_key6 =
6860 is_key7 = is_key8 = is_key9 = is_key0 = is_keyBACKSPACE = is_keyINSERT = is_keyHOME = is_keyPAGEUP = is_keyTAB =
6861 is_keyQ = is_keyW = is_keyE = is_keyR = is_keyT = is_keyY = is_keyU = is_keyI = is_keyO = is_keyP = is_keyDELETE =
6862 is_keyEND = is_keyPAGEDOWN = is_keyCAPSLOCK = is_keyA = is_keyS = is_keyD = is_keyF = is_keyG = is_keyH = is_keyJ =
6863 is_keyK = is_keyL = is_keyENTER = is_keySHIFTLEFT = is_keyZ = is_keyX = is_keyC = is_keyV = is_keyB = is_keyN =
6864 is_keyM = is_keySHIFTRIGHT = is_keyARROWUP = is_keyCTRLLEFT = is_keyAPPLEFT = is_keyALT = is_keySPACE = is_keyALTGR = is_keyAPPRIGHT =
6865 is_keyMENU = is_keyCTRLRIGHT = is_keyARROWLEFT = is_keyARROWDOWN = is_keyARROWRIGHT = is_keyPAD0 = is_keyPAD1 = is_keyPAD2 =
6866 is_keyPAD3 = is_keyPAD4 = is_keyPAD5 = is_keyPAD6 = is_keyPAD7 = is_keyPAD8 = is_keyPAD9 = is_keyPADADD = is_keyPADSUB =
6867 is_keyPADMUL = is_keyPADDIV = false;
6868 is_resized = is_moved = is_event = false;
6869 fps_timer = fps_frames = timer = wheel = 0;
6870 mouse_x = mouse_y = -1;
6871 fps_fps = 0;
6872 return *this;
6873 }
6875 // Update 'is_key' fields.
6876 void update_iskey(const unsigned int key, const bool pressed=true) {
6877 #define _cimg_iskey_case(k) if (key==cimg::key##k) is_key##k = pressed;
6878 _cimg_iskey_case(ESC); _cimg_iskey_case(F1); _cimg_iskey_case(F2); _cimg_iskey_case(F3);
6879 _cimg_iskey_case(F4); _cimg_iskey_case(F5); _cimg_iskey_case(F6); _cimg_iskey_case(F7);
6880 _cimg_iskey_case(F8); _cimg_iskey_case(F9); _cimg_iskey_case(F10); _cimg_iskey_case(F11);
6881 _cimg_iskey_case(F12); _cimg_iskey_case(PAUSE); _cimg_iskey_case(1); _cimg_iskey_case(2);
6882 _cimg_iskey_case(3); _cimg_iskey_case(4); _cimg_iskey_case(5); _cimg_iskey_case(6);
6883 _cimg_iskey_case(7); _cimg_iskey_case(8); _cimg_iskey_case(9); _cimg_iskey_case(0);
6884 _cimg_iskey_case(BACKSPACE); _cimg_iskey_case(INSERT); _cimg_iskey_case(HOME);
6885 _cimg_iskey_case(PAGEUP); _cimg_iskey_case(TAB); _cimg_iskey_case(Q); _cimg_iskey_case(W);
6886 _cimg_iskey_case(E); _cimg_iskey_case(R); _cimg_iskey_case(T); _cimg_iskey_case(Y);
6887 _cimg_iskey_case(U); _cimg_iskey_case(I); _cimg_iskey_case(O); _cimg_iskey_case(P);
6888 _cimg_iskey_case(DELETE); _cimg_iskey_case(END); _cimg_iskey_case(PAGEDOWN);
6889 _cimg_iskey_case(CAPSLOCK); _cimg_iskey_case(A); _cimg_iskey_case(S); _cimg_iskey_case(D);
6890 _cimg_iskey_case(F); _cimg_iskey_case(G); _cimg_iskey_case(H); _cimg_iskey_case(J);
6891 _cimg_iskey_case(K); _cimg_iskey_case(L); _cimg_iskey_case(ENTER);
6892 _cimg_iskey_case(SHIFTLEFT); _cimg_iskey_case(Z); _cimg_iskey_case(X); _cimg_iskey_case(C);
6893 _cimg_iskey_case(V); _cimg_iskey_case(B); _cimg_iskey_case(N); _cimg_iskey_case(M);
6894 _cimg_iskey_case(SHIFTRIGHT); _cimg_iskey_case(ARROWUP); _cimg_iskey_case(CTRLLEFT);
6895 _cimg_iskey_case(APPLEFT); _cimg_iskey_case(ALT); _cimg_iskey_case(SPACE); _cimg_iskey_case(ALTGR);
6896 _cimg_iskey_case(APPRIGHT); _cimg_iskey_case(MENU); _cimg_iskey_case(CTRLRIGHT);
6897 _cimg_iskey_case(ARROWLEFT); _cimg_iskey_case(ARROWDOWN); _cimg_iskey_case(ARROWRIGHT);
6898 _cimg_iskey_case(PAD0); _cimg_iskey_case(PAD1); _cimg_iskey_case(PAD2);
6899 _cimg_iskey_case(PAD3); _cimg_iskey_case(PAD4); _cimg_iskey_case(PAD5);
6900 _cimg_iskey_case(PAD6); _cimg_iskey_case(PAD7); _cimg_iskey_case(PAD8);
6901 _cimg_iskey_case(PAD9); _cimg_iskey_case(PADADD); _cimg_iskey_case(PADSUB);
6902 _cimg_iskey_case(PADMUL); _cimg_iskey_case(PADDIV);
6903 }
6905 //! Test if any key has been pressed.
6906 bool is_key(const bool remove=false) {
6907 for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs) { if (remove) *ptrs = 0; return true; }
6908 return false;
6909 }
6911 //! Test if a key has been pressed.
6912 bool is_key(const unsigned int key1, const bool remove) {
6913 for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs==key1) { if (remove) *ptrs = 0; return true; }
6914 return false;
6915 }
6917 //! Test if a key sequence has been typed.
6918 bool is_key(const unsigned int key1, const unsigned int key2, const bool remove) {
6919 const unsigned int seq[] = { key1, key2 };
6920 return is_key(seq,2,remove);
6921 }
6923 //! Test if a key sequence has been typed.
6924 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const bool remove) {
6925 const unsigned int seq[] = { key1, key2, key3 };
6926 return is_key(seq,3,remove);
6927 }
6929 //! Test if a key sequence has been typed.
6930 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6931 const unsigned int key4, const bool remove) {
6932 const unsigned int seq[] = { key1, key2, key3, key4 };
6933 return is_key(seq,4,remove);
6934 }
6936 //! Test if a key sequence has been typed.
6937 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6938 const unsigned int key4, const unsigned int key5, const bool remove) {
6939 const unsigned int seq[] = { key1, key2, key3, key4, key5 };
6940 return is_key(seq,5,remove);
6941 }
6943 //! Test if a key sequence has been typed.
6944 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6945 const unsigned int key4, const unsigned int key5, const unsigned int key6, const bool remove) {
6946 const unsigned int seq[] = { key1, key2, key3, key4, key5, key6 };
6947 return is_key(seq,6,remove);
6948 }
6950 //! Test if a key sequence has been typed.
6951 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6952 const unsigned int key4, const unsigned int key5, const unsigned int key6,
6953 const unsigned int key7, const bool remove) {
6954 const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7 };
6955 return is_key(seq,7,remove);
6956 }
6958 //! Test if a key sequence has been typed.
6959 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6960 const unsigned int key4, const unsigned int key5, const unsigned int key6,
6961 const unsigned int key7, const unsigned int key8, const bool remove) {
6962 const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8 };
6963 return is_key(seq,8,remove);
6964 }
6966 //! Test if a key sequence has been typed.
6967 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
6968 const unsigned int key4, const unsigned int key5, const unsigned int key6,
6969 const unsigned int key7, const unsigned int key8, const unsigned int key9, const bool remove) {
6970 const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8, key9 };
6971 return is_key(seq,9,remove);
6972 }
6974 //! Test if a key sequence has been typed.
6975 bool is_key(const unsigned int *const keyseq, const unsigned int N, const bool remove=true) {
6976 if (keyseq && N) {
6977 const unsigned int *const ps_end = keyseq+N-1, k = *ps_end, *const pk_end = (unsigned int*)keys+1+512-N;
6978 for (unsigned int *pk = (unsigned int*)keys; pk<pk_end; ) {
6979 if (*(pk++)==k) {
6980 bool res = true;
6981 const unsigned int *ps = ps_end, *pk2 = pk;
6982 for (unsigned int i=1; i<N; ++i) res = (*(--ps)==*(pk2++));
6983 if (res) {
6984 if (remove) cimg_std::memset((void*)(pk-1),0,sizeof(unsigned int)*N);
6985 return true;
6986 }
6987 }
6988 }
6989 }
6990 return false;
6991 }
6993 // Find the good width and height of a window to display an image (internal routine).
6994 #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false),CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
6995 static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1,
6996 const int dmin=128, const int dmax=-85,const bool return_last=false) {
6997 unsigned int nw = dx + (dz>1?dz:0), nh = dy + (dz>1?dz:0);
6998 const unsigned int
6999 sw = CImgDisplay::screen_dimx(), sh = CImgDisplay::screen_dimy(),
7000 mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin,
7001 mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin,
7002 Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax,
7003 Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax;
7004 if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0); nw = mw; }
7005 if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0); nh = mh; }
7006 if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0); nw = Mw; }
7007 if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0); nh = Mh; }
7008 if (nw<mw) nw = mw;
7009 if (nh<mh) nh = mh;
7010 if (return_last) return nh;
7011 return nw;
7012 }
7014 // When no display available
7015 //---------------------------
7016 #if cimg_display==0
7018 //! Return the width of the screen resolution.
7019 static int screen_dimx() {
7020 return 0;
7021 }
7023 //! Return the height of the screen resolution.
7024 static int screen_dimy() {
7025 return 0;
7026 }
7028 //! Wait for a window event in any CImg window.
7029 static void wait_all() {}
7031 //! In-place version of the destructor.
7032 CImgDisplay& assign() {
7033 return *this;
7034 }
7036 //! In-place version of the previous constructor.
7037 CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
7038 const unsigned int normalization_type=3,
7039 const bool fullscreen_flag=false, const bool closed_flag=false) {
7040 throw CImgDisplayException("CImgDisplay() : Display has been required but is not available (cimg_display=0)");
7041 const char* avoid_warning = title + dimw + dimh + normalization_type + (int)fullscreen_flag + (int)closed_flag;
7042 avoid_warning = 0;
7043 return *this;
7044 }
7046 //! In-place version of the previous constructor.
7047 template<typename T>
7048 CImgDisplay& assign(const CImg<T>& img, const char *title=0,
7049 const unsigned int normalization_type=3,
7050 const bool fullscreen_flag=false, const bool closed_flag=false) {
7051 throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
7052 const char* avoid_warning = title + img.width + normalization_type + (int)fullscreen_flag + (int)closed_flag;
7053 avoid_warning = 0;
7054 return assign(0,0);
7055 }
7057 //! In-place version of the previous constructor.
7058 template<typename T>
7059 CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
7060 const unsigned int normalization_type=3,
7061 const bool fullscreen_flag=false, const bool closed_flag=false) {
7062 throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
7063 const char* avoid_warning = title + list.size + normalization_type + (int)fullscreen_flag + (int)closed_flag;
7064 avoid_warning = 0;
7065 return assign(0,0);
7066 }
7068 //! In-place version of the previous constructor.
7069 CImgDisplay& assign(const CImgDisplay &disp) {
7070 return assign(disp.width,disp.height);
7071 }
7073 //! Resize window.
7074 CImgDisplay& resize(const int width, const int height, const bool redraw=true) {
7075 int avoid_warning = width | height | (int)redraw;
7076 avoid_warning = 0;
7077 return *this;
7078 }
7080 //! Toggle fullscreen mode.
7081 CImgDisplay& toggle_fullscreen(const bool redraw=true) {
7082 bool avoid_warning = redraw;
7083 avoid_warning = false;
7084 return *this;
7085 }
7087 //! Show a closed display.
7088 CImgDisplay& show() {
7089 return *this;
7090 }
7092 //! Close a visible display.
7093 CImgDisplay& close() {
7094 return *this;
7095 }
7097 //! Move window.
7098 CImgDisplay& move(const int posx, const int posy) {
7099 int avoid_warning = posx | posy;
7100 avoid_warning = 0;
7101 return *this;
7102 }
7104 //! Show mouse pointer.
7105 CImgDisplay& show_mouse() {
7106 return *this;
7107 }
7109 //! Hide mouse pointer.
7110 CImgDisplay& hide_mouse() {
7111 return *this;
7112 }
7114 //! Move mouse pointer to a specific location.
7115 CImgDisplay& set_mouse(const int posx, const int posy) {
7116 int avoid_warning = posx | posy;
7117 avoid_warning = 0;
7118 return *this;
7119 }
7121 //! Set the window title.
7122 CImgDisplay& set_title(const char *format, ...) {
7123 const char *avoid_warning = format;
7124 avoid_warning = 0;
7125 return *this;
7126 }
7128 //! Display an image in a window.
7129 template<typename T>
7130 CImgDisplay& display(const CImg<T>& img) {
7131 unsigned int avoid_warning = img.width;
7132 avoid_warning = 0;
7133 return *this;
7134 }
7136 //! Re-paint image content in window.
7137 CImgDisplay& paint() {
7138 return *this;
7139 }
7141 //! Render image buffer into GDI native image format.
7142 template<typename T>
7143 CImgDisplay& render(const CImg<T>& img) {
7144 unsigned int avoid_warning = img.width;
7145 avoid_warning = 0;
7146 return *this;
7147 }
7149 //! Take a snapshot of the display in the specified image.
7150 template<typename T>
7151 const CImgDisplay& snapshot(CImg<T>& img) const {
7152 img.assign(width,height,1,3,0);
7153 return *this;
7154 }
7156 // X11-based display
7157 //-------------------
7158 #elif cimg_display==1
7159 Atom wm_delete_window, wm_delete_protocol;
7160 Window window, background_window;
7161 Colormap colormap;
7162 XImage *image;
7163 void *data;
7164 #ifdef cimg_use_xshm
7165 XShmSegmentInfo *shminfo;
7166 #endif
7168 static int screen_dimx() {
7169 int res = 0;
7170 if (!cimg::X11attr().display) {
7171 Display *disp = XOpenDisplay((cimg_std::getenv("DISPLAY")?cimg_std::getenv("DISPLAY"):":0.0"));
7172 if (!disp)
7173 throw CImgDisplayException("CImgDisplay::screen_dimx() : Can't open X11 display.");
7174 res = DisplayWidth(disp,DefaultScreen(disp));
7175 XCloseDisplay(disp);
7176 } else {
7177 #ifdef cimg_use_xrandr
7178 if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
7179 res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width;
7180 else
7181 #endif
7182 res = DisplayWidth(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
7183 }
7184 return res;
7185 }
7187 static int screen_dimy() {
7188 int res = 0;
7189 if (!cimg::X11attr().display) {
7190 Display *disp = XOpenDisplay((cimg_std::getenv("DISPLAY") ? cimg_std::getenv("DISPLAY") : ":0.0"));
7191 if (!disp)
7192 throw CImgDisplayException("CImgDisplay::screen_dimy() : Can't open X11 display.");
7193 res = DisplayHeight(disp,DefaultScreen(disp));
7194 XCloseDisplay(disp);
7195 } else {
7196 #ifdef cimg_use_xrandr
7197 if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
7198 res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height;
7199 else
7200 #endif
7201 res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
7202 }
7203 return res;
7204 }
7206 static void wait_all() {
7207 if (cimg::X11attr().display) {
7208 XLockDisplay(cimg::X11attr().display);
7209 bool flag = true;
7210 XEvent event;
7211 while (flag) {
7212 XNextEvent(cimg::X11attr().display, &event);
7213 for (unsigned int i = 0; i<cimg::X11attr().nb_wins; ++i)
7214 if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window) {
7215 cimg::X11attr().wins[i]->_handle_events(&event);
7216 if (cimg::X11attr().wins[i]->is_event) flag = false;
7217 }
7218 }
7219 XUnlockDisplay(cimg::X11attr().display);
7220 }
7221 }
7223 void _handle_events(const XEvent *const pevent) {
7224 XEvent event = *pevent;
7225 switch (event.type) {
7226 case ClientMessage : {
7227 if ((int)event.xclient.message_type==(int)wm_delete_protocol &&
7228 (int)event.xclient.data.l[0]==(int)wm_delete_window) {
7229 XUnmapWindow(cimg::X11attr().display,window);
7230 mouse_x = mouse_y = -1;
7231 if (button) { cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button = 0; }
7232 if (key) { cimg_std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
7233 if (released_key) { cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
7234 is_closed = is_event = true;
7235 }
7236 } break;
7237 case ConfigureNotify : {
7238 while (XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event)) {}
7239 const unsigned int
7240 nw = event.xconfigure.width,
7241 nh = event.xconfigure.height;
7242 const int
7243 nx = event.xconfigure.x,
7244 ny = event.xconfigure.y;
7245 if (nw && nh && (nw!=window_width || nh!=window_height)) {
7246 window_width = nw;
7247 window_height = nh;
7248 mouse_x = mouse_y = -1;
7249 XResizeWindow(cimg::X11attr().display,window,window_width,window_height);
7250 is_resized = is_event = true;
7251 }
7252 if (nx!=window_x || ny!=window_y) {
7253 window_x = nx;
7254 window_y = ny;
7255 is_moved = is_event = true;
7256 }
7257 } break;
7258 case Expose : {
7259 while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event)) {}
7260 _paint(false);
7261 if (is_fullscreen) {
7262 XWindowAttributes attr;
7263 XGetWindowAttributes(cimg::X11attr().display, window, &attr);
7264 while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
7265 XSetInputFocus(cimg::X11attr().display, window, RevertToParent, CurrentTime);
7266 }
7267 } break;
7268 case ButtonPress : {
7269 do {
7270 mouse_x = event.xmotion.x;
7271 mouse_y = event.xmotion.y;
7272 if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7273 switch (event.xbutton.button) {
7274 case 1 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=1; is_event = true; break;
7275 case 2 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=4; is_event = true; break;
7276 case 3 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=2; is_event = true; break;
7277 }
7278 } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event));
7279 } break;
7280 case ButtonRelease : {
7281 do {
7282 mouse_x = event.xmotion.x;
7283 mouse_y = event.xmotion.y;
7284 if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7285 switch (event.xbutton.button) {
7286 case 1 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~1U; is_event = true; break;
7287 case 2 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~4U; is_event = true; break;
7288 case 3 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~2U; is_event = true; break;
7289 case 4 : ++wheel; is_event = true; break;
7290 case 5 : --wheel; is_event = true; break;
7291 }
7292 } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event));
7293 } break;
7294 case KeyPress : {
7295 char tmp;
7296 KeySym ksym;
7297 XLookupString(&event.xkey,&tmp,1,&ksym,0);
7298 update_iskey((unsigned int)ksym,true);
7299 if (key) cimg_std::memmove((void*)(keys+1),(void*)keys,512-1);
7300 key = (unsigned int)ksym;
7301 if (released_key) { cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
7302 is_event = true;
7303 } break;
7304 case KeyRelease : {
7305 char tmp;
7306 KeySym ksym;
7307 XLookupString(&event.xkey,&tmp,1,&ksym,0);
7308 update_iskey((unsigned int)ksym,false);
7309 if (key) { cimg_std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
7310 if (released_key) cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1);
7311 released_key = (unsigned int)ksym;
7312 is_event = true;
7313 } break;
7314 case EnterNotify: {
7315 while (XCheckWindowEvent(cimg::X11attr().display,window,EnterWindowMask,&event)) {}
7316 mouse_x = event.xmotion.x;
7317 mouse_y = event.xmotion.y;
7318 if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7319 } break;
7320 case LeaveNotify : {
7321 while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event)) {}
7322 mouse_x = mouse_y =-1;
7323 is_event = true;
7324 } break;
7325 case MotionNotify : {
7326 while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event)) {}
7327 mouse_x = event.xmotion.x;
7328 mouse_y = event.xmotion.y;
7329 if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
7330 is_event = true;
7331 } break;
7332 }
7333 }
7335 static void* _events_thread(void *arg) {
7336 arg = 0;
7337 XEvent event;
7338 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
7339 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
7340 for (;;) {
7341 XLockDisplay(cimg::X11attr().display);
7342 bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event);
7343 if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display,
7344 ExposureMask|StructureNotifyMask|ButtonPressMask|
7345 KeyPressMask|PointerMotionMask|EnterWindowMask|LeaveWindowMask|
7346 ButtonReleaseMask|KeyReleaseMask,&event);
7347 if (event_flag) {
7348 for (unsigned int i=0; i<cimg::X11attr().nb_wins; ++i)
7349 if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window)
7350 cimg::X11attr().wins[i]->_handle_events(&event);
7351 }
7352 XUnlockDisplay(cimg::X11attr().display);
7353 pthread_testcancel();
7354 cimg::sleep(7);
7355 }
7356 return 0;
7357 }
7359 void _set_colormap(Colormap& colormap, const unsigned int dim) {
7360 XColor palette[256];
7361 switch (dim) {
7362 case 1 : { // palette for greyscale images
7363 for (unsigned int index=0; index<256; ++index) {
7364 palette[index].pixel = index;
7365 palette[index].red = palette[index].green = palette[index].blue = (unsigned short)(index<<8);
7366 palette[index].flags = DoRed | DoGreen | DoBlue;
7367 }
7368 } break;
7369 case 2 : { // palette for RG images
7370 for (unsigned int index=0, r=8; r<256; r+=16)
7371 for (unsigned int g=8; g<256; g+=16) {
7372 palette[index].pixel = index;
7373 palette[index].red = palette[index].blue = (unsigned short)(r<<8);
7374 palette[index].green = (unsigned short)(g<<8);
7375 palette[index++].flags = DoRed | DoGreen | DoBlue;
7376 }
7377 } break;
7378 default : { // palette for RGB images
7379 for (unsigned int index=0, r=16; r<256; r+=32)
7380 for (unsigned int g=16; g<256; g+=32)
7381 for (unsigned int b=32; b<256; b+=64) {
7382 palette[index].pixel = index;
7383 palette[index].red = (unsigned short)(r<<8);
7384 palette[index].green = (unsigned short)(g<<8);
7385 palette[index].blue = (unsigned short)(b<<8);
7386 palette[index++].flags = DoRed | DoGreen | DoBlue;
7387 }
7388 }
7389 }
7390 XStoreColors(cimg::X11attr().display,colormap,palette,256);
7391 }
7393 void _map_window() {
7394 XWindowAttributes attr;
7395 XEvent event;
7396 bool exposed = false, mapped = false;
7397 XMapRaised(cimg::X11attr().display,window);
7398 XSync(cimg::X11attr().display,False);
7399 do {
7400 XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask | ExposureMask,&event);
7401 switch (event.type) {
7402 case MapNotify : mapped = true; break;
7403 case Expose : exposed = true; break;
7404 default : XSync(cimg::X11attr().display, False); cimg::sleep(10);
7405 }
7406 } while (!(exposed && mapped));
7407 do {
7408 XGetWindowAttributes(cimg::X11attr().display, window, &attr);
7409 if (attr.map_state!=IsViewable) { XSync(cimg::X11attr().display,False); cimg::sleep(10); }
7410 } while (attr.map_state != IsViewable);
7411 window_x = attr.x;
7412 window_y = attr.y;
7413 }
7415 void _paint(const bool wait_expose=true) {
7416 if (!is_closed) {
7417 if (wait_expose) {
7418 static XEvent event;
7419 event.xexpose.type = Expose;
7420 event.xexpose.serial = 0;
7421 event.xexpose.send_event = True;
7422 event.xexpose.display = cimg::X11attr().display;
7423 event.xexpose.window = window;
7424 event.xexpose.x = 0;
7425 event.xexpose.y = 0;
7426 event.xexpose.width = dimx();
7427 event.xexpose.height = dimy();
7428 event.xexpose.count = 0;
7429 XSendEvent(cimg::X11attr().display, window, False, 0, &event);
7430 } else {
7431 #ifdef cimg_use_xshm
7432 if (shminfo) XShmPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height,False);
7433 else
7434 #endif
7435 XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
7436 XSync(cimg::X11attr().display, False);
7437 }
7438 }
7439 }
7441 template<typename T>
7442 void _resize(T foo, const unsigned int ndimx, const unsigned int ndimy, const bool redraw) {
7443 foo = 0;
7444 #ifdef cimg_use_xshm
7445 if (shminfo) {
7446 XShmSegmentInfo *nshminfo = new XShmSegmentInfo;
7447 XImage *nimage = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7448 cimg::X11attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy);
7449 if (!nimage) {
7450 delete nshminfo;
7451 return;
7452 } else {
7453 nshminfo->shmid = shmget(IPC_PRIVATE, ndimx*ndimy*sizeof(T), IPC_CREAT | 0777);
7454 if (nshminfo->shmid==-1) {
7455 XDestroyImage(nimage);
7456 delete nshminfo;
7457 return;
7458 } else {
7459 nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0);
7460 if (nshminfo->shmaddr==(char*)-1) {
7461 shmctl(nshminfo->shmid,IPC_RMID,0);
7462 XDestroyImage(nimage);
7463 delete nshminfo;
7464 return;
7465 } else {
7466 nshminfo->readOnly = False;
7467 cimg::X11attr().shm_enabled = true;
7468 XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
7469 XShmAttach(cimg::X11attr().display, nshminfo);
7470 XSync(cimg::X11attr().display, False);
7471 XSetErrorHandler(oldXErrorHandler);
7472 if (!cimg::X11attr().shm_enabled) {
7473 shmdt(nshminfo->shmaddr);
7474 shmctl(nshminfo->shmid,IPC_RMID,0);
7475 XDestroyImage(nimage);
7476 delete nshminfo;
7477 return;
7478 } else {
7479 T *const ndata = (T*)nimage->data;
7480 if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
7481 else cimg_std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
7482 XShmDetach(cimg::X11attr().display, shminfo);
7483 XDestroyImage(image);
7484 shmdt(shminfo->shmaddr);
7485 shmctl(shminfo->shmid,IPC_RMID,0);
7486 delete shminfo;
7487 shminfo = nshminfo;
7488 image = nimage;
7489 data = (void*)ndata;
7490 }
7491 }
7492 }
7493 }
7494 } else
7495 #endif
7496 {
7497 T *ndata = (T*)cimg_std::malloc(ndimx*ndimy*sizeof(T));
7498 if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
7499 else cimg_std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
7500 data = (void*)ndata;
7501 XDestroyImage(image);
7502 image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7503 cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,ndimx,ndimy,8,0);
7504 }
7505 }
7507 void _init_fullscreen() {
7508 background_window = 0;
7509 if (is_fullscreen && !is_closed) {
7510 #ifdef cimg_use_xrandr
7511 int foo;
7512 if (XRRQueryExtension(cimg::X11attr().display,&foo,&foo)) {
7513 XRRRotations(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display), &cimg::X11attr().curr_rotation);
7514 if (!cimg::X11attr().resolutions) {
7515 cimg::X11attr().resolutions = XRRSizes(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display),&foo);
7516 cimg::X11attr().nb_resolutions = (unsigned int)foo;
7517 }
7518 if (cimg::X11attr().resolutions) {
7519 cimg::X11attr().curr_resolution = 0;
7520 for (unsigned int i=0; i<cimg::X11attr().nb_resolutions; ++i) {
7521 const unsigned int
7522 nw = (unsigned int)(cimg::X11attr().resolutions[i].width),
7523 nh = (unsigned int)(cimg::X11attr().resolutions[i].height);
7524 if (nw>=width && nh>=height &&
7525 nw<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width) &&
7526 nh<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height))
7527 cimg::X11attr().curr_resolution = i;
7528 }
7529 if (cimg::X11attr().curr_resolution>0) {
7530 XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
7531 XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
7532 cimg::X11attr().curr_resolution, cimg::X11attr().curr_rotation, CurrentTime);
7533 XRRFreeScreenConfigInfo(config);
7534 XSync(cimg::X11attr().display, False);
7535 }
7536 }
7537 }
7538 if (!cimg::X11attr().resolutions)
7539 cimg::warn("CImgDisplay::_create_window() : Xrandr extension is not supported by the X server.");
7540 #endif
7541 const unsigned int sx = screen_dimx(), sy = screen_dimy();
7542 XSetWindowAttributes winattr;
7543 winattr.override_redirect = True;
7544 if (sx!=width || sy!=height) {
7545 background_window = XCreateWindow(cimg::X11attr().display,
7546 RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),0,0,
7547 sx,sy,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
7548 const unsigned int bufsize = sx*sy*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
7549 void *background_data = cimg_std::malloc(bufsize);
7550 cimg_std::memset(background_data,0,bufsize);
7551 XImage *background_image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7552 cimg::X11attr().nb_bits,ZPixmap,0,(char*)background_data,sx,sy,8,0);
7553 XEvent event;
7554 XSelectInput(cimg::X11attr().display,background_window,StructureNotifyMask);
7555 XMapRaised(cimg::X11attr().display,background_window);
7556 do XWindowEvent(cimg::X11attr().display,background_window,StructureNotifyMask,&event);
7557 while (event.type!=MapNotify);
7558 #ifdef cimg_use_xshm
7559 if (shminfo) XShmPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy,False);
7560 else
7561 #endif
7562 XPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy);
7563 XWindowAttributes attr;
7564 XGetWindowAttributes(cimg::X11attr().display, background_window, &attr);
7565 while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
7566 XDestroyImage(background_image);
7567 }
7568 }
7569 }
7571 void _desinit_fullscreen() {
7572 if (is_fullscreen) {
7573 XUngrabKeyboard(cimg::X11attr().display,CurrentTime);
7574 #ifdef cimg_use_xrandr
7575 if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution) {
7576 XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
7577 XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
7578 0, cimg::X11attr().curr_rotation, CurrentTime);
7579 XRRFreeScreenConfigInfo(config);
7580 XSync(cimg::X11attr().display, False);
7581 cimg::X11attr().curr_resolution = 0;
7582 }
7583 #endif
7584 if (background_window) XDestroyWindow(cimg::X11attr().display,background_window);
7585 background_window = 0;
7586 is_fullscreen = false;
7587 }
7588 }
7590 static int _assign_xshm(Display *dpy, XErrorEvent *error) {
7591 dpy = 0; error = 0;
7592 cimg::X11attr().shm_enabled = false;
7593 return 0;
7594 }
7596 void _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
7597 const unsigned int normalization_type=3,
7598 const bool fullscreen_flag=false, const bool closed_flag=false) {
7600 // Allocate space for window title
7601 const int s = cimg::strlen(ptitle)+1;
7602 char *tmp_title = s?new char[s]:0;
7603 if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
7605 // Destroy previous display window if existing
7606 if (!is_empty()) assign();
7608 // Open X11 display if necessary.
7609 if (!cimg::X11attr().display) {
7610 static bool xinit_threads = false;
7611 if (!xinit_threads) { XInitThreads(); xinit_threads = true; }
7612 cimg::X11attr().nb_wins = 0;
7613 cimg::X11attr().display = XOpenDisplay((cimg_std::getenv("DISPLAY")?cimg_std::getenv("DISPLAY"):":0.0"));
7614 if (!cimg::X11attr().display)
7615 throw CImgDisplayException("CImgDisplay::_create_window() : Can't open X11 display");
7616 cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display));
7617 if (cimg::X11attr().nb_bits!=8 && cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24 && cimg::X11attr().nb_bits!=32)
7618 throw CImgDisplayException("CImgDisplay::_create_window() : %u bits mode is not supported "
7619 "(only 8, 16, 24 and 32 bits modes are supported)",cimg::X11attr().nb_bits);
7620 cimg::X11attr().gc = new GC;
7621 *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
7622 Visual *visual = DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
7623 XVisualInfo vtemplate;
7624 vtemplate.visualid = XVisualIDFromVisual(visual);
7625 int nb_visuals;
7626 XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals);
7627 if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11attr().blue_first = true;
7628 cimg::X11attr().byte_order = ImageByteOrder(cimg::X11attr().display);
7629 XFree(vinfo);
7630 XLockDisplay(cimg::X11attr().display);
7631 cimg::X11attr().event_thread = new pthread_t;
7632 pthread_create(cimg::X11attr().event_thread,0,_events_thread,0);
7633 } else XLockDisplay(cimg::X11attr().display);
7635 // Set display variables
7636 width = cimg::min(dimw,(unsigned int)screen_dimx());
7637 height = cimg::min(dimh,(unsigned int)screen_dimy());
7638 normalization = normalization_type<4?normalization_type:3;
7639 is_fullscreen = fullscreen_flag;
7640 window_x = window_y = 0;
7641 is_closed = closed_flag;
7642 title = tmp_title;
7643 flush();
7645 // Create X11 window and palette (if 8bits display)
7646 if (is_fullscreen) {
7647 if (!is_closed) _init_fullscreen();
7648 const unsigned int sx = screen_dimx(), sy = screen_dimy();
7649 XSetWindowAttributes winattr;
7650 winattr.override_redirect = True;
7651 window = XCreateWindow(cimg::X11attr().display,
7652 RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7653 (sx-width)/2,(sy-height)/2,
7654 width,height,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
7655 } else
7656 window = XCreateSimpleWindow(cimg::X11attr().display,
7657 RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7658 0,0,width,height,2,0,0x0L);
7659 XStoreName(cimg::X11attr().display,window,title?title:" ");
7660 if (cimg::X11attr().nb_bits==8) {
7661 colormap = XCreateColormap(cimg::X11attr().display,window,DefaultVisual(cimg::X11attr().display,
7662 DefaultScreen(cimg::X11attr().display)),AllocAll);
7663 _set_colormap(colormap,3);
7664 XSetWindowColormap(cimg::X11attr().display,window,colormap);
7665 }
7666 window_width = width;
7667 window_height = height;
7669 // Create XImage
7670 const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
7671 #ifdef cimg_use_xshm
7672 shminfo = 0;
7673 if (XShmQueryExtension(cimg::X11attr().display)) {
7674 shminfo = new XShmSegmentInfo;
7675 image = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7676 cimg::X11attr().nb_bits,ZPixmap,0,shminfo,width,height);
7677 if (!image) {
7678 delete shminfo;
7679 shminfo = 0;
7680 } else {
7681 shminfo->shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777);
7682 if (shminfo->shmid==-1) {
7683 XDestroyImage(image);
7684 delete shminfo;
7685 shminfo = 0;
7686 } else {
7687 shminfo->shmaddr = image->data = (char*)(data = shmat(shminfo->shmid,0,0));
7688 if (shminfo->shmaddr==(char*)-1) {
7689 shmctl(shminfo->shmid,IPC_RMID,0);
7690 XDestroyImage(image);
7691 delete shminfo;
7692 shminfo = 0;
7693 } else {
7694 shminfo->readOnly = False;
7695 cimg::X11attr().shm_enabled = true;
7696 XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
7697 XShmAttach(cimg::X11attr().display, shminfo);
7698 XSync(cimg::X11attr().display, False);
7699 XSetErrorHandler(oldXErrorHandler);
7700 if (!cimg::X11attr().shm_enabled) {
7701 shmdt(shminfo->shmaddr);
7702 shmctl(shminfo->shmid,IPC_RMID,0);
7703 XDestroyImage(image);
7704 delete shminfo;
7705 shminfo = 0;
7706 }
7707 }
7708 }
7709 }
7710 }
7711 if (!shminfo)
7712 #endif
7713 {
7714 data = cimg_std::malloc(bufsize);
7715 image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
7716 cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0);
7717 }
7719 wm_delete_window = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False);
7720 wm_delete_protocol = XInternAtom(cimg::X11attr().display, "WM_PROTOCOLS", False);
7721 XSetWMProtocols(cimg::X11attr().display, window, &wm_delete_window, 1);
7722 XSelectInput(cimg::X11attr().display,window,
7723 ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask |
7724 EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask);
7725 if (is_fullscreen) XGrabKeyboard(cimg::X11attr().display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
7726 cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this;
7727 if (!is_closed) _map_window(); else { window_x = window_y = cimg::type<int>::min(); }
7728 XUnlockDisplay(cimg::X11attr().display);
7729 }
7731 CImgDisplay& assign() {
7732 if (is_empty()) return *this;
7733 XLockDisplay(cimg::X11attr().display);
7735 // Remove display window from event thread list.
7736 unsigned int i;
7737 for (i = 0; i<cimg::X11attr().nb_wins && cimg::X11attr().wins[i]!=this; ++i) {}
7738 for (; i<cimg::X11attr().nb_wins-1; ++i) cimg::X11attr().wins[i] = cimg::X11attr().wins[i+1];
7739 --cimg::X11attr().nb_wins;
7741 // Destroy window, image, colormap and title.
7742 if (is_fullscreen && !is_closed) _desinit_fullscreen();
7743 XDestroyWindow(cimg::X11attr().display,window);
7744 window = 0;
7745 #ifdef cimg_use_xshm
7746 if (shminfo) {
7747 XShmDetach(cimg::X11attr().display, shminfo);
7748 XDestroyImage(image);
7749 shmdt(shminfo->shmaddr);
7750 shmctl(shminfo->shmid,IPC_RMID,0);
7751 delete shminfo;
7752 shminfo = 0;
7753 } else
7754 #endif
7755 XDestroyImage(image);
7756 data = 0; image = 0;
7757 if (cimg::X11attr().nb_bits==8) XFreeColormap(cimg::X11attr().display,colormap);
7758 colormap = 0;
7759 XSync(cimg::X11attr().display, False);
7761 // Reset display variables
7762 if (title) delete[] title;
7763 width = height = normalization = window_width = window_height = 0;
7764 window_x = window_y = 0;
7765 is_fullscreen = false;
7766 is_closed = true;
7767 min = max = 0;
7768 title = 0;
7769 flush();
7771 // End event thread and close display if necessary
7772 XUnlockDisplay(cimg::X11attr().display);
7774 /* The code below was used to close the X11 display when not used anymore,
7775 unfortunately, since the latest Xorg versions, it randomely hangs, so
7776 I prefer to remove it. A fix would be needed anyway.
7778 if (!cimg::X11attr().nb_wins) {
7779 // Kill event thread
7780 pthread_cancel(*cimg::X11attr().event_thread);
7781 XUnlockDisplay(cimg::X11attr().display);
7782 pthread_join(*cimg::X11attr().event_thread,0);
7783 delete cimg::X11attr().event_thread;
7784 cimg::X11attr().event_thread = 0;
7785 XCloseDisplay(cimg::X11attr().display);
7786 cimg::X11attr().display = 0;
7787 delete cimg::X11attr().gc;
7788 cimg::X11attr().gc = 0;
7789 } else XUnlockDisplay(cimg::X11attr().display);
7790 */
7791 return *this;
7792 }
7794 CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
7795 const unsigned int normalization_type=3,
7796 const bool fullscreen_flag=false, const bool closed_flag=false) {
7797 if (!dimw || !dimh) return assign();
7798 _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
7799 min = max = 0;
7800 cimg_std::memset(data,0,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
7801 (cimg::X11attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*width*height);
7802 return paint();
7803 }
7805 template<typename T>
7806 CImgDisplay& assign(const CImg<T>& img, const char *title=0,
7807 const unsigned int normalization_type=3,
7808 const bool fullscreen_flag=false, const bool closed_flag=false) {
7809 if (!img) return assign();
7810 CImg<T> tmp;
7811 const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
7812 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
7813 if (normalization==2) min = (float)nimg.minmax(max);
7814 return render(nimg).paint();
7815 }
7817 template<typename T>
7818 CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
7819 const unsigned int normalization_type=3,
7820 const bool fullscreen_flag=false, const bool closed_flag=false) {
7821 if (!list) return assign();
7822 CImg<T> tmp;
7823 const CImg<T> img = list.get_append('x','p'),
7824 &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
7825 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
7826 if (normalization==2) min = (float)nimg.minmax(max);
7827 return render(nimg).paint();
7828 }
7830 CImgDisplay& assign(const CImgDisplay& win) {
7831 if (!win) return assign();
7832 _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
7833 cimg_std::memcpy(data,win.data,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
7834 cimg::X11attr().nb_bits==16?sizeof(unsigned short):
7835 sizeof(unsigned int))*width*height);
7836 return paint();
7837 }
7839 CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
7840 if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
7841 if (is_empty()) return assign(nwidth,nheight);
7842 const unsigned int
7843 tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
7844 tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
7845 dimx = tmpdimx?tmpdimx:1,
7846 dimy = tmpdimy?tmpdimy:1;
7847 XLockDisplay(cimg::X11attr().display);
7848 if (window_width!=dimx || window_height!=dimy) XResizeWindow(cimg::X11attr().display,window,dimx,dimy);
7849 if (width!=dimx || height!=dimy) switch (cimg::X11attr().nb_bits) {
7850 case 8 : { unsigned char foo = 0; _resize(foo,dimx,dimy,redraw); } break;
7851 case 16 : { unsigned short foo = 0; _resize(foo,dimx,dimy,redraw); } break;
7852 default : { unsigned int foo = 0; _resize(foo,dimx,dimy,redraw); }
7853 }
7854 window_width = width = dimx; window_height = height = dimy;
7855 is_resized = false;
7856 XUnlockDisplay(cimg::X11attr().display);
7857 if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
7858 if (redraw) return paint();
7859 return *this;
7860 }
7862 CImgDisplay& toggle_fullscreen(const bool redraw=true) {
7863 if (is_empty()) return *this;
7864 if (redraw) {
7865 const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
7866 void *odata = cimg_std::malloc(bufsize);
7867 cimg_std::memcpy(odata,data,bufsize);
7868 assign(width,height,title,normalization,!is_fullscreen,false);
7869 cimg_std::memcpy(data,odata,bufsize);
7870 cimg_std::free(odata);
7871 return paint(false);
7872 }
7873 return assign(width,height,title,normalization,!is_fullscreen,false);
7874 }
7876 CImgDisplay& show() {
7877 if (!is_empty() && is_closed) {
7878 XLockDisplay(cimg::X11attr().display);
7879 if (is_fullscreen) _init_fullscreen();
7880 _map_window();
7881 is_closed = false;
7882 XUnlockDisplay(cimg::X11attr().display);
7883 return paint();
7884 }
7885 return *this;
7886 }
7888 CImgDisplay& close() {
7889 if (!is_empty() && !is_closed) {
7890 XLockDisplay(cimg::X11attr().display);
7891 if (is_fullscreen) _desinit_fullscreen();
7892 XUnmapWindow(cimg::X11attr().display,window);
7893 window_x = window_y = -1;
7894 is_closed = true;
7895 XUnlockDisplay(cimg::X11attr().display);
7896 }
7897 return *this;
7898 }
7900 CImgDisplay& move(const int posx, const int posy) {
7901 if (is_empty()) return *this;
7902 show();
7903 XLockDisplay(cimg::X11attr().display);
7904 XMoveWindow(cimg::X11attr().display,window,posx,posy);
7905 window_x = posx; window_y = posy;
7906 is_moved = false;
7907 XUnlockDisplay(cimg::X11attr().display);
7908 return paint();
7909 }
7911 CImgDisplay& show_mouse() {
7912 if (is_empty()) return *this;
7913 XLockDisplay(cimg::X11attr().display);
7914 XDefineCursor(cimg::X11attr().display,window,None);
7915 XUnlockDisplay(cimg::X11attr().display);
7916 return *this;
7917 }
7919 CImgDisplay& hide_mouse() {
7920 if (is_empty()) return *this;
7921 XLockDisplay(cimg::X11attr().display);
7922 const char pix_data[8] = { 0 };
7923 XColor col;
7924 col.red = col.green = col.blue = 0;
7925 Pixmap pix = XCreateBitmapFromData(cimg::X11attr().display,window,pix_data,8,8);
7926 Cursor cur = XCreatePixmapCursor(cimg::X11attr().display,pix,pix,&col,&col,0,0);
7927 XFreePixmap(cimg::X11attr().display,pix);
7928 XDefineCursor(cimg::X11attr().display,window,cur);
7929 XUnlockDisplay(cimg::X11attr().display);
7930 return *this;
7931 }
7933 CImgDisplay& set_mouse(const int posx, const int posy) {
7934 if (is_empty() || is_closed) return *this;
7935 XLockDisplay(cimg::X11attr().display);
7936 XWarpPointer(cimg::X11attr().display,None,window,0,0,0,0,posx,posy);
7937 mouse_x = posx; mouse_y = posy;
7938 is_moved = false;
7939 XSync(cimg::X11attr().display, False);
7940 XUnlockDisplay(cimg::X11attr().display);
7941 return *this;
7942 }
7944 CImgDisplay& set_title(const char *format, ...) {
7945 if (is_empty()) return *this;
7946 char tmp[1024] = {0};
7947 va_list ap;
7948 va_start(ap, format);
7949 cimg_std::vsprintf(tmp,format,ap);
7950 va_end(ap);
7951 if (title) delete[] title;
7952 const int s = cimg::strlen(tmp)+1;
7953 title = new char[s];
7954 cimg_std::memcpy(title,tmp,s*sizeof(char));
7955 XLockDisplay(cimg::X11attr().display);
7956 XStoreName(cimg::X11attr().display,window,tmp);
7957 XUnlockDisplay(cimg::X11attr().display);
7958 return *this;
7959 }
7961 template<typename T>
7962 CImgDisplay& display(const CImg<T>& img) {
7963 if (img.is_empty())
7964 throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
7965 if (is_empty()) assign(img.width,img.height);
7966 return render(img).paint(false);
7967 }
7969 CImgDisplay& paint(const bool wait_expose=true) {
7970 if (is_empty()) return *this;
7971 XLockDisplay(cimg::X11attr().display);
7972 _paint(wait_expose);
7973 XUnlockDisplay(cimg::X11attr().display);
7974 return *this;
7975 }
7977 template<typename T>
7978 CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
7979 if (is_empty()) return *this;
7980 if (!img)
7981 throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
7982 img.width,img.height,img.depth,img.dim,img.data);
7983 if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
7984 if (cimg::X11attr().nb_bits==8 && (img.width!=width || img.height!=height)) return render(img.get_resize(width,height,1,-100,1));
7985 if (cimg::X11attr().nb_bits==8 && !flag8 && img.dim==3) return render(img.get_RGBtoLUT(true),true);
7987 const T
7988 *data1 = img.data,
7989 *data2 = (img.dim>1)?img.ptr(0,0,0,1):data1,
7990 *data3 = (img.dim>2)?img.ptr(0,0,0,2):data1;
7992 if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
7993 XLockDisplay(cimg::X11attr().display);
7995 if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
7996 min = max = 0;
7997 switch (cimg::X11attr().nb_bits) {
7998 case 8 : { // 256 color palette, no normalization
7999 _set_colormap(colormap,img.dim);
8000 unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
8001 unsigned char *ptrd = (unsigned char*)ndata;
8002 switch (img.dim) {
8003 case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) (*ptrd++) = (unsigned char)*(data1++);
8004 break;
8005 case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8006 const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++);
8007 (*ptrd++) = (R&0xf0) | (G>>4);
8008 } break;
8009 default : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8010 const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
8011 (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
8012 }
8013 }
8014 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
8015 } break;
8016 case 16 : { // 16 bits colors, no normalization
8017 unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
8018 unsigned char *ptrd = (unsigned char*)ndata;
8019 const unsigned int M = 248;
8020 switch (img.dim) {
8021 case 1 :
8022 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8023 const unsigned char val = (unsigned char)*(data1++), G = val>>2;
8024 *(ptrd++) = (val&M) | (G>>3);
8025 *(ptrd++) = (G<<5) | (G>>1);
8026 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8027 const unsigned char val = (unsigned char)*(data1++), G = val>>2;
8028 *(ptrd++) = (G<<5) | (G>>1);
8029 *(ptrd++) = (val&M) | (G>>3);
8030 }
8031 break;
8032 case 2 :
8033 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8034 const unsigned char G = (unsigned char)*(data2++)>>2;
8035 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
8036 *(ptrd++) = (G<<5);
8037 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8038 const unsigned char G = (unsigned char)*(data2++)>>2;
8039 *(ptrd++) = (G<<5);
8040 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
8041 }
8042 break;
8043 default :
8044 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8045 const unsigned char G = (unsigned char)*(data2++)>>2;
8046 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
8047 *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
8048 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8049 const unsigned char G = (unsigned char)*(data2++)>>2;
8050 *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
8051 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
8052 }
8053 }
8054 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
8055 } break;
8056 default : { // 24 bits colors, no normalization
8057 unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
8058 if (sizeof(int)==4) { // 32 bits int uses optimized version
8059 unsigned int *ptrd = ndata;
8060 switch (img.dim) {
8061 case 1 :
8062 if (cimg::X11attr().byte_order==cimg::endianness())
8063 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8064 const unsigned char val = (unsigned char)*(data1++);
8065 *(ptrd++) = (val<<16) | (val<<8) | val;
8066 }
8067 else
8068 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8069 const unsigned char val = (unsigned char)*(data1++)<<8;
8070 *(ptrd++) = (val<<16) | (val<<8) | val;
8071 }
8072 break;
8073 case 2 :
8074 if (cimg::X11attr().byte_order==cimg::endianness())
8075 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8076 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
8077 else
8078 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8079 *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
8080 break;
8081 default :
8082 if (cimg::X11attr().byte_order==cimg::endianness())
8083 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8084 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
8085 else
8086 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8087 *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
8088 }
8089 } else {
8090 unsigned char *ptrd = (unsigned char*)ndata;
8091 switch (img.dim) {
8092 case 1 :
8093 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8094 *(ptrd++) = 0;
8095 *(ptrd++) = (unsigned char)*(data1++);
8096 *(ptrd++) = 0;
8097 *(ptrd++) = 0;
8098 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8099 *(ptrd++) = 0;
8100 *(ptrd++) = 0;
8101 *(ptrd++) = (unsigned char)*(data1++);
8102 *(ptrd++) = 0;
8103 }
8104 break;
8105 case 2 :
8106 if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
8107 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8108 *(ptrd++) = 0;
8109 *(ptrd++) = (unsigned char)*(data2++);
8110 *(ptrd++) = (unsigned char)*(data1++);
8111 *(ptrd++) = 0;
8112 }
8113 break;
8114 default :
8115 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8116 *(ptrd++) = 0;
8117 *(ptrd++) = (unsigned char)*(data1++);
8118 *(ptrd++) = (unsigned char)*(data2++);
8119 *(ptrd++) = (unsigned char)*(data3++);
8120 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8121 *(ptrd++) = (unsigned char)*(data3++);
8122 *(ptrd++) = (unsigned char)*(data2++);
8123 *(ptrd++) = (unsigned char)*(data1++);
8124 *(ptrd++) = 0;
8125 }
8126 }
8127 }
8128 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
8129 }
8130 };
8131 } else {
8132 if (normalization==3) {
8133 if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
8134 else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
8135 } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
8136 const float delta = max-min, mm = delta?delta:1.0f;
8137 switch (cimg::X11attr().nb_bits) {
8138 case 8 : { // 256 color palette, with normalization
8139 _set_colormap(colormap,img.dim);
8140 unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
8141 unsigned char *ptrd = (unsigned char*)ndata;
8142 switch (img.dim) {
8143 case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8144 const unsigned char R = (unsigned char)(255*(*(data1++)-min)/mm);
8145 *(ptrd++) = R;
8146 } break;
8147 case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8148 const unsigned char
8149 R = (unsigned char)(255*(*(data1++)-min)/mm),
8150 G = (unsigned char)(255*(*(data2++)-min)/mm);
8151 (*ptrd++) = (R&0xf0) | (G>>4);
8152 } break;
8153 default :
8154 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8155 const unsigned char
8156 R = (unsigned char)(255*(*(data1++)-min)/mm),
8157 G = (unsigned char)(255*(*(data2++)-min)/mm),
8158 B = (unsigned char)(255*(*(data3++)-min)/mm);
8159 *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
8160 }
8161 }
8162 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
8163 } break;
8164 case 16 : { // 16 bits colors, with normalization
8165 unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
8166 unsigned char *ptrd = (unsigned char*)ndata;
8167 const unsigned int M = 248;
8168 switch (img.dim) {
8169 case 1 :
8170 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8171 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
8172 *(ptrd++) = (val&M) | (G>>3);
8173 *(ptrd++) = (G<<5) | (val>>3);
8174 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8175 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
8176 *(ptrd++) = (G<<5) | (val>>3);
8177 *(ptrd++) = (val&M) | (G>>3);
8178 }
8179 break;
8180 case 2 :
8181 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8182 const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
8183 *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
8184 *(ptrd++) = (G<<5);
8185 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8186 const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
8187 *(ptrd++) = (G<<5);
8188 *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
8189 }
8190 break;
8191 default :
8192 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8193 const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
8194 *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
8195 *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
8196 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8197 const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
8198 *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
8199 *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
8200 }
8201 }
8202 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
8203 } break;
8204 default : { // 24 bits colors, with normalization
8205 unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
8206 if (sizeof(int)==4) { // 32 bits int uses optimized version
8207 unsigned int *ptrd = ndata;
8208 switch (img.dim) {
8209 case 1 :
8210 if (cimg::X11attr().byte_order==cimg::endianness())
8211 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8212 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8213 *(ptrd++) = (val<<16) | (val<<8) | val;
8214 }
8215 else
8216 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8217 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8218 *(ptrd++) = (val<<24) | (val<<16) | (val<<8);
8219 }
8220 break;
8221 case 2 :
8222 if (cimg::X11attr().byte_order==cimg::endianness())
8223 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8224 *(ptrd++) =
8225 ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
8226 ((unsigned char)(255*(*(data2++)-min)/mm)<<8);
8227 else
8228 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8229 *(ptrd++) =
8230 ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
8231 ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
8232 break;
8233 default :
8234 if (cimg::X11attr().byte_order==cimg::endianness())
8235 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8236 *(ptrd++) =
8237 ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
8238 ((unsigned char)(255*(*(data2++)-min)/mm)<<8) |
8239 (unsigned char)(255*(*(data3++)-min)/mm);
8240 else
8241 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8242 *(ptrd++) =
8243 ((unsigned char)(255*(*(data3++)-min)/mm)<<24) |
8244 ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
8245 ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
8246 }
8247 } else {
8248 unsigned char *ptrd = (unsigned char*)ndata;
8249 switch (img.dim) {
8250 case 1 :
8251 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8252 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8253 (*ptrd++) = 0;
8254 (*ptrd++) = val;
8255 (*ptrd++) = val;
8256 (*ptrd++) = val;
8257 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8258 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8259 (*ptrd++) = val;
8260 (*ptrd++) = val;
8261 (*ptrd++) = val;
8262 (*ptrd++) = 0;
8263 }
8264 break;
8265 case 2 :
8266 if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
8267 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8268 (*ptrd++) = 0;
8269 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
8270 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
8271 (*ptrd++) = 0;
8272 }
8273 break;
8274 default :
8275 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8276 (*ptrd++) = 0;
8277 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
8278 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
8279 (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
8280 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8281 (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
8282 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
8283 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
8284 (*ptrd++) = 0;
8285 }
8286 }
8287 }
8288 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
8289 }
8290 }
8291 }
8292 XUnlockDisplay(cimg::X11attr().display);
8293 return *this;
8294 }
8296 template<typename T>
8297 const CImgDisplay& snapshot(CImg<T>& img) const {
8298 if (is_empty()) img.assign();
8299 else {
8300 img.assign(width,height,1,3);
8301 T
8302 *data1 = img.ptr(0,0,0,0),
8303 *data2 = img.ptr(0,0,0,1),
8304 *data3 = img.ptr(0,0,0,2);
8305 if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
8306 switch (cimg::X11attr().nb_bits) {
8307 case 8 : {
8308 unsigned char *ptrs = (unsigned char*)data;
8309 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8310 const unsigned char val = *(ptrs++);
8311 *(data1++) = val&0xe0;
8312 *(data2++) = (val&0x1c)<<3;
8313 *(data3++) = val<<6;
8314 }
8315 } break;
8316 case 16 : {
8317 unsigned char *ptrs = (unsigned char*)data;
8318 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8319 const unsigned char val0 = *(ptrs++), val1 = *(ptrs++);
8320 *(data1++) = val0&0xf8;
8321 *(data2++) = (val0<<5) | ((val1&0xe0)>>5);
8322 *(data3++) = val1<<3;
8323 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8324 const unsigned short val0 = *(ptrs++), val1 = *(ptrs++);
8325 *(data1++) = val1&0xf8;
8326 *(data2++) = (val1<<5) | ((val0&0xe0)>>5);
8327 *(data3++) = val0<<3;
8328 }
8329 } break;
8330 default : {
8331 unsigned char *ptrs = (unsigned char*)data;
8332 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8333 ++ptrs;
8334 *(data1++) = *(ptrs++);
8335 *(data2++) = *(ptrs++);
8336 *(data3++) = *(ptrs++);
8337 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8338 *(data3++) = *(ptrs++);
8339 *(data2++) = *(ptrs++);
8340 *(data1++) = *(ptrs++);
8341 ++ptrs;
8342 }
8343 }
8344 }
8345 }
8346 return *this;
8347 }
8349 // Windows-based display
8350 //-----------------------
8351 #elif cimg_display==2
8352 CLIENTCREATESTRUCT ccs;
8353 BITMAPINFO bmi;
8354 unsigned int *data;
8355 DEVMODE curr_mode;
8356 HWND window;
8357 HWND background_window;
8358 HDC hdc;
8359 HANDLE thread;
8360 HANDLE created;
8361 HANDLE mutex;
8362 bool mouse_tracking;
8363 bool visible_cursor;
8365 static int screen_dimx() {
8366 DEVMODE mode;
8367 mode.dmSize = sizeof(DEVMODE);
8368 mode.dmDriverExtra = 0;
8369 EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
8370 return mode.dmPelsWidth;
8371 }
8373 static int screen_dimy() {
8374 DEVMODE mode;
8375 mode.dmSize = sizeof(DEVMODE);
8376 mode.dmDriverExtra = 0;
8377 EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
8378 return mode.dmPelsHeight;
8379 }
8381 static void wait_all() {
8382 WaitForSingleObject(cimg::Win32attr().wait_event,INFINITE);
8383 }
8385 static LRESULT APIENTRY _handle_events(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
8386 #ifdef _WIN64
8387 CImgDisplay* disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA);
8388 #else
8389 CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
8390 #endif
8391 MSG st_msg;
8393 switch (msg) {
8394 case WM_CLOSE :
8395 disp->mouse_x = disp->mouse_y = -1;
8396 disp->window_x = disp->window_y = 0;
8397 if (disp->button) {
8398 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8399 disp->button = 0;
8400 }
8401 if (disp->key) {
8402 cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
8403 disp->key = 0;
8404 }
8405 if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
8406 disp->is_closed = true;
8407 ReleaseMutex(disp->mutex);
8408 ShowWindow(disp->window,SW_HIDE);
8409 disp->is_event = true;
8410 SetEvent(cimg::Win32attr().wait_event);
8411 return 0;
8412 case WM_SIZE : {
8413 while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
8414 WaitForSingleObject(disp->mutex,INFINITE);
8415 const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);
8416 if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
8417 disp->window_width = nw;
8418 disp->window_height = nh;
8419 disp->mouse_x = disp->mouse_y = -1;
8420 disp->is_resized = disp->is_event = true;
8421 SetEvent(cimg::Win32attr().wait_event);
8422 }
8423 ReleaseMutex(disp->mutex);
8424 } break;
8425 case WM_MOVE : {
8426 while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
8427 WaitForSingleObject(disp->mutex,INFINITE);
8428 const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));
8429 if (nx!=disp->window_x || ny!=disp->window_y) {
8430 disp->window_x = nx;
8431 disp->window_y = ny;
8432 disp->is_moved = disp->is_event = true;
8433 SetEvent(cimg::Win32attr().wait_event);
8434 }
8435 ReleaseMutex(disp->mutex);
8436 } break;
8437 case WM_PAINT :
8438 disp->paint();
8439 break;
8440 case WM_KEYDOWN :
8441 disp->update_iskey((unsigned int)wParam,true);
8442 if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
8443 disp->key = (unsigned int)wParam;
8444 if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
8445 disp->is_event = true;
8446 SetEvent(cimg::Win32attr().wait_event);
8447 break;
8448 case WM_MOUSEMOVE : {
8449 while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {}
8450 disp->mouse_x = LOWORD(lParam);
8451 disp->mouse_y = HIWORD(lParam);
8452 #if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT)
8453 if (!disp->mouse_tracking) {
8454 TRACKMOUSEEVENT tme;
8455 tme.cbSize = sizeof(TRACKMOUSEEVENT);
8456 tme.dwFlags = TME_LEAVE;
8457 tme.hwndTrack = disp->window;
8458 if (TrackMouseEvent(&tme)) disp->mouse_tracking = true;
8459 }
8460 #endif
8461 if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
8462 disp->mouse_x = disp->mouse_y = -1;
8463 disp->is_event = true;
8464 SetEvent(cimg::Win32attr().wait_event);
8465 } break;
8466 case WM_MOUSELEAVE : {
8467 disp->mouse_x = disp->mouse_y = -1;
8468 disp->mouse_tracking = false;
8469 } break;
8470 case WM_LBUTTONDOWN :
8471 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8472 disp->button|=1U;
8473 disp->is_event = true;
8474 SetEvent(cimg::Win32attr().wait_event);
8475 break;
8476 case WM_RBUTTONDOWN :
8477 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8478 disp->button|=2U;
8479 disp->is_event = true;
8480 SetEvent(cimg::Win32attr().wait_event);
8481 break;
8482 case WM_MBUTTONDOWN :
8483 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8484 disp->button|=4U;
8485 disp->is_event = true;
8486 SetEvent(cimg::Win32attr().wait_event);
8487 break;
8488 case 0x020A : // WM_MOUSEWHEEL:
8489 disp->wheel+=(int)((short)HIWORD(wParam))/120;
8490 disp->is_event = true;
8491 SetEvent(cimg::Win32attr().wait_event);
8492 case WM_KEYUP :
8493 disp->update_iskey((unsigned int)wParam,false);
8494 if (disp->key) { cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
8495 if (disp->released_key) cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
8496 disp->released_key = (unsigned int)wParam;
8497 disp->is_event = true;
8498 SetEvent(cimg::Win32attr().wait_event);
8499 break;
8500 case WM_LBUTTONUP :
8501 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8502 disp->button&=~1U;
8503 disp->is_event = true;
8504 SetEvent(cimg::Win32attr().wait_event);
8505 break;
8506 case WM_RBUTTONUP :
8507 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8508 disp->button&=~2U;
8509 disp->is_event = true;
8510 SetEvent(cimg::Win32attr().wait_event);
8511 break;
8512 case WM_MBUTTONUP :
8513 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
8514 disp->button&=~4U;
8515 disp->is_event = true;
8516 SetEvent(cimg::Win32attr().wait_event);
8517 break;
8518 case WM_SETCURSOR :
8519 if (disp->visible_cursor) ShowCursor(TRUE);
8520 else ShowCursor(FALSE);
8521 break;
8522 }
8523 return DefWindowProc(window,msg,wParam,lParam);
8524 }
8526 static DWORD WINAPI _events_thread(void* arg) {
8527 CImgDisplay *disp = (CImgDisplay*)(((void**)arg)[0]);
8528 const char *title = (const char*)(((void**)arg)[1]);
8529 MSG msg;
8530 delete[] (void**)arg;
8531 disp->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
8532 disp->bmi.bmiHeader.biWidth = disp->width;
8533 disp->bmi.bmiHeader.biHeight = -(int)disp->height;
8534 disp->bmi.bmiHeader.biPlanes = 1;
8535 disp->bmi.bmiHeader.biBitCount = 32;
8536 disp->bmi.bmiHeader.biCompression = BI_RGB;
8537 disp->bmi.bmiHeader.biSizeImage = 0;
8538 disp->bmi.bmiHeader.biXPelsPerMeter = 1;
8539 disp->bmi.bmiHeader.biYPelsPerMeter = 1;
8540 disp->bmi.bmiHeader.biClrUsed = 0;
8541 disp->bmi.bmiHeader.biClrImportant = 0;
8542 disp->data = new unsigned int[disp->width*disp->height];
8543 if (!disp->is_fullscreen) { // Normal window
8544 RECT rect;
8545 rect.left = rect.top = 0; rect.right = disp->width-1; rect.bottom = disp->height-1;
8546 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8547 const int border1 = (rect.right-rect.left+1-disp->width)/2, border2 = rect.bottom-rect.top+1-disp->height-border1;
8548 disp->window = CreateWindowA("MDICLIENT",title?title:" ",
8549 WS_OVERLAPPEDWINDOW | (disp->is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
8550 disp->width + 2*border1, disp->height + border1 + border2,
8551 0,0,0,&(disp->ccs));
8552 if (!disp->is_closed) {
8553 GetWindowRect(disp->window,&rect);
8554 disp->window_x = rect.left + border1;
8555 disp->window_y = rect.top + border2;
8556 } else disp->window_x = disp->window_y = 0;
8557 } else { // Fullscreen window
8558 const unsigned int sx = screen_dimx(), sy = screen_dimy();
8559 disp->window = CreateWindowA("MDICLIENT",title?title:" ",
8560 WS_POPUP | (disp->is_closed?0:WS_VISIBLE), (sx-disp->width)/2, (sy-disp->height)/2,
8561 disp->width,disp->height,0,0,0,&(disp->ccs));
8562 disp->window_x = disp->window_y = 0;
8563 }
8564 SetForegroundWindow(disp->window);
8565 disp->hdc = GetDC(disp->window);
8566 disp->window_width = disp->width;
8567 disp->window_height = disp->height;
8568 disp->flush();
8569 #ifdef _WIN64
8570 SetWindowLongPtr(disp->window,GWLP_USERDATA,(LONG_PTR)disp);
8571 SetWindowLongPtr(disp->window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
8572 #else
8573 SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
8574 SetWindowLong(disp->window,GWL_WNDPROC,(LONG)_handle_events);
8575 #endif
8576 SetEvent(disp->created);
8577 while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
8578 return 0;
8579 }
8581 CImgDisplay& _update_window_pos() {
8582 if (!is_closed) {
8583 RECT rect;
8584 rect.left = rect.top = 0; rect.right = width-1; rect.bottom = height-1;
8585 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8586 const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
8587 GetWindowRect(window,&rect);
8588 window_x = rect.left + border1;
8589 window_y = rect.top + border2;
8590 } else window_x = window_y = -1;
8591 return *this;
8592 }
8594 void _init_fullscreen() {
8595 background_window = 0;
8596 if (is_fullscreen && !is_closed) {
8597 DEVMODE mode;
8598 unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U;
8599 for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) {
8600 const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight;
8601 if (nw>=width && nh>=height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) {
8602 bestbpp = mode.dmBitsPerPel;
8603 ibest = imode;
8604 bw = nw; bh = nh;
8605 }
8606 }
8607 if (bestbpp) {
8608 curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0;
8609 EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&curr_mode);
8610 EnumDisplaySettings(0,ibest,&mode);
8611 ChangeDisplaySettings(&mode,0);
8612 } else curr_mode.dmSize = 0;
8614 const unsigned int sx = screen_dimx(), sy = screen_dimy();
8615 if (sx!=width || sy!=height) {
8616 CLIENTCREATESTRUCT background_ccs;
8617 background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);
8618 SetForegroundWindow(background_window);
8619 }
8620 } else curr_mode.dmSize = 0;
8621 }
8623 void _desinit_fullscreen() {
8624 if (is_fullscreen) {
8625 if (background_window) DestroyWindow(background_window);
8626 background_window = 0;
8627 if (curr_mode.dmSize) ChangeDisplaySettings(&curr_mode,0);
8628 is_fullscreen = false;
8629 }
8630 }
8632 CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
8633 const unsigned int normalization_type=3,
8634 const bool fullscreen_flag=false, const bool closed_flag=false) {
8636 // Allocate space for window title
8637 const int s = cimg::strlen(ptitle)+1;
8638 char *tmp_title = s?new char[s]:0;
8639 if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
8641 // Destroy previous window if existing
8642 if (!is_empty()) assign();
8644 // Set display variables
8645 width = cimg::min(dimw,(unsigned int)screen_dimx());
8646 height = cimg::min(dimh,(unsigned int)screen_dimy());
8647 normalization = normalization_type<4?normalization_type:3;
8648 is_fullscreen = fullscreen_flag;
8649 window_x = window_y = 0;
8650 is_closed = closed_flag;
8651 visible_cursor = true;
8652 mouse_tracking = false;
8653 title = tmp_title;
8654 flush();
8655 if (is_fullscreen) _init_fullscreen();
8657 // Create event thread
8658 void *arg = (void*)(new void*[2]);
8659 ((void**)arg)[0]=(void*)this;
8660 ((void**)arg)[1]=(void*)title;
8661 unsigned long ThreadID = 0;
8662 mutex = CreateMutex(0,FALSE,0);
8663 created = CreateEvent(0,FALSE,FALSE,0);
8664 thread = CreateThread(0,0,_events_thread,arg,0,&ThreadID);
8665 WaitForSingleObject(created,INFINITE);
8666 return *this;
8667 }
8669 CImgDisplay& assign() {
8670 if (is_empty()) return *this;
8671 DestroyWindow(window);
8672 TerminateThread(thread,0);
8673 if (data) delete[] data;
8674 if (title) delete[] title;
8675 if (is_fullscreen) _desinit_fullscreen();
8676 width = height = normalization = window_width = window_height = 0;
8677 window_x = window_y = 0;
8678 is_fullscreen = false;
8679 is_closed = true;
8680 min = max = 0;
8681 title = 0;
8682 flush();
8683 return *this;
8684 }
8686 CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
8687 const unsigned int normalization_type=3,
8688 const bool fullscreen_flag=false, const bool closed_flag=false) {
8689 if (!dimw || !dimh) return assign();
8690 _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
8691 min = max = 0;
8692 cimg_std::memset(data,0,sizeof(unsigned int)*width*height);
8693 return paint();
8694 }
8696 template<typename T>
8697 CImgDisplay& assign(const CImg<T>& img, const char *title=0,
8698 const unsigned int normalization_type=3,
8699 const bool fullscreen_flag=false, const bool closed_flag=false) {
8700 if (!img) return assign();
8701 CImg<T> tmp;
8702 const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
8703 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
8704 if (normalization==2) min = (float)nimg.minmax(max);
8705 return display(nimg);
8706 }
8708 template<typename T>
8709 CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
8710 const unsigned int normalization_type=3,
8711 const bool fullscreen_flag=false, const bool closed_flag=false) {
8712 if (!list) return assign();
8713 CImg<T> tmp;
8714 const CImg<T> img = list.get_append('x','p'),
8715 &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
8716 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
8717 if (normalization==2) min = (float)nimg.minmax(max);
8718 return display(nimg);
8719 }
8721 CImgDisplay& assign(const CImgDisplay& win) {
8722 if (!win) return assign();
8723 _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
8724 cimg_std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
8725 return paint();
8726 }
8728 CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
8729 if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
8730 if (is_empty()) return assign(nwidth,nheight);
8731 const unsigned int
8732 tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100),
8733 tmpdimy=(nheight>0)?nheight:(-nheight*height/100),
8734 dimx = tmpdimx?tmpdimx:1,
8735 dimy = tmpdimy?tmpdimy:1;
8736 if (window_width!=dimx || window_height!=dimy) {
8737 RECT rect; rect.left = rect.top = 0; rect.right = dimx-1; rect.bottom = dimy-1;
8738 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8739 const int cwidth = rect.right-rect.left+1, cheight = rect.bottom-rect.top+1;
8740 SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
8741 }
8742 if (width!=dimx || height!=dimy) {
8743 unsigned int *ndata = new unsigned int[dimx*dimy];
8744 if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
8745 else cimg_std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
8746 delete[] data;
8747 data = ndata;
8748 bmi.bmiHeader.biWidth = dimx;
8749 bmi.bmiHeader.biHeight = -(int)dimy;
8750 width = dimx;
8751 height = dimy;
8752 }
8753 window_width = dimx; window_height = dimy;
8754 is_resized = false;
8755 if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
8756 if (redraw) return paint();
8757 return *this;
8758 }
8760 CImgDisplay& toggle_fullscreen(const bool redraw=true) {
8761 if (is_empty()) return *this;
8762 if (redraw) {
8763 const unsigned int bufsize = width*height*4;
8764 void *odata = cimg_std::malloc(bufsize);
8765 cimg_std::memcpy(odata,data,bufsize);
8766 assign(width,height,title,normalization,!is_fullscreen,false);
8767 cimg_std::memcpy(data,odata,bufsize);
8768 cimg_std::free(odata);
8769 return paint();
8770 }
8771 return assign(width,height,title,normalization,!is_fullscreen,false);
8772 }
8774 CImgDisplay& show() {
8775 if (is_empty()) return *this;
8776 if (is_closed) {
8777 is_closed = false;
8778 if (is_fullscreen) _init_fullscreen();
8779 ShowWindow(window,SW_SHOW);
8780 _update_window_pos();
8781 }
8782 return paint();
8783 }
8785 CImgDisplay& close() {
8786 if (is_empty()) return *this;
8787 if (!is_closed && !is_fullscreen) {
8788 if (is_fullscreen) _desinit_fullscreen();
8789 ShowWindow(window,SW_HIDE);
8790 is_closed = true;
8791 window_x = window_y = 0;
8792 }
8793 return *this;
8794 }
8796 CImgDisplay& move(const int posx, const int posy) {
8797 if (is_empty()) return *this;
8798 if (!is_fullscreen) {
8799 RECT rect; rect.left = rect.top = 0; rect.right=window_width-1; rect.bottom=window_height-1;
8800 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
8801 const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
8802 SetWindowPos(window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
8803 } else SetWindowPos(window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
8804 window_x = posx;
8805 window_y = posy;
8806 is_moved = false;
8807 return show();
8808 }
8810 CImgDisplay& show_mouse() {
8811 if (is_empty()) return *this;
8812 visible_cursor = true;
8813 ShowCursor(TRUE);
8814 SendMessage(window,WM_SETCURSOR,0,0);
8815 return *this;
8816 }
8818 CImgDisplay& hide_mouse() {
8819 if (is_empty()) return *this;
8820 visible_cursor = false;
8821 ShowCursor(FALSE);
8822 SendMessage(window,WM_SETCURSOR,0,0);
8823 return *this;
8824 }
8826 CImgDisplay& set_mouse(const int posx, const int posy) {
8827 if (!is_closed && posx>=0 && posy>=0) {
8828 _update_window_pos();
8829 const int res = (int)SetCursorPos(window_x+posx,window_y+posy);
8830 if (res) { mouse_x = posx; mouse_y = posy; }
8831 }
8832 return *this;
8833 }
8835 CImgDisplay& set_title(const char *format, ...) {
8836 if (is_empty()) return *this;
8837 char tmp[1024] = {0};
8838 va_list ap;
8839 va_start(ap, format);
8840 cimg_std::vsprintf(tmp,format,ap);
8841 va_end(ap);
8842 if (title) delete[] title;
8843 const int s = cimg::strlen(tmp)+1;
8844 title = new char[s];
8845 cimg_std::memcpy(title,tmp,s*sizeof(char));
8846 SetWindowTextA(window, tmp);
8847 return *this;
8848 }
8850 template<typename T>
8851 CImgDisplay& display(const CImg<T>& img) {
8852 if (img.is_empty())
8853 throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
8854 if (is_empty()) assign(img.width,img.height);
8855 return render(img).paint();
8856 }
8858 CImgDisplay& paint() {
8859 if (!is_closed) {
8860 WaitForSingleObject(mutex,INFINITE);
8861 SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
8862 ReleaseMutex(mutex);
8863 }
8864 return *this;
8865 }
8867 template<typename T>
8868 CImgDisplay& render(const CImg<T>& img) {
8869 if (is_empty()) return *this;
8870 if (!img)
8871 throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
8872 img.width,img.height,img.depth,img.dim,img.data);
8873 if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
8875 const T
8876 *data1 = img.data,
8877 *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
8878 *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
8880 WaitForSingleObject(mutex,INFINITE);
8881 unsigned int
8882 *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
8883 *ptrd = ndata;
8885 if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
8886 min = max = 0;
8887 switch (img.dim) {
8888 case 1 : {
8889 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8890 const unsigned char val = (unsigned char)*(data1++);
8891 *(ptrd++) = (val<<16) | (val<<8) | val;
8892 }} break;
8893 case 2 : {
8894 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8895 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
8896 } break;
8897 default : {
8898 for (unsigned int xy = img.width*img.height; xy>0; --xy)
8899 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
8900 }
8901 }
8902 } else {
8903 if (normalization==3) {
8904 if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
8905 else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
8906 } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
8907 const float delta = max-min, mm = delta?delta:1.0f;
8908 switch (img.dim) {
8909 case 1 : {
8910 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8911 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
8912 *(ptrd++) = (val<<16) | (val<<8) | val;
8913 }} break;
8914 case 2 : {
8915 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8916 const unsigned char
8917 R = (unsigned char)(255*(*(data1++)-min)/mm),
8918 G = (unsigned char)(255*(*(data2++)-min)/mm);
8919 *(ptrd++) = (R<<16) | (G<<8);
8920 }} break;
8921 default : {
8922 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8923 const unsigned char
8924 R = (unsigned char)(255*(*(data1++)-min)/mm),
8925 G = (unsigned char)(255*(*(data2++)-min)/mm),
8926 B = (unsigned char)(255*(*(data3++)-min)/mm);
8927 *(ptrd++) = (R<<16) | (G<<8) | B;
8928 }}
8929 }
8930 }
8931 if (ndata!=data) { _render_resize(ndata,img.width,img.height,data,width,height); delete[] ndata; }
8932 ReleaseMutex(mutex);
8933 return *this;
8934 }
8936 template<typename T>
8937 const CImgDisplay& snapshot(CImg<T>& img) const {
8938 if (is_empty()) img.assign();
8939 else {
8940 img.assign(width,height,1,3);
8941 T
8942 *data1 = img.ptr(0,0,0,0),
8943 *data2 = img.ptr(0,0,0,1),
8944 *data3 = img.ptr(0,0,0,2);
8945 unsigned int *ptrs = data;
8946 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
8947 const unsigned int val = *(ptrs++);
8948 *(data1++) = (unsigned char)(val>>16);
8949 *(data2++) = (unsigned char)((val>>8)&0xFF);
8950 *(data3++) = (unsigned char)(val&0xFF);
8951 }
8952 }
8953 return *this;
8954 }
8956 // MacOSX - Carbon-based display
8957 //-------------------------------
8958 // (Code by Adrien Reboisson && Romain Blei, supervised by Jean-Marie Favreau)
8959 //
8960 #elif cimg_display==3
8961 unsigned int *data; // The bits of the picture
8962 WindowRef carbonWindow; // The opaque carbon window struct associated with the display
8963 MPCriticalRegionID paintCriticalRegion; // Critical section used when drawing
8964 CGColorSpaceRef csr; // Needed for painting
8965 CGDataProviderRef dataProvider; // Needed for painting
8966 CGImageRef imageRef; // The image
8967 UInt32 lastKeyModifiers; // Buffer storing modifiers state
8969 // Define the kind of the queries which can be serialized using the event thread.
8970 typedef enum {
8971 COM_CREATEWINDOW = 0, // Create window query
8972 COM_RELEASEWINDOW, // Release window query
8973 COM_SHOWWINDOW, // Show window query
8974 COM_HIDEWINDOW, // Hide window query
8975 COM_SHOWMOUSE, // Show mouse query
8976 COM_HIDEMOUSE, // Hide mouse query
8977 COM_RESIZEWINDOW, // Resize window query
8978 COM_MOVEWINDOW, // Move window query
8979 COM_SETTITLE, // Set window title query
8980 COM_SETMOUSEPOS // Set cursor position query
8981 } CImgCarbonQueryKind;
8983 // The query destructor send to the event thread.
8984 struct CbSerializedQuery {
8985 CImgDisplay* sender; // Query's sender
8986 CImgCarbonQueryKind kind; // The kind of the query sent to the background thread
8987 short x, y; // X:Y values for move/resize operations
8988 char *c; // Char values for window title
8989 bool createFullScreenWindow; // Boolean value used for full-screen window creation
8990 bool createClosedWindow; // Boolean value used for closed-window creation
8991 bool update; // Boolean value used for resize
8992 bool success; // Succes or failure of the message, used as return value
8993 CbSerializedQuery(CImgDisplay *s, CImgCarbonQueryKind k):sender(s),kind(k),success(false) {};
8995 inline static CbSerializedQuery BuildReleaseWindowQuery(CImgDisplay* sender) {
8996 return CbSerializedQuery(sender, COM_RELEASEWINDOW);
8997 }
8998 inline static CbSerializedQuery BuildCreateWindowQuery(CImgDisplay* sender, const bool fullscreen, const bool closed) {
8999 CbSerializedQuery q(sender, COM_CREATEWINDOW);
9000 q.createFullScreenWindow = fullscreen;
9001 q.createClosedWindow = closed;
9002 return q;
9003 }
9004 inline static CbSerializedQuery BuildShowWindowQuery(CImgDisplay* sender) {
9005 return CbSerializedQuery(sender, COM_SHOWWINDOW);
9006 }
9007 inline static CbSerializedQuery BuildHideWindowQuery(CImgDisplay* sender) {
9008 return CbSerializedQuery(sender, COM_HIDEWINDOW);
9009 }
9010 inline static CbSerializedQuery BuildShowMouseQuery(CImgDisplay* sender) {
9011 return CbSerializedQuery(sender, COM_SHOWMOUSE);
9012 }
9013 inline static CbSerializedQuery BuildHideMouseQuery(CImgDisplay* sender) {
9014 return CbSerializedQuery(sender, COM_HIDEMOUSE);
9015 }
9016 inline static CbSerializedQuery BuildResizeWindowQuery(CImgDisplay* sender, const int x, const int y, bool update) {
9017 CbSerializedQuery q(sender, COM_RESIZEWINDOW);
9018 q.x = x, q.y = y;
9019 q.update = update;
9020 return q;
9021 }
9022 inline static CbSerializedQuery BuildMoveWindowQuery(CImgDisplay* sender, const int x, const int y) {
9023 CbSerializedQuery q(sender, COM_MOVEWINDOW);
9024 q.x = x, q.y = y;
9025 return q;
9026 }
9027 inline static CbSerializedQuery BuildSetWindowTitleQuery(CImgDisplay* sender, char* c) {
9028 CbSerializedQuery q(sender, COM_SETTITLE);
9029 q.c = c;
9030 return q;
9031 }
9032 inline static CbSerializedQuery BuildSetWindowPosQuery(CImgDisplay* sender, const int x, const int y) {
9033 CbSerializedQuery q(sender, COM_SETMOUSEPOS);
9034 q.x = x, q.y = y;
9035 return q;
9036 }
9037 };
9039 // Send a serialized query in a synchroneous way.
9040 // @param c Application Carbon global settings.
9041 // @param m The query to send.
9042 // @result Success/failure of the operation returned by the event thread.
9043 bool _CbSendMsg(cimg::CarbonInfo& c, CbSerializedQuery m) {
9044 MPNotifyQueue(c.com_queue,&m,0,0); // Send the given message
9045 MPWaitOnSemaphore(c.sync_event,kDurationForever); // Wait end of processing notification
9046 return m.success;
9047 }
9049 // Free the window attached to the current display.
9050 // @param c Application Carbon global settings.
9051 // @result Success/failure of the operation.
9052 bool _CbFreeAttachedWindow(cimg::CarbonInfo& c) {
9053 if (!_CbSendMsg(c, CbSerializedQuery::BuildReleaseWindowQuery(this))) // Ask the main thread to free the given window
9054 throw CImgDisplayException("Cannot release window associated with the current display.");
9055 // If a window existed, ask to release it
9056 MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
9057 --c.windowCount; //Decrement the window count
9058 MPExitCriticalRegion(c.windowListCR); // Unlock the list
9059 return c.windowCount == 0;
9060 }
9062 // Create the window attached to the current display.
9063 // @param c Application Carbon global settings.
9064 // @param title The window title, if any.
9065 // @param fullscreen Shoud we start in fullscreen mode ?
9066 // @param create_closed If true, the window is created but not displayed.
9067 // @result Success/failure of the operation.
9068 void _CbCreateAttachedWindow(cimg::CarbonInfo& c, const char* title, const bool fullscreen, const bool create_closed) {
9069 if (!_CbSendMsg(c,CbSerializedQuery::BuildCreateWindowQuery(this,fullscreen,create_closed))) // Ask the main thread to create the window
9070 throw CImgDisplayException("Cannot create the window associated with the current display.");
9071 if (title) set_title(title); // Set the title, if any
9072 // Now we can register the window
9073 MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
9074 ++c.windowCount; //Increment the window count
9075 MPExitCriticalRegion(c.windowListCR); // Unlock the list
9076 }
9078 // Destroy graphic objects previously allocated. We free the image, the data provider, then the colorspace.
9079 void _CbFinalizeGraphics() {
9080 CGImageRelease (imageRef); // Release the picture
9081 CGDataProviderRelease(dataProvider); // Release the DP
9082 CGColorSpaceRelease(csr); // Free the cs
9083 }
9085 // Create graphic objects associated to a display. We have to create a colormap, a data provider, and the image.
9086 void _CbInitializeGraphics() {
9087 csr = CGColorSpaceCreateDeviceRGB(); // Create the color space first
9088 if (!csr)
9089 throw CImgDisplayException("CGColorSpaceCreateDeviceRGB() failed.");
9090 // Create the DP
9091 dataProvider = CGDataProviderCreateWithData(0,data,height*width*sizeof(unsigned int),0);
9092 if (!dataProvider)
9093 throw CImgDisplayException("CGDataProviderCreateWithData() failed.");
9094 // ... and finally the image.
9095 if (cimg::endianness())
9096 imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
9097 kCGImageAlphaNoneSkipFirst,dataProvider,0,false,kCGRenderingIntentDefault);
9098 else
9099 imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
9100 kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,dataProvider,0,false,kCGRenderingIntentDefault);
9101 if (!imageRef)
9102 throw CImgDisplayException("CGImageCreate() failed.");
9103 }
9105 // Reinit graphic objects. Free them, then reallocate all.
9106 // This is used when image bounds are changed or when data source get invalid.
9107 void _CbReinitGraphics() {
9108 MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
9109 _CbFinalizeGraphics();
9110 _CbInitializeGraphics();
9111 MPExitCriticalRegion(paintCriticalRegion);
9112 }
9114 // Convert a point having global coordonates into the window coordonates.
9115 // We use this function to replace the deprecated GlobalToLocal QuickDraw API.
9116 // @param mouseEvent The mouse event which triggered the event handler.
9117 // @param window The window where the event occured.
9118 // @param point The modified point struct.
9119 // @result True if the point struct has been converted successfully.
9120 static bool _CbToLocalPointFromMouseEvent(EventRef mouseEvent, WindowRef window, HIPoint* point) {
9121 Rect bounds;
9122 if (GetWindowBounds(window,kWindowStructureRgn,&bounds)==noErr) {
9123 point->x -= bounds.left;
9124 point->y -= bounds.top;
9125 HIViewRef view = NULL;
9126 if (HIViewGetViewForMouseEvent(HIViewGetRoot(window),mouseEvent,&view)==noErr)
9127 return HIViewConvertPoint(point, NULL, view) == noErr;
9128 }
9129 return false;
9130 }
9132 static int screen_dimx() {
9133 return CGDisplayPixelsWide(kCGDirectMainDisplay);
9134 }
9136 static int screen_dimy() {
9137 return CGDisplayPixelsHigh(kCGDirectMainDisplay);
9138 }
9140 CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
9141 const unsigned int normalization_type=3,
9142 const bool fullscreen_flag=false, const bool closed_flag=false) {
9143 if (!dimw || !dimh) return assign();
9144 _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
9145 min = max = 0;
9146 cimg_std::memset(data,0,sizeof(unsigned int)*width*height);
9147 return paint();
9148 }
9150 template<typename T>
9151 CImgDisplay& assign(const CImg<T>& img, const char *title=0,
9152 const unsigned int normalization_type=3,
9153 const bool fullscreen_flag=false, const bool closed_flag=false) {
9154 if (!img) return assign();
9155 CImg<T> tmp;
9156 const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
9157 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
9158 if (normalization==2) min = (float)nimg.minmax(max);
9159 return display(nimg);
9160 }
9162 template<typename T>
9163 CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
9164 const unsigned int normalization_type=3,
9165 const bool fullscreen_flag=false, const bool closed_flag=false) {
9166 if (!list) return assign();
9167 CImg<T> tmp;
9168 const CImg<T> img = list.get_append('x','p'),
9169 &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
9170 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
9171 if (normalization==2) min = (float)nimg.minmax(max);
9172 return display(nimg);
9173 }
9175 CImgDisplay& assign(const CImgDisplay &win) {
9176 if (!win) return assign();
9177 _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
9178 cimg_std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
9179 return paint();
9180 }
9182 template<typename T>
9183 CImgDisplay& display(const CImg<T>& img) {
9184 if (is_empty()) assign(img.width,img.height);
9185 return render(img).paint();
9186 }
9188 CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
9189 if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
9190 if (is_empty()) return assign(nwidth,nheight);
9191 const unsigned int
9192 tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
9193 tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
9194 dimx = tmpdimx?tmpdimx:1,
9195 dimy = tmpdimy?tmpdimy:1;
9196 cimg::CarbonInfo& c = cimg::CarbonAttr();
9198 if ((window_width!=dimx || window_height!=dimy) &&
9199 !_CbSendMsg(c,CbSerializedQuery::BuildResizeWindowQuery(this,dimx,dimy,redraw)))
9200 throw CImgDisplayException("CImgDisplay::resize() : Cannot resize the window associated to the current display.");
9202 if (width!=dimx || height!=dimy) {
9203 unsigned int *ndata = new unsigned int[dimx*dimy];
9204 if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
9205 else cimg_std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
9206 unsigned int const* old_data = data;
9207 data = ndata;
9208 delete[] old_data;
9209 _CbReinitGraphics();
9210 }
9211 window_width = width = dimx; window_height = height = dimy;
9212 is_resized = false;
9213 if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
9214 if (redraw) return paint();
9215 return *this;
9216 }
9218 CImgDisplay& move(const int posx, const int posy) {
9219 if (is_empty()) return *this;
9220 if (!is_fullscreen) {
9221 // If the operation succeeds, window_x and window_y are updated by the event thread
9222 cimg::CarbonInfo& c = cimg::CarbonAttr();
9223 // Send the query
9224 if (!_CbSendMsg(c,CbSerializedQuery::BuildMoveWindowQuery(this,posx,posy)))
9225 throw CImgDisplayException("CImgDisplay::move() : Cannot move the window associated to the current display.");
9226 }
9227 return show();
9228 }
9230 CImgDisplay& set_mouse(const int posx, const int posy) {
9231 if (!is_closed && posx>=0 && posy>=0) {
9232 // If the operation succeeds, mouse_x and mouse_y are updated by the event thread
9233 cimg::CarbonInfo& c = cimg::CarbonAttr();
9234 // Send the query
9235 if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowPosQuery(this,posx,posy)))
9236 throw CImgDisplayException("CImgDisplay::set_mouse() : Cannot set the mouse position to the current display.");
9237 }
9238 return *this;
9239 }
9241 CImgDisplay& hide_mouse() {
9242 if (is_empty()) return *this;
9243 cimg::CarbonInfo& c = cimg::CarbonAttr();
9244 // Send the query
9245 if (!_CbSendMsg(c,CbSerializedQuery::BuildHideMouseQuery(this)))
9246 throw CImgDisplayException("CImgDisplay::hide_mouse() : Cannot hide the mouse associated to the current display.");
9247 return *this;
9248 }
9250 CImgDisplay& show_mouse() {
9251 if (is_empty()) return *this;
9252 cimg::CarbonInfo& c = cimg::CarbonAttr();
9253 // Send the query
9254 if (!_CbSendMsg(c,CbSerializedQuery::BuildShowMouseQuery(this)))
9255 throw CImgDisplayException("CImgDisplay::show_mouse() : Cannot show the mouse associated to the current display.");
9256 return *this;
9257 }
9259 static void wait_all() {
9260 cimg::CarbonInfo& c = cimg::CarbonAttr();
9261 MPWaitOnSemaphore(c.wait_event,kDurationForever);
9262 }
9264 CImgDisplay& show() {
9265 if (is_empty()) return *this;
9266 if (is_closed) {
9267 cimg::CarbonInfo& c = cimg::CarbonAttr();
9268 if (!_CbSendMsg(c,CbSerializedQuery::BuildShowWindowQuery(this)))
9269 throw CImgDisplayException("CImgDisplay::show() : Cannot show the window associated to the current display.");
9270 }
9271 return paint();
9272 }
9274 CImgDisplay& close() {
9275 if (is_empty()) return *this;
9276 if (!is_closed && !is_fullscreen) {
9277 cimg::CarbonInfo& c = cimg::CarbonAttr();
9278 // If the operation succeeds, window_x and window_y are updated on the event thread
9279 if (!_CbSendMsg(c,CbSerializedQuery::BuildHideWindowQuery(this)))
9280 throw CImgDisplayException("CImgDisplay::close() : Cannot hide the window associated to the current display.");
9281 }
9282 return *this;
9283 }
9285 CImgDisplay& set_title(const char *format, ...) {
9286 if (is_empty()) return *this;
9287 char tmp[1024] = {0};
9288 va_list ap;
9289 va_start(ap, format);
9290 cimg_std::vsprintf(tmp,format,ap);
9291 va_end(ap);
9292 if (title) delete[] title;
9293 const int s = cimg::strlen(tmp)+1;
9294 title = new char[s];
9295 cimg_std::memcpy(title,tmp,s*sizeof(char));
9296 cimg::CarbonInfo& c = cimg::CarbonAttr();
9297 if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowTitleQuery(this,tmp)))
9298 throw CImgDisplayException("CImgDisplay::set_title() : Cannot set the window title associated to the current display.");
9299 return *this;
9300 }
9302 CImgDisplay& paint() {
9303 if (!is_closed) {
9304 MPEnterCriticalRegion(paintCriticalRegion,kDurationForever);
9305 CGrafPtr portPtr = GetWindowPort(carbonWindow);
9306 CGContextRef currentContext = 0;
9307 QDBeginCGContext(portPtr,¤tContext);
9308 CGContextSetRGBFillColor(currentContext,255,255,255,255);
9309 CGContextFillRect(currentContext,CGRectMake(0,0,window_width,window_height));
9310 CGContextDrawImage(currentContext,CGRectMake(0,int(window_height-height)<0?0:window_height-height,width,height),imageRef);
9311 CGContextFlush(currentContext);
9312 QDEndCGContext(portPtr, ¤tContext);
9313 MPExitCriticalRegion(paintCriticalRegion);
9314 }
9315 return *this;
9316 }
9318 template<typename T>
9319 CImgDisplay& render(const CImg<T>& img) {
9320 if (is_empty()) return *this;
9321 if (!img)
9322 throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
9323 img.width,img.height,img.depth,img.dim,img.data);
9324 if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
9325 const T
9326 *data1 = img.data,
9327 *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
9328 *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
9329 MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
9330 unsigned int
9331 *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
9332 *ptrd = ndata;
9333 if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
9334 min = max = 0;
9335 for (unsigned int xy = img.width*img.height; xy>0; --xy)
9336 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
9337 } else {
9338 if (normalization==3) {
9339 if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
9340 else {
9341 min = (float)cimg::type<T>::min();
9342 max = (float)cimg::type<T>::max();
9343 }
9344 } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
9345 const float delta = max-min, mm = delta?delta:1.0f;
9346 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
9347 const unsigned char
9348 R = (unsigned char)(255*(*(data1++)-min)/mm),
9349 G = (unsigned char)(255*(*(data2++)-min)/mm),
9350 B = (unsigned char)(255*(*(data3++)-min)/mm);
9351 *(ptrd++) = (R<<16) | (G<<8) | (B);
9352 }
9353 }
9354 if (ndata!=data) {
9355 _render_resize(ndata,img.width,img.height,data,width,height);
9356 delete[] ndata;
9357 }
9358 MPExitCriticalRegion(paintCriticalRegion);
9359 return *this;
9360 }
9362 template<typename T>
9363 const CImgDisplay& snapshot(CImg<T>& img) const {
9364 if (is_empty()) img.assign();
9365 else {
9366 img.assign(width,height,1,3);
9367 T
9368 *data1 = img.ptr(0,0,0,0),
9369 *data2 = img.ptr(0,0,0,1),
9370 *data3 = img.ptr(0,0,0,2);
9371 unsigned int *ptrs = data;
9372 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
9373 const unsigned int val = *(ptrs++);
9374 *(data1++) = (unsigned char)(val>>16);
9375 *(data2++) = (unsigned char)((val>>8)&0xFF);
9376 *(data3++) = (unsigned char)(val&0xFF);
9377 }
9378 }
9379 return *this;
9380 }
9382 CImgDisplay& toggle_fullscreen(const bool redraw=true) {
9383 if (is_empty()) return *this;
9384 if (redraw) {
9385 const unsigned int bufsize = width*height*4;
9386 void *odata = cimg_std::malloc(bufsize);
9387 cimg_std::memcpy(odata,data,bufsize);
9388 assign(width,height,title,normalization,!is_fullscreen,false);
9389 cimg_std::memcpy(data,odata,bufsize);
9390 cimg_std::free(odata);
9391 return paint();
9392 }
9393 return assign(width,height,title,normalization,!is_fullscreen,false);
9394 }
9396 static OSStatus CarbonEventHandler(EventHandlerCallRef myHandler, EventRef theEvent, void* userData) {
9397 OSStatus result = eventNotHandledErr;
9398 CImgDisplay* disp = (CImgDisplay*) userData;
9399 (void)myHandler; // Avoid "unused parameter"
9400 cimg::CarbonInfo& c = cimg::CarbonAttr();
9401 // Gets the associated display
9402 if (disp) {
9403 // Window events are always handled
9404 if (GetEventClass(theEvent)==kEventClassWindow) switch (GetEventKind (theEvent)) {
9405 case kEventWindowClose :
9406 disp->mouse_x = disp->mouse_y = -1;
9407 disp->window_x = disp->window_y = 0;
9408 if (disp->button) {
9409 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
9410 disp->button = 0;
9411 }
9412 if (disp->key) {
9413 cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
9414 disp->key = 0;
9415 }
9416 if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
9417 disp->is_closed = true;
9418 HideWindow(disp->carbonWindow);
9419 disp->is_event = true;
9420 MPSignalSemaphore(c.wait_event);
9421 result = noErr;
9422 break;
9423 // There is a lot of case where we have to redraw our window
9424 case kEventWindowBoundsChanging :
9425 case kEventWindowResizeStarted :
9426 case kEventWindowCollapsed : //Not sure it's really needed :-)
9427 break;
9428 case kEventWindowZoomed :
9429 case kEventWindowExpanded :
9430 case kEventWindowResizeCompleted : {
9431 MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
9432 // Now we retrieve the new size of the window
9433 Rect newContentRect;
9434 GetWindowBounds(disp->carbonWindow,kWindowContentRgn,&newContentRect);
9435 const unsigned int
9436 nw = (unsigned int)(newContentRect.right - newContentRect.left),
9437 nh = (unsigned int)(newContentRect.bottom - newContentRect.top);
9439 // Then we update CImg internal settings
9440 if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
9441 disp->window_width = nw;
9442 disp->window_height = nh;
9443 disp->mouse_x = disp->mouse_y = -1;
9444 disp->is_resized = true;
9445 }
9446 disp->is_event = true;
9447 MPExitCriticalRegion(disp->paintCriticalRegion);
9448 disp->paint(); // Coords changed, must update the screen
9449 MPSignalSemaphore(c.wait_event);
9450 result = noErr;
9451 } break;
9452 case kEventWindowDragStarted :
9453 case kEventWindowDragCompleted : {
9454 MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
9455 // Now we retrieve the new size of the window
9456 Rect newContentRect ;
9457 GetWindowBounds(disp->carbonWindow,kWindowStructureRgn,&newContentRect);
9458 const int nx = (int)(newContentRect.left), ny = (int)(newContentRect.top);
9459 // Then we update CImg internal settings
9460 if (nx!=disp->window_x || ny!=disp->window_y) {
9461 disp->window_x = nx;
9462 disp->window_y = ny;
9463 disp->is_moved = true;
9464 }
9465 disp->is_event = true;
9466 MPExitCriticalRegion(disp->paintCriticalRegion);
9467 disp->paint(); // Coords changed, must update the screen
9468 MPSignalSemaphore(c.wait_event);
9469 result = noErr;
9470 } break;
9471 case kEventWindowPaint :
9472 disp->paint();
9473 break;
9474 }
9476 switch (GetEventClass(theEvent)) {
9477 case kEventClassKeyboard : {
9478 if (GetEventKind(theEvent)==kEventRawKeyModifiersChanged) {
9479 // Apple has special keys named "notifiers", we have to convert this (exotic ?) key handling into the regular CImg processing.
9480 UInt32 newModifiers;
9481 if (GetEventParameter(theEvent,kEventParamKeyModifiers,typeUInt32,0,sizeof(UInt32),0,&newModifiers)==noErr) {
9482 int newKeyCode = -1;
9483 UInt32 changed = disp->lastKeyModifiers^newModifiers;
9484 // Find what changed here
9485 if ((changed & rightShiftKey)!=0) newKeyCode = cimg::keySHIFTRIGHT;
9486 if ((changed & shiftKey)!=0) newKeyCode = cimg::keySHIFTLEFT;
9488 // On the Mac, the "option" key = the ALT key
9489 if ((changed & (optionKey | rightOptionKey))!=0) newKeyCode = cimg::keyALTGR;
9490 if ((changed & controlKey)!=0) newKeyCode = cimg::keyCTRLLEFT;
9491 if ((changed & rightControlKey)!=0) newKeyCode = cimg::keyCTRLRIGHT;
9492 if ((changed & cmdKey)!=0) newKeyCode = cimg::keyAPPLEFT;
9493 if ((changed & alphaLock)!=0) newKeyCode = cimg::keyCAPSLOCK;
9494 if (newKeyCode != -1) { // Simulate keystroke
9495 if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
9496 disp->key = (int)newKeyCode;
9497 }
9498 disp->lastKeyModifiers = newModifiers; // Save current state
9499 }
9500 disp->is_event = true;
9501 MPSignalSemaphore(c.wait_event);
9502 }
9503 if (GetEventKind(theEvent)==kEventRawKeyDown || GetEventKind(theEvent)==kEventRawKeyRepeat) {
9504 char keyCode;
9505 if (GetEventParameter(theEvent,kEventParamKeyMacCharCodes,typeChar,0,sizeof(keyCode),0,&keyCode)==noErr) {
9506 disp->update_iskey((unsigned int)keyCode,true);
9507 if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
9508 disp->key = (unsigned int)keyCode;
9509 if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
9510 }
9511 disp->is_event = true;
9512 MPSignalSemaphore(c.wait_event);
9513 }
9514 } break;
9516 case kEventClassMouse :
9517 switch (GetEventKind(theEvent)) {
9518 case kEventMouseDragged :
9519 // When you push the main button on the Apple mouse while moving it, you got NO kEventMouseMoved msg,
9520 // but a kEventMouseDragged one. So we merge them here.
9521 case kEventMouseMoved :
9522 HIPoint point;
9523 if (GetEventParameter(theEvent,kEventParamMouseLocation,typeHIPoint,0,sizeof(point),0,&point)==noErr) {
9524 if (_CbToLocalPointFromMouseEvent(theEvent,disp->carbonWindow,&point)) {
9525 disp->mouse_x = (int)point.x;
9526 disp->mouse_y = (int)point.y;
9527 if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
9528 disp->mouse_x = disp->mouse_y = -1;
9529 } else disp->mouse_x = disp->mouse_y = -1;
9530 }
9531 disp->is_event = true;
9532 MPSignalSemaphore(c.wait_event);
9533 break;
9534 case kEventMouseDown :
9535 UInt16 btn;
9536 if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
9537 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
9538 if (btn==kEventMouseButtonPrimary) disp->button|=1U;
9539 // For those who don't have a multi-mouse button (as me), I think it's better to allow the user
9540 // to emulate a right click by using the Control key
9541 if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
9542 cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Down]");
9543 if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button|=2U;
9544 if (btn==kEventMouseButtonTertiary) disp->button|=4U;
9545 }
9546 disp->is_event = true;
9547 MPSignalSemaphore(c.wait_event);
9548 break;
9549 case kEventMouseWheelMoved :
9550 EventMouseWheelAxis wheelax;
9551 SInt32 delta;
9552 if (GetEventParameter(theEvent,kEventParamMouseWheelAxis,typeMouseWheelAxis,0,sizeof(wheelax),0,&wheelax)==noErr)
9553 if (wheelax==kEventMouseWheelAxisY) {
9554 if (GetEventParameter(theEvent,kEventParamMouseWheelDelta,typeLongInteger,0,sizeof(delta),0,&delta)==noErr)
9555 if (delta>0) disp->wheel+=delta/120; //FIXME: why 120 ?
9556 disp->is_event = true;
9557 MPSignalSemaphore(c.wait_event);
9558 }
9559 break;
9560 }
9561 }
9563 switch (GetEventClass(theEvent)) {
9564 case kEventClassKeyboard :
9565 if (GetEventKind(theEvent)==kEventRawKeyUp) {
9566 UInt32 keyCode;
9567 if (GetEventParameter(theEvent,kEventParamKeyCode,typeUInt32,0,sizeof(keyCode),0,&keyCode)==noErr) {
9568 disp->update_iskey((unsigned int)keyCode,false);
9569 if (disp->key) { cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
9570 if (disp->released_key) cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
9571 disp->released_key = (int)keyCode;
9572 }
9573 disp->is_event = true;
9574 MPSignalSemaphore(c.wait_event);
9575 }
9576 break;
9578 case kEventClassMouse :
9579 switch (GetEventKind(theEvent)) {
9580 case kEventMouseUp :
9581 UInt16 btn;
9582 if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
9583 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
9584 if (btn==kEventMouseButtonPrimary) disp->button&=~1U;
9585 // See note in kEventMouseDown handler.
9586 if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
9587 cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Up]");
9588 if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button&=~2U;
9589 if (btn==kEventMouseButtonTertiary) disp->button&=~2U;
9590 }
9591 disp->is_event = true;
9592 MPSignalSemaphore(c.wait_event);
9593 break;
9594 }
9595 }
9596 }
9597 return (result);
9598 }
9600 static void* _events_thread(void* args) {
9601 (void)args; // Make the compiler happy
9602 cimg::CarbonInfo& c = cimg::CarbonAttr();
9603 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
9604 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
9605 MPSignalSemaphore(c.sync_event); // Notify the caller that all goes fine
9606 EventRef theEvent;
9607 EventTargetRef theTarget;
9608 OSStatus err;
9609 CbSerializedQuery* query;
9610 theTarget = GetEventDispatcherTarget();
9612 // Enter in the main loop
9613 while (true) {
9614 pthread_testcancel(); /* Check if cancelation happens */
9615 err = ReceiveNextEvent(0,0,kDurationImmediate,true,&theEvent); // Fetch new events
9616 if (err==noErr) { // Received a carbon event, so process it !
9617 SendEventToEventTarget (theEvent, theTarget);
9618 ReleaseEvent(theEvent);
9619 } else if (err == eventLoopTimedOutErr) { // There is no event to process, so check if there is new messages to process
9620 OSStatus r =MPWaitOnQueue(c.com_queue,(void**)&query,0,0,10*kDurationMillisecond);
9621 if (r!=noErr) continue; //nothing in the queue or an error.., bye
9622 // If we're here, we've something to do now.
9623 if (query) {
9624 switch (query->kind) {
9625 case COM_SETMOUSEPOS : { // change the cursor position
9626 query->success = CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,CGPointMake(query->sender->window_x+query->x,query->sender->window_y+query->y))
9627 == kCGErrorSuccess;
9628 if (query->success) {
9629 query->sender->mouse_x = query->x;
9630 query->sender->mouse_y = query->y;
9631 } else cimg::warn("CImgDisplay::_events_thread() : CGDisplayMoveCursorToPoint failed.");
9632 } break;
9633 case COM_SETTITLE : { // change the title bar caption
9634 CFStringRef windowTitle = CFStringCreateWithCString(0,query->c,kCFStringEncodingMacRoman);
9635 query->success = SetWindowTitleWithCFString(query->sender->carbonWindow,windowTitle)==noErr;
9636 if (!query->success)
9637 cimg::warn("CImgDisplay::_events_thread() : SetWindowTitleWithCFString failed.");
9638 CFRelease(windowTitle);
9639 } break;
9640 case COM_RESIZEWINDOW : { // Resize a window
9641 SizeWindow(query->sender->carbonWindow,query->x,query->y,query->update);
9642 // If the window has been resized successfully, update display informations
9643 query->sender->window_width = query->x;
9644 query->sender->window_height = query->y;
9645 query->success = true;
9646 } break;
9647 case COM_MOVEWINDOW : { // Move a window
9648 MoveWindow(query->sender->carbonWindow,query->x,query->y,false);
9649 query->sender->window_x = query->x;
9650 query->sender->window_y = query->y;
9651 query->sender->is_moved = false;
9652 query->success = true;
9653 } break;
9654 case COM_SHOWMOUSE : { // Show the mouse
9655 query->success = CGDisplayShowCursor(kCGDirectMainDisplay)==noErr;
9656 if (!query->success)
9657 cimg::warn("CImgDisplay::_events_thread() : CGDisplayShowCursor failed.");
9658 } break;
9659 case COM_HIDEMOUSE : { // Hide the mouse
9660 query->success = CGDisplayHideCursor(kCGDirectMainDisplay)==noErr;
9661 if (!query->success)
9662 cimg::warn("CImgDisplay::_events_thread() : CGDisplayHideCursor failed.");
9663 } break;
9664 case COM_SHOWWINDOW : { // We've to show a window
9665 ShowWindow(query->sender->carbonWindow);
9666 query->success = true;
9667 query->sender->is_closed = false;
9668 } break;
9669 case COM_HIDEWINDOW : { // We've to show a window
9670 HideWindow(query->sender->carbonWindow);
9671 query->sender->is_closed = true;
9672 query->sender->window_x = query->sender->window_y = 0;
9673 query->success = true;
9674 } break;
9675 case COM_RELEASEWINDOW : { // We have to release a given window handle
9676 query->success = true;
9677 CFRelease(query->sender->carbonWindow);
9678 } break;
9679 case COM_CREATEWINDOW : { // We have to create a window
9680 query->success = true;
9681 WindowAttributes windowAttrs;
9682 Rect contentRect;
9683 if (query->createFullScreenWindow) {
9684 // To simulate a "true" full screen, we remove menus and close boxes
9685 windowAttrs = (1L << 9); //Why ? kWindowNoTitleBarAttribute seems to be not defined on 10.3
9686 // Define a full screen bound rect
9687 SetRect(&contentRect,0,0,CGDisplayPixelsWide(kCGDirectMainDisplay),CGDisplayPixelsHigh(kCGDirectMainDisplay));
9688 } else { // Set the window size
9689 SetRect(&contentRect,0,0,query->sender->width,query->sender->height); // Window will be centered with RepositionWindow.
9690 // Use default attributes
9691 windowAttrs = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute | kWindowLiveResizeAttribute;
9692 }
9693 // Update window position
9694 if (query->createClosedWindow) query->sender->window_x = query->sender->window_y = 0;
9695 else {
9696 query->sender->window_x = contentRect.left;
9697 query->sender->window_y = contentRect.top;
9698 }
9699 // Update window flags
9700 query->sender->window_width = query->sender->width;
9701 query->sender->window_height = query->sender->height;
9702 query->sender->flush();
9703 // Create the window
9704 if (CreateNewWindow(kDocumentWindowClass,windowAttrs,&contentRect,&query->sender->carbonWindow)!=noErr) {
9705 query->success = false;
9706 cimg::warn("CImgDisplay::_events_thread() : CreateNewWindow() failed.");
9707 }
9708 // Send it to the foreground
9709 if (RepositionWindow(query->sender->carbonWindow,0,kWindowCenterOnMainScreen)!=noErr) query->success = false;
9710 // Show it, if needed
9711 if (!query->createClosedWindow) ShowWindow(query->sender->carbonWindow);
9713 // Associate a valid event handler
9714 EventTypeSpec eventList[] = {
9715 { kEventClassWindow, kEventWindowClose },
9716 { kEventClassWindow, kEventWindowResizeStarted },
9717 { kEventClassWindow, kEventWindowResizeCompleted },
9718 { kEventClassWindow, kEventWindowDragStarted},
9719 { kEventClassWindow, kEventWindowDragCompleted },
9720 { kEventClassWindow, kEventWindowPaint },
9721 { kEventClassWindow, kEventWindowBoundsChanging },
9722 { kEventClassWindow, kEventWindowCollapsed },
9723 { kEventClassWindow, kEventWindowExpanded },
9724 { kEventClassWindow, kEventWindowZoomed },
9725 { kEventClassKeyboard, kEventRawKeyDown },
9726 { kEventClassKeyboard, kEventRawKeyUp },
9727 { kEventClassKeyboard, kEventRawKeyRepeat },
9728 { kEventClassKeyboard, kEventRawKeyModifiersChanged },
9729 { kEventClassMouse, kEventMouseMoved },
9730 { kEventClassMouse, kEventMouseDown },
9731 { kEventClassMouse, kEventMouseUp },
9732 { kEventClassMouse, kEventMouseDragged }
9733 };
9735 // Set up the handler
9736 if (InstallWindowEventHandler(query->sender->carbonWindow,NewEventHandlerUPP(CarbonEventHandler),GetEventTypeCount(eventList),
9737 eventList,(void*)query->sender,0)!=noErr) {
9738 query->success = false;
9739 cimg::warn("CImgDisplay::_events_thread() : InstallWindowEventHandler failed.");
9740 }
9742 // Paint
9743 query->sender->paint();
9744 } break;
9745 default :
9746 cimg::warn("CImgDisplay::_events_thread() : Received unknow code %d.",query->kind);
9747 }
9748 // Signal that the message has been processed
9749 MPSignalSemaphore(c.sync_event);
9750 }
9751 }
9752 }
9753 // If we are here, the application is now finished
9754 pthread_exit(0);
9755 }
9757 CImgDisplay& assign() {
9758 if (is_empty()) return *this;
9759 cimg::CarbonInfo& c = cimg::CarbonAttr();
9760 // Destroy the window associated to the display
9761 _CbFreeAttachedWindow(c);
9762 // Don't destroy the background thread here.
9763 // If you check whether _CbFreeAttachedWindow() returned true,
9764 // - saying that there were no window left on screen - and
9765 // you destroy the background thread here, ReceiveNextEvent won't
9766 // work anymore if you create a new window after. So the
9767 // background thread must be killed (pthread_cancel() + pthread_join())
9768 // only on the application shutdown.
9770 // Finalize graphics
9771 _CbFinalizeGraphics();
9773 // Do some cleanup
9774 if (data) delete[] data;
9775 if (title) delete[] title;
9776 width = height = normalization = window_width = window_height = 0;
9777 window_x = window_y = 0;
9778 is_fullscreen = false;
9779 is_closed = true;
9780 min = max = 0;
9781 title = 0;
9782 flush();
9783 if (MPDeleteCriticalRegion(paintCriticalRegion)!=noErr)
9784 throw CImgDisplayException("CImgDisplay()::assign() : MPDeleteCriticalRegion failed.");
9785 return *this;
9786 }
9788 CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
9789 const unsigned int normalization_type=3,
9790 const bool fullscreen_flag=false, const bool closed_flag=false) {
9791 cimg::CarbonInfo& c = cimg::CarbonAttr();
9793 // Allocate space for window title
9794 const int s = cimg::strlen(ptitle)+1;
9795 char *tmp_title = s?new char[s]:0;
9796 if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
9798 // Destroy previous window if existing
9799 if (!is_empty()) assign();
9801 // Set display variables
9802 width = cimg::min(dimw,(unsigned int)screen_dimx());
9803 height = cimg::min(dimh,(unsigned int)screen_dimy());
9804 normalization = normalization_type<4?normalization_type:3;
9805 is_fullscreen = fullscreen_flag;
9806 is_closed = closed_flag;
9807 lastKeyModifiers = 0;
9808 title = tmp_title;
9809 flush();
9811 // Create the paint CR
9812 if (MPCreateCriticalRegion(&paintCriticalRegion) != noErr)
9813 throw CImgDisplayException("CImgDisplay::_assign() : MPCreateCriticalRegion() failed.");
9815 // Create the thread if it's not already created
9816 if (c.event_thread==0) {
9817 // Background thread does not exists, so create it !
9818 if (pthread_create(&c.event_thread,0,_events_thread,0)!=0)
9819 throw CImgDisplayException("CImgDisplay::_assign() : pthread_create() failed.");
9820 // Wait for thread initialization
9821 MPWaitOnSemaphore(c.sync_event, kDurationForever);
9822 }
9824 // Init disp. graphics
9825 data = new unsigned int[width*height];
9826 _CbInitializeGraphics();
9828 // Now ask the thread to create the window
9829 _CbCreateAttachedWindow(c,ptitle,fullscreen_flag,closed_flag);
9830 return *this;
9831 }
9833 #endif
9835 };
9837 /*
9838 #--------------------------------------
9839 #
9840 #
9841 #
9842 # Definition of the CImg<T> structure
9843 #
9844 #
9845 #
9846 #--------------------------------------
9847 */
9849 //! Class representing an image (up to 4 dimensions wide), each pixel being of type \c T.
9850 /**
9851 This is the main class of the %CImg Library. It declares and constructs
9852 an image, allows access to its pixel values, and is able to perform various image operations.
9854 \par Image representation
9856 A %CImg image is defined as an instance of the container \ref CImg<\c T>, which contains a regular grid of pixels,
9857 each pixel value being of type \c T. The image grid can have up to 4 dimensions : width, height, depth
9858 and number of channels.
9859 Usually, the three first dimensions are used to describe spatial coordinates <tt>(x,y,z)</tt>, while the number of channels
9860 is rather used as a vector-valued dimension (it may describe the R,G,B color channels for instance).
9861 If you need a fifth dimension, you can use image lists \ref CImgList<\c T> rather than simple images \ref CImg<\c T>.
9863 Thus, the \ref CImg<\c T> class is able to represent volumetric images of vector-valued pixels,
9864 as well as images with less dimensions (1D scalar signal, 2D color images, ...).
9865 Most member functions of the class CImg<\c T> are designed to handle this maximum case of (3+1) dimensions.
9867 Concerning the pixel value type \c T :
9868 fully supported template types are the basic C++ types : <tt>unsigned char, char, short, unsigned int, int,
9869 unsigned long, long, float, double, ... </tt>.
9870 Typically, fast image display can be done using <tt>CImg<unsigned char></tt> images,
9871 while complex image processing algorithms may be rather coded using <tt>CImg<float></tt> or <tt>CImg<double></tt>
9872 images that have floating-point pixel values. The default value for the template T is \c float.
9873 Using your own template types may be possible. However, you will certainly have to define the complete set
9874 of arithmetic and logical operators for your class.
9876 \par Image structure
9878 The \ref CImg<\c T> structure contains \a six fields :
9879 - \ref width defines the number of \a columns of the image (size along the X-axis).
9880 - \ref height defines the number of \a rows of the image (size along the Y-axis).
9881 - \ref depth defines the number of \a slices of the image (size along the Z-axis).
9882 - \ref dim defines the number of \a channels of the image (size along the V-axis).
9883 - \ref data defines a \a pointer to the \a pixel \a data (of type \c T).
9884 - \ref is_shared is a boolean that tells if the memory buffer \ref data is shared with
9885 another image.
9887 You can access these fields publicly although it is recommended to use the dedicated functions
9888 dimx(), dimy(), dimz(), dimv() and ptr() to do so.
9889 Image dimensions are not limited to a specific range (as long as you got enough available memory).
9890 A value of \e 1 usually means that the corresponding dimension is \a flat.
9891 If one of the dimensions is \e 0, or if the data pointer is null, the image is considered as \e empty.
9892 Empty images should not contain any pixel data and thus, will not be processed by CImg member functions
9893 (a CImgInstanceException will be thrown instead).
9894 Pixel data are stored in memory, in a non interlaced mode (See \ref cimg_storage).
9896 \par Image declaration and construction
9898 Declaring an image can be done by using one of the several available constructors.
9899 Here is a list of the most used :
9901 - Construct images from arbitrary dimensions :
9902 - <tt>CImg<char> img;</tt> declares an empty image.
9903 - <tt>CImg<unsigned char> img(128,128);</tt> declares a 128x128 greyscale image with
9904 \c unsigned \c char pixel values.
9905 - <tt>CImg<double> img(3,3);</tt> declares a 3x3 matrix with \c double coefficients.
9906 - <tt>CImg<unsigned char> img(256,256,1,3);</tt> declares a 256x256x1x3 (color) image
9907 (colors are stored as an image with three channels).
9908 - <tt>CImg<double> img(128,128,128);</tt> declares a 128x128x128 volumetric and greyscale image
9909 (with \c double pixel values).
9910 - <tt>CImg<> img(128,128,128,3);</tt> declares a 128x128x128 volumetric color image
9911 (with \c float pixels, which is the default value of the template parameter \c T).
9912 - \b Note : images pixels are <b>not automatically initialized to 0</b>. You may use the function \ref fill() to
9913 do it, or use the specific constructor taking 5 parameters like this :
9914 <tt>CImg<> img(128,128,128,3,0);</tt> declares a 128x128x128 volumetric color image with all pixel values to 0.
9916 - Construct images from filenames :
9917 - <tt>CImg<unsigned char> img("image.jpg");</tt> reads a JPEG color image from the file "image.jpg".
9918 - <tt>CImg<float> img("analyze.hdr");</tt> reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr".
9919 - \b Note : You need to install <a href="http://www.imagemagick.org">ImageMagick</a>
9920 to be able to read common compressed image formats (JPG,PNG, ...) (See \ref cimg_files_io).
9922 - Construct images from C-style arrays :
9923 - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer
9924 \c data_buffer (of size 256x256=65536).
9925 - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,false);</tt> constructs a 256x256 color image
9926 from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others).
9927 - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,true);</tt> constructs a 256x256 color image
9928 from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels are multiplexed).
9930 The complete list of constructors can be found <a href="#constructors">here</a>.
9932 \par Most useful functions
9934 The \ref CImg<\c T> class contains a lot of functions that operates on images.
9935 Some of the most useful are :
9937 - operator()(), operator[]() : allows to access or write pixel values.
9938 - display() : displays the image in a new window.
9939 **/
9940 template<typename T>
9941 struct CImg {
9943 //! Variable representing the width of the instance image (i.e. dimensions along the X-axis).
9944 /**
9945 \remark
9946 - Prefer using the function CImg<T>::dimx() to get information about the width of an image.
9947 - Use function CImg<T>::resize() to set a new width for an image. Setting directly the variable \c width would probably
9948 result in a library crash.
9949 - Empty images have \c width defined to \c 0.
9950 **/
9951 unsigned int width;
9953 //! Variable representing the height of the instance image (i.e. dimensions along the Y-axis).
9954 /**
9955 \remark
9956 - Prefer using the function CImg<T>::dimy() to get information about the height of an image.
9957 - Use function CImg<T>::resize() to set a new height for an image. Setting directly the variable \c height would probably
9958 result in a library crash.
9959 - 1D signals have \c height defined to \c 1.
9960 - Empty images have \c height defined to \c 0.
9961 **/
9962 unsigned int height;
9964 //! Variable representing the depth of the instance image (i.e. dimensions along the Z-axis).
9965 /**
9966 \remark
9967 - Prefer using the function CImg<T>::dimz() to get information about the depth of an image.
9968 - Use function CImg<T>::resize() to set a new depth for an image. Setting directly the variable \c depth would probably
9969 result in a library crash.
9970 - Classical 2D images have \c depth defined to \c 1.
9971 - Empty images have \c depth defined to \c 0.
9972 **/
9973 unsigned int depth;
9975 //! Variable representing the number of channels of the instance image (i.e. dimensions along the V-axis).
9976 /**
9977 \remark
9978 - Prefer using the function CImg<T>::dimv() to get information about the depth of an image.
9979 - Use function CImg<T>::resize() to set a new vector dimension for an image. Setting directly the variable \c dim would probably
9980 result in a library crash.
9981 - Scalar-valued images (one value per pixel) have \c dim defined to \c 1.
9982 - Empty images have \c depth defined to \c 0.
9983 **/
9984 unsigned int dim;
9986 //! Variable telling if pixel buffer of the instance image is shared with another one.
9987 bool is_shared;
9989 //! Pointer to the first pixel of the pixel buffer.
9990 T *data;
9992 //! Iterator type for CImg<T>.
9993 /**
9994 \remark
9995 - An \p iterator is a <tt>T*</tt> pointer (address of a pixel value in the pixel buffer).
9996 - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL.
9997 **/
9998 typedef T* iterator;
10000 //! Const iterator type for CImg<T>.
10001 /**
10002 \remark
10003 - A \p const_iterator is a <tt>const T*</tt> pointer (address of a pixel value in the pixel buffer).
10004 - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL.
10005 **/
10006 typedef const T* const_iterator;
10008 //! Get value type
10009 typedef T value_type;
10011 // Define common T-dependant types.
10012 typedef typename cimg::superset<T,bool>::type Tbool;
10013 typedef typename cimg::superset<T,unsigned char>::type Tuchar;
10014 typedef typename cimg::superset<T,char>::type Tchar;
10015 typedef typename cimg::superset<T,unsigned short>::type Tushort;
10016 typedef typename cimg::superset<T,short>::type Tshort;
10017 typedef typename cimg::superset<T,unsigned int>::type Tuint;
10018 typedef typename cimg::superset<T,int>::type Tint;
10019 typedef typename cimg::superset<T,unsigned long>::type Tulong;
10020 typedef typename cimg::superset<T,long>::type Tlong;
10021 typedef typename cimg::superset<T,float>::type Tfloat;
10022 typedef typename cimg::superset<T,double>::type Tdouble;
10023 typedef typename cimg::last<T,bool>::type boolT;
10024 typedef typename cimg::last<T,unsigned char>::type ucharT;
10025 typedef typename cimg::last<T,char>::type charT;
10026 typedef typename cimg::last<T,unsigned short>::type ushortT;
10027 typedef typename cimg::last<T,short>::type shortT;
10028 typedef typename cimg::last<T,unsigned int>::type uintT;
10029 typedef typename cimg::last<T,int>::type intT;
10030 typedef typename cimg::last<T,unsigned long>::type ulongT;
10031 typedef typename cimg::last<T,long>::type longT;
10032 typedef typename cimg::last<T,float>::type floatT;
10033 typedef typename cimg::last<T,double>::type doubleT;
10035 //@}
10036 //---------------------------
10037 //
10038 //! \name Plugins
10039 //@{
10040 //---------------------------
10041 #ifdef cimg_plugin
10042 #include cimg_plugin
10043 #endif
10044 #ifdef cimg_plugin1
10045 #include cimg_plugin1
10046 #endif
10047 #ifdef cimg_plugin2
10048 #include cimg_plugin2
10049 #endif
10050 #ifdef cimg_plugin3
10051 #include cimg_plugin3
10052 #endif
10053 #ifdef cimg_plugin4
10054 #include cimg_plugin4
10055 #endif
10056 #ifdef cimg_plugin5
10057 #include cimg_plugin5
10058 #endif
10059 #ifdef cimg_plugin6
10060 #include cimg_plugin6
10061 #endif
10062 #ifdef cimg_plugin7
10063 #include cimg_plugin7
10064 #endif
10065 #ifdef cimg_plugin8
10066 #include cimg_plugin8
10067 #endif
10068 #ifndef cimg_plugin_greycstoration
10069 #define cimg_plugin_greycstoration_count
10070 #endif
10071 #ifndef cimg_plugin_greycstoration_lock
10072 #define cimg_plugin_greycstoration_lock
10073 #endif
10074 #ifndef cimg_plugin_greycstoration_unlock
10075 #define cimg_plugin_greycstoration_unlock
10076 #endif
10078 //@}
10080 //--------------------------------------
10081 //
10082 //! \name Constructors-Destructor-Copy
10083 //@{
10084 //--------------------------------------
10086 //! Destructor.
10087 /**
10088 The destructor destroys the instance image.
10089 \remark
10090 - Destructing an empty or shared image does nothing.
10091 - Otherwise, all memory used to store the pixel data of the instance image is freed.
10092 - When destroying a non-shared image, be sure that every shared instances of the same image are
10093 also destroyed to avoid further access to desallocated memory buffers.
10094 **/
10095 ~CImg() {
10096 if (data && !is_shared) delete[] data;
10097 }
10099 //! Default constructor.
10100 /**
10101 The default constructor creates an empty instance image.
10102 \remark
10103 - An empty image does not contain any data and has all of its dimensions \ref width, \ref height, \ref depth, \ref dim
10104 set to 0 as well as its pointer to the pixel buffer \ref data.
10105 - An empty image is non-shared.
10106 **/
10107 CImg():
10108 width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {}
10110 //! Constructs a new image with given size (\p dx,\p dy,\p dz,\p dv).
10111 /**
10112 This constructors create an instance image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T.
10113 \param dx Desired size along the X-axis, i.e. the \ref width of the image.
10114 \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
10115 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
10116 \param dv Desired size along the V-axis, i.e. the number of image channels \ref dim.
10117 \remark
10118 - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the created image is empty
10119 and all has its dimensions set to 0. No memory for pixel data is then allocated.
10120 - This constructor creates only non-shared images.
10121 - Image pixels allocated by this constructor are \b not \b initialized.
10122 Use the constructor CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
10123 to get an image of desired size with pixels set to a particular value.
10124 **/
10125 explicit CImg(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1):
10126 is_shared(false) {
10127 const unsigned long siz = dx*dy*dz*dv;
10128 if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; }
10129 else { width = height = depth = dim = 0; data = 0; }
10130 }
10132 //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with pixel having a default value \p val.
10133 /**
10134 This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T and sets all pixel
10135 values of the created instance image to \p val.
10136 \param dx Desired size along the X-axis, i.e. the \ref width of the image.
10137 \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
10138 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
10139 \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
10140 \param val Default value for image pixels.
10141 \remark
10142 - This constructor has the same properties as CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
10143 **/
10144 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val):
10145 is_shared(false) {
10146 const unsigned long siz = dx*dy*dz*dv;
10147 if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(val); }
10148 else { width = height = depth = dim = 0; data = 0; }
10149 }
10151 //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (int version).
10152 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10153 const int val0, const int val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10154 #define _CImg_stdarg(img,a0,a1,N,t) { \
10155 unsigned int _siz = (unsigned int)N; \
10156 if (_siz--) { \
10157 va_list ap; \
10158 va_start(ap,a1); \
10159 T *ptrd = (img).data; \
10160 *(ptrd++) = (T)a0; \
10161 if (_siz--) { \
10162 *(ptrd++) = (T)a1; \
10163 for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \
10164 } \
10165 va_end(ap); \
10166 }}
10167 assign(dx,dy,dz,dv);
10168 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
10169 }
10171 //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (double version).
10172 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10173 const double val0, const double val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10174 assign(dx,dy,dz,dv);
10175 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
10176 }
10178 //! Construct an image with given size and with specified values given in a string.
10179 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10180 const char *const values, const bool repeat_pattern):is_shared(false) {
10181 const unsigned long siz = dx*dy*dz*dv;
10182 if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(values,repeat_pattern); }
10183 else { width = height = depth = dim = 0; data = 0; }
10184 }
10186 //! Construct an image from a raw memory buffer.
10187 /**
10188 This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dv) and fill its pixel buffer by
10189 copying data values from the input raw pixel buffer \p data_buffer.
10190 **/
10191 template<typename t>
10192 CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
10193 const unsigned int dz=1, const unsigned int dv=1, const bool shared=false):is_shared(false) {
10194 if (shared)
10195 throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a (%s*) buffer "
10196 "(different pixel types).",
10197 pixel_type(),CImg<t>::pixel_type());
10198 const unsigned long siz = dx*dy*dz*dv;
10199 if (data_buffer && siz) {
10200 width = dx; height = dy; depth = dz; dim = dv; data = new T[siz];
10201 const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
10202 } else { width = height = depth = dim = 0; data = 0; }
10203 }
10205 #ifndef cimg_use_visualcpp6
10206 CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
10207 const unsigned int dz=1, const unsigned int dv=1, const bool shared=false)
10208 #else
10209 CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
10210 const unsigned int dz, const unsigned int dv, const bool shared)
10211 #endif
10212 {
10213 const unsigned long siz = dx*dy*dz*dv;
10214 if (data_buffer && siz) {
10215 width = dx; height = dy; depth = dz; dim = dv; is_shared = shared;
10216 if (is_shared) data = const_cast<T*>(data_buffer);
10217 else { data = new T[siz]; cimg_std::memcpy(data,data_buffer,siz*sizeof(T)); }
10218 } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
10219 }
10221 //! Default copy constructor.
10222 /**
10223 The default copy constructor creates a new instance image having same dimensions
10224 (\ref width, \ref height, \ref depth, \ref dim) and same pixel values as the input image \p img.
10225 \param img The input image to copy.
10226 \remark
10227 - If the input image \p img is non-shared or have a different template type \p t != \p T,
10228 the default copy constructor allocates a new pixel buffer and copy the pixel data
10229 of \p img into it. In this case, the pointers \ref data to the pixel buffers of the two images are different
10230 and the resulting instance image is non-shared.
10231 - If the input image \p img is shared and has the same template type \p t == \p T,
10232 the default copy constructor does not allocate a new pixel buffer and the resulting instance image
10233 shares its pixel buffer with the input image \p img, which means that modifying pixels of \p img also modifies
10234 the created instance image.
10235 - Copying an image having a different template type \p t != \p T performs a crude static cast conversion of each pixel value from
10236 type \p t to type \p T.
10237 - Copying an image having the same template type \p t == \p T is significantly faster.
10238 **/
10239 template<typename t>
10240 CImg(const CImg<t>& img):is_shared(false) {
10241 const unsigned int siz = img.size();
10242 if (img.data && siz) {
10243 width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
10244 const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
10245 } else { width = height = depth = dim = 0; data = 0; }
10246 }
10248 CImg(const CImg<T>& img) {
10249 const unsigned int siz = img.size();
10250 if (img.data && siz) {
10251 width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = img.is_shared;
10252 if (is_shared) data = const_cast<T*>(img.data);
10253 else { data = new T[siz]; cimg_std::memcpy(data,img.data,siz*sizeof(T)); }
10254 } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
10255 }
10257 //! Advanced copy constructor.
10258 /**
10259 The advanced copy constructor - as the default constructor CImg(const CImg< t >&) - creates a new instance image having same dimensions
10260 \ref width, \ref height, \ref depth, \ref dim and same pixel values as the input image \p img.
10261 But it also decides if the created instance image shares its memory with the input image \p img (if the input parameter
10262 \p shared is set to \p true) or not (if the input parameter \p shared is set to \p false).
10263 \param img The input image to copy.
10264 \param shared Boolean flag that decides if the copy is shared on non-shared.
10265 \remark
10266 - It is not possible to create a shared copy if the input image \p img is empty or has a different pixel type \p t != \p T.
10267 - If a non-shared copy of the input image \p img is created, a new memory buffer is allocated for pixel data.
10268 - If a shared copy of the input image \p img is created, no extra memory is allocated and the pixel buffer of the instance
10269 image is the same as the one used by the input image \p img.
10270 **/
10271 template<typename t>
10272 CImg(const CImg<t>& img, const bool shared):is_shared(false) {
10273 if (shared)
10274 throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a CImg<%s> instance "
10275 "(different pixel types).",
10276 pixel_type(),CImg<t>::pixel_type());
10277 const unsigned int siz = img.size();
10278 if (img.data && siz) {
10279 width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
10280 const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
10281 } else { width = height = depth = dim = 0; data = 0; }
10282 }
10284 CImg(const CImg<T>& img, const bool shared) {
10285 const unsigned int siz = img.size();
10286 if (img.data && siz) {
10287 width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = shared;
10288 if (is_shared) data = const_cast<T*>(img.data);
10289 else { data = new T[siz]; cimg_std::memcpy(data,img.data,siz*sizeof(T)); }
10290 } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
10291 }
10293 //! Construct an image using dimensions of another image
10294 template<typename t>
10295 CImg(const CImg<t>& img, const char *const dimensions):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10296 assign(img,dimensions);
10297 }
10299 //! Construct an image using dimensions of another image, and fill it with a default value
10300 template<typename t>
10301 CImg(const CImg<t>& img, const char *const dimensions, const T val):
10302 width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10303 assign(img,dimensions).fill(val);
10304 }
10306 //! Construct an image from an image file.
10307 /**
10308 This constructor creates an instance image by reading it from a file.
10309 \param filename Filename of the image file.
10310 \remark
10311 - The image format is deduced from the filename only by looking for the filename extension i.e. without
10312 analyzing the file itself.
10313 - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
10314 More informations on this topic can be found in cimg_files_io.
10315 - If the filename is not found, a CImgIOException is thrown by this constructor.
10316 **/
10317 CImg(const char *const filename):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10318 assign(filename);
10319 }
10321 //! Construct an image from the content of a CImgDisplay instance.
10322 CImg(const CImgDisplay &disp):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
10323 disp.snapshot(*this);
10324 }
10326 //! In-place version of the default constructor/destructor.
10327 /**
10328 This function replaces the instance image by an empty image.
10329 \remark
10330 - Memory used by the previous content of the instance image is freed if necessary.
10331 - If the instance image was initially shared, it is replaced by a (non-shared) empty image.
10332 - This function is useful to free memory used by an image that is not of use, but which
10333 has been created in the current code scope (i.e. not destroyed yet).
10334 **/
10335 CImg<T>& assign() {
10336 if (data && !is_shared) delete[] data;
10337 width = height = depth = dim = 0; is_shared = false; data = 0;
10338 return *this;
10339 }
10341 //! In-place version of the default constructor.
10342 /**
10343 This function is strictly equivalent to \ref assign() and has been
10344 introduced for having a STL-compliant function name.
10345 **/
10346 CImg<T>& clear() {
10347 return assign();
10348 }
10350 //! In-place version of the previous constructor.
10351 /**
10352 This function replaces the instance image by a new image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T.
10353 \param dx Desired size along the X-axis, i.e. the \ref width of the image.
10354 \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
10355 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
10356 \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
10357 - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the instance image becomes empty
10358 and all has its dimensions set to 0. No memory for pixel data is then allocated.
10359 - Memory buffer used to store previous pixel values is freed if necessary.
10360 - If the instance image is shared, this constructor actually does nothing more than verifying
10361 that new and old image dimensions fit.
10362 - Image pixels allocated by this function are \b not \b initialized.
10363 Use the function assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
10364 to assign an image of desired size with pixels set to a particular value.
10365 **/
10366 CImg<T>& assign(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1) {
10367 const unsigned long siz = dx*dy*dz*dv;
10368 if (!siz) return assign();
10369 const unsigned long curr_siz = size();
10370 if (siz!=curr_siz) {
10371 if (is_shared)
10372 throw CImgArgumentException("CImg<%s>::assign() : Cannot assign image (%u,%u,%u,%u) to shared instance image (%u,%u,%u,%u,%p).",
10373 pixel_type(),dx,dy,dz,dv,width,height,depth,dim,data);
10374 else { if (data) delete[] data; data = new T[siz]; }
10375 }
10376 width = dx; height = dy; depth = dz; dim = dv;
10377 return *this;
10378 }
10380 //! In-place version of the previous constructor.
10381 /**
10382 This function replaces the instance image by a new image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T
10383 and sets all pixel values of the instance image to \p val.
10384 \param dx Desired size along the X-axis, i.e. the \ref width of the image.
10385 \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
10386 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
10387 \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
10388 \param val Default value for image pixels.
10389 \remark
10390 - This function has the same properties as assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
10391 **/
10392 CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val) {
10393 return assign(dx,dy,dz,dv).fill(val);
10394 }
10396 //! In-place version of the previous constructor.
10397 CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10398 const int val0, const int val1, ...) {
10399 assign(dx,dy,dz,dv);
10400 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
10401 return *this;
10402 }
10404 //! In-place version of the previous constructor.
10405 CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
10406 const double val0, const double val1, ...) {
10407 assign(dx,dy,dz,dv);
10408 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
10409 return *this;
10410 }
10412 //! In-place version of the previous constructor.
10413 template<typename t>
10414 CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
10415 const unsigned int dz=1, const unsigned int dv=1) {
10416 const unsigned long siz = dx*dy*dz*dv;
10417 if (!data_buffer || !siz) return assign();
10418 assign(dx,dy,dz,dv);
10419 const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
10420 return *this;
10421 }
10423 #ifndef cimg_use_visualcpp6
10424 CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
10425 const unsigned int dz=1, const unsigned int dv=1)
10426 #else
10427 CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
10428 const unsigned int dz, const unsigned int dv)
10429 #endif
10430 {
10431 const unsigned long siz = dx*dy*dz*dv;
10432 if (!data_buffer || !siz) return assign();
10433 const unsigned long curr_siz = size();
10434 if (data_buffer==data && siz==curr_siz) return assign(dx,dy,dz,dv);
10435 if (is_shared || data_buffer+siz<data || data_buffer>=data+size()) {
10436 assign(dx,dy,dz,dv);
10437 if (is_shared) cimg_std::memmove(data,data_buffer,siz*sizeof(T));
10438 else cimg_std::memcpy(data,data_buffer,siz*sizeof(T));
10439 } else {
10440 T *new_data = new T[siz];
10441 cimg_std::memcpy(new_data,data_buffer,siz*sizeof(T));
10442 delete[] data; data = new_data; width = dx; height = dy; depth = dz; dim = dv;
10443 }
10444 return *this;
10445 }
10447 //! In-place version of the previous constructor, allowing to force the shared state of the instance image.
10448 template<typename t>
10449 CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy,
10450 const unsigned int dz, const unsigned int dv, const bool shared) {
10451 if (shared)
10452 throw CImgArgumentException("CImg<%s>::assign() : Cannot assign buffer (%s*) to shared instance image (%u,%u,%u,%u,%p)"
10453 "(different pixel types).",
10454 pixel_type(),CImg<t>::pixel_type(),width,height,depth,dim,data);
10455 return assign(data_buffer,dx,dy,dz,dv);
10456 }
10458 CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
10459 const unsigned int dz, const unsigned int dv, const bool shared) {
10460 const unsigned long siz = dx*dy*dz*dv;
10461 if (!data_buffer || !siz) return assign();
10462 if (!shared) { if (is_shared) assign(); assign(data_buffer,dx,dy,dz,dv); }
10463 else {
10464 if (!is_shared) {
10465 if (data_buffer+siz<data || data_buffer>=data+size()) assign();
10466 else cimg::warn("CImg<%s>::assign() : Shared instance image has overlapping memory !",
10467 pixel_type());
10468 }
10469 width = dx; height = dy; depth = dz; dim = dv; is_shared = true;
10470 data = const_cast<T*>(data_buffer);
10471 }
10472 return *this;
10473 }
10475 //! In-place version of the default copy constructor.
10476 /**
10477 This function assigns a copy of the input image \p img to the current instance image.
10478 \param img The input image to copy.
10479 \remark
10480 - If the instance image is not shared, the content of the input image \p img is copied into a new buffer
10481 becoming the new pixel buffer of the instance image, while the old pixel buffer is freed if necessary.
10482 - If the instance image is shared, the content of the input image \p img is copied into the current (shared) pixel buffer
10483 of the instance image, modifying then the image referenced by the shared instance image. The instance image still remains shared.
10484 **/
10485 template<typename t>
10486 CImg<T>& assign(const CImg<t>& img) {
10487 return assign(img.data,img.width,img.height,img.depth,img.dim);
10488 }
10490 //! In-place version of the advanced constructor.
10491 /**
10492 This function - as the simpler function assign(const CImg< t >&) - assigns a copy of the input image \p img to the
10493 current instance image. But it also decides if the copy is shared (if the input parameter \p shared is set to \c true)
10494 or non-shared (if the input parameter \p shared is set to \c false).
10495 \param img The input image to copy.
10496 \param shared Boolean flag that decides if the copy is shared or non-shared.
10497 \remark
10498 - It is not possible to assign a shared copy if the input image \p img is empty or has a different pixel type \p t != \p T.
10499 - If a non-shared copy of the input image \p img is assigned, a new memory buffer is allocated for pixel data.
10500 - If a shared copy of the input image \p img is assigned, no extra memory is allocated and the pixel buffer of the instance
10501 image is the same as the one used by the input image \p img.
10502 **/
10503 template<typename t>
10504 CImg<T>& assign(const CImg<t>& img, const bool shared) {
10505 return assign(img.data,img.width,img.height,img.depth,img.dim,shared);
10506 }
10508 //! In-place version of the previous constructor.
10509 template<typename t>
10510 CImg<T>& assign(const CImg<t>& img, const char *const dimensions) {
10511 if (dimensions) {
10512 unsigned int siz[4] = { 0,1,1,1 };
10513 const char *s = dimensions;
10514 char tmp[256] = { 0 }, c = 0;
10515 int val = 0;
10516 for (unsigned int k=0; k<4; ++k) {
10517 const int err = cimg_std::sscanf(s,"%[-0-9]%c",tmp,&c);
10518 if (err>=1) {
10519 const int err = cimg_std::sscanf(s,"%d",&val);
10520 if (err==1) {
10521 int val2 = val<0?-val:(c=='%'?val:-1);
10522 if (val2>=0) {
10523 val = (int)((k==0?img.width:(k==1?img.height:(k==2?img.depth:img.dim)))*val2/100);
10524 if (c!='%' && !val) val = 1;
10525 }
10526 siz[k] = val;
10527 }
10528 s+=cimg::strlen(tmp);
10529 if (c=='%') ++s;
10530 }
10531 if (!err) {
10532 if (!cimg::strncasecmp(s,"x",1)) { ++s; siz[k] = img.width; }
10533 else if (!cimg::strncasecmp(s,"y",1)) { ++s; siz[k] = img.height; }
10534 else if (!cimg::strncasecmp(s,"z",1)) { ++s; siz[k] = img.depth; }
10535 else if (!cimg::strncasecmp(s,"v",1)) { ++s; siz[k] = img.dim; }
10536 else if (!cimg::strncasecmp(s,"dx",2)) { s+=2; siz[k] = img.width; }
10537 else if (!cimg::strncasecmp(s,"dy",2)) { s+=2; siz[k] = img.height; }
10538 else if (!cimg::strncasecmp(s,"dz",2)) { s+=2; siz[k] = img.depth; }
10539 else if (!cimg::strncasecmp(s,"dv",2)) { s+=2; siz[k] = img.dim; }
10540 else if (!cimg::strncasecmp(s,"dimx",4)) { s+=4; siz[k] = img.width; }
10541 else if (!cimg::strncasecmp(s,"dimy",4)) { s+=4; siz[k] = img.height; }
10542 else if (!cimg::strncasecmp(s,"dimz",4)) { s+=4; siz[k] = img.depth; }
10543 else if (!cimg::strncasecmp(s,"dimv",4)) { s+=4; siz[k] = img.dim; }
10544 else if (!cimg::strncasecmp(s,"width",5)) { s+=5; siz[k] = img.width; }
10545 else if (!cimg::strncasecmp(s,"height",6)) { s+=6; siz[k] = img.height; }
10546 else if (!cimg::strncasecmp(s,"depth",5)) { s+=5; siz[k] = img.depth; }
10547 else if (!cimg::strncasecmp(s,"dim",3)) { s+=3; siz[k] = img.dim; }
10548 else { ++s; --k; }
10549 }
10550 }
10551 return assign(siz[0],siz[1],siz[2],siz[3]);
10552 }
10553 return assign();
10554 }
10556 //! In-place version of the previous constructor.
10557 template<typename t>
10558 CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T val) {
10559 return assign(img,dimensions).fill(val);
10560 }
10562 //! In-place version of the previous constructor.
10563 /**
10564 This function replaces the instance image by the one that have been read from the given file.
10565 \param filename Filename of the image file.
10566 - The image format is deduced from the filename only by looking for the filename extension i.e. without
10567 analyzing the file itself.
10568 - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
10569 More informations on this topic can be found in cimg_files_io.
10570 - If the filename is not found, a CImgIOException is thrown by this constructor.
10571 **/
10572 CImg<T>& assign(const char *const filename) {
10573 return load(filename);
10574 }
10576 //! In-place version of the previous constructor.
10577 CImg<T>& assign(const CImgDisplay &disp) {
10578 disp.snapshot(*this);
10579 return *this;
10580 }
10582 //! Transfer the content of the instance image into another one in a way that memory copies are avoided if possible.
10583 /**
10584 The instance image is always empty after a call to this function.
10585 **/
10586 template<typename t>
10587 CImg<t>& transfer_to(CImg<t>& img) {
10588 img.assign(*this);
10589 assign();
10590 return img;
10591 }
10593 CImg<T>& transfer_to(CImg<T>& img) {
10594 if (is_shared || img.is_shared) { img.assign(*this); assign(); } else { img.assign(); swap(img); }
10595 return img;
10596 }
10598 //! Swap all fields of two images. Use with care !
10599 CImg<T>& swap(CImg<T>& img) {
10600 cimg::swap(width,img.width);
10601 cimg::swap(height,img.height);
10602 cimg::swap(depth,img.depth);
10603 cimg::swap(dim,img.dim);
10604 cimg::swap(data,img.data);
10605 cimg::swap(is_shared,img.is_shared);
10606 return img;
10607 }
10609 //@}
10610 //-------------------------------------
10611 //
10612 //! \name Image Informations
10613 //@{
10614 //-------------------------------------
10616 //! Return the type of the pixel values.
10617 /**
10618 \return a string describing the type of the image pixels (template parameter \p T).
10619 - The string returned may contains spaces (<tt>"unsigned char"</tt>).
10620 - If the template parameter T does not correspond to a registered type, the string <tt>"unknown"</tt> is returned.
10621 **/
10622 static const char* pixel_type() {
10623 return cimg::type<T>::string();
10624 }
10626 //! Return the total number of pixel values in an image.
10627 /**
10628 - Equivalent to : dimx() * dimy() * dimz() * dimv().
10630 \par example:
10631 \code
10632 CImg<> img(100,100,1,3);
10633 if (img.size()==100*100*3) std::fprintf(stderr,"This statement is true");
10634 \endcode
10635 **/
10636 unsigned long size() const {
10637 return width*height*depth*dim;
10638 }
10640 //! Return the number of columns of the instance image (size along the X-axis, i.e image width).
10641 int dimx() const {
10642 return (int)width;
10643 }
10645 //! Return the number of rows of the instance image (size along the Y-axis, i.e image height).
10646 int dimy() const {
10647 return (int)height;
10648 }
10650 //! Return the number of slices of the instance image (size along the Z-axis).
10651 int dimz() const {
10652 return (int)depth;
10653 }
10655 //! Return the number of vector channels of the instance image (size along the V-axis).
10656 int dimv() const {
10657 return (int)dim;
10658 }
10660 //! Return \c true if image (*this) has the specified width.
10661 bool is_sameX(const unsigned int dx) const {
10662 return (width==dx);
10663 }
10665 //! Return \c true if images \c (*this) and \c img have same width.
10666 template<typename t>
10667 bool is_sameX(const CImg<t>& img) const {
10668 return is_sameX(img.width);
10669 }
10671 //! Return \c true if images \c (*this) and the display \c disp have same width.
10672 bool is_sameX(const CImgDisplay& disp) const {
10673 return is_sameX(disp.width);
10674 }
10676 //! Return \c true if image (*this) has the specified height.
10677 bool is_sameY(const unsigned int dy) const {
10678 return (height==dy);
10679 }
10681 //! Return \c true if images \c (*this) and \c img have same height.
10682 template<typename t>
10683 bool is_sameY(const CImg<t>& img) const {
10684 return is_sameY(img.height);
10685 }
10687 //! Return \c true if images \c (*this) and the display \c disp have same height.
10688 bool is_sameY(const CImgDisplay& disp) const {
10689 return is_sameY(disp.height);
10690 }
10692 //! Return \c true if image (*this) has the specified depth.
10693 bool is_sameZ(const unsigned int dz) const {
10694 return (depth==dz);
10695 }
10697 //! Return \c true if images \c (*this) and \c img have same depth.
10698 template<typename t>
10699 bool is_sameZ(const CImg<t>& img) const {
10700 return is_sameZ(img.depth);
10701 }
10703 //! Return \c true if image (*this) has the specified number of channels.
10704 bool is_sameV(const unsigned int dv) const {
10705 return (dim==dv);
10706 }
10708 //! Return \c true if images \c (*this) and \c img have same dim.
10709 template<typename t>
10710 bool is_sameV(const CImg<t>& img) const {
10711 return is_sameV(img.dim);
10712 }
10714 //! Return \c true if image (*this) has the specified width and height.
10715 bool is_sameXY(const unsigned int dx, const unsigned int dy) const {
10716 return (is_sameX(dx) && is_sameY(dy));
10717 }
10719 //! Return \c true if images have same width and same height.
10720 template<typename t>
10721 bool is_sameXY(const CImg<t>& img) const {
10722 return (is_sameX(img) && is_sameY(img));
10723 }
10725 //! Return \c true if image \c (*this) and the display \c disp have same width and same height.
10726 bool is_sameXY(const CImgDisplay& disp) const {
10727 return (is_sameX(disp) && is_sameY(disp));
10728 }
10730 //! Return \c true if image (*this) has the specified width and depth.
10731 bool is_sameXZ(const unsigned int dx, const unsigned int dz) const {
10732 return (is_sameX(dx) && is_sameZ(dz));
10733 }
10735 //! Return \c true if images have same width and same depth.
10736 template<typename t>
10737 bool is_sameXZ(const CImg<t>& img) const {
10738 return (is_sameX(img) && is_sameZ(img));
10739 }
10741 //! Return \c true if image (*this) has the specified width and number of channels.
10742 bool is_sameXV(const unsigned int dx, const unsigned int dv) const {
10743 return (is_sameX(dx) && is_sameV(dv));
10744 }
10746 //! Return \c true if images have same width and same number of channels.
10747 template<typename t>
10748 bool is_sameXV(const CImg<t>& img) const {
10749 return (is_sameX(img) && is_sameV(img));
10750 }
10752 //! Return \c true if image (*this) has the specified height and depth.
10753 bool is_sameYZ(const unsigned int dy, const unsigned int dz) const {
10754 return (is_sameY(dy) && is_sameZ(dz));
10755 }
10757 //! Return \c true if images have same height and same depth.
10758 template<typename t>
10759 bool is_sameYZ(const CImg<t>& img) const {
10760 return (is_sameY(img) && is_sameZ(img));
10761 }
10763 //! Return \c true if image (*this) has the specified height and number of channels.
10764 bool is_sameYV(const unsigned int dy, const unsigned int dv) const {
10765 return (is_sameY(dy) && is_sameV(dv));
10766 }
10768 //! Return \c true if images have same height and same number of channels.
10769 template<typename t>
10770 bool is_sameYV(const CImg<t>& img) const {
10771 return (is_sameY(img) && is_sameV(img));
10772 }
10774 //! Return \c true if image (*this) has the specified depth and number of channels.
10775 bool is_sameZV(const unsigned int dz, const unsigned int dv) const {
10776 return (is_sameZ(dz) && is_sameV(dv));
10777 }
10779 //! Return \c true if images have same depth and same number of channels.
10780 template<typename t>
10781 bool is_sameZV(const CImg<t>& img) const {
10782 return (is_sameZ(img) && is_sameV(img));
10783 }
10785 //! Return \c true if image (*this) has the specified width, height and depth.
10786 bool is_sameXYZ(const unsigned int dx, const unsigned int dy, const unsigned int dz) const {
10787 return (is_sameXY(dx,dy) && is_sameZ(dz));
10788 }
10790 //! Return \c true if images have same width, same height and same depth.
10791 template<typename t>
10792 bool is_sameXYZ(const CImg<t>& img) const {
10793 return (is_sameXY(img) && is_sameZ(img));
10794 }
10796 //! Return \c true if image (*this) has the specified width, height and depth.
10797 bool is_sameXYV(const unsigned int dx, const unsigned int dy, const unsigned int dv) const {
10798 return (is_sameXY(dx,dy) && is_sameV(dv));
10799 }
10801 //! Return \c true if images have same width, same height and same number of channels.
10802 template<typename t>
10803 bool is_sameXYV(const CImg<t>& img) const {
10804 return (is_sameXY(img) && is_sameV(img));
10805 }
10807 //! Return \c true if image (*this) has the specified width, height and number of channels.
10808 bool is_sameXZV(const unsigned int dx, const unsigned int dz, const unsigned int dv) const {
10809 return (is_sameXZ(dx,dz) && is_sameV(dv));
10810 }
10812 //! Return \c true if images have same width, same depth and same number of channels.
10813 template<typename t>
10814 bool is_sameXZV(const CImg<t>& img) const {
10815 return (is_sameXZ(img) && is_sameV(img));
10816 }
10818 //! Return \c true if image (*this) has the specified height, depth and number of channels.
10819 bool is_sameYZV(const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
10820 return (is_sameYZ(dy,dz) && is_sameV(dv));
10821 }
10823 //! Return \c true if images have same heigth, same depth and same number of channels.
10824 template<typename t>
10825 bool is_sameYZV(const CImg<t>& img) const {
10826 return (is_sameYZ(img) && is_sameV(img));
10827 }
10829 //! Return \c true if image (*this) has the specified width, height, depth and number of channels.
10830 bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
10831 return (is_sameXYZ(dx,dy,dz) && is_sameV(dv));
10832 }
10834 //! Return \c true if images \c (*this) and \c img have same width, same height, same depth and same number of channels.
10835 template<typename t>
10836 bool is_sameXYZV(const CImg<t>& img) const {
10837 return (is_sameXYZ(img) && is_sameV(img));
10838 }
10840 //! Return \c true if current image is empty.
10841 bool is_empty() const {
10842 return !(data && width && height && depth && dim);
10843 }
10845 //! Return \p true if image is not empty.
10846 operator bool() const {
10847 return !is_empty();
10848 }
10850 //! Return an iterator to the first image pixel
10851 iterator begin() {
10852 return data;
10853 }
10855 const_iterator begin() const {
10856 return data;
10857 }
10859 //! Return reference to the first image pixel
10860 const T& first() const {
10861 return *data;
10862 }
10864 T& first() {
10865 return *data;
10866 }
10868 //! Return an iterator pointing after the last image pixel
10869 iterator end() {
10870 return data + size();
10871 }
10873 const_iterator end() const {
10874 return data + size();
10875 }
10877 //! Return a reference to the last image pixel
10878 const T& last() const {
10879 return data[size() - 1];
10880 }
10882 T& last() {
10883 return data[size() - 1];
10884 }
10886 //! Return a pointer to the pixel buffer.
10887 T* ptr() {
10888 return data;
10889 }
10891 const T* ptr() const {
10892 return data;
10893 }
10895 //! Return a pointer to the pixel value located at (\p x,\p y,\p z,\p v).
10896 /**
10897 \param x X-coordinate of the pixel.
10898 \param y Y-coordinate of the pixel.
10899 \param z Z-coordinate of the pixel.
10900 \param v V-coordinate of the pixel.
10902 - When called without parameters, ptr() returns a pointer to the begining of the pixel buffer.
10903 - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear if
10904 given coordinates are outside the image range (but function performances decrease).
10906 \par example:
10907 \code
10908 CImg<float> img(100,100,1,1,0); // Define a 100x100 greyscale image with float-valued pixels.
10909 float *ptr = ptr(10,10); // Get a pointer to the pixel located at (10,10).
10910 float val = *ptr; // Get the pixel value.
10911 \endcode
10912 **/
10913 #if cimg_debug>=3
10914 T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
10915 const long off = offset(x,y,z,v);
10916 if (off<0 || off>=(long)size()) {
10917 cimg::warn("CImg<%s>::ptr() : Asked for a pointer at coordinates (%u,%u,%u,%u) (offset=%ld), "
10918 "outside image range (%u,%u,%u,%u) (size=%lu)",
10919 pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
10920 return data;
10921 }
10922 return data + off;
10923 }
10925 const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
10926 return const_cast<CImg<T>*>(this)->ptr(x,y,z,v);
10927 }
10928 #else
10929 T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
10930 return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
10931 }
10933 const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
10934 return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
10935 }
10936 #endif
10938 //! Return \c true if the memory buffers of the two images overlaps.
10939 /**
10940 May happen when using shared images.
10941 **/
10942 template<typename t>
10943 bool is_overlapped(const CImg<t>& img) const {
10944 const unsigned long csiz = size(), isiz = img.size();
10945 return !((void*)(data+csiz)<=(void*)img.data || (void*)data>=(void*)(img.data+isiz));
10946 }
10948 //! Return the offset of the pixel coordinates (\p x,\p y,\p z,\p v) with respect to the data pointer \c data.
10949 /**
10950 \param x X-coordinate of the pixel.
10951 \param y Y-coordinate of the pixel.
10952 \param z Z-coordinate of the pixel.
10953 \param v V-coordinate of the pixel.
10955 - No checking is done on the validity of the given coordinates.
10957 \par Example:
10958 \code
10959 CImg<float> img(100,100,1,3,0); // Define a 100x100 color image with float-valued black pixels.
10960 long off = img.offset(10,10,0,2); // Get the offset of the blue value of the pixel located at (10,10).
10961 float val = img[off]; // Get the blue value of the pixel.
10962 \endcode
10963 **/
10964 long offset(const int x, const int y=0, const int z=0, const int v=0) const {
10965 return (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
10966 }
10968 //! Fast access to pixel value for reading or writing.
10969 /**
10970 \param x X-coordinate of the pixel.
10971 \param y Y-coordinate of the pixel.
10972 \param z Z-coordinate of the pixel.
10973 \param v V-coordinate of the pixel.
10975 - If one image dimension is equal to 1, it can be omitted in the coordinate list (see example below).
10976 - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
10977 (but function performances decrease).
10979 \par example:
10980 \code
10981 CImg<float> img(100,100,1,3,0); // Define a 100x100 color image with float-valued black pixels.
10982 const float valR = img(10,10,0,0); // Read the red component at coordinates (10,10).
10983 const float valG = img(10,10,0,1); // Read the green component at coordinates (10,10)
10984 const float valB = img(10,10,2); // Read the blue component at coordinates (10,10) (Z-coordinate omitted here).
10985 const float avg = (valR + valG + valB)/3; // Compute average pixel value.
10986 img(10,10,0) = img(10,10,1) = img(10,10,2) = avg; // Replace the pixel (10,10) by the average grey value.
10987 \endcode
10988 **/
10989 #if cimg_debug>=3
10990 T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
10991 const long off = offset(x,y,z,v);
10992 if (!data || off>=(long)size()) {
10993 cimg::warn("CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%ld) "
10994 "outside the image range (%u,%u,%u,%u) (size=%lu)",
10995 pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
10996 return *data;
10997 }
10998 else return data[off];
10999 }
11001 const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
11002 return const_cast<CImg<T>*>(this)->operator()(x,y,z,v);
11003 }
11004 #else
11005 T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
11006 return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
11007 }
11009 const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
11010 return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
11011 }
11012 #endif
11014 //! Fast access to pixel value for reading or writing, using an offset to the image pixel.
11015 /**
11016 \param off Offset of the pixel according to the begining of the pixel buffer, given by ptr().
11018 - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
11019 (but function performances decrease).
11020 - As pixel values are aligned in memory, this operator can sometime useful to access values easier than
11021 with operator()() (see example below).
11023 \par example:
11024 \code
11025 CImg<float> vec(1,10); // Define a vector of float values (10 lines, 1 row).
11026 const float val1 = vec(0,4); // Get the fifth element using operator()().
11027 const float val2 = vec[4]; // Get the fifth element using operator[]. Here, val2==val1.
11028 \endcode
11029 **/
11030 #if cimg_debug>=3
11031 T& operator[](const unsigned long off) {
11032 if (!data || off>=size()) {
11033 cimg::warn("CImg<%s>::operator[] : Pixel access requested at offset=%lu "
11034 "outside the image range (%u,%u,%u,%u) (size=%lu)",
11035 pixel_type(),off,width,height,depth,dim,size());
11036 return *data;
11037 }
11038 else return data[off];
11039 }
11041 const T& operator[](const unsigned long off) const {
11042 return const_cast<CImg<T>*>(this)->operator[](off);
11043 }
11044 #else
11045 T& operator[](const unsigned long off) {
11046 return data[off];
11047 }
11049 const T& operator[](const unsigned long off) const {
11050 return data[off];
11051 }
11052 #endif
11054 //! Return a reference to the last image value
11055 T& back() {
11056 return operator()(size()-1);
11057 }
11059 const T& back() const {
11060 return operator()(size()-1);
11061 }
11063 //! Return a reference to the first image value
11064 T& front() {
11065 return *data;
11066 }
11068 const T& front() const {
11069 return *data;
11070 }
11072 //! Return \c true if pixel (x,y,z,v) is inside image boundaries.
11073 bool containsXYZV(const int x, const int y=0, const int z=0, const int v=0) const {
11074 return !is_empty() && x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz() && v>=0 && v<dimv();
11075 }
11077 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z,v).
11078 template<typename t>
11079 bool contains(const T& pixel, t& x, t& y, t& z, t& v) const {
11080 const unsigned long wh = width*height, whz = wh*depth, siz = whz*dim;
11081 const T *const ppixel = &pixel;
11082 if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
11083 unsigned long off = (unsigned long)(ppixel - data);
11084 const unsigned long nv = off/whz;
11085 off%=whz;
11086 const unsigned long nz = off/wh;
11087 off%=wh;
11088 const unsigned long ny = off/width, nx = off%width;
11089 x = (t)nx; y = (t)ny; z = (t)nz; v = (t)nv;
11090 return true;
11091 }
11093 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z).
11094 template<typename t>
11095 bool contains(const T& pixel, t& x, t& y, t& z) const {
11096 const unsigned long wh = width*height, whz = wh*depth, siz = whz*dim;
11097 const T *const ppixel = &pixel;
11098 if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
11099 unsigned long off = ((unsigned long)(ppixel - data))%whz;
11100 const unsigned long nz = off/wh;
11101 off%=wh;
11102 const unsigned long ny = off/width, nx = off%width;
11103 x = (t)nx; y = (t)ny; z = (t)nz;
11104 return true;
11105 }
11107 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y).
11108 template<typename t>
11109 bool contains(const T& pixel, t& x, t& y) const {
11110 const unsigned long wh = width*height, siz = wh*depth*dim;
11111 const T *const ppixel = &pixel;
11112 if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
11113 unsigned long off = ((unsigned long)(ppixel - data))%wh;
11114 const unsigned long ny = off/width, nx = off%width;
11115 x = (t)nx; y = (t)ny;
11116 return true;
11117 }
11119 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x).
11120 template<typename t>
11121 bool contains(const T& pixel, t& x) const {
11122 const T *const ppixel = &pixel;
11123 if (is_empty() || ppixel<data || ppixel>=data+size()) return false;
11124 x = (t)(((unsigned long)(ppixel - data))%width);
11125 return true;
11126 }
11128 //! Return \c true if specified referenced value is inside the image boundaries.
11129 bool contains(const T& pixel) const {
11130 const T *const ppixel = &pixel;
11131 return !is_empty() && ppixel>=data && ppixel<data+size();
11132 }
11134 //! Read a pixel value with Dirichlet boundary conditions.
11135 T& at(const int off, const T out_val) {
11136 return (off<0 || off>=(int)size())?(cimg::temporary(out_val)=out_val):(*this)[off];
11137 }
11139 T at(const int off, const T out_val) const {
11140 return (off<0 || off>=(int)size())?out_val:(*this)[off];
11141 }
11143 //! Read a pixel value with Neumann boundary conditions.
11144 T& at(const int off) {
11145 if (!size())
11146 throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
11147 pixel_type());
11148 return _at(off);
11149 }
11151 T at(const int off) const {
11152 if (!size())
11153 throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
11154 pixel_type());
11155 return _at(off);
11156 }
11158 T& _at(const int off) {
11159 const unsigned int siz = (unsigned int)size();
11160 return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
11161 }
11163 T _at(const int off) const {
11164 const unsigned int siz = (unsigned int)size();
11165 return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
11166 }
11168 //! Read a pixel value with Dirichlet boundary conditions.
11169 T& atXYZV(const int x, const int y, const int z, const int v, const T out_val) {
11170 return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?
11171 (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11172 }
11174 T atXYZV(const int x, const int y, const int z, const int v, const T out_val) const {
11175 return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v);
11176 }
11178 //! Read a pixel value with Neumann boundary conditions.
11179 T& atXYZV(const int x, const int y, const int z, const int v) {
11180 if (is_empty())
11181 throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
11182 pixel_type());
11183 return _atXYZV(x,y,z,v);
11184 }
11186 T atXYZV(const int x, const int y, const int z, const int v) const {
11187 if (is_empty())
11188 throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
11189 pixel_type());
11190 return _atXYZV(x,y,z,v);
11191 }
11193 T& _atXYZV(const int x, const int y, const int z, const int v) {
11194 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
11195 z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
11196 }
11198 T _atXYZV(const int x, const int y, const int z, const int v) const {
11199 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
11200 z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
11201 }
11203 //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c x,\c y,\c z).
11204 T& atXYZ(const int x, const int y, const int z, const int v, const T out_val) {
11205 return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?
11206 (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11207 }
11209 T atXYZ(const int x, const int y, const int z, const int v, const T out_val) const {
11210 return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v);
11211 }
11213 //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c x,\c y,\c z).
11214 T& atXYZ(const int x, const int y, const int z, const int v=0) {
11215 if (is_empty())
11216 throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
11217 pixel_type());
11218 return _atXYZ(x,y,z,v);
11219 }
11221 T atXYZ(const int x, const int y, const int z, const int v=0) const {
11222 if (is_empty())
11223 throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
11224 pixel_type());
11225 return _atXYZ(x,y,z,v);
11226 }
11228 T& _atXYZ(const int x, const int y, const int z, const int v=0) {
11229 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
11230 z<0?0:(z>=dimz()?dimz()-1:z),v);
11231 }
11233 T _atXYZ(const int x, const int y, const int z, const int v=0) const {
11234 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
11235 z<0?0:(z>=dimz()?dimz()-1:z),v);
11236 }
11238 //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c x,\c y).
11239 T& atXY(const int x, const int y, const int z, const int v, const T out_val) {
11240 return (x<0 || y<0 || x>=dimx() || y>=dimy())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11241 }
11243 T atXY(const int x, const int y, const int z, const int v, const T out_val) const {
11244 return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v);
11245 }
11247 //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c x,\c y).
11248 T& atXY(const int x, const int y, const int z=0, const int v=0) {
11249 if (is_empty())
11250 throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
11251 pixel_type());
11252 return _atXY(x,y,z,v);
11253 }
11255 T atXY(const int x, const int y, const int z=0, const int v=0) const {
11256 if (is_empty())
11257 throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
11258 pixel_type());
11259 return _atXY(x,y,z,v);
11260 }
11262 T& _atXY(const int x, const int y, const int z=0, const int v=0) {
11263 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
11264 }
11266 T _atXY(const int x, const int y, const int z=0, const int v=0) const {
11267 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
11268 }
11270 //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c x).
11271 T& atX(const int x, const int y, const int z, const int v, const T out_val) {
11272 return (x<0 || x>=dimx())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
11273 }
11275 T atX(const int x, const int y, const int z, const int v, const T out_val) const {
11276 return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v);
11277 }
11279 //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c x).
11280 T& atX(const int x, const int y=0, const int z=0, const int v=0) {
11281 if (is_empty())
11282 throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
11283 pixel_type());
11284 return _atX(x,y,z,v);
11285 }
11287 T atX(const int x, const int y=0, const int z=0, const int v=0) const {
11288 if (is_empty())
11289 throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
11290 pixel_type());
11291 return _atX(x,y,z,v);
11292 }
11294 T& _atX(const int x, const int y=0, const int z=0, const int v=0) {
11295 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
11296 }
11298 T _atX(const int x, const int y=0, const int z=0, const int v=0) const {
11299 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
11300 }
11302 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions.
11303 Tfloat linear_atXYZV(const float fx, const float fy, const float fz, const float fv, const T out_val) const {
11304 const int
11305 x = (int)fx-(fx>=0?0:1), nx = x+1,
11306 y = (int)fy-(fy>=0?0:1), ny = y+1,
11307 z = (int)fz-(fz>=0?0:1), nz = z+1,
11308 v = (int)fv-(fv>=0?0:1), nv = v+1;
11309 const float
11310 dx = fx-x,
11311 dy = fy-y,
11312 dz = fz-z,
11313 dv = fv-v;
11314 const Tfloat
11315 Icccc = (Tfloat)atXYZV(x,y,z,v,out_val), Inccc = (Tfloat)atXYZV(nx,y,z,v,out_val),
11316 Icncc = (Tfloat)atXYZV(x,ny,z,v,out_val), Inncc = (Tfloat)atXYZV(nx,ny,z,v,out_val),
11317 Iccnc = (Tfloat)atXYZV(x,y,nz,v,out_val), Incnc = (Tfloat)atXYZV(nx,y,nz,v,out_val),
11318 Icnnc = (Tfloat)atXYZV(x,ny,nz,v,out_val), Innnc = (Tfloat)atXYZV(nx,ny,nz,v,out_val),
11319 Icccn = (Tfloat)atXYZV(x,y,z,nv,out_val), Inccn = (Tfloat)atXYZV(nx,y,z,nv,out_val),
11320 Icncn = (Tfloat)atXYZV(x,ny,z,nv,out_val), Inncn = (Tfloat)atXYZV(nx,ny,z,nv,out_val),
11321 Iccnn = (Tfloat)atXYZV(x,y,nz,nv,out_val), Incnn = (Tfloat)atXYZV(nx,y,nz,nv,out_val),
11322 Icnnn = (Tfloat)atXYZV(x,ny,nz,nv,out_val), Innnn = (Tfloat)atXYZV(nx,ny,nz,nv,out_val);
11323 return Icccc +
11324 dx*(Inccc-Icccc +
11325 dy*(Icccc+Inncc-Icncc-Inccc +
11326 dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
11327 dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
11328 dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
11329 dz*(Icccc+Incnc-Iccnc-Inccc +
11330 dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
11331 dv*(Icccc+Inccn-Inccc-Icccn)) +
11332 dy*(Icncc-Icccc +
11333 dz*(Icccc+Icnnc-Iccnc-Icncc +
11334 dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
11335 dv*(Icccc+Icncn-Icncc-Icccn)) +
11336 dz*(Iccnc-Icccc +
11337 dv*(Icccc+Iccnn-Iccnc-Icccn)) +
11338 dv*(Icccn-Icccc);
11339 }
11341 //! Read a pixel value using linear interpolation and Neumann boundary conditions.
11342 Tfloat linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
11343 if (is_empty())
11344 throw CImgInstanceException("CImg<%s>::linear_atXYZV() : Instance image is empty.",
11345 pixel_type());
11346 return _linear_atXYZV(fx,fy,fz,fv);
11347 }
11349 Tfloat _linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
11350 const float
11351 nfx = fx<0?0:(fx>width-1?width-1:fx),
11352 nfy = fy<0?0:(fy>height-1?height-1:fy),
11353 nfz = fz<0?0:(fz>depth-1?depth-1:fz),
11354 nfv = fv<0?0:(fv>dim-1?dim-1:fv);
11355 const unsigned int
11356 x = (unsigned int)nfx,
11357 y = (unsigned int)nfy,
11358 z = (unsigned int)nfz,
11359 v = (unsigned int)nfv;
11360 const float
11361 dx = nfx-x,
11362 dy = nfy-y,
11363 dz = nfz-z,
11364 dv = nfv-v;
11365 const unsigned int
11366 nx = dx>0?x+1:x,
11367 ny = dy>0?y+1:y,
11368 nz = dz>0?z+1:z,
11369 nv = dv>0?v+1:v;
11370 const Tfloat
11371 Icccc = (Tfloat)(*this)(x,y,z,v), Inccc = (Tfloat)(*this)(nx,y,z,v),
11372 Icncc = (Tfloat)(*this)(x,ny,z,v), Inncc = (Tfloat)(*this)(nx,ny,z,v),
11373 Iccnc = (Tfloat)(*this)(x,y,nz,v), Incnc = (Tfloat)(*this)(nx,y,nz,v),
11374 Icnnc = (Tfloat)(*this)(x,ny,nz,v), Innnc = (Tfloat)(*this)(nx,ny,nz,v),
11375 Icccn = (Tfloat)(*this)(x,y,z,nv), Inccn = (Tfloat)(*this)(nx,y,z,nv),
11376 Icncn = (Tfloat)(*this)(x,ny,z,nv), Inncn = (Tfloat)(*this)(nx,ny,z,nv),
11377 Iccnn = (Tfloat)(*this)(x,y,nz,nv), Incnn = (Tfloat)(*this)(nx,y,nz,nv),
11378 Icnnn = (Tfloat)(*this)(x,ny,nz,nv), Innnn = (Tfloat)(*this)(nx,ny,nz,nv);
11379 return Icccc +
11380 dx*(Inccc-Icccc +
11381 dy*(Icccc+Inncc-Icncc-Inccc +
11382 dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
11383 dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
11384 dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
11385 dz*(Icccc+Incnc-Iccnc-Inccc +
11386 dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
11387 dv*(Icccc+Inccn-Inccc-Icccn)) +
11388 dy*(Icncc-Icccc +
11389 dz*(Icccc+Icnnc-Iccnc-Icncc +
11390 dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
11391 dv*(Icccc+Icncn-Icncc-Icccn)) +
11392 dz*(Iccnc-Icccc +
11393 dv*(Icccc+Iccnn-Iccnc-Icccn)) +
11394 dv*(Icccn-Icccc);
11395 }
11397 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first three coordinates).
11398 Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int v, const T out_val) const {
11399 const int
11400 x = (int)fx-(fx>=0?0:1), nx = x+1,
11401 y = (int)fy-(fy>=0?0:1), ny = y+1,
11402 z = (int)fz-(fz>=0?0:1), nz = z+1;
11403 const float
11404 dx = fx-x,
11405 dy = fy-y,
11406 dz = fz-z;
11407 const Tfloat
11408 Iccc = (Tfloat)atXYZ(x,y,z,v,out_val), Incc = (Tfloat)atXYZ(nx,y,z,v,out_val),
11409 Icnc = (Tfloat)atXYZ(x,ny,z,v,out_val), Innc = (Tfloat)atXYZ(nx,ny,z,v,out_val),
11410 Iccn = (Tfloat)atXYZ(x,y,nz,v,out_val), Incn = (Tfloat)atXYZ(nx,y,nz,v,out_val),
11411 Icnn = (Tfloat)atXYZ(x,ny,nz,v,out_val), Innn = (Tfloat)atXYZ(nx,ny,nz,v,out_val);
11412 return Iccc +
11413 dx*(Incc-Iccc +
11414 dy*(Iccc+Innc-Icnc-Incc +
11415 dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
11416 dz*(Iccc+Incn-Iccn-Incc)) +
11417 dy*(Icnc-Iccc +
11418 dz*(Iccc+Icnn-Iccn-Icnc)) +
11419 dz*(Iccn-Iccc);
11420 }
11422 //! Read a pixel value using linear interpolation and Neumann boundary conditions (first three coordinates).
11423 Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
11424 if (is_empty())
11425 throw CImgInstanceException("CImg<%s>::linear_atXYZ() : Instance image is empty.",
11426 pixel_type());
11427 return _linear_atXYZ(fx,fy,fz,v);
11428 }
11430 Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
11431 const float
11432 nfx = fx<0?0:(fx>width-1?width-1:fx),
11433 nfy = fy<0?0:(fy>height-1?height-1:fy),
11434 nfz = fz<0?0:(fz>depth-1?depth-1:fz);
11435 const unsigned int
11436 x = (unsigned int)nfx,
11437 y = (unsigned int)nfy,
11438 z = (unsigned int)nfz;
11439 const float
11440 dx = nfx-x,
11441 dy = nfy-y,
11442 dz = nfz-z;
11443 const unsigned int
11444 nx = dx>0?x+1:x,
11445 ny = dy>0?y+1:y,
11446 nz = dz>0?z+1:z;
11447 const Tfloat
11448 Iccc = (Tfloat)(*this)(x,y,z,v), Incc = (Tfloat)(*this)(nx,y,z,v),
11449 Icnc = (Tfloat)(*this)(x,ny,z,v), Innc = (Tfloat)(*this)(nx,ny,z,v),
11450 Iccn = (Tfloat)(*this)(x,y,nz,v), Incn = (Tfloat)(*this)(nx,y,nz,v),
11451 Icnn = (Tfloat)(*this)(x,ny,nz,v), Innn = (Tfloat)(*this)(nx,ny,nz,v);
11452 return Iccc +
11453 dx*(Incc-Iccc +
11454 dy*(Iccc+Innc-Icnc-Incc +
11455 dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
11456 dz*(Iccc+Incn-Iccn-Incc)) +
11457 dy*(Icnc-Iccc +
11458 dz*(Iccc+Icnn-Iccn-Icnc)) +
11459 dz*(Iccn-Iccc);
11460 }
11462 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first two coordinates).
11463 Tfloat linear_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
11464 const int
11465 x = (int)fx-(fx>=0?0:1), nx = x+1,
11466 y = (int)fy-(fy>=0?0:1), ny = y+1;
11467 const float
11468 dx = fx-x,
11469 dy = fy-y;
11470 const Tfloat
11471 Icc = (Tfloat)atXY(x,y,z,v,out_val), Inc = (Tfloat)atXY(nx,y,z,v,out_val),
11472 Icn = (Tfloat)atXY(x,ny,z,v,out_val), Inn = (Tfloat)atXY(nx,ny,z,v,out_val);
11473 return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
11474 }
11476 //! Read a pixel value using linear interpolation and Neumann boundary conditions (first two coordinates).
11477 Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11478 if (is_empty())
11479 throw CImgInstanceException("CImg<%s>::linear_atXY() : Instance image is empty.",
11480 pixel_type());
11481 return _linear_atXY(fx,fy,z,v);
11482 }
11484 Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11485 const float
11486 nfx = fx<0?0:(fx>width-1?width-1:fx),
11487 nfy = fy<0?0:(fy>height-1?height-1:fy);
11488 const unsigned int
11489 x = (unsigned int)nfx,
11490 y = (unsigned int)nfy;
11491 const float
11492 dx = nfx-x,
11493 dy = nfy-y;
11494 const unsigned int
11495 nx = dx>0?x+1:x,
11496 ny = dy>0?y+1:y;
11497 const Tfloat
11498 Icc = (Tfloat)(*this)(x,y,z,v), Inc = (Tfloat)(*this)(nx,y,z,v),
11499 Icn = (Tfloat)(*this)(x,ny,z,v), Inn = (Tfloat)(*this)(nx,ny,z,v);
11500 return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
11501 }
11503 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first coordinate).
11504 Tfloat linear_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
11505 const int
11506 x = (int)fx-(fx>=0?0:1), nx = x+1;
11507 const float
11508 dx = fx-x;
11509 const Tfloat
11510 Ic = (Tfloat)atX(x,y,z,v,out_val), In = (Tfloat)atXY(nx,y,z,v,out_val);
11511 return Ic + dx*(In-Ic);
11512 }
11514 //! Read a pixel value using linear interpolation and Neumann boundary conditions (first coordinate).
11515 Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11516 if (is_empty())
11517 throw CImgInstanceException("CImg<%s>::linear_atX() : Instance image is empty.",
11518 pixel_type());
11519 return _linear_atX(fx,y,z,v);
11520 }
11522 Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11523 const float
11524 nfx = fx<0?0:(fx>width-1?width-1:fx);
11525 const unsigned int
11526 x = (unsigned int)nfx;
11527 const float
11528 dx = nfx-x;
11529 const unsigned int
11530 nx = dx>0?x+1:x;
11531 const Tfloat
11532 Ic = (Tfloat)(*this)(x,y,z,v), In = (Tfloat)(*this)(nx,y,z,v);
11533 return Ic + dx*(In-Ic);
11534 }
11536 //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions.
11537 Tfloat cubic_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
11538 const int
11539 x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2,
11540 y = (int)fy-(fy>=0?0:1), py = y-1, ny = y+1, ay = y+2;
11541 const float
11542 dx = fx-x, dx2 = dx*dx, dx3 = dx2*dx,
11543 dy = fy-y;
11544 const Tfloat
11545 Ipp = (Tfloat)atXY(px,py,z,v,out_val), Icp = (Tfloat)atXY(x,py,z,v,out_val),
11546 Inp = (Tfloat)atXY(nx,py,z,v,out_val), Iap = (Tfloat)atXY(ax,py,z,v,out_val),
11547 Ipc = (Tfloat)atXY(px,y,z,v,out_val), Icc = (Tfloat)atXY(x,y,z,v,out_val),
11548 Inc = (Tfloat)atXY(nx,y,z,v,out_val), Iac = (Tfloat)atXY(ax,y,z,v,out_val),
11549 Ipn = (Tfloat)atXY(px,ny,z,v,out_val), Icn = (Tfloat)atXY(x,ny,z,v,out_val),
11550 Inn = (Tfloat)atXY(nx,ny,z,v,out_val), Ian = (Tfloat)atXY(ax,ny,z,v,out_val),
11551 Ipa = (Tfloat)atXY(px,ay,z,v,out_val), Ica = (Tfloat)atXY(x,ay,z,v,out_val),
11552 Ina = (Tfloat)atXY(nx,ay,z,v,out_val), Iaa = (Tfloat)atXY(ax,ay,z,v,out_val),
11553 valm = cimg::min(cimg::min(Ipp,Icp,Inp,Iap),cimg::min(Ipc,Icc,Inc,Iac),cimg::min(Ipn,Icn,Inn,Ian),cimg::min(Ipa,Ica,Ina,Iaa)),
11554 valM = cimg::max(cimg::max(Ipp,Icp,Inp,Iap),cimg::max(Ipc,Icc,Inc,Iac),cimg::max(Ipn,Icn,Inn,Ian),cimg::max(Ipa,Ica,Ina,Iaa)),
11555 u0p = Icp - Ipp,
11556 u1p = Iap - Inp,
11557 ap = 2*(Icp-Inp) + u0p + u1p,
11558 bp = 3*(Inp-Icp) - 2*u0p - u1p,
11559 u0c = Icc - Ipc,
11560 u1c = Iac - Inc,
11561 ac = 2*(Icc-Inc) + u0c + u1c,
11562 bc = 3*(Inc-Icc) - 2*u0c - u1c,
11563 u0n = Icn - Ipn,
11564 u1n = Ian - Inn,
11565 an = 2*(Icn-Inn) + u0n + u1n,
11566 bn = 3*(Inn-Icn) - 2*u0n - u1n,
11567 u0a = Ica - Ipa,
11568 u1a = Iaa - Ina,
11569 aa = 2*(Ica-Ina) + u0a + u1a,
11570 ba = 3*(Ina-Ica) - 2*u0a - u1a,
11571 valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
11572 valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
11573 valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
11574 vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
11575 u0 = valc - valp,
11576 u1 = vala - valn,
11577 a = 2*(valc-valn) + u0 + u1,
11578 b = 3*(valn-valc) - 2*u0 - u1,
11579 val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
11580 return val<valm?valm:(val>valM?valM:val);
11581 }
11583 //! Read a pixel value using cubic interpolation and Neumann boundary conditions.
11584 Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11585 if (is_empty())
11586 throw CImgInstanceException("CImg<%s>::cubic_atXY() : Instance image is empty.",
11587 pixel_type());
11588 return _cubic_atXY(fx,fy,z,v);
11589 }
11591 Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
11592 const float
11593 nfx = fx<0?0:(fx>width-1?width-1:fx),
11594 nfy = fy<0?0:(fy>height-1?height-1:fy);
11595 const int
11596 x = (int)nfx,
11597 y = (int)nfy;
11598 const float
11599 dx = nfx-x, dx2 = dx*dx, dx3 = dx2*dx,
11600 dy = nfy-y;
11601 const int
11602 px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2,
11603 py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=dimy()?dimy()-1:y+2;
11604 const Tfloat
11605 Ipp = (Tfloat)(*this)(px,py,z,v), Icp = (Tfloat)(*this)(x,py,z,v),
11606 Inp = (Tfloat)(*this)(nx,py,z,v), Iap = (Tfloat)(*this)(ax,py,z,v),
11607 Ipc = (Tfloat)(*this)(px,y,z,v), Icc = (Tfloat)(*this)(x,y,z,v),
11608 Inc = (Tfloat)(*this)(nx,y,z,v), Iac = (Tfloat)(*this)(ax,y,z,v),
11609 Ipn = (Tfloat)(*this)(px,ny,z,v), Icn = (Tfloat)(*this)(x,ny,z,v),
11610 Inn = (Tfloat)(*this)(nx,ny,z,v), Ian = (Tfloat)(*this)(ax,ny,z,v),
11611 Ipa = (Tfloat)(*this)(px,ay,z,v), Ica = (Tfloat)(*this)(x,ay,z,v),
11612 Ina = (Tfloat)(*this)(nx,ay,z,v), Iaa = (Tfloat)(*this)(ax,ay,z,v),
11613 valm = cimg::min(cimg::min(Ipp,Icp,Inp,Iap),cimg::min(Ipc,Icc,Inc,Iac),cimg::min(Ipn,Icn,Inn,Ian),cimg::min(Ipa,Ica,Ina,Iaa)),
11614 valM = cimg::max(cimg::max(Ipp,Icp,Inp,Iap),cimg::max(Ipc,Icc,Inc,Iac),cimg::max(Ipn,Icn,Inn,Ian),cimg::max(Ipa,Ica,Ina,Iaa)),
11615 u0p = Icp - Ipp,
11616 u1p = Iap - Inp,
11617 ap = 2*(Icp-Inp) + u0p + u1p,
11618 bp = 3*(Inp-Icp) - 2*u0p - u1p,
11619 u0c = Icc - Ipc,
11620 u1c = Iac - Inc,
11621 ac = 2*(Icc-Inc) + u0c + u1c,
11622 bc = 3*(Inc-Icc) - 2*u0c - u1c,
11623 u0n = Icn - Ipn,
11624 u1n = Ian - Inn,
11625 an = 2*(Icn-Inn) + u0n + u1n,
11626 bn = 3*(Inn-Icn) - 2*u0n - u1n,
11627 u0a = Ica - Ipa,
11628 u1a = Iaa - Ina,
11629 aa = 2*(Ica-Ina) + u0a + u1a,
11630 ba = 3*(Ina-Ica) - 2*u0a - u1a,
11631 valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
11632 valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
11633 valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
11634 vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
11635 u0 = valc - valp,
11636 u1 = vala - valn,
11637 a = 2*(valc-valn) + u0 + u1,
11638 b = 3*(valn-valc) - 2*u0 - u1,
11639 val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
11640 return val<valm?valm:(val>valM?valM:val);
11641 }
11643 //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions (first coordinates).
11644 Tfloat cubic_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
11645 const int
11646 x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2;
11647 const float
11648 dx = fx-x;
11649 const Tfloat
11650 Ip = (Tfloat)atX(px,y,z,v,out_val), Ic = (Tfloat)atX(x,y,z,v,out_val),
11651 In = (Tfloat)atX(nx,y,z,v,out_val), Ia = (Tfloat)atX(ax,y,z,v,out_val),
11652 valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
11653 u0 = Ic - Ip,
11654 u1 = Ia - In,
11655 a = 2*(Ic-In) + u0 + u1,
11656 b = 3*(In-Ic) - 2*u0 - u1,
11657 val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
11658 return val<valm?valm:(val>valM?valM:val);
11659 }
11661 //! Read a pixel value using cubic interpolation and Neumann boundary conditions (first coordinates).
11662 Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11663 if (is_empty())
11664 throw CImgInstanceException("CImg<%s>::cubic_atX() : Instance image is empty.",
11665 pixel_type());
11666 return _cubic_atX(fx,y,z,v);
11667 }
11669 Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
11670 const float
11671 nfx = fx<0?0:(fx>width-1?width-1:fx);
11672 const int
11673 x = (int)nfx;
11674 const float
11675 dx = nfx-x;
11676 const int
11677 px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2;
11678 const Tfloat
11679 Ip = (Tfloat)(*this)(px,y,z,v), Ic = (Tfloat)(*this)(x,y,z,v),
11680 In = (Tfloat)(*this)(nx,y,z,v), Ia = (Tfloat)(*this)(ax,y,z,v),
11681 valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
11682 u0 = Ic - Ip,
11683 u1 = Ia - In,
11684 a = 2*(Ic-In) + u0 + u1,
11685 b = 3*(In-Ic) - 2*u0 - u1,
11686 val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
11687 return val<valm?valm:(val>valM?valM:val);
11688 }
11690 //! Set a pixel value, with 3D float coordinates, using linear interpolation.
11691 CImg& set_linear_atXYZ(const T& val, const float fx, const float fy=0, const float fz=0, const int v=0,
11692 const bool add=false) {
11693 const int
11694 x = (int)fx-(fx>=0?0:1), nx = x+1,
11695 y = (int)fy-(fy>=0?0:1), ny = y+1,
11696 z = (int)fz-(fz>=0?0:1), nz = z+1;
11697 const float
11698 dx = fx-x,
11699 dy = fy-y,
11700 dz = fz-z;
11701 if (v>=0 && v<dimv()) {
11702 if (z>=0 && z<dimz()) {
11703 if (y>=0 && y<dimy()) {
11704 if (x>=0 && x<dimx()) {
11705 const float w1 = (1-dx)*(1-dy)*(1-dz), w2 = add?1:(1-w1);
11706 (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
11707 }
11708 if (nx>=0 && nx<dimx()) {
11709 const float w1 = dx*(1-dy)*(1-dz), w2 = add?1:(1-w1);
11710 (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
11711 }
11712 }
11713 if (ny>=0 && ny<dimy()) {
11714 if (x>=0 && x<dimx()) {
11715 const float w1 = (1-dx)*dy*(1-dz), w2 = add?1:(1-w1);
11716 (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
11717 }
11718 if (nx>=0 && nx<dimx()) {
11719 const float w1 = dx*dy*(1-dz), w2 = add?1:(1-w1);
11720 (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
11721 }
11722 }
11723 }
11724 if (nz>=0 && nz<dimz()) {
11725 if (y>=0 && y<dimy()) {
11726 if (x>=0 && x<dimx()) {
11727 const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
11728 (*this)(x,y,nz,v) = (T)(w1*val + w2*(*this)(x,y,nz,v));
11729 }
11730 if (nx>=0 && nx<dimx()) {
11731 const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
11732 (*this)(nx,y,nz,v) = (T)(w1*val + w2*(*this)(nx,y,nz,v));
11733 }
11734 }
11735 if (ny>=0 && ny<dimy()) {
11736 if (x>=0 && x<dimx()) {
11737 const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
11738 (*this)(x,ny,nz,v) = (T)(w1*val + w2*(*this)(x,ny,nz,v));
11739 }
11740 if (nx>=0 && nx<dimx()) {
11741 const float w1 = dx*dy, w2 = add?1:(1-w1);
11742 (*this)(nx,ny,nz,v) = (T)(w1*val + w2*(*this)(nx,ny,nz,v));
11743 }
11744 }
11745 }
11746 }
11747 return *this;
11748 }
11750 //! Set a pixel value, with 2D float coordinates, using linear interpolation.
11751 CImg& set_linear_atXY(const T& val, const float fx, const float fy=0, const int z=0, const int v=0,
11752 const bool add=false) {
11753 const int
11754 x = (int)fx-(fx>=0?0:1), nx = x+1,
11755 y = (int)fy-(fy>=0?0:1), ny = y+1;
11756 const float
11757 dx = fx-x,
11758 dy = fy-y;
11759 if (z>=0 && z<dimz() && v>=0 && v<dimv()) {
11760 if (y>=0 && y<dimy()) {
11761 if (x>=0 && x<dimx()) {
11762 const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
11763 (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
11764 }
11765 if (nx>=0 && nx<dimx()) {
11766 const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
11767 (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
11768 }
11769 }
11770 if (ny>=0 && ny<dimy()) {
11771 if (x>=0 && x<dimx()) {
11772 const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
11773 (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
11774 }
11775 if (nx>=0 && nx<dimx()) {
11776 const float w1 = dx*dy, w2 = add?1:(1-w1);
11777 (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
11778 }
11779 }
11780 }
11781 return *this;
11782 }
11784 //! Return a reference to the minimum pixel value of the instance image
11785 const T& min() const {
11786 if (is_empty())
11787 throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",
11788 pixel_type());
11789 const T *ptrmin = data;
11790 T min_value = *ptrmin;
11791 cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
11792 return *ptrmin;
11793 }
11795 //! Return a reference to the minimum pixel value of the instance image
11796 T& min() {
11797 if (is_empty())
11798 throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",
11799 pixel_type());
11800 T *ptrmin = data;
11801 T min_value = *ptrmin;
11802 cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
11803 return *ptrmin;
11804 }
11806 //! Return a reference to the maximum pixel value of the instance image
11807 const T& max() const {
11808 if (is_empty())
11809 throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",
11810 pixel_type());
11811 const T *ptrmax = data;
11812 T max_value = *ptrmax;
11813 cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
11814 return *ptrmax;
11815 }
11817 //! Return a reference to the maximum pixel value of the instance image
11818 T& max() {
11819 if (is_empty())
11820 throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",
11821 pixel_type());
11822 T *ptrmax = data;
11823 T max_value = *ptrmax;
11824 cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
11825 return *ptrmax;
11826 }
11828 //! Return a reference to the minimum pixel value and return also the maximum pixel value.
11829 template<typename t>
11830 const T& minmax(t& max_val) const {
11831 if (is_empty())
11832 throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",
11833 pixel_type());
11834 const T *ptrmin = data;
11835 T min_value = *ptrmin, max_value = min_value;
11836 cimg_for(*this,ptr,T) {
11837 const T val = *ptr;
11838 if (val<min_value) { min_value = val; ptrmin = ptr; }
11839 if (val>max_value) max_value = val;
11840 }
11841 max_val = (t)max_value;
11842 return *ptrmin;
11843 }
11845 //! Return a reference to the minimum pixel value and return also the maximum pixel value.
11846 template<typename t>
11847 T& minmax(t& max_val) {
11848 if (is_empty())
11849 throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",
11850 pixel_type());
11851 T *ptrmin = data;
11852 T min_value = *ptrmin, max_value = min_value;
11853 cimg_for(*this,ptr,T) {
11854 const T val = *ptr;
11855 if (val<min_value) { min_value = val; ptrmin = ptr; }
11856 if (val>max_value) max_value = val;
11857 }
11858 max_val = (t)max_value;
11859 return *ptrmin;
11860 }
11862 //! Return a reference to the maximum pixel value and return also the minimum pixel value.
11863 template<typename t>
11864 const T& maxmin(t& min_val) const {
11865 if (is_empty())
11866 throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",
11867 pixel_type());
11868 const T *ptrmax = data;
11869 T max_value = *ptrmax, min_value = max_value;
11870 cimg_for(*this,ptr,T) {
11871 const T val = *ptr;
11872 if (val>max_value) { max_value = val; ptrmax = ptr; }
11873 if (val<min_value) min_value = val;
11874 }
11875 min_val = (t)min_value;
11876 return *ptrmax;
11877 }
11879 //! Return a reference to the maximum pixel value and return also the minimum pixel value.
11880 template<typename t>
11881 T& maxmin(t& min_val) {
11882 if (is_empty())
11883 throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",
11884 pixel_type());
11885 T *ptrmax = data;
11886 T max_value = *ptrmax, min_value = max_value;
11887 cimg_for(*this,ptr,T) {
11888 const T val = *ptr;
11889 if (val>max_value) { max_value = val; ptrmax = ptr; }
11890 if (val<min_value) min_value = val;
11891 }
11892 min_val = (t)min_value;
11893 return *ptrmax;
11894 }
11896 //! Return the sum of all the pixel values in an image.
11897 Tfloat sum() const {
11898 if (is_empty())
11899 throw CImgInstanceException("CImg<%s>::sum() : Instance image (%u,%u,%u,%u,%p) is empty.",
11900 pixel_type(),width,height,depth,dim,data);
11901 Tfloat res = 0;
11902 cimg_for(*this,ptr,T) res+=*ptr;
11903 return res;
11904 }
11906 //! Return the mean pixel value of the instance image.
11907 Tfloat mean() const {
11908 if (is_empty())
11909 throw CImgInstanceException("CImg<%s>::mean() : Instance image is empty.",
11910 pixel_type());
11911 Tfloat val = 0;
11912 cimg_for(*this,ptr,T) val+=*ptr;
11913 return val/size();
11914 }
11916 //! Return the variance of the image.
11917 /**
11918 @param variance_method Determines how to calculate the variance
11919 <table border="0">
11920 <tr><td>0</td>
11921 <td>Second moment:
11922 @f$ v = 1/N \sum\limits_{k=1}^{N} (x_k - \bar x)^2
11923 = 1/N \left( \sum\limits_{k=1}^N x_k^2 - \left( \sum\limits_{k=1}^N x_k \right)^2 / N \right) @f$
11924 with @f$ \bar x = 1/N \sum\limits_{k=1}^N x_k \f$</td></tr>
11925 <tr><td>1</td>
11926 <td>Best unbiased estimator: @f$ v = \frac{1}{N-1} \sum\limits_{k=1}^{N} (x_k - \bar x)^2 @f$</td></tr>
11927 <tr><td>2</td>
11928 <td>Least median of squares</td></tr>
11929 <tr><td>3</td>
11930 <td>Least trimmed of squares</td></tr>
11931 </table>
11932 */
11933 Tfloat variance(const unsigned int variance_method=1) const {
11934 Tfloat foo;
11935 return variancemean(variance_method,foo);
11936 }
11938 //! Return the variance and the mean of the image.
11939 template<typename t>
11940 Tfloat variancemean(const unsigned int variance_method, t& mean) const {
11941 if (is_empty())
11942 throw CImgInstanceException("CImg<%s>::variance() : Instance image is empty.",
11943 pixel_type());
11944 Tfloat variance = 0, average = 0;
11945 const unsigned int siz = size();
11946 switch (variance_method) {
11947 case 3 : { // Least trimmed of Squares
11948 CImg<Tfloat> buf(*this);
11949 const unsigned int siz2 = siz>>1;
11950 { cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; (*ptrs)*=val; average+=val; }}
11951 buf.sort();
11952 Tfloat a = 0;
11953 const Tfloat *ptrs = buf.ptr();
11954 for (unsigned int j = 0; j<siz2; ++j) a+=*(ptrs++);
11955 const Tfloat sig = (Tfloat)(2.6477*cimg_std::sqrt(a/siz2));
11956 variance = sig*sig;
11957 } break;
11958 case 2 : { // Least Median of Squares (MAD)
11959 CImg<Tfloat> buf(*this);
11960 buf.sort();
11961 const unsigned int siz2 = siz>>1;
11962 const Tfloat med_i = buf[siz2];
11963 cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; *ptrs = cimg::abs(val - med_i); average+=val; }
11964 buf.sort();
11965 const Tfloat sig = (Tfloat)(1.4828*buf[siz2]);
11966 variance = sig*sig;
11967 } break;
11968 case 1 : { // Least mean square (robust definition)
11969 Tfloat S = 0, S2 = 0;
11970 cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val; S2+=val*val; }
11971 variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;
11972 average = S;
11973 } break;
11974 case 0 :{ // Least mean square (standard definition)
11975 Tfloat S = 0, S2 = 0;
11976 cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val; S2+=val*val; }
11977 variance = (S2 - S*S/siz)/siz;
11978 average = S;
11979 } break;
11980 default :
11981 throw CImgArgumentException("CImg<%s>::variancemean() : Incorrect parameter 'variance_method = %d' (correct values are 0,1,2 or 3).",
11982 pixel_type(),variance_method);
11983 }
11984 mean = (t)(average/siz);
11985 return variance>0?variance:0;
11986 }
11988 //! Return the kth smallest element of the image.
11989 // (Adapted from the numerical recipies for CImg)
11990 T kth_smallest(const unsigned int k) const {
11991 if (is_empty())
11992 throw CImgInstanceException("CImg<%s>::kth_smallest() : Instance image (%u,%u,%u,%u,%p) is empty.",
11993 pixel_type(),width,height,depth,dim,data);
11994 CImg<T> arr(*this);
11995 unsigned long l = 0, ir = size()-1;
11996 for (;;) {
11997 if (ir<=l+1) {
11998 if (ir==l+1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
11999 return arr[k];
12000 } else {
12001 const unsigned long mid = (l+ir)>>1;
12002 cimg::swap(arr[mid],arr[l+1]);
12003 if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);
12004 if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]);
12005 if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]);
12006 unsigned long i = l+1, j = ir;
12007 const T pivot = arr[l+1];
12008 for (;;) {
12009 do ++i; while (arr[i]<pivot);
12010 do --j; while (arr[j]>pivot);
12011 if (j<i) break;
12012 cimg::swap(arr[i],arr[j]);
12013 }
12014 arr[l+1] = arr[j];
12015 arr[j] = pivot;
12016 if (j>=k) ir=j-1;
12017 if (j<=k) l=i;
12018 }
12019 }
12020 return 0;
12021 }
12023 //! Compute a statistics vector (min,max,mean,variance,xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax).
12024 CImg<T>& stats(const unsigned int variance_method=1) {
12025 return get_stats(variance_method).transfer_to(*this);
12026 }
12028 CImg<Tfloat> get_stats(const unsigned int variance_method=1) const {
12029 if (is_empty()) return CImg<Tfloat>();
12030 const unsigned long siz = size();
12031 const T *const odata = data;
12032 const T *pm = odata, *pM = odata;
12033 Tfloat S = 0, S2 = 0;
12034 T m = *pm, M = m;
12035 cimg_for(*this,ptr,T) {
12036 const T val = *ptr;
12037 const Tfloat fval = (Tfloat)val;
12038 if (val<m) { m = val; pm = ptr; }
12039 if (val>M) { M = val; pM = ptr; }
12040 S+=fval;
12041 S2+=fval*fval;
12042 }
12043 const Tfloat
12044 mean_value = S/siz,
12045 _variance_value = variance_method==0?(S2 - S*S/siz)/siz:
12046 (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0):
12047 variance(variance_method)),
12048 variance_value = _variance_value>0?_variance_value:0;
12049 int
12050 xm = 0, ym = 0, zm = 0, vm = 0,
12051 xM = 0, yM = 0, zM = 0, vM = 0;
12052 contains(*pm,xm,ym,zm,vm);
12053 contains(*pM,xM,yM,zM,vM);
12054 return CImg<Tfloat>(1,12).fill((Tfloat)m,(Tfloat)M,mean_value,variance_value,
12055 (Tfloat)xm,(Tfloat)ym,(Tfloat)zm,(Tfloat)vm,
12056 (Tfloat)xM,(Tfloat)yM,(Tfloat)zM,(Tfloat)vM);
12057 }
12059 //! Return the median value of the image.
12060 T median() const {
12061 const unsigned int s = size();
12062 const T res = kth_smallest(s>>1);
12063 return (s%2)?res:((res+kth_smallest((s>>1)-1))/2);
12064 }
12066 //! Compute the MSE (Mean-Squared Error) between two images.
12067 template<typename t>
12068 Tfloat MSE(const CImg<t>& img) const {
12069 if (img.size()!=size())
12070 throw CImgArgumentException("CImg<%s>::MSE() : Instance image (%u,%u,%u,%u) and given image (%u,%u,%u,%u) have different dimensions.",
12071 pixel_type(),width,height,depth,dim,img.width,img.height,img.depth,img.dim);
12073 Tfloat vMSE = 0;
12074 const t* ptr2 = img.end();
12075 cimg_for(*this,ptr1,T) {
12076 const Tfloat diff = (Tfloat)*ptr1 - (Tfloat)*(--ptr2);
12077 vMSE += diff*diff;
12078 }
12079 vMSE/=img.size();
12080 return vMSE;
12081 }
12083 //! Compute the PSNR between two images.
12084 template<typename t>
12085 Tfloat PSNR(const CImg<t>& img, const Tfloat valmax=(Tfloat)255) const {
12086 const Tfloat vMSE = (Tfloat)cimg_std::sqrt(MSE(img));
12087 return (vMSE!=0)?(Tfloat)(20*cimg_std::log10(valmax/vMSE)):(Tfloat)(cimg::type<Tfloat>::max());
12088 }
12090 //! Return the trace of the image, viewed as a matrix.
12091 Tfloat trace() const {
12092 if (is_empty())
12093 throw CImgInstanceException("CImg<%s>::trace() : Instance matrix (%u,%u,%u,%u,%p) is empty.",
12094 pixel_type(),width,height,depth,dim,data);
12095 Tfloat res = 0;
12096 cimg_forX(*this,k) res+=(*this)(k,k);
12097 return res;
12098 }
12100 //! Return the dot product of the current vector/matrix with the vector/matrix \p img.
12101 template<typename t>
12102 Tfloat dot(const CImg<t>& img) const {
12103 if (is_empty())
12104 throw CImgInstanceException("CImg<%s>::dot() : Instance object (%u,%u,%u,%u,%p) is empty.",
12105 pixel_type(),width,height,depth,dim,data);
12106 if (!img)
12107 throw CImgArgumentException("CImg<%s>::trace() : Specified argument (%u,%u,%u,%u,%p) is empty.",
12108 pixel_type(),img.width,img.height,img.depth,img.dim,img.data);
12109 const unsigned long nb = cimg::min(size(),img.size());
12110 Tfloat res = 0;
12111 for (unsigned long off = 0; off<nb; ++off) res+=(Tfloat)data[off]*(Tfloat)img[off];
12112 return res;
12113 }
12115 //! Return the determinant of the image, viewed as a matrix.
12116 Tfloat det() const {
12117 if (is_empty() || width!=height || depth!=1 || dim!=1)
12118 throw CImgInstanceException("CImg<%s>::det() : Instance matrix (%u,%u,%u,%u,%p) is not square or is empty.",
12119 pixel_type(),width,height,depth,dim,data);
12120 switch (width) {
12121 case 1 : return (Tfloat)((*this)(0,0));
12122 case 2 : return (Tfloat)((*this)(0,0))*(Tfloat)((*this)(1,1)) - (Tfloat)((*this)(0,1))*(Tfloat)((*this)(1,0));
12123 case 3 : {
12124 const Tfloat
12125 a = (Tfloat)data[0], d = (Tfloat)data[1], g = (Tfloat)data[2],
12126 b = (Tfloat)data[3], e = (Tfloat)data[4], h = (Tfloat)data[5],
12127 c = (Tfloat)data[6], f = (Tfloat)data[7], i = (Tfloat)data[8];
12128 return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e;
12129 }
12130 default : {
12131 CImg<Tfloat> lu(*this);
12132 CImg<uintT> indx;
12133 bool d;
12134 lu._LU(indx,d);
12135 Tfloat res = d?(Tfloat)1:(Tfloat)-1;
12136 cimg_forX(lu,i) res*=lu(i,i);
12137 return res;
12138 }
12139 }
12140 return 0;
12141 }
12143 //! Return the norm of the current vector/matrix. \p ntype = norm type (0=L2, 1=L1, -1=Linf).
12144 Tfloat norm(const int norm_type=2) const {
12145 if (is_empty())
12146 throw CImgInstanceException("CImg<%s>::norm() : Instance object (%u,%u,%u,%u,%p) is empty.",
12147 pixel_type(),width,height,depth,dim,data);
12148 Tfloat res = 0;
12149 switch (norm_type) {
12150 case -1 : {
12151 cimg_foroff(*this,off) {
12152 const Tfloat tmp = cimg::abs((Tfloat)data[off]);
12153 if (tmp>res) res = tmp;
12154 }
12155 return res;
12156 } break;
12157 case 1 : {
12158 cimg_foroff(*this,off) res+=cimg::abs((Tfloat)data[off]);
12159 return res;
12160 } break;
12161 case 2 : return (Tfloat)cimg_std::sqrt(dot(*this)); break;
12162 default :
12163 throw CImgArgumentException("CImg<%s>::norm() : Incorrect parameter 'norm_type=%d' (correct values are -1,1 or 2).",
12164 pixel_type(),norm_type);
12165 }
12166 return 0;
12167 }
12169 //! Return a C-string containing the values of the instance image.
12170 CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
12171 if (is_empty()) return CImg<charT>(1,1,1,1,0);
12172 const unsigned int siz = (unsigned int)size();
12173 CImgList<charT> items;
12174 char item[256] = { 0 };
12175 const T *ptrs = ptr();
12176 for (unsigned int off = 0; off<siz-1; ++off) {
12177 cimg_std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*(ptrs++)));
12178 const int l = cimg::strlen(item);
12179 items.insert(CImg<charT>(item,l+1));
12180 items[items.size-1](l) = separator;
12181 }
12182 cimg_std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*ptrs));
12183 items.insert(CImg<charT>(item,cimg::strlen(item)+1));
12184 CImg<ucharT> res = items.get_append('x');
12185 if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
12186 return res;
12187 }
12189 //! Display informations about the image on the standard error output.
12190 /**
12191 \param title Name for the considered image (optional).
12192 \param display_stats Compute and display image statistics (optional).
12193 **/
12194 const CImg<T>& print(const char *title=0, const bool display_stats=true) const {
12195 int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0;
12196 static CImg<doubleT> st;
12197 if (!is_empty() && display_stats) {
12198 st = get_stats();
12199 xm = (int)st[4]; ym = (int)st[5], zm = (int)st[6], vm = (int)st[7];
12200 xM = (int)st[8]; yM = (int)st[9], zM = (int)st[10], vM = (int)st[11];
12201 }
12202 const unsigned long siz = size(), msiz = siz*sizeof(T), siz1 = siz-1;
12203 const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2), width1 = width-1;
12204 char ntitle[64] = { 0 };
12205 if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
12206 cimg_std::fprintf(cimg_stdout,"%s: this = %p, size = (%u,%u,%u,%u) [%lu %s], data = (%s*)%p (%s) = [ ",
12207 title?title:ntitle,(void*)this,width,height,depth,dim,
12208 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
12209 mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
12210 pixel_type(),(void*)data,is_shared?"shared":"not shared");
12211 if (!is_empty()) cimg_foroff(*this,off) {
12212 cimg_std::fprintf(cimg_stdout,cimg::type<T>::format(),cimg::type<T>::format(data[off]));
12213 if (off!=siz1) cimg_std::fprintf(cimg_stdout,"%s",off%width==width1?" ; ":" ");
12214 if (off==7 && siz>16) { off = siz1-8; if (off!=7) cimg_std::fprintf(cimg_stdout,"... "); }
12215 }
12216 if (!is_empty() && display_stats)
12217 cimg_std::fprintf(cimg_stdout," ], min = %g, max = %g, mean = %g, std = %g, coords(min) = (%u,%u,%u,%u), coords(max) = (%u,%u,%u,%u).\n",
12218 st[0],st[1],st[2],cimg_std::sqrt(st[3]),xm,ym,zm,vm,xM,yM,zM,vM);
12219 else cimg_std::fprintf(cimg_stdout,"%s].\n",is_empty()?"":" ");
12220 return *this;
12221 }
12223 //@}
12224 //------------------------------------------
12225 //
12226 //! \name Arithmetic and Boolean Operators
12227 //@{
12228 //------------------------------------------
12230 //! Assignment operator.
12231 /**
12232 This operator assigns a copy of the input image \p img to the current instance image.
12233 \param img The input image to copy.
12234 \remark
12235 - This operator is strictly equivalent to the function assign(const CImg< t >&) and has exactly the same properties.
12236 **/
12237 template<typename t>
12238 CImg<T>& operator=(const CImg<t>& img) {
12239 return assign(img);
12240 }
12242 CImg<T>& operator=(const CImg<T>& img) {
12243 return assign(img);
12244 }
12246 //! Assign values of a C-array to the instance image.
12247 /**
12248 \param buf Pointer to a C-style array having a size of (at least) <tt>this->size()</tt>.
12250 - Replace pixel values by the content of the array \c buf.
12251 - Warning : the value types in the array and in the image must be the same.
12253 \par example:
12254 \code
12255 float tab[4*4] = { 1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16 }; // Define a 4x4 matrix in C-style.
12256 CImg<float> matrice(4,4); // Define a 4x4 greyscale image.
12257 matrice = tab; // Fill the image by the values in tab.
12258 \endcode
12259 **/
12260 CImg<T>& operator=(const T *buf) {
12261 return assign(buf,width,height,depth,dim);
12262 }
12264 //! Assign a value to each image pixel of the instance image.
12265 CImg<T>& operator=(const T val) {
12266 return fill(val);
12267 }
12269 //! Operator+
12270 /**
12271 \remark
12272 - This operator can be used to get a non-shared copy of an image.
12273 **/
12274 CImg<T> operator+() const {
12275 return CImg<T>(*this,false);
12276 }
12278 //! Operator+=;
12279 #ifdef cimg_use_visualcpp6
12280 CImg<T>& operator+=(const T val)
12281 #else
12282 template<typename t>
12283 CImg<T>& operator+=(const t val)
12284 #endif
12285 {
12286 cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)+val);
12287 return *this;
12288 }
12290 //! Operator+=
12291 template<typename t>
12292 CImg<T>& operator+=(const CImg<t>& img) {
12293 if (is_overlapped(img)) return *this+=+img;
12294 const unsigned int smin = cimg::min(size(),img.size());
12295 t *ptrs = img.data + smin;
12296 for (T *ptrd = data + smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs)))) {}
12297 return *this;
12298 }
12300 //! Operator++ (prefix)
12301 CImg<T>& operator++() {
12302 cimg_for(*this,ptr,T) ++(*ptr);
12303 return *this;
12304 }
12306 //! Operator++ (postfix)
12307 CImg<T> operator++(int) {
12308 const CImg<T> copy(*this,false);
12309 ++*this;
12310 return copy;
12311 }
12313 //! Operator-.
12314 CImg<T> operator-() const {
12315 return CImg<T>(width,height,depth,dim,0)-=*this;
12316 }
12318 //! Operator-=.
12319 #ifdef cimg_use_visualcpp6
12320 CImg<T>& operator-=(const T val)
12321 #else
12322 template<typename t>
12323 CImg<T>& operator-=(const t val)
12324 #endif
12325 {
12326 cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)-val);
12327 return *this;
12328 }
12330 //! Operator-=.
12331 template<typename t>
12332 CImg<T>& operator-=(const CImg<t>& img) {
12333 if (is_overlapped(img)) return *this-=+img;
12334 const unsigned int smin = cimg::min(size(),img.size());
12335 t *ptrs = img.data+smin;
12336 for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd) = (T)((*ptrd)-(*(--ptrs)))) {}
12337 return *this;
12338 }
12340 //! Operator-- (prefix).
12341 CImg<T>& operator--() {
12342 cimg_for(*this,ptr,T) *ptr = *ptr-(T)1;
12343 return *this;
12344 }
12346 //! Operator-- (postfix).
12347 CImg<T> operator--(int) {
12348 CImg<T> copy(*this,false);
12349 --*this;
12350 return copy;
12351 }
12353 //! Operator*=.
12354 #ifdef cimg_use_visualcpp6
12355 CImg<T>& operator*=(const double val)
12356 #else
12357 template<typename t>
12358 CImg<T>& operator*=(const t val)
12359 #endif
12360 {
12361 cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)*val);
12362 return *this;
12363 }
12365 //! Operator*=.
12366 template<typename t>
12367 CImg<T>& operator*=(const CImg<t>& img) {
12368 return ((*this)*img).transfer_to(*this);
12369 }
12371 //! Operator/=.
12372 #ifdef cimg_use_visualcpp6
12373 CImg<T>& operator/=(const double val)
12374 #else
12375 template<typename t>
12376 CImg<T>& operator/=(const t val)
12377 #endif
12378 {
12379 cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)/val);
12380 return *this;
12381 }
12383 //! Operator/=.
12384 template<typename t>
12385 CImg<T>& operator/=(const CImg<t>& img) {
12386 return assign(*this*img.get_invert());
12387 }
12389 //! Modulo.
12390 template<typename t>
12391 CImg<typename cimg::superset<T,t>::type> operator%(const CImg<t>& img) const {
12392 typedef typename cimg::superset<T,t>::type Tt;
12393 return CImg<Tt>(*this,false)%=img;
12394 }
12396 //! Modulo.
12397 CImg<T> operator%(const T val) const {
12398 return (+*this)%=val;
12399 }
12401 //! In-place modulo.
12402 CImg<T>& operator%=(const T val) {
12403 cimg_for(*this,ptr,T) (*ptr) = (T)cimg::mod(*ptr,val);
12404 return *this;
12405 }
12407 //! In-place modulo.
12408 template<typename t>
12409 CImg<T>& operator%=(const CImg<t>& img) {
12410 if (is_overlapped(img)) return *this%=+img;
12411 typedef typename cimg::superset<T,t>::type Tt;
12412 const unsigned int smin = cimg::min(size(),img.size());
12413 const t *ptrs = img.data + smin;
12414 for (T *ptrd = data + smin; ptrd>data; ) {
12415 T& val = *(--ptrd);
12416 val = (T)cimg::mod((Tt)val,(Tt)*(--ptrs));
12417 }
12418 return *this;
12419 }
12421 //! Bitwise AND.
12422 template<typename t>
12423 CImg<typename cimg::superset<T,t>::type> operator&(const CImg<t>& img) const {
12424 typedef typename cimg::superset<T,t>::type Tt;
12425 return CImg<Tt>(*this,false)&=img;
12426 }
12428 //! Bitwise AND.
12429 CImg<T> operator&(const T val) const {
12430 return (+*this)&=val;
12431 }
12433 //! In-place bitwise AND.
12434 template<typename t>
12435 CImg<T>& operator&=(const CImg<t>& img) {
12436 if (is_overlapped(img)) return *this&=+img;
12437 const unsigned int smin = cimg::min(size(),img.size());
12438 const t *ptrs = img.data + smin;
12439 for (T *ptrd = data + smin; ptrd>data; ) {
12440 T& val = *(--ptrd);
12441 val = (T)((unsigned long)val & (unsigned long)*(--ptrs));
12442 }
12443 return *this;
12444 }
12446 //! In-place bitwise AND.
12447 CImg<T>& operator&=(const T val) {
12448 cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr & (unsigned long)val);
12449 return *this;
12450 }
12452 //! Bitwise OR.
12453 template<typename t>
12454 CImg<typename cimg::superset<T,t>::type> operator|(const CImg<t>& img) const {
12455 typedef typename cimg::superset<T,t>::type Tt;
12456 return CImg<Tt>(*this,false)|=img;
12457 }
12459 //! Bitwise OR.
12460 CImg<T> operator|(const T val) const {
12461 return (+*this)|=val;
12462 }
12464 //! In-place bitwise OR.
12465 template<typename t>
12466 CImg<T>& operator|=(const CImg<t>& img) {
12467 if (is_overlapped(img)) return *this|=+img;
12468 const unsigned int smin = cimg::min(size(),img.size());
12469 const t *ptrs = img.data + smin;
12470 for (T *ptrd = data + smin; ptrd>data; ) {
12471 T& val = *(--ptrd);
12472 val = (T)((unsigned long)val | (unsigned long)*(--ptrs));
12473 }
12474 return *this;
12475 }
12477 //! In-place bitwise OR.
12478 CImg<T>& operator|=(const T val) {
12479 cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr | (unsigned long)val);
12480 return *this;
12481 }
12483 //! Bitwise XOR.
12484 template<typename t>
12485 CImg<typename cimg::superset<T,t>::type> operator^(const CImg<t>& img) const {
12486 typedef typename cimg::superset<T,t>::type Tt;
12487 return CImg<Tt>(*this,false)^=img;
12488 }
12490 //! Bitwise XOR.
12491 CImg<T> operator^(const T val) const {
12492 return (+*this)^=val;
12493 }
12495 //! In-place bitwise XOR.
12496 template<typename t>
12497 CImg<T>& operator^=(const CImg<t>& img) {
12498 if (is_overlapped(img)) return *this^=+img;
12499 const unsigned int smin = cimg::min(size(),img.size());
12500 const t *ptrs = img.data + smin;
12501 for (T *ptrd = data+smin; ptrd>data; ) {
12502 T& val = *(--ptrd);
12503 val =(T)((unsigned long)val ^ (unsigned long)*(--ptrs));
12504 }
12505 return *this;
12506 }
12508 //! In-place bitwise XOR.
12509 CImg<T>& operator^=(const T val) {
12510 cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr ^ (unsigned long)val);
12511 return *this;
12512 }
12514 //! Bitwise NOT.
12515 CImg<T> operator~() const {
12516 CImg<T> res(width,height,depth,dim);
12517 const T *ptrs = end();
12518 cimg_for(res,ptrd,T) { const unsigned long val = (unsigned long)*(--ptrs); *ptrd = (T)~val; }
12519 return res;
12520 }
12522 //! Bitwise left shift.
12523 CImg<T>& operator<<=(const int n) {
12524 cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)<<n);
12525 return *this;
12526 }
12528 //! Bitwise left shift.
12529 CImg<T> operator<<(const int n) const {
12530 return (+*this)<<=n;
12531 }
12533 //! Bitwise right shift.
12534 CImg<T>& operator>>=(const int n) {
12535 cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)>>n);
12536 return *this;
12537 }
12539 //! Bitwise right shift.
12540 CImg<T> operator>>(const int n) const {
12541 return (+*this)>>=n;
12542 }
12544 //! Boolean equality.
12545 template<typename t>
12546 bool operator==(const CImg<t>& img) const {
12547 const unsigned int siz = size();
12548 bool vequal = true;
12549 if (siz!=img.size()) return false;
12550 t *ptrs = img.data + siz;
12551 for (T *ptrd = data + siz; vequal && ptrd>data; vequal = vequal && ((*(--ptrd))==(*(--ptrs)))) {}
12552 return vequal;
12553 }
12555 //! Boolean difference.
12556 template<typename t>
12557 bool operator!=(const CImg<t>& img) const {
12558 return !((*this)==img);
12559 }
12561 //! Return a list of two images { *this, img }.
12562 template<typename t>
12563 CImgList<typename cimg::superset<T,t>::type> operator<<(const CImg<t>& img) const {
12564 typedef typename cimg::superset<T,t>::type Tt;
12565 return CImgList<Tt>(*this,img);
12566 }
12568 //! Return a copy of \p list, where image *this has been inserted at first position.
12569 template<typename t>
12570 CImgList<typename cimg::superset<T,t>::type> operator<<(const CImgList<t>& list) const {
12571 typedef typename cimg::superset<T,t>::type Tt;
12572 return CImgList<Tt>(list).insert(*this,0);
12573 }
12575 //! Return a list of two images { *this, img }.
12576 template<typename t>
12577 CImgList<typename cimg::superset<T,t>::type> operator>>(const CImg<t>& img) const {
12578 return (*this)<<img;
12579 }
12581 //! Insert an image into the begining of an image list.
12582 template<typename t>
12583 CImgList<t>& operator>>(const CImgList<t>& list) const {
12584 return list.insert(*this,0);
12585 }
12587 //! Display an image into a CImgDisplay.
12588 const CImg<T>& operator>>(CImgDisplay& disp) const {
12589 return display(disp);
12590 }
12592 //@}
12593 //---------------------------------------
12594 //
12595 //! \name Usual Mathematics Functions
12596 //@{
12597 //---------------------------------------
12599 //! Apply a R->R function on all pixel values.
12600 template<typename t>
12601 CImg<T>& apply(t& func) {
12602 cimg_for(*this,ptr,T) *ptr = func(*ptr);
12603 return *this;
12604 }
12606 template<typename t>
12607 CImg<T> get_apply(t& func) const {
12608 return (+*this).apply(func);
12609 }
12611 //! Pointwise multiplication between two images.
12612 template<typename t>
12613 CImg<T>& mul(const CImg<t>& img) {
12614 if (is_overlapped(img)) return mul(+img);
12615 t *ptrs = img.data;
12616 T *ptrf = data + cimg::min(size(),img.size());
12617 for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd*(*(ptrs++)));
12618 return *this;
12619 }
12621 template<typename t>
12622 CImg<typename cimg::superset<T,t>::type> get_mul(const CImg<t>& img) const {
12623 typedef typename cimg::superset<T,t>::type Tt;
12624 return CImg<Tt>(*this,false).mul(img);
12625 }
12627 //! Pointwise division between two images.
12628 template<typename t>
12629 CImg<T>& div(const CImg<t>& img) {
12630 if (is_overlapped(img)) return div(+img);
12631 t *ptrs = img.data;
12632 T *ptrf = data + cimg::min(size(),img.size());
12633 for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd/(*(ptrs++)));
12634 return *this;
12635 }
12637 template<typename t>
12638 CImg<typename cimg::superset<T,t>::type> get_div(const CImg<t>& img) const {
12639 typedef typename cimg::superset<T,t>::type Tt;
12640 return CImg<Tt>(*this,false).div(img);
12641 }
12643 //! Pointwise max operator between two images.
12644 template<typename t>
12645 CImg<T>& max(const CImg<t>& img) {
12646 if (is_overlapped(img)) return max(+img);
12647 t *ptrs = img.data;
12648 T *ptrf = data + cimg::min(size(),img.size());
12649 for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::max((T)*(ptrs++),*ptrd);
12650 return *this;
12651 }
12653 template<typename t>
12654 CImg<typename cimg::superset<T,t>::type> get_max(const CImg<t>& img) const {
12655 typedef typename cimg::superset<T,t>::type Tt;
12656 return CImg<Tt>(*this,false).max(img);
12657 }
12659 //! Pointwise max operator between an image and a value.
12660 CImg<T>& max(const T val) {
12661 cimg_for(*this,ptr,T) (*ptr) = cimg::max(*ptr,val);
12662 return *this;
12663 }
12665 CImg<T> get_max(const T val) const {
12666 return (+*this).max(val);
12667 }
12669 //! Pointwise min operator between two images.
12670 template<typename t>
12671 CImg<T>& min(const CImg<t>& img) {
12672 if (is_overlapped(img)) return min(+img);
12673 t *ptrs = img.data;
12674 T *ptrf = data + cimg::min(size(),img.size());
12675 for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::min((T)*(ptrs++),*ptrd);
12676 return *this;
12677 }
12679 template<typename t>
12680 CImg<typename cimg::superset<T,t>::type> get_min(const CImg<t>& img) const {
12681 typedef typename cimg::superset<T,t>::type Tt;
12682 return CImg<Tt>(*this,false).min(img);
12683 }
12685 //! Pointwise min operator between an image and a value.
12686 CImg<T>& min(const T val) {
12687 cimg_for(*this,ptr,T) (*ptr) = cimg::min(*ptr,val);
12688 return *this;
12689 }
12691 CImg<T> get_min(const T val) const {
12692 return (+*this).min(val);
12693 }
12695 //! Compute the square value of each pixel.
12696 CImg<T>& sqr() {
12697 cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)(val*val); };
12698 return *this;
12699 }
12701 CImg<Tfloat> get_sqr() const {
12702 return CImg<Tfloat>(*this,false).sqr();
12703 }
12705 //! Compute the square root of each pixel value.
12706 CImg<T>& sqrt() {
12707 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::sqrt((double)(*ptr));
12708 return *this;
12709 }
12711 CImg<Tfloat> get_sqrt() const {
12712 return CImg<Tfloat>(*this,false).sqrt();
12713 }
12715 //! Compute the exponential of each pixel value.
12716 CImg<T>& exp() {
12717 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::exp((double)(*ptr));
12718 return *this;
12719 }
12721 CImg<Tfloat> get_exp() const {
12722 return CImg<Tfloat>(*this,false).exp();
12723 }
12725 //! Compute the log of each each pixel value.
12726 CImg<T>& log() {
12727 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::log((double)(*ptr));
12728 return *this;
12729 }
12731 CImg<Tfloat> get_log() const {
12732 return CImg<Tfloat>(*this,false).log();
12733 }
12735 //! Compute the log10 of each each pixel value.
12736 CImg<T>& log10() {
12737 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::log10((double)(*ptr));
12738 return *this;
12739 }
12741 CImg<Tfloat> get_log10() const {
12742 return CImg<Tfloat>(*this,false).log10();
12743 }
12745 //! Compute the power by p of each pixel value.
12746 CImg<T>& pow(const double p) {
12747 if (p==0) return fill(1);
12748 if (p==0.5) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)cimg_std::sqrt((double)val); } return *this; }
12749 if (p==1) return *this;
12750 if (p==2) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val; } return *this; }
12751 if (p==3) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val; } return *this; }
12752 if (p==4) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val*val; } return *this; }
12753 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::pow((double)(*ptr),p);
12754 return *this;
12755 }
12757 CImg<Tfloat> get_pow(const double p) const {
12758 return CImg<Tfloat>(*this,false).pow(p);
12759 }
12761 //! Compute the power of each pixel value.
12762 template<typename t>
12763 CImg<T>& pow(const CImg<t>& img) {
12764 if (is_overlapped(img)) return pow(+img);
12765 t *ptrs = img.data;
12766 T *ptrf = data + cimg::min(size(),img.size());
12767 for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)cimg_std::pow((double)*ptrd,(double)(*(ptrs++)));
12768 return *this;
12769 }
12771 template<typename t>
12772 CImg<Tfloat> get_pow(const CImg<t>& img) const {
12773 return CImg<Tfloat>(*this,false).pow(img);
12774 }
12776 //! Compute the absolute value of each pixel value.
12777 CImg<T>& abs() {
12778 cimg_for(*this,ptr,T) (*ptr) = cimg::abs(*ptr);
12779 return *this;
12780 }
12782 CImg<Tfloat> get_abs() const {
12783 return CImg<Tfloat>(*this,false).abs();
12784 }
12786 //! Compute the cosinus of each pixel value.
12787 CImg<T>& cos() {
12788 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::cos((double)(*ptr));
12789 return *this;
12790 }
12792 CImg<Tfloat> get_cos() const {
12793 return CImg<Tfloat>(*this,false).cos();
12794 }
12796 //! Compute the sinus of each pixel value.
12797 CImg<T>& sin() {
12798 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::sin((double)(*ptr));
12799 return *this;
12800 }
12802 CImg<Tfloat> get_sin() const {
12803 return CImg<Tfloat>(*this,false).sin();
12804 }
12806 //! Compute the tangent of each pixel.
12807 CImg<T>& tan() {
12808 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::tan((double)(*ptr));
12809 return *this;
12810 }
12812 CImg<Tfloat> get_tan() const {
12813 return CImg<Tfloat>(*this,false).tan();
12814 }
12816 //! Compute the arc-cosine of each pixel value.
12817 CImg<T>& acos() {
12818 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::acos((double)(*ptr));
12819 return *this;
12820 }
12822 CImg<Tfloat> get_acos() const {
12823 return CImg<Tfloat>(*this,false).acos();
12824 }
12826 //! Compute the arc-sinus of each pixel value.
12827 CImg<T>& asin() {
12828 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::asin((double)(*ptr));
12829 return *this;
12830 }
12832 CImg<Tfloat> get_asin() const {
12833 return CImg<Tfloat>(*this,false).asin();
12834 }
12836 //! Compute the arc-tangent of each pixel.
12837 CImg<T>& atan() {
12838 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::atan((double)(*ptr));
12839 return *this;
12840 }
12842 CImg<Tfloat> get_atan() const {
12843 return CImg<Tfloat>(*this,false).atan();
12844 }
12846 //! Compute image with rounded pixel values.
12847 /**
12848 \param x Rounding precision.
12849 \param rounding_type Roundin type, can be 0 (nearest), 1 (forward), -1(backward).
12850 **/
12851 CImg<T>& round(const float x, const int rounding_type=0) {
12852 cimg_for(*this,ptr,T) (*ptr) = (T)cimg::round(*ptr,x,rounding_type);
12853 return *this;
12854 }
12856 CImg<T> get_round(const float x, const unsigned int rounding_type=0) const {
12857 return (+*this).round(x,rounding_type);
12858 }
12860 //! Fill the instance image with random values between specified range.
12861 CImg<T>& rand(const T val_min, const T val_max) {
12862 const float delta = (float)val_max - (float)val_min;
12863 cimg_for(*this,ptr,T) *ptr = (T)(val_min + cimg::rand()*delta);
12864 return *this;
12865 }
12867 CImg<T> get_rand(const T val_min, const T val_max) const {
12868 return (+*this).rand(val_min,val_max);
12869 }
12871 //@}
12872 //-----------------------------------
12873 //
12874 //! \name Usual Image Transformations
12875 //@{
12876 //-----------------------------------
12878 //! Fill an image by a value \p val.
12879 /**
12880 \param val = fill value
12881 \note All pixel values of the instance image will be initialized by \p val.
12882 **/
12883 CImg<T>& fill(const T val) {
12884 if (is_empty()) return *this;
12885 if (val && sizeof(T)!=1) cimg_for(*this,ptr,T) *ptr = val;
12886 else cimg_std::memset(data,(int)val,size()*sizeof(T));
12887 return *this;
12888 }
12890 CImg<T> get_fill(const T val) const {
12891 return CImg<T>(width,height,depth,dim).fill(val);
12892 }
12894 //! Fill sequentially all pixel values with values \a val0 and \a val1 respectively.
12895 CImg<T>& fill(const T val0, const T val1) {
12896 if (is_empty()) return *this;
12897 T *ptr, *ptr_end = end()-1;
12898 for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; }
12899 if (ptr!=ptr_end+1) *(ptr++) = val0;
12900 return *this;
12901 }
12903 CImg<T> get_fill(const T val0, const T val1) const {
12904 return CImg<T>(width,height,depth,dim).fill(val0,val1);
12905 }
12907 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2.
12908 CImg<T>& fill(const T val0, const T val1, const T val2) {
12909 if (is_empty()) return *this;
12910 T *ptr, *ptr_end = end()-2;
12911 for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; }
12912 ptr_end+=2;
12913 switch (ptr_end-ptr) {
12914 case 2 : *(--ptr_end) = val1;
12915 case 1 : *(--ptr_end) = val0;
12916 }
12917 return *this;
12918 }
12920 CImg<T> get_fill(const T val0, const T val1, const T val2) const {
12921 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2);
12922 }
12924 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3.
12925 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3) {
12926 if (is_empty()) return *this;
12927 T *ptr, *ptr_end = end()-3;
12928 for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; }
12929 ptr_end+=3;
12930 switch (ptr_end-ptr) {
12931 case 3 : *(--ptr_end) = val2;
12932 case 2 : *(--ptr_end) = val1;
12933 case 1 : *(--ptr_end) = val0;
12934 }
12935 return *this;
12936 }
12938 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3) const {
12939 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3);
12940 }
12942 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4.
12943 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4) {
12944 if (is_empty()) return *this;
12945 T *ptr, *ptr_end = end()-4;
12946 for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; }
12947 ptr_end+=4;
12948 switch (ptr_end-ptr) {
12949 case 4 : *(--ptr_end) = val3;
12950 case 3 : *(--ptr_end) = val2;
12951 case 2 : *(--ptr_end) = val1;
12952 case 1 : *(--ptr_end) = val0;
12953 }
12954 return *this;
12955 }
12957 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4) const {
12958 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4);
12959 }
12961 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5.
12962 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) {
12963 if (is_empty()) return *this;
12964 T *ptr, *ptr_end = end()-5;
12965 for (ptr = data; ptr<ptr_end; ) {
12966 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
12967 }
12968 ptr_end+=5;
12969 switch (ptr_end-ptr) {
12970 case 5 : *(--ptr_end) = val4;
12971 case 4 : *(--ptr_end) = val3;
12972 case 3 : *(--ptr_end) = val2;
12973 case 2 : *(--ptr_end) = val1;
12974 case 1 : *(--ptr_end) = val0;
12975 }
12976 return *this;
12977 }
12979 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) const {
12980 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5);
12981 }
12983 //! Fill sequentially pixel values.
12984 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) {
12985 if (is_empty()) return *this;
12986 T *ptr, *ptr_end = end()-6;
12987 for (ptr = data; ptr<ptr_end; ) {
12988 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6;
12989 }
12990 ptr_end+=6;
12991 switch (ptr_end-ptr) {
12992 case 6 : *(--ptr_end) = val5;
12993 case 5 : *(--ptr_end) = val4;
12994 case 4 : *(--ptr_end) = val3;
12995 case 3 : *(--ptr_end) = val2;
12996 case 2 : *(--ptr_end) = val1;
12997 case 1 : *(--ptr_end) = val0;
12998 }
12999 return *this;
13000 }
13002 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) const {
13003 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6);
13004 }
13006 //! Fill sequentially pixel values.
13007 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13008 const T val7) {
13009 if (is_empty()) return *this;
13010 T *ptr, *ptr_end = end()-7;
13011 for (ptr = data; ptr<ptr_end; ) {
13012 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3;
13013 *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7;
13014 }
13015 ptr_end+=7;
13016 switch (ptr_end-ptr) {
13017 case 7 : *(--ptr_end) = val6;
13018 case 6 : *(--ptr_end) = val5;
13019 case 5 : *(--ptr_end) = val4;
13020 case 4 : *(--ptr_end) = val3;
13021 case 3 : *(--ptr_end) = val2;
13022 case 2 : *(--ptr_end) = val1;
13023 case 1 : *(--ptr_end) = val0;
13024 }
13025 return *this;
13026 }
13028 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13029 const T val7) const {
13030 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7);
13031 }
13033 //! Fill sequentially pixel values.
13034 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13035 const T val7, const T val8) {
13036 if (is_empty()) return *this;
13037 T *ptr, *ptr_end = end()-8;
13038 for (ptr = data; ptr<ptr_end; ) {
13039 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2;
13040 *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13041 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8;
13042 }
13043 ptr_end+=8;
13044 switch (ptr_end-ptr) {
13045 case 8 : *(--ptr_end) = val7;
13046 case 7 : *(--ptr_end) = val6;
13047 case 6 : *(--ptr_end) = val5;
13048 case 5 : *(--ptr_end) = val4;
13049 case 4 : *(--ptr_end) = val3;
13050 case 3 : *(--ptr_end) = val2;
13051 case 2 : *(--ptr_end) = val1;
13052 case 1 : *(--ptr_end) = val0;
13053 }
13054 return *this;
13055 }
13057 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13058 const T val7, const T val8) const {
13059 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);
13060 }
13062 //! Fill sequentially pixel values.
13063 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13064 const T val7, const T val8, const T val9) {
13065 if (is_empty()) return *this;
13066 T *ptr, *ptr_end = end()-9;
13067 for (ptr = data; ptr<ptr_end; ) {
13068 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
13069 *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
13070 }
13071 ptr_end+=9;
13072 switch (ptr_end-ptr) {
13073 case 9 : *(--ptr_end) = val8;
13074 case 8 : *(--ptr_end) = val7;
13075 case 7 : *(--ptr_end) = val6;
13076 case 6 : *(--ptr_end) = val5;
13077 case 5 : *(--ptr_end) = val4;
13078 case 4 : *(--ptr_end) = val3;
13079 case 3 : *(--ptr_end) = val2;
13080 case 2 : *(--ptr_end) = val1;
13081 case 1 : *(--ptr_end) = val0;
13082 }
13083 return *this;
13084 }
13086 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13087 const T val7, const T val8, const T val9) const {
13088 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);
13089 }
13091 //! Fill sequentially pixel values.
13092 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13093 const T val7, const T val8, const T val9, const T val10) {
13094 if (is_empty()) return *this;
13095 T *ptr, *ptr_end = end()-10;
13096 for (ptr = data; ptr<ptr_end; ) {
13097 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
13098 *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
13099 *(ptr++) = val10;
13100 }
13101 ptr_end+=10;
13102 switch (ptr_end-ptr) {
13103 case 10 : *(--ptr_end) = val9;
13104 case 9 : *(--ptr_end) = val8;
13105 case 8 : *(--ptr_end) = val7;
13106 case 7 : *(--ptr_end) = val6;
13107 case 6 : *(--ptr_end) = val5;
13108 case 5 : *(--ptr_end) = val4;
13109 case 4 : *(--ptr_end) = val3;
13110 case 3 : *(--ptr_end) = val2;
13111 case 2 : *(--ptr_end) = val1;
13112 case 1 : *(--ptr_end) = val0;
13113 }
13114 return *this;
13115 }
13117 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13118 const T val7, const T val8, const T val9, const T val10) const {
13119 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10);
13120 }
13122 //! Fill sequentially pixel values.
13123 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13124 const T val7, const T val8, const T val9, const T val10, const T val11) {
13125 if (is_empty()) return *this;
13126 T *ptr, *ptr_end = end()-11;
13127 for (ptr = data; ptr<ptr_end; ) {
13128 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13129 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
13130 }
13131 ptr_end+=11;
13132 switch (ptr_end-ptr) {
13133 case 11 : *(--ptr_end) = val10;
13134 case 10 : *(--ptr_end) = val9;
13135 case 9 : *(--ptr_end) = val8;
13136 case 8 : *(--ptr_end) = val7;
13137 case 7 : *(--ptr_end) = val6;
13138 case 6 : *(--ptr_end) = val5;
13139 case 5 : *(--ptr_end) = val4;
13140 case 4 : *(--ptr_end) = val3;
13141 case 3 : *(--ptr_end) = val2;
13142 case 2 : *(--ptr_end) = val1;
13143 case 1 : *(--ptr_end) = val0;
13144 }
13145 return *this;
13146 }
13148 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13149 const T val7, const T val8, const T val9, const T val10, const T val11) const {
13150 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11);
13151 }
13153 //! Fill sequentially pixel values.
13154 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13155 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) {
13156 if (is_empty()) return *this;
13157 T *ptr, *ptr_end = end()-12;
13158 for (ptr = data; ptr<ptr_end; ) {
13159 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13160 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
13161 *(ptr++) = val12;
13162 }
13163 ptr_end+=12;
13164 switch (ptr_end-ptr) {
13165 case 12 : *(--ptr_end) = val11;
13166 case 11 : *(--ptr_end) = val10;
13167 case 10 : *(--ptr_end) = val9;
13168 case 9 : *(--ptr_end) = val8;
13169 case 8 : *(--ptr_end) = val7;
13170 case 7 : *(--ptr_end) = val6;
13171 case 6 : *(--ptr_end) = val5;
13172 case 5 : *(--ptr_end) = val4;
13173 case 4 : *(--ptr_end) = val3;
13174 case 3 : *(--ptr_end) = val2;
13175 case 2 : *(--ptr_end) = val1;
13176 case 1 : *(--ptr_end) = val0;
13177 }
13178 return *this;
13179 }
13181 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13182 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) const {
13183 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12);
13184 }
13186 //! Fill sequentially pixel values.
13187 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13188 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13189 const T val13) {
13190 if (is_empty()) return *this;
13191 T *ptr, *ptr_end = end()-13;
13192 for (ptr = data; ptr<ptr_end; ) {
13193 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13194 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
13195 *(ptr++) = val12; *(ptr++) = val13;
13196 }
13197 ptr_end+=13;
13198 switch (ptr_end-ptr) {
13199 case 13 : *(--ptr_end) = val12;
13200 case 12 : *(--ptr_end) = val11;
13201 case 11 : *(--ptr_end) = val10;
13202 case 10 : *(--ptr_end) = val9;
13203 case 9 : *(--ptr_end) = val8;
13204 case 8 : *(--ptr_end) = val7;
13205 case 7 : *(--ptr_end) = val6;
13206 case 6 : *(--ptr_end) = val5;
13207 case 5 : *(--ptr_end) = val4;
13208 case 4 : *(--ptr_end) = val3;
13209 case 3 : *(--ptr_end) = val2;
13210 case 2 : *(--ptr_end) = val1;
13211 case 1 : *(--ptr_end) = val0;
13212 }
13213 return *this;
13214 }
13216 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13217 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13218 const T val13) const {
13219 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
13220 val13);
13221 }
13223 //! Fill sequentially pixel values.
13224 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13225 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13226 const T val13, const T val14) {
13227 if (is_empty()) return *this;
13228 T *ptr, *ptr_end = end()-14;
13229 for (ptr = data; ptr<ptr_end; ) {
13230 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13231 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
13232 *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14;
13233 }
13234 ptr_end+=14;
13235 switch (ptr_end-ptr) {
13236 case 14 : *(--ptr_end) = val13;
13237 case 13 : *(--ptr_end) = val12;
13238 case 12 : *(--ptr_end) = val11;
13239 case 11 : *(--ptr_end) = val10;
13240 case 10 : *(--ptr_end) = val9;
13241 case 9 : *(--ptr_end) = val8;
13242 case 8 : *(--ptr_end) = val7;
13243 case 7 : *(--ptr_end) = val6;
13244 case 6 : *(--ptr_end) = val5;
13245 case 5 : *(--ptr_end) = val4;
13246 case 4 : *(--ptr_end) = val3;
13247 case 3 : *(--ptr_end) = val2;
13248 case 2 : *(--ptr_end) = val1;
13249 case 1 : *(--ptr_end) = val0;
13250 }
13251 return *this;
13252 }
13254 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13255 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13256 const T val13, const T val14) const {
13257 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
13258 val13,val14);
13259 }
13261 //! Fill sequentially pixel values.
13262 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13263 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13264 const T val13, const T val14, const T val15) {
13265 if (is_empty()) return *this;
13266 T *ptr, *ptr_end = end()-15;
13267 for (ptr = data; ptr<ptr_end; ) {
13268 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
13269 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
13270 *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14; *(ptr++) = val15;
13271 }
13272 ptr_end+=15;
13273 switch (ptr_end-ptr) {
13274 case 15 : *(--ptr_end) = val14;
13275 case 14 : *(--ptr_end) = val13;
13276 case 13 : *(--ptr_end) = val12;
13277 case 12 : *(--ptr_end) = val11;
13278 case 11 : *(--ptr_end) = val10;
13279 case 10 : *(--ptr_end) = val9;
13280 case 9 : *(--ptr_end) = val8;
13281 case 8 : *(--ptr_end) = val7;
13282 case 7 : *(--ptr_end) = val6;
13283 case 6 : *(--ptr_end) = val5;
13284 case 5 : *(--ptr_end) = val4;
13285 case 4 : *(--ptr_end) = val3;
13286 case 3 : *(--ptr_end) = val2;
13287 case 2 : *(--ptr_end) = val1;
13288 case 1 : *(--ptr_end) = val0;
13289 }
13290 return *this;
13291 }
13293 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
13294 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
13295 const T val13, const T val14, const T val15) const {
13296 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
13297 val13,val14,val15);
13298 }
13300 //! Fill image values according to the values found in the specified string.
13301 CImg<T>& fill(const char *const values, const bool repeat_pattern) {
13302 if (is_empty() || !values) return *this;
13303 T *ptrd = data, *ptr_end = data + size();
13304 const char *nvalues = values;
13305 const unsigned int siz = size();
13306 char cval[64] = { 0 }, sep = 0;
13307 int err = 0; double val = 0; unsigned int nb = 0;
13308 while ((err=cimg_std::sscanf(nvalues,"%63[ \n\t0-9e.+-]%c",cval,&sep))>0 &&
13309 cimg_std::sscanf(cval,"%lf",&val)>0 && nb<siz) {
13310 nvalues += cimg::strlen(cval);
13311 *(ptrd++) = (T)val;
13312 ++nb;
13313 if (err!=2) break; else ++nvalues;
13314 }
13315 if (repeat_pattern && nb) for (T *ptrs = data; ptrd<ptr_end; ++ptrs) *(ptrd++) = *ptrs;
13316 return *this;
13317 }
13319 CImg<T> get_fill(const char *const values, const bool repeat_pattern) const {
13320 return repeat_pattern?CImg<T>(width,height,depth,dim).fill(values,repeat_pattern):(+*this).fill(values,repeat_pattern);
13321 }
13323 //! Fill image values according to the values found in the specified image.
13324 template<typename t>
13325 CImg<T>& fill(const CImg<t>& values, const bool repeat_pattern=true) {
13326 if (is_empty() || !values) return *this;
13327 T *ptrd = data, *ptrd_end = ptrd + size();
13328 for (t *ptrs = values.data, *ptrs_end = ptrs + values.size(); ptrs<ptrs_end && ptrd<ptrd_end; ++ptrs) *(ptrd++) = (T)*ptrs;
13329 if (repeat_pattern && ptrd<ptrd_end) for (T *ptrs = data; ptrd<ptrd_end; ++ptrs) *(ptrd++) = *ptrs;
13330 return *this;
13331 }
13333 template<typename t>
13334 CImg<T> get_fill(const CImg<t>& values, const bool repeat_pattern=true) const {
13335 return repeat_pattern?CImg<T>(width,height,depth,dim).fill(values,repeat_pattern):(+*this).fill(values,repeat_pattern);
13336 }
13338 //! Fill image values along the X-axis at the specified pixel position (y,z,v).
13339 CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const int a0, ...) {
13340 #define _cimg_fill1(x,y,z,v,off,siz,t) { \
13341 va_list ap; va_start(ap,a0); T *ptrd = ptr(x,y,z,v); *ptrd = (T)a0; \
13342 for (unsigned int k = 1; k<siz; ++k) { ptrd+=off; *ptrd = (T)va_arg(ap,t); } \
13343 va_end(ap); }
13344 if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,int);
13345 return *this;
13346 }
13348 CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const double a0, ...) {
13349 if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,double);
13350 return *this;
13351 }
13353 //! Fill image values along the Y-axis at the specified pixel position (x,z,v).
13354 CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const int a0, ...) {
13355 if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,int);
13356 return *this;
13357 }
13359 CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const double a0, ...) {
13360 if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,double);
13361 return *this;
13362 }
13364 //! Fill image values along the Z-axis at the specified pixel position (x,y,v).
13365 CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const int a0, ...) {
13366 const unsigned int wh = width*height;
13367 if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,int);
13368 return *this;
13369 }
13371 CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const double a0, ...) {
13372 const unsigned int wh = width*height;
13373 if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,double);
13374 return *this;
13375 }
13377 //! Fill image values along the V-axis at the specified pixel position (x,y,z).
13378 CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) {
13379 const unsigned int whz = width*height*depth;
13380 if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,int);
13381 return *this;
13382 }
13384 CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) {
13385 const unsigned int whz = width*height*depth;
13386 if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,double);
13387 return *this;
13388 }
13390 //! Linear normalization of the pixel values between \a a and \a b.
13391 CImg<T>& normalize(const T a, const T b) {
13392 if (is_empty()) return *this;
13393 const T na = a<b?a:b, nb = a<b?b:a;
13394 T m, M = maxmin(m);
13395 const Tfloat fm = (Tfloat)m, fM = (Tfloat)M;
13396 if (m==M) return fill(0);
13397 if (m!=na || M!=nb) cimg_for(*this,ptr,T) *ptr = (T)((*ptr-fm)/(fM-fm)*(nb-na)+na);
13398 return *this;
13399 }
13401 CImg<T> get_normalize(const T a, const T b) const {
13402 return (+*this).normalize(a,b);
13403 }
13405 //! Cut pixel values between \a a and \a b.
13406 CImg<T>& cut(const T a, const T b) {
13407 if (is_empty()) return *this;
13408 const T na = a<b?a:b, nb = a<b?b:a;
13409 cimg_for(*this,ptr,T) *ptr = (*ptr<na)?na:((*ptr>nb)?nb:*ptr);
13410 return *this;
13411 }
13413 CImg<T> get_cut(const T a, const T b) const {
13414 return (+*this).cut(a,b);
13415 }
13417 //! Quantize pixel values into \n levels.
13418 CImg<T>& quantize(const unsigned int n, const bool keep_range=true) {
13419 if (is_empty()) return *this;
13420 if (!n)
13421 throw CImgArgumentException("CImg<%s>::quantize() : Cannot quantize image to 0 values.",
13422 pixel_type());
13423 Tfloat m, M = (Tfloat)maxmin(m), range = M - m;
13424 if (range>0) {
13425 if (keep_range) cimg_for(*this,ptr,T) {
13426 const unsigned int val = (unsigned int)((*ptr-m)*n/range);
13427 *ptr = (T)(m + cimg::min(val,n-1)*range/n);
13428 } else cimg_for(*this,ptr,T) {
13429 const unsigned int val = (unsigned int)((*ptr-m)*n/range);
13430 *ptr = (T)cimg::min(val,n-1);
13431 }
13432 }
13433 return *this;
13434 }
13436 CImg<T> get_quantize(const unsigned int n, const bool keep_range=true) const {
13437 return (+*this).quantize(n,keep_range);
13438 }
13440 //! Threshold the image.
13441 /**
13442 \param value Threshold value.
13443 \param soft Enable soft thresholding.
13444 \param strict Tells if the threshold is strict.
13445 **/
13446 CImg<T>& threshold(const T value, const bool soft=false, const bool strict=false) {
13447 if (is_empty()) return *this;
13448 if (strict) {
13449 if (soft) cimg_for(*this,ptr,T) { const T v = *ptr; *ptr = v>value?(T)(v-value):v<-value?(T)(v+value):(T)0; }
13450 else cimg_for(*this,ptr,T) *ptr = *ptr>value?(T)1:(T)0;
13451 } else {
13452 if (soft) cimg_for(*this,ptr,T) { const T v = *ptr; *ptr = v>=value?(T)(v-value):v<=-value?(T)(v+value):(T)0; }
13453 else cimg_for(*this,ptr,T) *ptr = *ptr>=value?(T)1:(T)0;
13454 }
13455 return *this;
13456 }
13458 CImg<T> get_threshold(const T value, const bool soft=false, const bool strict=false) const {
13459 return (+*this).threshold(value,soft,strict);
13460 }
13462 //! Rotate an image.
13463 /**
13464 \param angle = rotation angle (in degrees).
13465 \param cond = rotation type. can be :
13466 - 0 = zero-value at borders
13467 - 1 = nearest pixel.
13468 - 2 = Fourier style.
13469 \note Returned image will probably have a different size than the instance image *this.
13470 **/
13471 CImg<T>& rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) {
13472 return get_rotate(angle,border_conditions,interpolation).transfer_to(*this);
13473 }
13475 CImg<T> get_rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
13476 if (is_empty()) return *this;
13477 CImg<T> dest;
13478 const float nangle = cimg::mod(angle,360.0f);
13479 if (border_conditions!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
13480 const int wm1 = dimx()-1, hm1 = dimy()-1;
13481 const int iangle = (int)nangle/90;
13482 switch (iangle) {
13483 case 1 : {
13484 dest.assign(height,width,depth,dim);
13485 cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,hm1-x,z,v);
13486 } break;
13487 case 2 : {
13488 dest.assign(width,height,depth,dim);
13489 cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-x,hm1-y,z,v);
13490 } break;
13491 case 3 : {
13492 dest.assign(height,width,depth,dim);
13493 cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-y,x,z,v);
13494 } break;
13495 default :
13496 return *this;
13497 }
13498 } else { // generic version
13499 const float
13500 rad = (float)(nangle*cimg::valuePI/180.0),
13501 ca = (float)cimg_std::cos(rad),
13502 sa = (float)cimg_std::sin(rad),
13503 ux = cimg::abs(width*ca), uy = cimg::abs(width*sa),
13504 vx = cimg::abs(height*sa), vy = cimg::abs(height*ca),
13505 w2 = 0.5f*width, h2 = 0.5f*height,
13506 dw2 = 0.5f*(ux+vx), dh2 = 0.5f*(uy+vy);
13507 dest.assign((int)(ux+vx), (int)(uy+vy),depth,dim);
13508 switch (border_conditions) {
13509 case 0 : {
13510 switch (interpolation) {
13511 case 2 : {
13512 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13513 dest(x,y,z,v) = (T)cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v,0);
13514 } break;
13515 case 1 : {
13516 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13517 dest(x,y,z,v) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v,0);
13518 } break;
13519 default : {
13520 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13521 dest(x,y,z,v) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v,0);
13522 }
13523 }
13524 } break;
13525 case 1 : {
13526 switch (interpolation) {
13527 case 2 :
13528 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13529 dest(x,y,z,v) = (T)cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
13530 break;
13531 case 1 :
13532 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13533 dest(x,y,z,v) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
13534 break;
13535 default :
13536 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13537 dest(x,y,z,v) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v);
13538 }
13539 } break;
13540 case 2 : {
13541 switch (interpolation) {
13542 case 2 :
13543 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13544 dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
13545 cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
13546 break;
13547 case 1 :
13548 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13549 dest(x,y,z,v) = (T)linear_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
13550 cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
13551 break;
13552 default :
13553 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
13554 dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),dimx()),
13555 cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),dimy()),z,v);
13556 }
13557 } break;
13558 default :
13559 throw CImgArgumentException("CImg<%s>::get_rotate() : Invalid border conditions %d (should be 0,1 or 2).",
13560 pixel_type(),border_conditions);
13561 }
13562 }
13563 return dest;
13564 }
13566 //! Rotate an image around a center point (\c cx,\c cy).
13567 /**
13568 \param angle = rotation angle (in degrees).
13569 \param cx = X-coordinate of the rotation center.
13570 \param cy = Y-coordinate of the rotation center.
13571 \param zoom = zoom.
13572 \param cond = rotation type. can be :
13573 - 0 = zero-value at borders
13574 - 1 = repeat image at borders
13575 - 2 = zero-value at borders and linear interpolation
13576 **/
13577 CImg<T>& rotate(const float angle, const float cx, const float cy, const float zoom,
13578 const unsigned int border_conditions=3, const unsigned int interpolation=1) {
13579 return get_rotate(angle,cx,cy,zoom,border_conditions,interpolation).transfer_to(*this);
13580 }
13582 CImg<T> get_rotate(const float angle, const float cx, const float cy, const float zoom,
13583 const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
13584 if (interpolation>2)
13585 throw CImgArgumentException("CImg<%s>::get_rotate() : Invalid interpolation parameter %d (should be {0=none, 1=linear or 2=cubic}).",
13586 pixel_type(),interpolation);
13587 if (is_empty()) return *this;
13588 CImg<T> dest(width,height,depth,dim);
13589 const float nangle = cimg::mod(angle,360.0f);
13590 if (border_conditions!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
13591 const int iangle = (int)nangle/90;
13592 switch (iangle) {
13593 case 1 : {
13594 dest.fill(0);
13595 const unsigned int
13596 xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
13597 ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
13598 xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
13599 yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
13600 cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
13601 dest(x,y,z,v) = (*this)(y-yoff,height-1-x+xoff,z,v);
13602 } break;
13603 case 2 : {
13604 cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v);
13605 } break;
13606 case 3 : {
13607 dest.fill(0);
13608 const unsigned int
13609 xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
13610 ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
13611 xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
13612 yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
13613 cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
13614 dest(x,y,z,v) = (*this)(width-1-y+yoff,x-xoff,z,v);
13615 } break;
13616 default :
13617 return *this;
13618 }
13619 } else {
13620 const float
13621 rad = (float)((nangle*cimg::valuePI)/180.0),
13622 ca = (float)cimg_std::cos(rad)/zoom,
13623 sa = (float)cimg_std::sin(rad)/zoom;
13624 switch (border_conditions) { // generic version
13625 case 0 : {
13626 switch (interpolation) {
13627 case 2 : {
13628 cimg_forXY(dest,x,y)
13629 cimg_forZV(*this,z,v)
13630 dest(x,y,z,v) = (T)cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v,0);
13631 } break;
13632 case 1 : {
13633 cimg_forXY(dest,x,y)
13634 cimg_forZV(*this,z,v)
13635 dest(x,y,z,v) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v,0);
13636 } break;
13637 default : {
13638 cimg_forXY(dest,x,y)
13639 cimg_forZV(*this,z,v)
13640 dest(x,y,z,v) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v,0);
13641 }
13642 }
13643 } break;
13644 case 1 : {
13645 switch (interpolation) {
13646 case 2 : {
13647 cimg_forXY(dest,x,y)
13648 cimg_forZV(*this,z,v)
13649 dest(x,y,z,v) = (T)cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
13650 } break;
13651 case 1 : {
13652 cimg_forXY(dest,x,y)
13653 cimg_forZV(*this,z,v)
13654 dest(x,y,z,v) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
13655 } break;
13656 default : {
13657 cimg_forXY(dest,x,y)
13658 cimg_forZV(*this,z,v)
13659 dest(x,y,z,v) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v);
13660 }
13661 }
13662 } break;
13663 case 2 : {
13664 switch (interpolation) {
13665 case 2 : {
13666 cimg_forXY(dest,x,y)
13667 cimg_forZV(*this,z,v)
13668 dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
13669 cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
13670 } break;
13671 case 1 : {
13672 cimg_forXY(dest,x,y)
13673 cimg_forZV(*this,z,v)
13674 dest(x,y,z,v) = (T)linear_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
13675 cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
13676 } break;
13677 default : {
13678 cimg_forXY(dest,x,y)
13679 cimg_forZV(*this,z,v)
13680 dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),dimx()),
13681 cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),dimy()),z,v);
13682 }
13683 }
13684 } break;
13685 default :
13686 throw CImgArgumentException("CImg<%s>::get_rotate() : Incorrect border conditions %d (should be 0,1 or 2).",
13687 pixel_type(),border_conditions);
13688 }
13689 }
13690 return dest;
13691 }
13693 //! Resize an image.
13694 /**
13695 \param pdx Number of columns (new size along the X-axis).
13696 \param pdy Number of rows (new size along the Y-axis).
13697 \param pdz Number of slices (new size along the Z-axis).
13698 \param pdv Number of vector-channels (new size along the V-axis).
13699 \param interpolation_type Method of interpolation :
13700 - -1 = no interpolation : raw memory resizing.
13701 - 0 = no interpolation : additional space is filled according to \p border_condition.
13702 - 1 = bloc interpolation (nearest point).
13703 - 2 = moving average interpolation.
13704 - 3 = linear interpolation.
13705 - 4 = grid interpolation.
13706 - 5 = bi-cubic interpolation.
13707 \param border_condition Border condition type.
13708 \param center Set centering type (only if \p interpolation_type=0).
13709 \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
13710 **/
13711 CImg<T>& resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
13712 const int interpolation_type=1, const int border_condition=-1, const bool center=false) {
13713 if (!pdx || !pdy || !pdz || !pdv) return assign();
13714 const unsigned int
13715 tdx = pdx<0?-pdx*width/100:pdx,
13716 tdy = pdy<0?-pdy*height/100:pdy,
13717 tdz = pdz<0?-pdz*depth/100:pdz,
13718 tdv = pdv<0?-pdv*dim/100:pdv,
13719 dx = tdx?tdx:1,
13720 dy = tdy?tdy:1,
13721 dz = tdz?tdz:1,
13722 dv = tdv?tdv:1;
13723 if (width==dx && height==dy && depth==dz && dim==dv) return *this;
13724 if (interpolation_type==-1 && dx*dy*dz*dv==size()) {
13725 width = dx; height = dy; depth = dz; dim = dv;
13726 return *this;
13727 }
13728 return get_resize(dx,dy,dz,dv,interpolation_type,border_condition,center).transfer_to(*this);
13729 }
13731 CImg<T> get_resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
13732 const int interpolation_type=1, const int border_condition=-1, const bool center=false) const {
13733 if (!pdx || !pdy || !pdz || !pdv) return CImg<T>();
13734 const unsigned int
13735 tdx = pdx<0?-pdx*width/100:pdx,
13736 tdy = pdy<0?-pdy*height/100:pdy,
13737 tdz = pdz<0?-pdz*depth/100:pdz,
13738 tdv = pdv<0?-pdv*dim/100:pdv,
13739 dx = tdx?tdx:1,
13740 dy = tdy?tdy:1,
13741 dz = tdz?tdz:1,
13742 dv = tdv?tdv:1;
13743 if (width==dx && height==dy && depth==dz && dim==dv) return +*this;
13744 if (is_empty()) return CImg<T>(dx,dy,dz,dv,0);
13746 CImg<T> res;
13748 switch (interpolation_type) {
13749 case -1 : // Raw resizing
13750 cimg_std::memcpy(res.assign(dx,dy,dz,dv,0).data,data,sizeof(T)*cimg::min(size(),(long unsigned int)dx*dy*dz*dv));
13751 break;
13753 case 0 : { // No interpolation
13754 const unsigned int bx = width-1, by = height-1, bz = depth-1, bv = dim-1;
13755 res.assign(dx,dy,dz,dv);
13756 switch (border_condition) {
13757 case 1 : {
13758 if (center) {
13759 const int
13760 x0 = (res.dimx()-dimx())/2,
13761 y0 = (res.dimy()-dimy())/2,
13762 z0 = (res.dimz()-dimz())/2,
13763 v0 = (res.dimv()-dimv())/2,
13764 x1 = x0 + (int)bx,
13765 y1 = y0 + (int)by,
13766 z1 = z0 + (int)bz,
13767 v1 = v0 + (int)bv;
13768 res.draw_image(x0,y0,z0,v0,*this);
13769 cimg_for_outXYZV(res,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) res(x,y,z,v) = _atXYZV(x-x0,y-y0,z-z0,v-v0);
13770 } else {
13771 res.draw_image(*this);
13772 cimg_for_outXYZV(res,0,0,0,0,bx,by,bz,bv,x,y,z,v) res(x,y,z,v) = _atXYZV(x,y,z,v);
13773 }
13774 } break;
13775 case 2 : {
13776 int nx0 = 0, ny0 = 0, nz0 = 0, nv0 = 0;
13777 if (center) {
13778 const int
13779 x0 = (res.dimx()-dimx())/2,
13780 y0 = (res.dimy()-dimy())/2,
13781 z0 = (res.dimz()-dimz())/2,
13782 v0 = (res.dimv()-dimv())/2;
13783 nx0 = x0>0?x0-(1+x0/width)*width:x0;
13784 ny0 = y0>0?y0-(1+y0/height)*height:y0;
13785 nz0 = z0>0?z0-(1+z0/depth)*depth:z0;
13786 nv0 = v0>0?v0-(1+v0/dim)*dim:v0;
13787 }
13788 for (int k = nv0; k<(int)dv; k+=dimv())
13789 for (int z = nz0; z<(int)dz; z+=dimz())
13790 for (int y = ny0; y<(int)dy; y+=dimy())
13791 for (int x = nx0; x<(int)dx; x+=dimx()) res.draw_image(x,y,z,k,*this);
13792 } break;
13793 default : {
13794 res.fill(0);
13795 if (center) res.draw_image((res.dimx()-dimx())/2,(res.dimy()-dimy())/2,(res.dimz()-dimz())/2,(res.dimv()-dimv())/2,*this);
13796 else res.draw_image(*this);
13797 }
13798 }
13799 } break;
13801 case 1 : { // Nearest-neighbor interpolation
13802 res.assign(dx,dy,dz,dv);
13803 unsigned int
13804 *const offx = new unsigned int[dx],
13805 *const offy = new unsigned int[dy+1],
13806 *const offz = new unsigned int[dz+1],
13807 *const offv = new unsigned int[dv+1],
13808 *poffx, *poffy, *poffz, *poffv,
13809 curr, old;
13810 const unsigned int wh = width*height, whd = width*height*depth, rwh = dx*dy, rwhd = dx*dy*dz;
13811 poffx = offx; curr = 0; { cimg_forX(res,x) { old=curr; curr=(x+1)*width/dx; *(poffx++) = (unsigned int)curr-(unsigned int)old; }}
13812 poffy = offy; curr = 0; { cimg_forY(res,y) { old=curr; curr=(y+1)*height/dy; *(poffy++) = width*((unsigned int)curr-(unsigned int)old); }} *poffy=0;
13813 poffz = offz; curr = 0; { cimg_forZ(res,z) { old=curr; curr=(z+1)*depth/dz; *(poffz++) = wh*((unsigned int)curr-(unsigned int)old); }} *poffz=0;
13814 poffv = offv; curr = 0; { cimg_forV(res,k) { old=curr; curr=(k+1)*dim/dv; *(poffv++) = whd*((unsigned int)curr-(unsigned int)old); }} *poffv=0;
13815 T *ptrd = res.data;
13816 const T* ptrv = data;
13817 poffv = offv;
13818 for (unsigned int k=0; k<dv; ) {
13819 const T *ptrz = ptrv;
13820 poffz = offz;
13821 for (unsigned int z=0; z<dz; ) {
13822 const T *ptry = ptrz;
13823 poffy = offy;
13824 for (unsigned int y=0; y<dy; ) {
13825 const T *ptrx = ptry;
13826 poffx = offx;
13827 cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poffx++); }
13828 ++y;
13829 unsigned int dy = *(poffy++);
13830 for (;!dy && y<dy; cimg_std::memcpy(ptrd, ptrd-dx, sizeof(T)*dx), ++y, ptrd+=dx, dy=*(poffy++)) {}
13831 ptry+=dy;
13832 }
13833 ++z;
13834 unsigned int dz = *(poffz++);
13835 for (;!dz && z<dz; cimg_std::memcpy(ptrd, ptrd-rwh, sizeof(T)*rwh), ++z, ptrd+=rwh, dz=*(poffz++)) {}
13836 ptrz+=dz;
13837 }
13838 ++k;
13839 unsigned int dv = *(poffv++);
13840 for (;!dv && k<dv; cimg_std::memcpy(ptrd, ptrd-rwhd, sizeof(T)*rwhd), ++k, ptrd+=rwhd, dv=*(poffv++)) {}
13841 ptrv+=dv;
13842 }
13843 delete[] offx; delete[] offy; delete[] offz; delete[] offv;
13844 } break;
13846 case 2 : { // Moving average
13847 bool instance_first = true;
13848 if (dx!=width) {
13849 CImg<Tfloat> tmp(dx,height,depth,dim,0);
13850 for (unsigned int a = width*dx, b = width, c = dx, s = 0, t = 0; a; ) {
13851 const unsigned int d = cimg::min(b,c);
13852 a-=d; b-=d; c-=d;
13853 cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d;
13854 if (!b) { cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)/=width; ++t; b = width; }
13855 if (!c) { ++s; c = dx; }
13856 }
13857 tmp.transfer_to(res);
13858 instance_first = false;
13859 }
13860 if (dy!=height) {
13861 CImg<Tfloat> tmp(dx,dy,depth,dim,0);
13862 for (unsigned int a = height*dy, b = height, c = dy, s = 0, t = 0; a; ) {
13863 const unsigned int d = cimg::min(b,c);
13864 a-=d; b-=d; c-=d;
13865 if (instance_first) cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d;
13866 else cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d;
13867 if (!b) { cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)/=height; ++t; b = height; }
13868 if (!c) { ++s; c = dy; }
13869 }
13870 tmp.transfer_to(res);
13871 instance_first = false;
13872 }
13873 if (dz!=depth) {
13874 CImg<Tfloat> tmp(dx,dy,dz,dim,0);
13875 for (unsigned int a = depth*dz, b = depth, c = dz, s = 0, t = 0; a; ) {
13876 const unsigned int d = cimg::min(b,c);
13877 a-=d; b-=d; c-=d;
13878 if (instance_first) cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d;
13879 else cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d;
13880 if (!b) { cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)/=depth; ++t; b = depth; }
13881 if (!c) { ++s; c = dz; }
13882 }
13883 tmp.transfer_to(res);
13884 instance_first = false;
13885 }
13886 if (dv!=dim) {
13887 CImg<Tfloat> tmp(dx,dy,dz,dv,0);
13888 for (unsigned int a = dim*dv, b = dim, c = dv, s = 0, t = 0; a; ) {
13889 const unsigned int d = cimg::min(b,c);
13890 a-=d; b-=d; c-=d;
13891 if (instance_first) cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d;
13892 else cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d;
13893 if (!b) { cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)/=dim; ++t; b = dim; }
13894 if (!c) { ++s; c = dv; }
13895 }
13896 tmp.transfer_to(res);
13897 instance_first = false;
13898 }
13899 } break;
13901 case 3 : { // Linear interpolation
13902 const unsigned int dimmax = cimg::max(dx,dy,dz,dv);
13903 const float
13904 sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
13905 sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
13906 sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
13907 sv = (border_condition<0 && dv>dim )?(dv>1?(dim-1.0f)/(dv-1) :0):(float)dim/dv;
13909 unsigned int *const off = new unsigned int[dimmax], *poff;
13910 float *const foff = new float[dimmax], *pfoff, old, curr;
13911 CImg<T> resx, resy, resz, resv;
13912 T *ptrd;
13914 if (dx!=width) {
13915 if (width==1) resx = get_resize(dx,height,depth,dim,1,0);
13916 else {
13917 resx.assign(dx,height,depth,dim);
13918 curr = old = 0; poff = off; pfoff = foff;
13919 cimg_forX(resx,x) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sx; *(poff++) = (unsigned int)curr-(unsigned int)old; }
13920 ptrd = resx.data;
13921 const T *ptrs0 = data;
13922 cimg_forYZV(resx,y,z,k) {
13923 poff = off; pfoff = foff;
13924 const T *ptrs = ptrs0, *const ptrsmax = ptrs0 + (width-1);
13925 cimg_forX(resx,x) {
13926 const float alpha = *(pfoff++);
13927 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+1):(border_condition?val1:(T)0);
13928 *(ptrd++) = (T)((1-alpha)*val1 + alpha*val2);
13929 ptrs+=*(poff++);
13930 }
13931 ptrs0+=width;
13932 }
13933 }
13934 } else resx.assign(*this,true);
13936 if (dy!=height) {
13937 if (height==1) resy = resx.get_resize(dx,dy,depth,dim,1,0);
13938 else {
13939 resy.assign(dx,dy,depth,dim);
13940 curr = old = 0; poff = off; pfoff = foff;
13941 cimg_forY(resy,y) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sy; *(poff++) = dx*((unsigned int)curr-(unsigned int)old); }
13942 cimg_forXZV(resy,x,z,k) {
13943 ptrd = resy.ptr(x,0,z,k);
13944 const T *ptrs = resx.ptr(x,0,z,k), *const ptrsmax = ptrs + (height-1)*dx;
13945 poff = off; pfoff = foff;
13946 cimg_forY(resy,y) {
13947 const float alpha = *(pfoff++);
13948 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+dx):(border_condition?val1:(T)0);
13949 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
13950 ptrd+=dx;
13951 ptrs+=*(poff++);
13952 }
13953 }
13954 }
13955 resx.assign();
13956 } else resy.assign(resx,true);
13958 if (dz!=depth) {
13959 if (depth==1) resz = resy.get_resize(dx,dy,dz,dim,1,0);
13960 else {
13961 const unsigned int wh = dx*dy;
13962 resz.assign(dx,dy,dz,dim);
13963 curr = old = 0; poff = off; pfoff = foff;
13964 cimg_forZ(resz,z) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sz; *(poff++) = wh*((unsigned int)curr-(unsigned int)old); }
13965 cimg_forXYV(resz,x,y,k) {
13966 ptrd = resz.ptr(x,y,0,k);
13967 const T *ptrs = resy.ptr(x,y,0,k), *const ptrsmax = ptrs + (depth-1)*wh;
13968 poff = off; pfoff = foff;
13969 cimg_forZ(resz,z) {
13970 const float alpha = *(pfoff++);
13971 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+wh):(border_condition?val1:(T)0);
13972 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
13973 ptrd+=wh;
13974 ptrs+=*(poff++);
13975 }
13976 }
13977 }
13978 resy.assign();
13979 } else resz.assign(resy,true);
13981 if (dv!=dim) {
13982 if (dim==1) resv = resz.get_resize(dx,dy,dz,dv,1,0);
13983 else {
13984 const unsigned int whd = dx*dy*dz;
13985 resv.assign(dx,dy,dz,dv);
13986 curr = old = 0; poff = off; pfoff = foff;
13987 cimg_forV(resv,k) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sv; *(poff++) = whd*((unsigned int)curr-(unsigned int)old); }
13988 cimg_forXYZ(resv,x,y,z) {
13989 ptrd = resv.ptr(x,y,z,0);
13990 const T *ptrs = resz.ptr(x,y,z,0), *const ptrsmax = ptrs + (dim-1)*whd;
13991 poff = off; pfoff = foff;
13992 cimg_forV(resv,k) {
13993 const float alpha = *(pfoff++);
13994 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+whd):(border_condition?val1:(T)0);
13995 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
13996 ptrd+=whd;
13997 ptrs+=*(poff++);
13998 }
13999 }
14000 }
14001 resz.assign();
14002 } else resv.assign(resz,true);
14004 delete[] off; delete[] foff;
14005 return resv.is_shared?(resz.is_shared?(resy.is_shared?(resx.is_shared?(+(*this)):resx):resy):resz):resv;
14006 } break;
14008 case 4 : { // Grid filling
14009 res.assign(dx,dy,dz,dv,0);
14010 cimg_forXYZV(*this,x,y,z,k) res(x*dx/width,y*dy/height,z*dz/depth,k*dv/dim) = (*this)(x,y,z,k);
14011 } break;
14013 case 5 : { // Cubic interpolation
14014 const float
14015 sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
14016 sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
14017 sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
14018 sv = (border_condition<0 && dv>dim )?(dv>1?(dim-1.0f)/(dv-1) :0):(float)dim/dv;
14019 res.assign(dx,dy,dz,dv);
14020 T *ptrd = res.ptr();
14021 float cx, cy, cz, ck = 0;
14022 cimg_forV(res,k) { cz = 0;
14023 cimg_forZ(res,z) { cy = 0;
14024 cimg_forY(res,y) { cx = 0;
14025 cimg_forX(res,x) {
14026 *(ptrd++) = (T)(border_condition?_cubic_atXY(cx,cy,(int)cz,(int)ck):cubic_atXY(cx,cy,(int)cz,(int)ck,0));
14027 cx+=sx;
14028 } cy+=sy;
14029 } cz+=sz;
14030 } ck+=sv;
14031 }
14032 } break;
14034 default : // Invalid interpolation method
14035 throw CImgArgumentException("CImg<%s>::resize() : Invalid interpolation_type %d "
14036 "(should be { -1=raw, 0=zero, 1=nearest, 2=average, 3=linear, 4=grid, 5=bicubic}).",
14037 pixel_type(),interpolation_type);
14038 }
14039 return res;
14040 }
14042 //! Resize an image.
14043 /**
14044 \param src Image giving the geometry of the resize.
14045 \param interpolation_type Interpolation method :
14046 - 1 = raw memory
14047 - 0 = no interpolation : additional space is filled with 0.
14048 - 1 = bloc interpolation (nearest point).
14049 - 2 = mosaic : image is repeated if necessary.
14050 - 3 = linear interpolation.
14051 - 4 = grid interpolation.
14052 - 5 = bi-cubic interpolation.
14053 \param border_condition Border condition type.
14054 \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
14055 **/
14056 template<typename t>
14057 CImg<T>& resize(const CImg<t>& src, const int interpolation_type=1,
14058 const int border_condition=-1, const bool center=false) {
14059 return resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
14060 }
14062 template<typename t>
14063 CImg<T> get_resize(const CImg<t>& src, const int interpolation_type=1,
14064 const int border_condition=-1, const bool center=false) const {
14065 return get_resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
14066 }
14068 //! Resize an image.
14069 /**
14070 \param disp = Display giving the geometry of the resize.
14071 \param interpolation_type = Resizing type :
14072 - 0 = no interpolation : additional space is filled with 0.
14073 - 1 = bloc interpolation (nearest point).
14074 - 2 = mosaic : image is repeated if necessary.
14075 - 3 = linear interpolation.
14076 - 4 = grid interpolation.
14077 - 5 = bi-cubic interpolation.
14078 - 6 = moving average (best quality for photographs)
14079 \param border_condition Border condition type.
14080 \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
14081 **/
14082 CImg<T>& resize(const CImgDisplay& disp, const int interpolation_type=1,
14083 const int border_condition=-1, const bool center=false) {
14084 return resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
14085 }
14087 CImg<T> get_resize(const CImgDisplay& disp, const int interpolation_type=1,
14088 const int border_condition=-1, const bool center=false) const {
14089 return get_resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
14090 }
14092 //! Half-resize an image, using a special optimized filter.
14093 CImg<T>& resize_halfXY() {
14094 return get_resize_halfXY().transfer_to(*this);
14095 }
14097 CImg<T> get_resize_halfXY() const {
14098 if (is_empty()) return *this;
14099 const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f,
14100 0.1231940459f, 0.1935127547f, 0.1231940459f,
14101 0.07842776544f, 0.1231940459f, 0.07842776544f };
14102 T I[9] = { 0 };
14103 CImg<T> dest(width/2,height/2,depth,dim);
14104 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I)
14105 if (x%2 && y%2) dest(x/2,y/2,z,k) = (T)
14106 (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
14107 I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
14108 I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
14109 return dest;
14110 }
14112 //! Upscale an image by a factor 2x.
14113 /**
14114 Use anisotropic upscaling algorithm described at
14115 http://scale2x.sourceforge.net/algorithm.html
14116 **/
14117 CImg<T>& resize_doubleXY() {
14118 return get_resize_doubleXY().transfer_to(*this);
14119 }
14121 CImg<T> get_resize_doubleXY() const {
14122 #define _cimg_gs2x_for3(bound,i) \
14123 for (int i = 0, _p1##i = 0, \
14124 _n1##i = 1>=(bound)?(int)(bound)-1:1; \
14125 _n1##i<(int)(bound) || i==--_n1##i; \
14126 _p1##i = i++, ++_n1##i, ptrd1+=(res).width, ptrd2+=(res).width)
14128 #define _cimg_gs2x_for3x3(img,x,y,z,v,I) \
14129 _cimg_gs2x_for3((img).height,y) for (int x = 0, \
14130 _p1##x = 0, \
14131 _n1##x = (int)( \
14132 (I[1] = (img)(0,_p1##y,z,v)), \
14133 (I[3] = I[4] = (img)(0,y,z,v)), \
14134 (I[7] = (img)(0,_n1##y,z,v)), \
14135 1>=(img).width?(int)((img).width)-1:1); \
14136 (_n1##x<(int)((img).width) && ( \
14137 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
14138 (I[5] = (img)(_n1##x,y,z,v)), \
14139 (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
14140 x==--_n1##x; \
14141 I[1] = I[2], \
14142 I[3] = I[4], I[4] = I[5], \
14143 I[7] = I[8], \
14144 _p1##x = x++, ++_n1##x)
14146 if (is_empty()) return *this;
14147 CImg<T> res(2*width,2*height,depth,dim);
14148 CImg_3x3(I,T);
14149 cimg_forZV(*this,z,k) {
14150 T
14151 *ptrd1 = res.ptr(0,0,0,k),
14152 *ptrd2 = ptrd1 + res.width;
14153 _cimg_gs2x_for3x3(*this,x,y,0,k,I) {
14154 if (Icp!=Icn && Ipc!=Inc) {
14155 *(ptrd1++) = Ipc==Icp?Ipc:Icc;
14156 *(ptrd1++) = Icp==Inc?Inc:Icc;
14157 *(ptrd2++) = Ipc==Icn?Ipc:Icc;
14158 *(ptrd2++) = Icn==Inc?Inc:Icc;
14159 } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; }
14160 }
14161 }
14162 return res;
14163 }
14165 //! Upscale an image by a factor 3x.
14166 /**
14167 Use anisotropic upscaling algorithm described at
14168 http://scale2x.sourceforge.net/algorithm.html
14169 **/
14170 CImg<T>& resize_tripleXY() {
14171 return get_resize_tripleXY().transfer_to(*this);
14172 }
14174 CImg<T> get_resize_tripleXY() const {
14175 #define _cimg_gs3x_for3(bound,i) \
14176 for (int i = 0, _p1##i = 0, \
14177 _n1##i = 1>=(bound)?(int)(bound)-1:1; \
14178 _n1##i<(int)(bound) || i==--_n1##i; \
14179 _p1##i = i++, ++_n1##i, ptrd1+=2*(res).width, ptrd2+=2*(res).width, ptrd3+=2*(res).width)
14181 #define _cimg_gs3x_for3x3(img,x,y,z,v,I) \
14182 _cimg_gs3x_for3((img).height,y) for (int x = 0, \
14183 _p1##x = 0, \
14184 _n1##x = (int)( \
14185 (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
14186 (I[3] = I[4] = (img)(0,y,z,v)), \
14187 (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
14188 1>=(img).width?(int)((img).width)-1:1); \
14189 (_n1##x<(int)((img).width) && ( \
14190 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
14191 (I[5] = (img)(_n1##x,y,z,v)), \
14192 (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
14193 x==--_n1##x; \
14194 I[0] = I[1], I[1] = I[2], \
14195 I[3] = I[4], I[4] = I[5], \
14196 I[6] = I[7], I[7] = I[8], \
14197 _p1##x = x++, ++_n1##x)
14199 if (is_empty()) return *this;
14200 CImg<T> res(3*width,3*height,depth,dim);
14201 CImg_3x3(I,T);
14202 cimg_forZV(*this,z,k) {
14203 T
14204 *ptrd1 = res.ptr(0,0,0,k),
14205 *ptrd2 = ptrd1 + res.width,
14206 *ptrd3 = ptrd2 + res.width;
14207 _cimg_gs3x_for3x3(*this,x,y,0,k,I) {
14208 if (Icp != Icn && Ipc != Inc) {
14209 *(ptrd1++) = Ipc==Icp?Ipc:Icc;
14210 *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc;
14211 *(ptrd1++) = Icp==Inc?Inc:Icc;
14212 *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc;
14213 *(ptrd2++) = Icc;
14214 *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc;
14215 *(ptrd3++) = Ipc==Icn?Ipc:Icc;
14216 *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc;
14217 *(ptrd3++) = Icn==Inc?Inc:Icc;
14218 } else {
14219 *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc;
14220 *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc;
14221 *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc;
14222 }
14223 }
14224 }
14225 return res;
14226 }
14228 // Warp an image.
14229 template<typename t>
14230 CImg<T>& warp(const CImg<t>& warp, const bool relative=false,
14231 const bool interpolation=true, const unsigned int border_conditions=0) {
14232 return get_warp(warp,relative,interpolation,border_conditions).transfer_to(*this);
14233 }
14235 template<typename t>
14236 CImg<T> get_warp(const CImg<t>& warp, const bool relative=false,
14237 const bool interpolation=true, const unsigned int border_conditions=0) const {
14238 if (is_empty() || !warp) return *this;
14239 if (!is_sameXYZ(warp))
14240 throw CImgArgumentException("CImg<%s>::warp() : Instance image (%u,%u,%u,%u,%p) and warping field (%u,%u,%u,%u,%p) "
14241 "have different XYZ dimensions.",
14242 pixel_type(),width,height,depth,dim,data,
14243 warp.width,warp.height,warp.depth,warp.dim,warp.data);
14244 CImg<T> res(width,height,depth,dim);
14245 switch (warp.dim) {
14246 case 1 : // 1D warping.
14247 if (relative) { // Relative warp coordinates
14248 if (interpolation) switch (border_conditions) {
14249 case 2 : {
14250 cimg_forXYZV(*this,x,y,z,v)
14251 res(x,y,z,v) = (T)_linear_atX(cimg::mod(x-(float)warp(x,y,z,0),(float)width),y,z,v);
14252 } break;
14253 case 1 : {
14254 cimg_forXYZV(*this,x,y,z,v)
14255 res(x,y,z,v) = (T)_linear_atX(x-(float)warp(x,y,z,0),y,z,v);
14256 } break;
14257 default : {
14258 cimg_forXYZV(*this,x,y,z,v)
14259 res(x,y,z,v) = (T)linear_atX(x-(float)warp(x,y,z,0),y,z,v,0);
14260 }
14261 } else switch (border_conditions) {
14262 case 2 : {
14263 cimg_forXYZV(*this,x,y,z,v)
14264 res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),y,z,v);
14265 } break;
14266 case 1 : {
14267 cimg_forXYZV(*this,x,y,z,v)
14268 res(x,y,z,v) = _atX(x-(int)warp(x,y,z,0),y,z,v);
14269 } break;
14270 default : {
14271 cimg_forXYZV(*this,x,y,z,v)
14272 res(x,y,z,v) = atX(x-(int)warp(x,y,z,0),y,z,v,0);
14273 }
14274 }
14275 } else { // Absolute warp coordinates
14276 if (interpolation) switch (border_conditions) {
14277 case 2 : {
14278 cimg_forXYZV(*this,x,y,z,v)
14279 res(x,y,z,v) = (T)_linear_atX(cimg::mod((float)warp(x,y,z,0),(float)width),y,z,v);
14280 } break;
14281 case 1 : {
14282 cimg_forXYZV(*this,x,y,z,v)
14283 res(x,y,z,v) = (T)_linear_atX((float)warp(x,y,z,0),y,z,v);
14284 } break;
14285 default : {
14286 cimg_forXYZV(*this,x,y,z,v)
14287 res(x,y,z,v) = (T)linear_atX((float)warp(x,y,z,0),y,z,v,0);
14288 }
14289 } else switch (border_conditions) {
14290 case 2 : {
14291 cimg_forXYZV(*this,x,y,z,v)
14292 res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),y,z,v);
14293 } break;
14294 case 1 : {
14295 cimg_forXYZV(*this,x,y,z,v)
14296 res(x,y,z,v) = _atX((int)warp(x,y,z,0),y,z,v);
14297 } break;
14298 default : {
14299 cimg_forXYZV(*this,x,y,z,v)
14300 res(x,y,z,v) = atX((int)warp(x,y,z,0),y,z,v,0);
14301 }
14302 }
14303 }
14304 break;
14306 case 2 : // 2D warping
14307 if (relative) { // Relative warp coordinates
14308 if (interpolation) switch (border_conditions) {
14309 case 2 : {
14310 cimg_forXYZV(*this,x,y,z,v)
14311 res(x,y,z,v) = (T)_linear_atXY(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
14312 cimg::mod(y-(float)warp(x,y,z,1),(float)height),z,v);
14313 } break;
14314 case 1 : {
14315 cimg_forXYZV(*this,x,y,z,v)
14316 res(x,y,z,v) = (T)_linear_atXY(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z,v);
14317 } break;
14318 default : {
14319 cimg_forXYZV(*this,x,y,z,v)
14320 res(x,y,z,v) = (T)linear_atXY(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z,v,0);
14321 }
14322 } else switch (border_conditions) {
14323 case 2 : {
14324 cimg_forXYZV(*this,x,y,z,v)
14325 res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
14326 cimg::mod(y-(int)warp(x,y,z,1),(int)height),z,v);
14327 } break;
14328 case 1 : {
14329 cimg_forXYZV(*this,x,y,z,v)
14330 res(x,y,z,v) = _atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v);
14331 } break;
14332 default : {
14333 cimg_forXYZV(*this,x,y,z,v)
14334 res(x,y,z,v) = atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v,0);
14335 }
14336 }
14337 } else { // Absolute warp coordinates
14338 if (interpolation) switch (border_conditions) {
14339 case 2 : {
14340 cimg_forXYZV(*this,x,y,z,v)
14341 res(x,y,z,v) = (T)_linear_atXY(cimg::mod((float)warp(x,y,z,0),(float)width),
14342 cimg::mod((float)warp(x,y,z,1),(float)height),z,v);
14343 } break;
14344 case 1 : {
14345 cimg_forXYZV(*this,x,y,z,v)
14346 res(x,y,z,v) = (T)_linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v);
14347 } break;
14348 default : {
14349 cimg_forXYZV(*this,x,y,z,v)
14350 res(x,y,z,v) = (T)linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v,0);
14351 }
14352 } else switch (border_conditions) {
14353 case 2 : {
14354 cimg_forXYZV(*this,x,y,z,v)
14355 res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
14356 cimg::mod((int)warp(x,y,z,1),(int)depth),z,v);
14357 } break;
14358 case 1 : {
14359 cimg_forXYZV(*this,x,y,z,v)
14360 res(x,y,z,v) = _atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v);
14361 } break;
14362 default : {
14363 cimg_forXYZV(*this,x,y,z,v)
14364 res(x,y,z,v) = atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v,0);
14365 }
14366 }
14367 }
14368 break;
14370 case 3 : // 3D warping
14371 if (relative) { // Relative warp coordinates
14372 if (interpolation) switch (border_conditions) {
14373 case 2 : {
14374 cimg_forXYZV(*this,x,y,z,v)
14375 res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
14376 cimg::mod(y-(float)warp(x,y,z,1),(float)height),
14377 cimg::mod(z-(float)warp(x,y,z,2),(float)depth),v);
14378 } break;
14379 case 1 : {
14380 cimg_forXYZV(*this,x,y,z,v)
14381 res(x,y,z,v) = (T)_linear_atXYZ(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v);
14382 } break;
14383 default : {
14384 cimg_forXYZV(*this,x,y,z,v)
14385 res(x,y,z,v) = (T)linear_atXYZ(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v,0);
14386 }
14387 } else switch (border_conditions) {
14388 case 2 : {
14389 cimg_forXYZV(*this,x,y,z,v)
14390 res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
14391 cimg::mod(y-(int)warp(x,y,z,1),(int)height),
14392 cimg::mod(z-(int)warp(x,y,z,2),(int)depth),v);
14393 } break;
14394 case 1 : {
14395 cimg_forXYZV(*this,x,y,z,v)
14396 res(x,y,z,v) = _atXYZ(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v);
14397 } break;
14398 default : {
14399 cimg_forXYZV(*this,x,y,z,v)
14400 res(x,y,z,v) = atXYZ(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v,0);
14401 }
14402 }
14403 } else { // Absolute warp coordinates
14404 if (interpolation) switch (border_conditions) {
14405 case 2 : {
14406 cimg_forXYZV(*this,x,y,z,v)
14407 res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod((float)warp(x,y,z,0),(float)width),
14408 cimg::mod((float)warp(x,y,z,1),(float)height),
14409 cimg::mod((float)warp(x,y,z,2),(float)depth),v);
14410 } break;
14411 case 1 : {
14412 cimg_forXYZV(*this,x,y,z,v)
14413 res(x,y,z,v) = (T)_linear_atXYZ((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),v);
14414 } break;
14415 default : {
14416 cimg_forXYZV(*this,x,y,z,v)
14417 res(x,y,z,v) = (T)linear_atXYZ((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),v,0);
14418 }
14419 } else switch (border_conditions) {
14420 case 2 : {
14421 cimg_forXYZV(*this,x,y,z,v)
14422 res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
14423 cimg::mod((int)warp(x,y,z,1),(int)height),
14424 cimg::mod((int)warp(x,y,z,2),(int)depth),v);
14425 } break;
14426 case 1 : {
14427 cimg_forXYZV(*this,x,y,z,v)
14428 res(x,y,z,v) = _atXYZ((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),v);
14429 } break;
14430 default : {
14431 cimg_forXYZV(*this,x,y,z,v)
14432 res(x,y,z,v) = atXYZ((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),v,0);
14433 }
14434 }
14435 }
14436 break;
14438 default : // 4D warping
14439 if (relative) { // Relative warp coordinates
14440 if (interpolation) switch (border_conditions) {
14441 case 2 : {
14442 cimg_forXYZV(*this,x,y,z,v)
14443 res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
14444 cimg::mod(y-(float)warp(x,y,z,1),(float)height),
14445 cimg::mod(z-(float)warp(x,y,z,2),(float)depth),
14446 cimg::mod(z-(float)warp(x,y,z,3),(float)dim));
14447 } break;
14448 case 1 : {
14449 cimg_forXYZV(*this,x,y,z,v)
14450 res(x,y,z,v) = (T)_linear_atXYZV(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v-(float)warp(x,y,z,3));
14451 } break;
14452 default : {
14453 cimg_forXYZV(*this,x,y,z,v)
14454 res(x,y,z,v) = (T)linear_atXYZV(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v-(float)warp(x,y,z,3),0);
14455 }
14456 } else switch (border_conditions) {
14457 case 2 : {
14458 cimg_forXYZV(*this,x,y,z,v)
14459 res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
14460 cimg::mod(y-(int)warp(x,y,z,1),(int)height),
14461 cimg::mod(z-(int)warp(x,y,z,2),(int)depth),
14462 cimg::mod(v-(int)warp(x,y,z,3),(int)dim));
14463 } break;
14464 case 1 : {
14465 cimg_forXYZV(*this,x,y,z,v)
14466 res(x,y,z,v) = _atXYZV(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v-(int)warp(x,y,z,3));
14467 } break;
14468 default : {
14469 cimg_forXYZV(*this,x,y,z,v)
14470 res(x,y,z,v) = atXYZ(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v-(int)warp(x,y,z,3),0);
14471 }
14472 }
14473 } else { // Absolute warp coordinates
14474 if (interpolation) switch (border_conditions) {
14475 case 2 : {
14476 cimg_forXYZV(*this,x,y,z,v)
14477 res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod((float)warp(x,y,z,0),(float)width),
14478 cimg::mod((float)warp(x,y,z,1),(float)height),
14479 cimg::mod((float)warp(x,y,z,2),(float)depth),
14480 cimg::mod((float)warp(x,y,z,3),(float)dim));
14481 } break;
14482 case 1 : {
14483 cimg_forXYZV(*this,x,y,z,v)
14484 res(x,y,z,v) = (T)_linear_atXYZV((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),(float)warp(x,y,z,3));
14485 } break;
14486 default : {
14487 cimg_forXYZV(*this,x,y,z,v)
14488 res(x,y,z,v) = (T)linear_atXYZV((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),(float)warp(x,y,z,3),0);
14489 }
14490 } else switch (border_conditions) {
14491 case 2 : {
14492 cimg_forXYZV(*this,x,y,z,v)
14493 res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
14494 cimg::mod((int)warp(x,y,z,1),(int)height),
14495 cimg::mod((int)warp(x,y,z,2),(int)depth),
14496 cimg::mod((int)warp(x,y,z,3),(int)dim));
14497 } break;
14498 case 1 : {
14499 cimg_forXYZV(*this,x,y,z,v)
14500 res(x,y,z,v) = _atXYZV((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),(int)warp(x,y,z,3));
14501 } break;
14502 default : {
14503 cimg_forXYZV(*this,x,y,z,v)
14504 res(x,y,z,v) = atXYZV((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),(int)warp(x,y,z,3),0);
14505 }
14506 }
14507 }
14508 }
14509 return res;
14510 }
14512 // Permute axes order (internal).
14513 template<typename t>
14514 CImg<t> _get_permute_axes(const char *permut, const t&) const {
14515 if (is_empty() || !permut) return CImg<t>(*this,false);
14516 CImg<t> res;
14517 const T* ptrs = data;
14518 if (!cimg::strncasecmp(permut,"xyzv",4)) return (+*this);
14519 if (!cimg::strncasecmp(permut,"xyvz",4)) {
14520 res.assign(width,height,dim,depth);
14521 cimg_forXYZV(*this,x,y,z,v) res(x,y,v,z) = (t)*(ptrs++);
14522 }
14523 if (!cimg::strncasecmp(permut,"xzyv",4)) {
14524 res.assign(width,depth,height,dim);
14525 cimg_forXYZV(*this,x,y,z,v) res(x,z,y,v) = (t)*(ptrs++);
14526 }
14527 if (!cimg::strncasecmp(permut,"xzvy",4)) {
14528 res.assign(width,depth,dim,height);
14529 cimg_forXYZV(*this,x,y,z,v) res(x,z,v,y) = (t)*(ptrs++);
14530 }
14531 if (!cimg::strncasecmp(permut,"xvyz",4)) {
14532 res.assign(width,dim,height,depth);
14533 cimg_forXYZV(*this,x,y,z,v) res(x,v,y,z) = (t)*(ptrs++);
14534 }
14535 if (!cimg::strncasecmp(permut,"xvzy",4)) {
14536 res.assign(width,dim,depth,height);
14537 cimg_forXYZV(*this,x,y,z,v) res(x,v,z,y) = (t)*(ptrs++);
14538 }
14539 if (!cimg::strncasecmp(permut,"yxzv",4)) {
14540 res.assign(height,width,depth,dim);
14541 cimg_forXYZV(*this,x,y,z,v) res(y,x,z,v) = (t)*(ptrs++);
14542 }
14543 if (!cimg::strncasecmp(permut,"yxvz",4)) {
14544 res.assign(height,width,dim,depth);
14545 cimg_forXYZV(*this,x,y,z,v) res(y,x,v,z) = (t)*(ptrs++);
14546 }
14547 if (!cimg::strncasecmp(permut,"yzxv",4)) {
14548 res.assign(height,depth,width,dim);
14549 cimg_forXYZV(*this,x,y,z,v) res(y,z,x,v) = (t)*(ptrs++);
14550 }
14551 if (!cimg::strncasecmp(permut,"yzvx",4)) {
14552 res.assign(height,depth,dim,width);
14553 switch (width) {
14554 case 1 : {
14555 t *ptrR = res.ptr(0,0,0,0);
14556 for (unsigned long siz = height*depth*dim; siz; --siz) {
14557 *(ptrR++) = (t)*(ptrs++);
14558 }
14559 } break;
14560 case 2 : {
14561 t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1);
14562 for (unsigned long siz = height*depth*dim; siz; --siz) {
14563 *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++);
14564 }
14565 } break;
14566 case 3 : { // Optimization for the classical conversion from interleaved RGB to planar RGB
14567 t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1), *ptrB = res.ptr(0,0,0,2);
14568 for (unsigned long siz = height*depth*dim; siz; --siz) {
14569 *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++);
14570 }
14571 } break;
14572 case 4 : { // Optimization for the classical conversion from interleaved RGBA to planar RGBA
14573 t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1), *ptrB = res.ptr(0,0,0,2), *ptrA = res.ptr(0,0,0,3);
14574 for (unsigned long siz = height*depth*dim; siz; --siz) {
14575 *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++); *(ptrA++) = (t)*(ptrs++);
14576 }
14577 } break;
14578 default : {
14579 cimg_forXYZV(*this,x,y,z,v) res(y,z,v,x) = *(ptrs++);
14580 return res;
14581 }
14582 }
14583 }
14584 if (!cimg::strncasecmp(permut,"yvxz",4)) {
14585 res.assign(height,dim,width,depth);
14586 cimg_forXYZV(*this,x,y,z,v) res(y,v,x,z) = (t)*(ptrs++);
14587 }
14588 if (!cimg::strncasecmp(permut,"yvzx",4)) {
14589 res.assign(height,dim,depth,width);
14590 cimg_forXYZV(*this,x,y,z,v) res(y,v,z,x) = (t)*(ptrs++);
14591 }
14592 if (!cimg::strncasecmp(permut,"zxyv",4)) {
14593 res.assign(depth,width,height,dim);
14594 cimg_forXYZV(*this,x,y,z,v) res(z,x,y,v) = (t)*(ptrs++);
14595 }
14596 if (!cimg::strncasecmp(permut,"zxvy",4)) {
14597 res.assign(depth,width,dim,height);
14598 cimg_forXYZV(*this,x,y,z,v) res(z,x,v,y) = (t)*(ptrs++);
14599 }
14600 if (!cimg::strncasecmp(permut,"zyxv",4)) {
14601 res.assign(depth,height,width,dim);
14602 cimg_forXYZV(*this,x,y,z,v) res(z,y,x,v) = (t)*(ptrs++);
14603 }
14604 if (!cimg::strncasecmp(permut,"zyvx",4)) {
14605 res.assign(depth,height,dim,width);
14606 cimg_forXYZV(*this,x,y,z,v) res(z,y,v,x) = (t)*(ptrs++);
14607 }
14608 if (!cimg::strncasecmp(permut,"zvxy",4)) {
14609 res.assign(depth,dim,width,height);
14610 cimg_forXYZV(*this,x,y,z,v) res(z,v,x,y) = (t)*(ptrs++);
14611 }
14612 if (!cimg::strncasecmp(permut,"zvyx",4)) {
14613 res.assign(depth,dim,height,width);
14614 cimg_forXYZV(*this,x,y,z,v) res(z,v,y,x) = (t)*(ptrs++);
14615 }
14616 if (!cimg::strncasecmp(permut,"vxyz",4)) {
14617 res.assign(dim,width,height,depth);
14618 switch (dim) {
14619 case 1 : {
14620 const T *ptrR = ptr(0,0,0,0);
14621 t *ptrd = res.ptr();
14622 for (unsigned long siz = width*height*depth; siz; --siz) {
14623 *(ptrd++) = (t)*(ptrR++);
14624 }
14625 } break;
14626 case 2 : {
14627 const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1);
14628 t *ptrd = res.ptr();
14629 for (unsigned long siz = width*height*depth; siz; --siz) {
14630 *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++);
14631 }
14632 } break;
14633 case 3 : { // Optimization for the classical conversion from planar RGB to interleaved RGB
14634 const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1), *ptrB = ptr(0,0,0,2);
14635 t *ptrd = res.ptr();
14636 for (unsigned long siz = width*height*depth; siz; --siz) {
14637 *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++);
14638 }
14639 } break;
14640 case 4 : { // Optimization for the classical conversion from planar RGBA to interleaved RGBA
14641 const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1), *ptrB = ptr(0,0,0,2), *ptrA = ptr(0,0,0,3);
14642 t *ptrd = res.ptr();
14643 for (unsigned long siz = width*height*depth; siz; --siz) {
14644 *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++); *(ptrd++) = (t)*(ptrA++);
14645 }
14646 } break;
14647 default : {
14648 cimg_forXYZV(*this,x,y,z,v) res(v,x,y,z) = (t)*(ptrs++);
14649 }
14650 }
14651 }
14652 if (!cimg::strncasecmp(permut,"vxzy",4)) {
14653 res.assign(dim,width,depth,height);
14654 cimg_forXYZV(*this,x,y,z,v) res(v,x,z,y) = (t)*(ptrs++);
14655 }
14656 if (!cimg::strncasecmp(permut,"vyxz",4)) {
14657 res.assign(dim,height,width,depth);
14658 cimg_forXYZV(*this,x,y,z,v) res(v,y,x,z) = (t)*(ptrs++);
14659 }
14660 if (!cimg::strncasecmp(permut,"vyzx",4)) {
14661 res.assign(dim,height,depth,width);
14662 cimg_forXYZV(*this,x,y,z,v) res(v,y,z,x) = (t)*(ptrs++);
14663 }
14664 if (!cimg::strncasecmp(permut,"vzxy",4)) {
14665 res.assign(dim,depth,width,height);
14666 cimg_forXYZV(*this,x,y,z,v) res(v,z,x,y) = (t)*(ptrs++);
14667 }
14668 if (!cimg::strncasecmp(permut,"vzyx",4)) {
14669 res.assign(dim,depth,height,width);
14670 cimg_forXYZV(*this,x,y,z,v) res(v,z,y,x) = (t)*(ptrs++);
14671 }
14672 if (!res)
14673 throw CImgArgumentException("CImg<%s>::permute_axes() : Invalid input permutation '%s'.",
14674 pixel_type(),permut);
14675 return res;
14676 }
14678 //! Permute axes order.
14679 /**
14680 This function permutes image axes.
14681 \param permut = String describing the permutation (4 characters).
14682 **/
14683 CImg<T>& permute_axes(const char *order) {
14684 return get_permute_axes(order).transfer_to(*this);
14685 }
14687 CImg<T> get_permute_axes(const char *order) const {
14688 const T foo = (T)0;
14689 return _get_permute_axes(order,foo);
14690 }
14692 //! Invert endianness.
14693 CImg<T>& invert_endianness() {
14694 cimg::invert_endianness(data,size());
14695 return *this;
14696 }
14698 CImg<T> get_invert_endianness() const {
14699 return (+*this).invert_endianness();
14700 }
14702 //! Mirror an image along the specified axis.
14703 CImg<T>& mirror(const char axis) {
14704 if (is_empty()) return *this;
14705 T *pf, *pb, *buf = 0;
14706 switch (cimg::uncase(axis)) {
14707 case 'x' : {
14708 pf = data; pb = ptr(width-1);
14709 const unsigned int width2 = width/2;
14710 for (unsigned int yzv = 0; yzv<height*depth*dim; ++yzv) {
14711 for (unsigned int x = 0; x<width2; ++x) { const T val = *pf; *(pf++) = *pb; *(pb--) = val; }
14712 pf+=width - width2;
14713 pb+=width + width2;
14714 }
14715 } break;
14716 case 'y' : {
14717 buf = new T[width];
14718 pf = data; pb = ptr(0,height-1);
14719 const unsigned int height2 = height/2;
14720 for (unsigned int zv=0; zv<depth*dim; ++zv) {
14721 for (unsigned int y=0; y<height2; ++y) {
14722 cimg_std::memcpy(buf,pf,width*sizeof(T));
14723 cimg_std::memcpy(pf,pb,width*sizeof(T));
14724 cimg_std::memcpy(pb,buf,width*sizeof(T));
14725 pf+=width;
14726 pb-=width;
14727 }
14728 pf+=width*(height - height2);
14729 pb+=width*(height + height2);
14730 }
14731 } break;
14732 case 'z' : {
14733 buf = new T[width*height];
14734 pf = data; pb = ptr(0,0,depth-1);
14735 const unsigned int depth2 = depth/2;
14736 cimg_forV(*this,v) {
14737 for (unsigned int z=0; z<depth2; ++z) {
14738 cimg_std::memcpy(buf,pf,width*height*sizeof(T));
14739 cimg_std::memcpy(pf,pb,width*height*sizeof(T));
14740 cimg_std::memcpy(pb,buf,width*height*sizeof(T));
14741 pf+=width*height;
14742 pb-=width*height;
14743 }
14744 pf+=width*height*(depth - depth2);
14745 pb+=width*height*(depth + depth2);
14746 }
14747 } break;
14748 case 'v' : {
14749 buf = new T[width*height*depth];
14750 pf = data; pb = ptr(0,0,0,dim-1);
14751 const unsigned int dim2 = dim/2;
14752 for (unsigned int v=0; v<dim2; ++v) {
14753 cimg_std::memcpy(buf,pf,width*height*depth*sizeof(T));
14754 cimg_std::memcpy(pf,pb,width*height*depth*sizeof(T));
14755 cimg_std::memcpy(pb,buf,width*height*depth*sizeof(T));
14756 pf+=width*height*depth;
14757 pb-=width*height*depth;
14758 }
14759 } break;
14760 default :
14761 throw CImgArgumentException("CImg<%s>::mirror() : unknow axis '%c', must be 'x','y','z' or 'v'.",
14762 pixel_type(),axis);
14763 }
14764 if (buf) delete[] buf;
14765 return *this;
14766 }
14768 CImg<T> get_mirror(const char axis) const {
14769 return (+*this).mirror(axis);
14770 }
14772 //! Translate the image.
14773 /**
14774 \param deltax Amount of displacement along the X-axis.
14775 \param deltay Amount of displacement along the Y-axis.
14776 \param deltaz Amount of displacement along the Z-axis.
14777 \param deltav Amount of displacement along the V-axis.
14778 \param border_condition Border condition.
14780 - \c border_condition can be :
14781 - 0 : Zero border condition (Dirichlet).
14782 - 1 : Nearest neighbors (Neumann).
14783 - 2 : Repeat Pattern (Fourier style).
14784 **/
14785 CImg<T>& translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
14786 const int border_condition=0) {
14787 if (is_empty()) return *this;
14788 if (deltax) // Translate along X-axis
14789 switch (border_condition) {
14790 case 0 :
14791 if (cimg::abs(deltax)>=dimx()) return fill(0);
14792 if (deltax>0) cimg_forYZV(*this,y,z,k) {
14793 cimg_std::memmove(ptr(0,y,z,k),ptr(deltax,y,z,k),(width-deltax)*sizeof(T));
14794 cimg_std::memset(ptr(width-deltax,y,z,k),0,deltax*sizeof(T));
14795 } else cimg_forYZV(*this,y,z,k) {
14796 cimg_std::memmove(ptr(-deltax,y,z,k),ptr(0,y,z,k),(width+deltax)*sizeof(T));
14797 cimg_std::memset(ptr(0,y,z,k),0,-deltax*sizeof(T));
14798 }
14799 break;
14800 case 1 :
14801 if (deltax>0) {
14802 const int ndeltax = (deltax>=dimx())?width-1:deltax;
14803 if (!ndeltax) return *this;
14804 cimg_forYZV(*this,y,z,k) {
14805 cimg_std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
14806 T *ptrd = ptr(width-1,y,z,k);
14807 const T val = *ptrd;
14808 for (int l = 0; l<ndeltax-1; ++l) *(--ptrd) = val;
14809 }
14810 } else {
14811 const int ndeltax = (-deltax>=dimx())?width-1:-deltax;
14812 if (!ndeltax) return *this;
14813 cimg_forYZV(*this,y,z,k) {
14814 cimg_std::memmove(ptr(ndeltax,y,z,k),ptr(0,y,z,k),(width-ndeltax)*sizeof(T));
14815 T *ptrd = ptr(0,y,z,k);
14816 const T val = *ptrd;
14817 for (int l = 0; l<ndeltax-1; ++l) *(++ptrd) = val;
14818 }
14819 }
14820 break;
14821 case 2 : {
14822 const int ml = cimg::mod(deltax,dimx()), ndeltax = (ml<=dimx()/2)?ml:(ml-dimx());
14823 if (!ndeltax) return *this;
14824 T* buf = new T[cimg::abs(ndeltax)];
14825 if (ndeltax>0) cimg_forYZV(*this,y,z,k) {
14826 cimg_std::memcpy(buf,ptr(0,y,z,k),ndeltax*sizeof(T));
14827 cimg_std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
14828 cimg_std::memcpy(ptr(width-ndeltax,y,z,k),buf,ndeltax*sizeof(T));
14829 } else cimg_forYZV(*this,y,z,k) {
14830 cimg_std::memcpy(buf,ptr(width+ndeltax,y,z,k),-ndeltax*sizeof(T));
14831 cimg_std::memmove(ptr(-ndeltax,y,z,k),ptr(0,y,z,k),(width+ndeltax)*sizeof(T));
14832 cimg_std::memcpy(ptr(0,y,z,k),buf,-ndeltax*sizeof(T));
14833 }
14834 delete[] buf;
14835 } break;
14836 }
14838 if (deltay) // Translate along Y-axis
14839 switch (border_condition) {
14840 case 0 :
14841 if (cimg::abs(deltay)>=dimy()) return fill(0);
14842 if (deltay>0) cimg_forZV(*this,z,k) {
14843 cimg_std::memmove(ptr(0,0,z,k),ptr(0,deltay,z,k),width*(height-deltay)*sizeof(T));
14844 cimg_std::memset(ptr(0,height-deltay,z,k),0,width*deltay*sizeof(T));
14845 } else cimg_forZV(*this,z,k) {
14846 cimg_std::memmove(ptr(0,-deltay,z,k),ptr(0,0,z,k),width*(height+deltay)*sizeof(T));
14847 cimg_std::memset(ptr(0,0,z,k),0,-deltay*width*sizeof(T));
14848 }
14849 break;
14850 case 1 :
14851 if (deltay>0) {
14852 const int ndeltay = (deltay>=dimy())?height-1:deltay;
14853 if (!ndeltay) return *this;
14854 cimg_forZV(*this,z,k) {
14855 cimg_std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
14856 T *ptrd = ptr(0,height-ndeltay,z,k), *ptrs = ptr(0,height-1,z,k);
14857 for (int l = 0; l<ndeltay-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
14858 }
14859 } else {
14860 const int ndeltay = (-deltay>=dimy())?height-1:-deltay;
14861 if (!ndeltay) return *this;
14862 cimg_forZV(*this,z,k) {
14863 cimg_std::memmove(ptr(0,ndeltay,z,k),ptr(0,0,z,k),width*(height-ndeltay)*sizeof(T));
14864 T *ptrd = ptr(0,1,z,k), *ptrs = ptr(0,0,z,k);
14865 for (int l = 0; l<ndeltay-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
14866 }
14867 }
14868 break;
14869 case 2 : {
14870 const int ml = cimg::mod(deltay,dimy()), ndeltay = (ml<=dimy()/2)?ml:(ml-dimy());
14871 if (!ndeltay) return *this;
14872 T* buf = new T[width*cimg::abs(ndeltay)];
14873 if (ndeltay>0) cimg_forZV(*this,z,k) {
14874 cimg_std::memcpy(buf,ptr(0,0,z,k),width*ndeltay*sizeof(T));
14875 cimg_std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
14876 cimg_std::memcpy(ptr(0,height-ndeltay,z,k),buf,width*ndeltay*sizeof(T));
14877 } else cimg_forZV(*this,z,k) {
14878 cimg_std::memcpy(buf,ptr(0,height+ndeltay,z,k),-ndeltay*width*sizeof(T));
14879 cimg_std::memmove(ptr(0,-ndeltay,z,k),ptr(0,0,z,k),width*(height+ndeltay)*sizeof(T));
14880 cimg_std::memcpy(ptr(0,0,z,k),buf,-ndeltay*width*sizeof(T));
14881 }
14882 delete[] buf;
14883 } break;
14884 }
14886 if (deltaz) // Translate along Z-axis
14887 switch (border_condition) {
14888 case 0 :
14889 if (cimg::abs(deltaz)>=dimz()) return fill(0);
14890 if (deltaz>0) cimg_forV(*this,k) {
14891 cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,deltaz,k),width*height*(depth-deltaz)*sizeof(T));
14892 cimg_std::memset(ptr(0,0,depth-deltaz,k),0,width*height*deltaz*sizeof(T));
14893 } else cimg_forV(*this,k) {
14894 cimg_std::memmove(ptr(0,0,-deltaz,k),ptr(0,0,0,k),width*height*(depth+deltaz)*sizeof(T));
14895 cimg_std::memset(ptr(0,0,0,k),0,-deltaz*width*height*sizeof(T));
14896 }
14897 break;
14898 case 1 :
14899 if (deltaz>0) {
14900 const int ndeltaz = (deltaz>=dimz())?depth-1:deltaz;
14901 if (!ndeltaz) return *this;
14902 cimg_forV(*this,k) {
14903 cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
14904 T *ptrd = ptr(0,0,depth-ndeltaz,k), *ptrs = ptr(0,0,depth-1,k);
14905 for (int l = 0; l<ndeltaz-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
14906 }
14907 } else {
14908 const int ndeltaz = (-deltaz>=dimz())?depth-1:-deltaz;
14909 if (!ndeltaz) return *this;
14910 cimg_forV(*this,k) {
14911 cimg_std::memmove(ptr(0,0,ndeltaz,k),ptr(0,0,0,k),width*height*(depth-ndeltaz)*sizeof(T));
14912 T *ptrd = ptr(0,0,1,k), *ptrs = ptr(0,0,0,k);
14913 for (int l = 0; l<ndeltaz-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
14914 }
14915 }
14916 break;
14917 case 2 : {
14918 const int ml = cimg::mod(deltaz,dimz()), ndeltaz = (ml<=dimz()/2)?ml:(ml-dimz());
14919 if (!ndeltaz) return *this;
14920 T* buf = new T[width*height*cimg::abs(ndeltaz)];
14921 if (ndeltaz>0) cimg_forV(*this,k) {
14922 cimg_std::memcpy(buf,ptr(0,0,0,k),width*height*ndeltaz*sizeof(T));
14923 cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
14924 cimg_std::memcpy(ptr(0,0,depth-ndeltaz,k),buf,width*height*ndeltaz*sizeof(T));
14925 } else cimg_forV(*this,k) {
14926 cimg_std::memcpy(buf,ptr(0,0,depth+ndeltaz,k),-ndeltaz*width*height*sizeof(T));
14927 cimg_std::memmove(ptr(0,0,-ndeltaz,k),ptr(0,0,0,k),width*height*(depth+ndeltaz)*sizeof(T));
14928 cimg_std::memcpy(ptr(0,0,0,k),buf,-ndeltaz*width*height*sizeof(T));
14929 }
14930 delete[] buf;
14931 } break;
14932 }
14934 if (deltav) // Translate along V-axis
14935 switch (border_condition) {
14936 case 0 :
14937 if (cimg::abs(deltav)>=dimv()) return fill(0);
14938 if (deltav>0) {
14939 cimg_std::memmove(data,ptr(0,0,0,deltav),width*height*depth*(dim-deltav)*sizeof(T));
14940 cimg_std::memset(ptr(0,0,0,dim-deltav),0,width*height*depth*deltav*sizeof(T));
14941 } else cimg_forV(*this,k) {
14942 cimg_std::memmove(ptr(0,0,0,-deltav),data,width*height*depth*(dim+deltav)*sizeof(T));
14943 cimg_std::memset(data,0,-deltav*width*height*depth*sizeof(T));
14944 }
14945 break;
14946 case 1 :
14947 if (deltav>0) {
14948 const int ndeltav = (deltav>=dimv())?dim-1:deltav;
14949 if (!ndeltav) return *this;
14950 cimg_std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
14951 T *ptrd = ptr(0,0,0,dim-ndeltav), *ptrs = ptr(0,0,0,dim-1);
14952 for (int l = 0; l<ndeltav-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
14953 } else {
14954 const int ndeltav = (-deltav>=dimv())?dim-1:-deltav;
14955 if (!ndeltav) return *this;
14956 cimg_std::memmove(ptr(0,0,0,ndeltav),data,width*height*depth*(dim-ndeltav)*sizeof(T));
14957 T *ptrd = ptr(0,0,0,1);
14958 for (int l = 0; l<ndeltav-1; ++l) { cimg_std::memcpy(ptrd,data,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
14959 }
14960 break;
14961 case 2 : {
14962 const int ml = cimg::mod(deltav,dimv()), ndeltav = (ml<=dimv()/2)?ml:(ml-dimv());
14963 if (!ndeltav) return *this;
14964 T* buf = new T[width*height*depth*cimg::abs(ndeltav)];
14965 if (ndeltav>0) {
14966 cimg_std::memcpy(buf,data,width*height*depth*ndeltav*sizeof(T));
14967 cimg_std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
14968 cimg_std::memcpy(ptr(0,0,0,dim-ndeltav),buf,width*height*depth*ndeltav*sizeof(T));
14969 } else {
14970 cimg_std::memcpy(buf,ptr(0,0,0,dim+ndeltav),-ndeltav*width*height*depth*sizeof(T));
14971 cimg_std::memmove(ptr(0,0,0,-ndeltav),data,width*height*depth*(dim+ndeltav)*sizeof(T));
14972 cimg_std::memcpy(data,buf,-ndeltav*width*height*depth*sizeof(T));
14973 }
14974 delete[] buf;
14975 } break;
14976 }
14977 return *this;
14978 }
14980 CImg<T> get_translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
14981 const int border_condition=0) const {
14982 return (+*this).translate(deltax,deltay,deltaz,deltav,border_condition);
14983 }
14985 //! Get a square region of the image.
14986 /**
14987 \param x0 = X-coordinate of the upper-left crop rectangle corner.
14988 \param y0 = Y-coordinate of the upper-left crop rectangle corner.
14989 \param z0 = Z-coordinate of the upper-left crop rectangle corner.
14990 \param v0 = V-coordinate of the upper-left crop rectangle corner.
14991 \param x1 = X-coordinate of the lower-right crop rectangle corner.
14992 \param y1 = Y-coordinate of the lower-right crop rectangle corner.
14993 \param z1 = Z-coordinate of the lower-right crop rectangle corner.
14994 \param v1 = V-coordinate of the lower-right crop rectangle corner.
14995 \param border_condition = Dirichlet (false) or Neumann border conditions.
14996 **/
14997 CImg<T>& crop(const int x0, const int y0, const int z0, const int v0,
14998 const int x1, const int y1, const int z1, const int v1,
14999 const bool border_condition=false) {
15000 return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).transfer_to(*this);
15001 }
15003 CImg<T> get_crop(const int x0, const int y0, const int z0, const int v0,
15004 const int x1, const int y1, const int z1, const int v1,
15005 const bool border_condition=false) const {
15006 if (is_empty()) return *this;
15007 const int
15008 nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
15009 ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0,
15010 nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0,
15011 nv0 = v0<v1?v0:v1, nv1 = v0^v1^nv0;
15012 CImg<T> dest(1U+nx1-nx0,1U+ny1-ny0,1U+nz1-nz0,1U+nv1-nv0);
15013 if (nx0<0 || nx1>=dimx() || ny0<0 || ny1>=dimy() || nz0<0 || nz1>=dimz() || nv0<0 || nv1>=dimv()) {
15014 if (border_condition) cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = _atXYZV(nx0+x,ny0+y,nz0+z,nv0+v);
15015 else dest.fill(0).draw_image(-nx0,-ny0,-nz0,-nv0,*this);
15016 } else dest.draw_image(-nx0,-ny0,-nz0,-nv0,*this);
15017 return dest;
15018 }
15020 //! Get a rectangular part of the instance image.
15021 /**
15022 \param x0 = X-coordinate of the upper-left crop rectangle corner.
15023 \param y0 = Y-coordinate of the upper-left crop rectangle corner.
15024 \param z0 = Z-coordinate of the upper-left crop rectangle corner.
15025 \param x1 = X-coordinate of the lower-right crop rectangle corner.
15026 \param y1 = Y-coordinate of the lower-right crop rectangle corner.
15027 \param z1 = Z-coordinate of the lower-right crop rectangle corner.
15028 \param border_condition = determine the type of border condition if
15029 some of the desired region is outside the image.
15030 **/
15031 CImg<T>& crop(const int x0, const int y0, const int z0,
15032 const int x1, const int y1, const int z1,
15033 const bool border_condition=false) {
15034 return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
15035 }
15037 CImg<T> get_crop(const int x0, const int y0, const int z0,
15038 const int x1, const int y1, const int z1,
15039 const bool border_condition=false) const {
15040 return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
15041 }
15043 //! Get a rectangular part of the instance image.
15044 /**
15045 \param x0 = X-coordinate of the upper-left crop rectangle corner.
15046 \param y0 = Y-coordinate of the upper-left crop rectangle corner.
15047 \param x1 = X-coordinate of the lower-right crop rectangle corner.
15048 \param y1 = Y-coordinate of the lower-right crop rectangle corner.
15049 \param border_condition = determine the type of border condition if
15050 some of the desired region is outside the image.
15051 **/
15052 CImg<T>& crop(const int x0, const int y0,
15053 const int x1, const int y1,
15054 const bool border_condition=false) {
15055 return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
15056 }
15058 CImg<T> get_crop(const int x0, const int y0,
15059 const int x1, const int y1,
15060 const bool border_condition=false) const {
15061 return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
15062 }
15064 //! Get a rectangular part of the instance image.
15065 /**
15066 \param x0 = X-coordinate of the upper-left crop rectangle corner.
15067 \param x1 = X-coordinate of the lower-right crop rectangle corner.
15068 \param border_condition = determine the type of border condition if
15069 some of the desired region is outside the image.
15070 **/
15071 CImg<T>& crop(const int x0, const int x1, const bool border_condition=false) {
15072 return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
15073 }
15075 CImg<T> get_crop(const int x0, const int x1, const bool border_condition=false) const {
15076 return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
15077 }
15079 //! Autocrop an image, regarding of the specified backround value.
15080 CImg<T>& autocrop(const T value, const char *const axes="vzyx") {
15081 if (is_empty()) return *this;
15082 const int lmax = cimg::strlen(axes);
15083 for (int l = 0; l<lmax; ++l) autocrop(value,axes[l]);
15084 return *this;
15085 }
15087 CImg<T> get_autocrop(const T value, const char *const axes="vzyx") const {
15088 return (+*this).autocrop(value,axes);
15089 }
15091 //! Autocrop an image, regarding of the specified backround color.
15092 CImg<T>& autocrop(const T *const color, const char *const axes="zyx") {
15093 if (is_empty()) return *this;
15094 const int lmax = cimg::strlen(axes);
15095 for (int l = 0; l<lmax; ++l) autocrop(color,axes[l]);
15096 return *this;
15097 }
15099 CImg<T> get_autocrop(const T *const color, const char *const axes="zyx") const {
15100 return (+*this).autocrop(color,axes);
15101 }
15103 //! Autocrop an image, regarding of the specified backround color.
15104 template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char *const axes="zyx") {
15105 return get_autocrop(color,axes).transfer_to(*this);
15106 }
15108 template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char *const axes="zyx") const {
15109 return get_autocrop(color.data,axes);
15110 }
15112 //! Autocrop an image along specified axis, regarding of the specified backround value.
15113 CImg<T>& autocrop(const T value, const char axis) {
15114 return get_autocrop(value,axis).transfer_to(*this);
15115 }
15117 CImg<T> get_autocrop(const T value, const char axis) const {
15118 if (is_empty()) return *this;
15119 CImg<T> res;
15120 const CImg<intT> coords = _get_autocrop(value,axis);
15121 switch (cimg::uncase(axis)) {
15122 case 'x' : {
15123 const int x0 = coords[0], x1 = coords[1];
15124 if (x0>=0 && x1>=0) res = get_crop(x0,x1);
15125 } break;
15126 case 'y' : {
15127 const int y0 = coords[0], y1 = coords[1];
15128 if (y0>=0 && y1>=0) res = get_crop(0,y0,width-1,y1);
15129 } break;
15130 case 'z' : {
15131 const int z0 = coords[0], z1 = coords[1];
15132 if (z0>=0 && z1>=0) res = get_crop(0,0,z0,width-1,height-1,z1);
15133 } break;
15134 case 'v' : {
15135 const int v0 = coords[0], v1 = coords[1];
15136 if (v0>=0 && v1>=0) res = get_crop(0,0,0,v0,width-1,height-1,depth-1,v1);
15137 } break;
15138 }
15139 return res;
15140 }
15142 //! Autocrop an image along specified axis, regarding of the specified backround color.
15143 CImg<T>& autocrop(const T *const color, const char axis) {
15144 return get_autocrop(color,axis).transfer_to(*this);
15145 }
15147 CImg<T> get_autocrop(const T *const color, const char axis) const {
15148 if (is_empty()) return *this;
15149 CImg<T> res;
15150 switch (cimg::uncase(axis)) {
15151 case 'x' : {
15152 int x0 = width, x1 = -1;
15153 cimg_forV(*this,k) {
15154 const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
15155 const int nx0 = coords[0], nx1 = coords[1];
15156 if (nx0>=0 && nx1>=0) { x0 = cimg::min(x0,nx0); x1 = cimg::max(x1,nx1); }
15157 }
15158 if (x0<=x1) res = get_crop(x0,x1);
15159 } break;
15160 case 'y' : {
15161 int y0 = height, y1 = -1;
15162 cimg_forV(*this,k) {
15163 const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
15164 const int ny0 = coords[0], ny1 = coords[1];
15165 if (ny0>=0 && ny1>=0) { y0 = cimg::min(y0,ny0); y1 = cimg::max(y1,ny1); }
15166 }
15167 if (y0<=y1) res = get_crop(0,y0,width-1,y1);
15168 } break;
15169 case 'z' : {
15170 int z0 = depth, z1 = -1;
15171 cimg_forV(*this,k) {
15172 const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
15173 const int nz0 = coords[0], nz1 = coords[1];
15174 if (nz0>=0 && nz1>=0) { z0 = cimg::min(z0,nz0); z1 = cimg::max(z1,nz1); }
15175 }
15176 if (z0<=z1) res = get_crop(0,0,z0,width-1,height-1,z1);
15177 } break;
15178 default :
15179 throw CImgArgumentException("CImg<%s>::autocrop() : Invalid axis '%c', must be 'x','y' or 'z'.",
15180 pixel_type(),axis);
15181 }
15182 return res;
15183 }
15185 //! Autocrop an image along specified axis, regarding of the specified backround color.
15186 template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char axis) {
15187 return get_autocrop(color,axis).transfer_to(*this);
15188 }
15190 template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char axis) const {
15191 return get_autocrop(color.data,axis);
15192 }
15194 CImg<intT> _get_autocrop(const T value, const char axis) const {
15195 CImg<intT> res;
15196 int x0 = -1, y0 = -1, z0 = -1, v0 = -1, x1 = -1, y1 = -1, z1 = -1, v1 = -1;
15197 switch (cimg::uncase(axis)) {
15198 case 'x' : {
15199 cimg_forX(*this,x) cimg_forYZV(*this,y,z,v)
15200 if ((*this)(x,y,z,v)!=value) { x0 = x; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
15201 if (x0>=0) {
15202 for (int x = dimx()-1; x>=0; --x) cimg_forYZV(*this,y,z,v)
15203 if ((*this)(x,y,z,v)!=value) { x1 = x; x = 0; y = dimy(); z = dimz(); v = dimv(); }
15204 }
15205 res = CImg<intT>::vector(x0,x1);
15206 } break;
15207 case 'y' : {
15208 cimg_forY(*this,y) cimg_forXZV(*this,x,z,v)
15209 if ((*this)(x,y,z,v)!=value) { y0 = y; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
15210 if (y0>=0) {
15211 for (int y = dimy()-1; y>=0; --y) cimg_forXZV(*this,x,z,v)
15212 if ((*this)(x,y,z,v)!=value) { y1 = y; x = dimx(); y = 0; z = dimz(); v = dimv(); }
15213 }
15214 res = CImg<intT>::vector(y0,y1);
15215 } break;
15216 case 'z' : {
15217 cimg_forZ(*this,z) cimg_forXYV(*this,x,y,v)
15218 if ((*this)(x,y,z,v)!=value) { z0 = z; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
15219 if (z0>=0) {
15220 for (int z = dimz()-1; z>=0; --z) cimg_forXYV(*this,x,y,v)
15221 if ((*this)(x,y,z,v)!=value) { z1 = z; x = dimx(); y = dimy(); z = 0; v = dimv(); }
15222 }
15223 res = CImg<intT>::vector(z0,z1);
15224 } break;
15225 case 'v' : {
15226 cimg_forV(*this,v) cimg_forXYZ(*this,x,y,z)
15227 if ((*this)(x,y,z,v)!=value) { v0 = v; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
15228 if (v0>=0) {
15229 for (int v = dimv()-1; v>=0; --v) cimg_forXYZ(*this,x,y,z)
15230 if ((*this)(x,y,z,v)!=value) { v1 = v; x = dimx(); y = dimy(); z = dimz(); v = 0; }
15231 }
15232 res = CImg<intT>::vector(v0,v1);
15233 } break;
15234 default :
15235 throw CImgArgumentException("CImg<%s>::autocrop() : unknow axis '%c', must be 'x','y','z' or 'v'",
15236 pixel_type(),axis);
15237 }
15238 return res;
15239 }
15241 //! Get a set of columns.
15242 CImg<T>& columns(const unsigned int x0, const unsigned int x1) {
15243 return get_columns(x0,x1).transfer_to(*this);
15244 }
15246 CImg<T> get_columns(const unsigned int x0, const unsigned int x1) const {
15247 return get_crop((int)x0,0,0,0,(int)x1,dimy()-1,dimz()-1,dimv()-1);
15248 }
15250 //! Get one column.
15251 CImg<T>& column(const unsigned int x0) {
15252 return columns(x0,x0);
15253 }
15255 CImg<T> get_column(const unsigned int x0) const {
15256 return get_columns(x0,x0);
15257 }
15259 //! Get a set of lines.
15260 CImg<T>& lines(const unsigned int y0, const unsigned int y1) {
15261 return get_lines(y0,y1).transfer_to(*this);
15262 }
15264 CImg<T> get_lines(const unsigned int y0, const unsigned int y1) const {
15265 return get_crop(0,(int)y0,0,0,dimx()-1,(int)y1,dimz()-1,dimv()-1);
15266 }
15268 //! Get a line.
15269 CImg<T>& line(const unsigned int y0) {
15270 return lines(y0,y0);
15271 }
15273 CImg<T> get_line(const unsigned int y0) const {
15274 return get_lines(y0,y0);
15275 }
15277 //! Get a set of slices.
15278 CImg<T>& slices(const unsigned int z0, const unsigned int z1) {
15279 return get_slices(z0,z1).transfer_to(*this);
15280 }
15282 CImg<T> get_slices(const unsigned int z0, const unsigned int z1) const {
15283 return get_crop(0,0,(int)z0,0,dimx()-1,dimy()-1,(int)z1,dimv()-1);
15284 }
15286 //! Get a slice.
15287 CImg<T>& slice(const unsigned int z0) {
15288 return slices(z0,z0);
15289 }
15291 CImg<T> get_slice(const unsigned int z0) const {
15292 return get_slices(z0,z0);
15293 }
15295 //! Get a set of channels.
15296 CImg<T>& channels(const unsigned int v0, const unsigned int v1) {
15297 return get_channels(v0,v1).transfer_to(*this);
15298 }
15300 CImg<T> get_channels(const unsigned int v0, const unsigned int v1) const {
15301 return get_crop(0,0,0,(int)v0,dimx()-1,dimy()-1,dimz()-1,(int)v1);
15302 }
15304 //! Get a channel.
15305 CImg<T>& channel(const unsigned int v0) {
15306 return channels(v0,v0);
15307 }
15309 CImg<T> get_channel(const unsigned int v0) const {
15310 return get_channels(v0,v0);
15311 }
15313 //! Get a shared-memory image referencing a set of points of the instance image.
15314 CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
15315 const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) {
15316 const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
15317 if (beg>end || beg>=size() || end>=size())
15318 throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
15319 "a (%u,%u,%u,%u) image.",
15320 pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
15321 return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
15322 }
15324 const CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
15325 const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const {
15326 const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
15327 if (beg>end || beg>=size() || end>=size())
15328 throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
15329 "a (%u,%u,%u,%u) image.",
15330 pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
15331 return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
15332 }
15334 //! Return a shared-memory image referencing a set of lines of the instance image.
15335 CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
15336 const unsigned int z0=0, const unsigned int v0=0) {
15337 const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
15338 if (beg>end || beg>=size() || end>=size())
15339 throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
15340 "a (%u,%u,%u,%u) image.",
15341 pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
15342 return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
15343 }
15345 const CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
15346 const unsigned int z0=0, const unsigned int v0=0) const {
15347 const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
15348 if (beg>end || beg>=size() || end>=size())
15349 throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
15350 "a (%u,%u,%u,%u) image.",
15351 pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
15352 return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
15353 }
15355 //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image.
15356 CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) {
15357 return get_shared_lines(y0,y0,z0,v0);
15358 }
15360 const CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) const {
15361 return get_shared_lines(y0,y0,z0,v0);
15362 }
15364 //! Return a shared memory image referencing a set of planes (z0->z1,v0) of the instance image.
15365 CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) {
15366 const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
15367 if (beg>end || beg>=size() || end>=size())
15368 throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
15369 "a (%u,%u,%u,%u) image.",
15370 pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
15371 return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
15372 }
15374 const CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const {
15375 const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
15376 if (beg>end || beg>=size() || end>=size())
15377 throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
15378 "a (%u,%u,%u,%u) image.",
15379 pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
15380 return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
15381 }
15383 //! Return a shared-memory image referencing one plane (z0,v0) of the instance image.
15384 CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) {
15385 return get_shared_planes(z0,z0,v0);
15386 }
15388 const CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) const {
15389 return get_shared_planes(z0,z0,v0);
15390 }
15392 //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image.
15393 CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) {
15394 const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
15395 if (beg>end || beg>=size() || end>=size())
15396 throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
15397 "a (%u,%u,%u,%u) image.",
15398 pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
15399 return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
15400 }
15402 const CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) const {
15403 const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
15404 if (beg>end || beg>=size() || end>=size())
15405 throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
15406 "a (%u,%u,%u,%u) image.",
15407 pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
15408 return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
15409 }
15411 //! Return a shared-memory image referencing one channel v0 of the instance image.
15412 CImg<T> get_shared_channel(const unsigned int v0) {
15413 return get_shared_channels(v0,v0);
15414 }
15416 const CImg<T> get_shared_channel(const unsigned int v0) const {
15417 return get_shared_channels(v0,v0);
15418 }
15420 //! Return a shared version of the instance image.
15421 CImg<T> get_shared() {
15422 return CImg<T>(data,width,height,depth,dim,true);
15423 }
15425 const CImg<T> get_shared() const {
15426 return CImg<T>(data,width,height,depth,dim,true);
15427 }
15429 //! Return a 2D representation of a 3D image, with three slices.
15430 CImg<T>& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
15431 const int dx=-100, const int dy=-100, const int dz=-100) {
15432 return get_projections2d(x0,y0,z0,dx,dy,dz).transfer_to(*this);
15433 }
15435 CImg<T> get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
15436 const int dx=-100, const int dy=-100, const int dz=-100) const {
15437 if (is_empty()) return *this;
15438 const unsigned int
15439 nx0 = (x0>=width)?width-1:x0,
15440 ny0 = (y0>=height)?height-1:y0,
15441 nz0 = (z0>=depth)?depth-1:z0;
15442 CImg<T>
15443 imgxy(width,height,1,dim),
15444 imgzy(depth,height,1,dim),
15445 imgxz(width,depth,1,dim);
15446 { cimg_forXYV(*this,x,y,k) imgxy(x,y,k) = (*this)(x,y,nz0,k); }
15447 { cimg_forYZV(*this,y,z,k) imgzy(z,y,k) = (*this)(nx0,y,z,k); }
15448 { cimg_forXZV(*this,x,z,k) imgxz(x,z,k) = (*this)(x,ny0,z,k); }
15449 imgxy.resize(dx,dy,1,dim,1);
15450 imgzy.resize(dz,dy,1,dim,1);
15451 imgxz.resize(dx,dz,1,dim,1);
15452 return CImg<T>(imgxy.width+imgzy.width,imgxy.height+imgxz.height,1,dim,0).
15453 draw_image(imgxy).draw_image(imgxy.width,imgzy).draw_image(0,imgxy.height,imgxz);
15454 }
15456 //! Compute the image histogram.
15457 /**
15458 The histogram H of an image I is a 1D-function where H(x) is the number of
15459 occurences of the value x in I.
15460 \param nblevels = Number of different levels of the computed histogram.
15461 For classical images, this value is 256. You should specify more levels
15462 if you are working with CImg<float> or images with high range of pixel values.
15463 \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
15464 won't be counted.
15465 \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
15466 won't be counted.
15467 \note If val_min==val_max==0 (default values), the function first estimates the minimum and maximum
15468 pixel values of the current image, then uses these values for the histogram computation.
15469 \result The histogram is returned as a 1D CImg<float> image H, having a size of (nblevels,1,1,1) such that
15470 H(0) and H(nblevels-1) are respectively equal to the number of occurences of the values val_min and val_max in I.
15471 \note Histogram computation always returns a 1D function. Histogram of multi-valued (such as color) images
15472 are not multi-dimensional.
15473 **/
15474 CImg<T>& histogram(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) {
15475 return get_histogram(nblevels,val_min,val_max).transfer_to(*this);
15476 }
15478 CImg<floatT> get_histogram(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const {
15479 if (is_empty()) return CImg<floatT>();
15480 if (!nblevels)
15481 throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with 0 levels",
15482 pixel_type());
15483 T vmin = val_min, vmax = val_max;
15484 CImg<floatT> res(nblevels,1,1,1,0);
15485 if (vmin>=vmax && vmin==0) vmin = minmax(vmax);
15486 if (vmin<vmax) cimg_for(*this,ptr,T) {
15487 const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin));
15488 if (pos>=0 && pos<(int)nblevels) ++res[pos];
15489 } else res[0]+=size();
15490 return res;
15491 }
15493 //! Compute the histogram-equalized version of the instance image.
15494 /**
15495 The histogram equalization is a classical image processing algorithm that enhances the image contrast
15496 by expanding its histogram.
15497 \param nblevels = Number of different levels of the computed histogram.
15498 For classical images, this value is 256. You should specify more levels
15499 if you are working with CImg<float> or images with high range of pixel values.
15500 \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
15501 won't be changed.
15502 \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
15503 won't be changed.
15504 \note If val_min==val_max==0 (default values), the function acts on all pixel values of the image.
15505 \return A new image with same size is returned, where pixels have been equalized.
15506 **/
15507 CImg<T>& equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) {
15508 if (is_empty()) return *this;
15509 T vmin = val_min, vmax = val_max;
15510 if (vmin==vmax && vmin==0) vmin = minmax(vmax);
15511 if (vmin<vmax) {
15512 CImg<floatT> hist = get_histogram(nblevels,vmin,vmax);
15513 float cumul = 0;
15514 cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos]=cumul; }
15515 cimg_for(*this,ptr,T) {
15516 const int pos = (unsigned int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin));
15517 if (pos>=0 && pos<(int)nblevels) *ptr = (T)(vmin + (vmax-vmin)*hist[pos]/size());
15518 }
15519 }
15520 return *this;
15521 }
15523 CImg<T> get_equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const {
15524 return (+*this).equalize(nblevels,val_min,val_max);
15525 }
15527 //! Get a label map of disconnected regions with same intensities.
15528 CImg<T>& label_regions() {
15529 return get_label_regions().transfer_to(*this);
15530 }
15532 CImg<uintT> get_label_regions() const {
15533 #define _cimg_get_label_test(p,q) { \
15534 flag = true; \
15535 const T *ptr1 = ptr(x,y) + siz, *ptr2 = ptr(p,q) + siz; \
15536 for (unsigned int i = dim; flag && i; --i) { ptr1-=wh; ptr2-=wh; flag = (*ptr1==*ptr2); } \
15537 }
15538 if (depth>1)
15539 throw CImgInstanceException("CImg<%s>::label_regions() : Instance image must be a 2D image");
15540 CImg<uintT> res(width,height,depth,1,0);
15541 unsigned int label = 1;
15542 const unsigned int wh = width*height, siz = width*height*dim;
15543 const int W1 = dimx()-1, H1 = dimy()-1;
15544 bool flag;
15545 cimg_forXY(*this,x,y) {
15546 bool done = false;
15547 if (y) {
15548 _cimg_get_label_test(x,y-1);
15549 if (flag) {
15550 const unsigned int lab = (res(x,y) = res(x,y-1));
15551 done = true;
15552 if (x && res(x-1,y)!=lab) {
15553 _cimg_get_label_test(x-1,y);
15554 if (flag) {
15555 const unsigned int lold = res(x-1,y), *const cptr = res.ptr(x,y);
15556 for (unsigned int *ptr = res.ptr(); ptr<cptr; ++ptr) if (*ptr==lold) *ptr = lab;
15557 }
15558 }
15559 }
15560 }
15561 if (x && !done) { _cimg_get_label_test(x-1,y); if (flag) { res(x,y) = res(x-1,y); done = true; }}
15562 if (!done) res(x,y) = label++;
15563 }
15564 { for (int y = H1; y>=0; --y) for (int x=W1; x>=0; --x) {
15565 bool done = false;
15566 if (y<H1) {
15567 _cimg_get_label_test(x,y+1);
15568 if (flag) {
15569 const unsigned int lab = (res(x,y) = res(x,y+1));
15570 done = true;
15571 if (x<W1 && res(x+1,y)!=lab) {
15572 _cimg_get_label_test(x+1,y);
15573 if (flag) {
15574 const unsigned int lold = res(x+1,y), *const cptr = res.ptr(x,y);
15575 for (unsigned int *ptr = res.ptr()+res.size()-1; ptr>cptr; --ptr) if (*ptr==lold) *ptr = lab;
15576 }
15577 }
15578 }
15579 }
15580 if (x<W1 && !done) { _cimg_get_label_test(x+1,y); if (flag) res(x,y) = res(x+1,y); done = true; }
15581 }}
15582 const unsigned int lab0 = res.max()+1;
15583 label = lab0;
15584 cimg_foroff(res,off) { // Relabel regions
15585 const unsigned int lab = res[off];
15586 if (lab<lab0) { cimg_for(res,ptr,unsigned int) if (*ptr==lab) *ptr = label; ++label; }
15587 }
15588 return (res-=lab0);
15589 }
15591 //! Compute the scalar image of vector norms.
15592 /**
15593 When dealing with vector-valued images (i.e images with dimv()>1), this function computes the L1,L2 or Linf norm of each
15594 vector-valued pixel.
15595 \param norm_type = Type of the norm being computed (1 = L1, 2 = L2, -1 = Linf).
15596 \return A scalar-valued image CImg<float> with size (dimx(),dimy(),dimz(),1), where each pixel is the norm
15597 of the corresponding pixels in the original vector-valued image.
15598 **/
15599 CImg<T>& pointwise_norm(int norm_type=2) {
15600 return get_pointwise_norm(norm_type).transfer_to(*this);
15601 }
15603 CImg<Tfloat> get_pointwise_norm(int norm_type=2) const {
15604 if (is_empty()) return *this;
15605 if (dim==1) return get_abs();
15606 CImg<Tfloat> res(width,height,depth);
15607 switch (norm_type) {
15608 case -1 : { // Linf norm
15609 cimg_forXYZ(*this,x,y,z) {
15610 Tfloat n = 0; cimg_forV(*this,v) {
15611 const Tfloat tmp = (Tfloat)cimg::abs((*this)(x,y,z,v));
15612 if (tmp>n) n=tmp; res(x,y,z) = n;
15613 }
15614 }
15615 } break;
15616 case 1 : { // L1 norm
15617 cimg_forXYZ(*this,x,y,z) {
15618 Tfloat n = 0; cimg_forV(*this,v) n+=cimg::abs((*this)(x,y,z,v)); res(x,y,z) = n;
15619 }
15620 } break;
15621 default : { // L2 norm
15622 cimg_forXYZ(*this,x,y,z) {
15623 Tfloat n = 0; cimg_forV(*this,v) n+=(*this)(x,y,z,v)*(*this)(x,y,z,v); res(x,y,z) = (Tfloat)cimg_std::sqrt((double)n);
15624 }
15625 }
15626 }
15627 return res;
15628 }
15630 //! Compute the image of normalized vectors.
15631 /**
15632 When dealing with vector-valued images (i.e images with dimv()>1), this function return the image of normalized vectors
15633 (unit vectors). Null vectors are unchanged. The L2-norm is computed for the normalization.
15634 \return A new vector-valued image with same size, where each vector-valued pixels have been normalized.
15635 **/
15636 CImg<T>& pointwise_orientation() {
15637 cimg_forXYZ(*this,x,y,z) {
15638 float n = 0;
15639 cimg_forV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v));
15640 n = (float)cimg_std::sqrt(n);
15641 if (n>0) cimg_forV(*this,v) (*this)(x,y,z,v) = (T)((*this)(x,y,z,v)/n);
15642 else cimg_forV(*this,v) (*this)(x,y,z,v) = 0;
15643 }
15644 return *this;
15645 }
15647 CImg<Tfloat> get_pointwise_orientation() const {
15648 if (is_empty()) return *this;
15649 return CImg<Tfloat>(*this,false).pointwise_orientation();
15650 }
15652 //! Split image into a list.
15653 CImgList<T> get_split(const char axis, const unsigned int nb=0) const {
15654 if (is_empty()) return CImgList<T>();
15655 CImgList<T> res;
15656 switch (cimg::uncase(axis)) {
15657 case 'x' : {
15658 if (nb>width)
15659 throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'x' into %u images.",
15660 pixel_type(),width,height,depth,dim,data,nb);
15661 res.assign(nb?nb:width);
15662 const unsigned int delta = (unsigned int)cimg::round((float)width/res.size,1);
15663 unsigned int l, x;
15664 for (l = 0, x = 0; l<res.size-1; ++l, x+=delta) res[l] = get_crop(x,0,0,0,x+delta-1,height-1,depth-1,dim-1);
15665 res[res.size-1] = get_crop(x,0,0,0,width-1,height-1,depth-1,dim-1);
15666 } break;
15667 case 'y' : {
15668 if (nb>height)
15669 throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'y' into %u images.",
15670 pixel_type(),width,height,depth,dim,data,nb);
15671 res.assign(nb?nb:height);
15672 const unsigned int delta = (unsigned int)cimg::round((float)height/res.size,1);
15673 unsigned int l, y;
15674 for (l = 0, y = 0; l<res.size-1; ++l, y+=delta) res[l] = get_crop(0,y,0,0,width-1,y+delta-1,depth-1,dim-1);
15675 res[res.size-1] = get_crop(0,y,0,0,width-1,height-1,depth-1,dim-1);
15676 } break;
15677 case 'z' : {
15678 if (nb>depth)
15679 throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'z' into %u images.",
15680 pixel_type(),width,height,depth,dim,data,nb);
15681 res.assign(nb?nb:depth);
15682 const unsigned int delta = (unsigned int)cimg::round((float)depth/res.size,1);
15683 unsigned int l, z;
15684 for (l = 0, z = 0; l<res.size-1; ++l, z+=delta) res[l] = get_crop(0,0,z,0,width-1,height-1,z+delta-1,dim-1);
15685 res[res.size-1] = get_crop(0,0,z,0,width-1,height-1,depth-1,dim-1);
15686 } break;
15687 case 'v' : {
15688 if (nb>dim)
15689 throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'v' into %u images.",
15690 pixel_type(),width,height,depth,dim,data,nb);
15691 res.assign(nb?nb:dim);
15692 const unsigned int delta = (unsigned int)cimg::round((float)dim/res.size,1);
15693 unsigned int l, v;
15694 for (l = 0, v = 0; l<res.size-1; ++l, v+=delta) res[l] = get_crop(0,0,0,v,width-1,height-1,depth-1,v+delta-1);
15695 res[res.size-1] = get_crop(0,0,0,v,width-1,height-1,depth-1,dim-1);
15696 } break;
15697 default :
15698 throw CImgArgumentException("CImg<%s>::get_split() : Unknow axis '%c', must be 'x','y','z' or 'v'",
15699 pixel_type(),axis);
15700 }
15701 return res;
15702 }
15704 // Split image into a list of vectors, according to a given splitting value.
15705 CImgList<T> get_split(const T value, const bool keep_values, const bool shared) const {
15706 CImgList<T> res;
15707 const T *ptr0 = data, *const ptr_end = data + size();
15708 while (ptr0<ptr_end) {
15709 const T *ptr1 = ptr0;
15710 while (ptr1<ptr_end && *ptr1==value) ++ptr1;
15711 const unsigned int siz0 = ptr1 - ptr0;
15712 if (siz0 && keep_values) res.insert(CImg<T>(ptr0,1,siz0,1,1,shared));
15713 ptr0 = ptr1;
15714 while (ptr1<ptr_end && *ptr1!=value) ++ptr1;
15715 const unsigned int siz1 = ptr1 - ptr0;
15716 if (siz1) res.insert(CImg<T>(ptr0,1,siz1,1,1,shared),~0U,shared);
15717 ptr0 = ptr1;
15718 }
15719 return res;
15720 }
15722 //! Append an image to another one.
15723 CImg<T>& append(const CImg<T>& img, const char axis, const char align='p') {
15724 if (!img) return *this;
15725 if (is_empty()) return (*this=img);
15726 return get_append(img,axis,align).transfer_to(*this);
15727 }
15729 CImg<T> get_append(const CImg<T>& img, const char axis, const char align='p') const {
15730 if (!img) return *this;
15731 if (is_empty()) return img;
15732 CImgList<T> temp(2);
15733 temp[0].width = width; temp[0].height = height; temp[0].depth = depth;
15734 temp[0].dim = dim; temp[0].data = data;
15735 temp[1].width = img.width; temp[1].height = img.height; temp[1].depth = img.depth;
15736 temp[1].dim = img.dim; temp[1].data = img.data;
15737 const CImg<T> res = temp.get_append(axis,align);
15738 temp[0].width = temp[0].height = temp[0].depth = temp[0].dim = 0; temp[0].data = 0;
15739 temp[1].width = temp[1].height = temp[1].depth = temp[1].dim = 0; temp[1].data = 0;
15740 return res;
15741 }
15743 //! Compute the list of images, corresponding to the XY-gradients of an image.
15744 /**
15745 \param scheme = Numerical scheme used for the gradient computation :
15746 - -1 = Backward finite differences
15747 - 0 = Centered finite differences
15748 - 1 = Forward finite differences
15749 - 2 = Using Sobel masks
15750 - 3 = Using rotation invariant masks
15751 - 4 = Using Deriche recusrsive filter.
15752 **/
15753 CImgList<Tfloat> get_gradient(const char *const axes=0, const int scheme=3) const {
15754 CImgList<Tfloat> grad(2,width,height,depth,dim);
15755 bool threed = false;
15756 if (axes) {
15757 for (unsigned int a = 0; axes[a]; ++a) {
15758 const char axis = cimg::uncase(axes[a]);
15759 switch (axis) {
15760 case 'x' : case 'y' : break;
15761 case 'z' : threed = true; break;
15762 default :
15763 throw CImgArgumentException("CImg<%s>::get_gradient() : Unknown specified axis '%c'.",
15764 pixel_type(),axis);
15765 }
15766 }
15767 } else threed = (depth>1);
15768 if (threed) {
15769 grad.insert(1); grad[2].assign(width,height,depth,dim);
15770 switch (scheme) { // Compute 3D gradient
15771 case -1 : { // backward finite differences
15772 CImg_3x3x3(I,T);
15773 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
15774 grad[0](x,y,z,k) = (Tfloat)Iccc - Ipcc;
15775 grad[1](x,y,z,k) = (Tfloat)Iccc - Icpc;
15776 grad[2](x,y,z,k) = (Tfloat)Iccc - Iccp;
15777 }
15778 } break;
15779 case 1 : { // forward finite differences
15780 CImg_2x2x2(I,T);
15781 cimg_forV(*this,k) cimg_for2x2x2(*this,x,y,z,k,I) {
15782 grad[0](x,y,z,k) = (Tfloat)Incc - Iccc;
15783 grad[1](x,y,z,k) = (Tfloat)Icnc - Iccc;
15784 grad[2](x,y,z,k) = (Tfloat)Iccn - Iccc;
15785 }
15786 } break;
15787 case 4 : { // using Deriche filter with low standard variation
15788 grad[0] = get_deriche(0,1,'x');
15789 grad[1] = get_deriche(0,1,'y');
15790 grad[2] = get_deriche(0,1,'z');
15791 } break;
15792 default : { // central finite differences
15793 CImg_3x3x3(I,T);
15794 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
15795 grad[0](x,y,z,k) = 0.5f*((Tfloat)Incc - Ipcc);
15796 grad[1](x,y,z,k) = 0.5f*((Tfloat)Icnc - Icpc);
15797 grad[2](x,y,z,k) = 0.5f*((Tfloat)Iccn - Iccp);
15798 }
15799 }
15800 }
15801 } else switch (scheme) { // Compute 2D-gradient
15802 case -1 : { // backward finite differences
15803 CImg_3x3(I,T);
15804 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
15805 grad[0](x,y,z,k) = (Tfloat)Icc - Ipc;
15806 grad[1](x,y,z,k) = (Tfloat)Icc - Icp;
15807 }
15808 } break;
15809 case 1 : { // forward finite differences
15810 CImg_2x2(I,T);
15811 cimg_forZV(*this,z,k) cimg_for2x2(*this,x,y,z,k,I) {
15812 grad[0](x,y,0,k) = (Tfloat)Inc - Icc;
15813 grad[1](x,y,z,k) = (Tfloat)Icn - Icc;
15814 }
15815 } break;
15816 case 2 : { // using Sobel mask
15817 CImg_3x3(I,T);
15818 const Tfloat a = 1, b = 2;
15819 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
15820 grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
15821 grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
15822 }
15823 } break;
15824 case 3 : { // using rotation invariant mask
15825 CImg_3x3(I,T);
15826 const Tfloat a = (Tfloat)(0.25f*(2-cimg_std::sqrt(2.0f))), b = (Tfloat)(0.5f*(cimg_std::sqrt(2.0f)-1));
15827 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
15828 grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
15829 grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
15830 }
15831 } break;
15832 case 4 : { // using Deriche filter with low standard variation
15833 grad[0] = get_deriche(0,1,'x');
15834 grad[1] = get_deriche(0,1,'y');
15835 } break;
15836 default : { // central finite differences
15837 CImg_3x3(I,T);
15838 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
15839 grad[0](x,y,z,k) = 0.5f*((Tfloat)Inc - Ipc);
15840 grad[1](x,y,z,k) = 0.5f*((Tfloat)Icn - Icp);
15841 }
15842 }
15843 }
15844 if (!axes) return grad;
15845 CImgList<Tfloat> res;
15846 for (unsigned int l = 0; axes[l]; ++l) {
15847 const char axis = cimg::uncase(axes[l]);
15848 switch (axis) {
15849 case 'x' : res.insert(grad[0]); break;
15850 case 'y' : res.insert(grad[1]); break;
15851 case 'z' : res.insert(grad[2]); break;
15852 }
15853 }
15854 grad.assign();
15855 return res;
15856 }
15858 //! Compute the structure tensor field of an image.
15859 CImg<T>& structure_tensor(const bool central_scheme=false) {
15860 return get_structure_tensor(central_scheme).transfer_to(*this);
15861 }
15863 CImg<Tfloat> get_structure_tensor(const bool central_scheme=false) const {
15864 if (is_empty()) return *this;
15865 CImg<Tfloat> res;
15866 if (depth>1) { // 3D version
15867 res.assign(width,height,depth,6,0);
15868 CImg_3x3x3(I,T);
15869 if (central_scheme) cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { // classical central finite differences
15870 const Tfloat
15871 ix = 0.5f*((Tfloat)Incc - Ipcc),
15872 iy = 0.5f*((Tfloat)Icnc - Icpc),
15873 iz = 0.5f*((Tfloat)Iccn - Iccp);
15874 res(x,y,z,0)+=ix*ix;
15875 res(x,y,z,1)+=ix*iy;
15876 res(x,y,z,2)+=ix*iz;
15877 res(x,y,z,3)+=iy*iy;
15878 res(x,y,z,4)+=iy*iz;
15879 res(x,y,z,5)+=iz*iz;
15880 } else cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { // Precise forward/backward finite differences
15881 const Tfloat
15882 ixf = (Tfloat)Incc - Iccc, ixb = (Tfloat)Iccc - Ipcc,
15883 iyf = (Tfloat)Icnc - Iccc, iyb = (Tfloat)Iccc - Icpc,
15884 izf = (Tfloat)Iccn - Iccc, izb = (Tfloat)Iccc - Iccp;
15885 res(x,y,z,0) += 0.5f*(ixf*ixf + ixb*ixb);
15886 res(x,y,z,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb);
15887 res(x,y,z,2) += 0.25f*(ixf*izf + ixf*izb + ixb*izf + ixb*izb);
15888 res(x,y,z,3) += 0.5f*(iyf*iyf + iyb*iyb);
15889 res(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb);
15890 res(x,y,z,5) += 0.5f*(izf*izf + izb*izb);
15891 }
15892 } else { // 2D version
15893 res.assign(width,height,depth,3,0);
15894 CImg_3x3(I,T);
15895 if (central_scheme) cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { // classical central finite differences
15896 const Tfloat
15897 ix = 0.5f*((Tfloat)Inc - Ipc),
15898 iy = 0.5f*((Tfloat)Icn - Icp);
15899 res(x,y,0,0)+=ix*ix;
15900 res(x,y,0,1)+=ix*iy;
15901 res(x,y,0,2)+=iy*iy;
15902 } else cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { // Precise forward/backward finite differences
15903 const Tfloat
15904 ixf = (Tfloat)Inc - Icc, ixb = (Tfloat)Icc - Ipc,
15905 iyf = (Tfloat)Icn - Icc, iyb = (Tfloat)Icc - Icp;
15906 res(x,y,0,0) += 0.5f*(ixf*ixf+ixb*ixb);
15907 res(x,y,0,1) += 0.25f*(ixf*iyf+ixf*iyb+ixb*iyf+ixb*iyb);
15908 res(x,y,0,2) += 0.5f*(iyf*iyf+iyb*iyb);
15909 }
15910 }
15911 return res;
15912 }
15914 //! Get components of the Hessian matrix of an image.
15915 CImgList<Tfloat> get_hessian(const char *const axes=0) const {
15916 const char *naxes = axes, *const def_axes2d = "xxxyyy", *const def_axes3d = "xxxyxzyyyzzz";
15917 if (!axes) naxes = depth>1?def_axes3d:def_axes2d;
15918 CImgList<Tfloat> res;
15919 const int lmax = cimg::strlen(naxes);
15920 if (lmax%2)
15921 throw CImgArgumentException("CImg<%s>::get_hessian() : Incomplete parameter axes = '%s'.",
15922 pixel_type(),naxes);
15923 res.assign(lmax/2,width,height,depth,dim);
15924 if (!cimg::strcasecmp(naxes,def_axes3d)) { // Default 3D version
15925 CImg_3x3x3(I,T);
15926 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
15927 res[0](x,y,z,k) = (Tfloat)Ipcc + Incc - 2*Iccc; // Ixx
15928 res[1](x,y,z,k) = 0.25f*((Tfloat)Ippc + Innc - Ipnc - Inpc); // Ixy
15929 res[2](x,y,z,k) = 0.25f*((Tfloat)Ipcp + Incn - Ipcn - Incp); // Ixz
15930 res[3](x,y,z,k) = (Tfloat)Icpc + Icnc - 2*Iccc; // Iyy
15931 res[4](x,y,z,k) = 0.25f*((Tfloat)Icpp + Icnn - Icpn - Icnp); // Iyz
15932 res[5](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc; // Izz
15933 }
15934 } else if (!cimg::strcasecmp(naxes,def_axes2d)) { // Default 2D version
15935 CImg_3x3(I,T);
15936 cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
15937 res[0](x,y,0,k) = (Tfloat)Ipc + Inc - 2*Icc; // Ixx
15938 res[1](x,y,0,k) = 0.25f*((Tfloat)Ipp + Inn - Ipn - Inp); // Ixy
15939 res[2](x,y,0,k) = (Tfloat)Icp + Icn - 2*Icc; // Iyy
15940 }
15941 } else for (int l = 0; l<lmax; ) { // Version with custom axes.
15942 const int l2 = l/2;
15943 char axis1 = naxes[l++], axis2 = naxes[l++];
15944 if (axis1>axis2) cimg::swap(axis1,axis2);
15945 bool valid_axis = false;
15946 if (axis1=='x' && axis2=='x') { // Ixx
15947 valid_axis = true; CImg_3x3(I,T);
15948 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Ipc + Inc - 2*Icc;
15949 }
15950 else if (axis1=='x' && axis2=='y') { // Ixy
15951 valid_axis = true; CImg_3x3(I,T);
15952 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = 0.25f*((Tfloat)Ipp + Inn - Ipn - Inp);
15953 }
15954 else if (axis1=='x' && axis2=='z') { // Ixz
15955 valid_axis = true; CImg_3x3x3(I,T);
15956 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = 0.25f*((Tfloat)Ipcp + Incn - Ipcn - Incp);
15957 }
15958 else if (axis1=='y' && axis2=='y') { // Iyy
15959 valid_axis = true; CImg_3x3(I,T);
15960 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Icp + Icn - 2*Icc;
15961 }
15962 else if (axis1=='y' && axis2=='z') { // Iyz
15963 valid_axis = true; CImg_3x3x3(I,T);
15964 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = 0.25f*((Tfloat)Icpp + Icnn - Icpn - Icnp);
15965 }
15966 else if (axis1=='z' && axis2=='z') { // Izz
15967 valid_axis = true; CImg_3x3x3(I,T);
15968 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc;
15969 }
15970 else if (!valid_axis) throw CImgArgumentException("CImg<%s>::get_hessian() : Invalid parameter axes = '%s'.",
15971 pixel_type(),naxes);
15972 }
15973 return res;
15974 }
15976 //! Compute distance function from 0-valued isophotes by the application of an Hamilton-Jacobi PDE.
15977 CImg<T>& distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) {
15978 if (is_empty()) return *this;
15979 CImg<Tfloat> veloc(*this);
15980 for (unsigned int iter = 0; iter<nb_iter; ++iter) {
15981 veloc.fill(0);
15982 if (depth>1) { // 3D version
15983 CImg_3x3x3(I,T);
15984 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) if (band_size<=0 || cimg::abs(Iccc)<band_size) {
15985 const Tfloat
15986 gx = 0.5f*((Tfloat)Incc - Ipcc),
15987 gy = 0.5f*((Tfloat)Icnc - Icpc),
15988 gz = 0.5f*((Tfloat)Iccn - Iccp),
15989 sgn = -cimg::sign((Tfloat)Iccc),
15990 ix = gx*sgn>0?(Tfloat)Incc - Iccc:(Tfloat)Iccc - Ipcc,
15991 iy = gy*sgn>0?(Tfloat)Icnc - Iccc:(Tfloat)Iccc - Icpc,
15992 iz = gz*sgn>0?(Tfloat)Iccn - Iccc:(Tfloat)Iccc - Iccp,
15993 ng = 1e-5f + (Tfloat)cimg_std::sqrt(gx*gx + gy*gy + gz*gz),
15994 ngx = gx/ng,
15995 ngy = gy/ng,
15996 ngz = gz/ng;
15997 veloc(x,y,z,k) = sgn*(ngx*ix + ngy*iy + ngz*iz - 1);
15998 }
15999 } else { // 2D version
16000 CImg_3x3(I,T);
16001 cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) if (band_size<=0 || cimg::abs(Icc)<band_size) {
16002 const Tfloat
16003 gx = 0.5f*((Tfloat)Inc - Ipc),
16004 gy = 0.5f*((Tfloat)Icn - Icp),
16005 sgn = -cimg::sign((Tfloat)Icc),
16006 ix = gx*sgn>0?(Tfloat)Inc - Icc:(Tfloat)Icc - Ipc,
16007 iy = gy*sgn>0?(Tfloat)Icn - Icc:(Tfloat)Icc - Icp,
16008 ng = 1e-5f + (Tfloat)cimg_std::sqrt(gx*gx + gy*gy),
16009 ngx = gx/ng,
16010 ngy = gy/ng;
16011 veloc(x,y,k) = sgn*(ngx*ix + ngy*iy - 1);
16012 }
16013 }
16014 float m, M = (float)veloc.maxmin(m), xdt = precision/(float)cimg::max(cimg::abs(m),cimg::abs(M));
16015 *this+=(veloc*=xdt);
16016 }
16017 return *this;
16018 }
16020 CImg<Tfloat> get_distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) const {
16021 return CImg<Tfloat>(*this,false).distance_hamilton(nb_iter,band_size,precision);
16022 }
16024 //! Compute the Euclidean distance map to a shape of specified isovalue.
16025 CImg<T>& distance(const T isovalue,
16026 const float sizex=1, const float sizey=1, const float sizez=1,
16027 const bool compute_sqrt=true) {
16028 return get_distance(isovalue,sizex,sizey,sizez,compute_sqrt).transfer_to(*this);
16029 }
16031 CImg<floatT> get_distance(const T isovalue,
16032 const float sizex=1, const float sizey=1, const float sizez=1,
16033 const bool compute_sqrt=true) const {
16034 if (is_empty()) return *this;
16035 const int dx = dimx(), dy = dimy(), dz = dimz();
16036 CImg<floatT> res(dx,dy,dz,dim);
16037 const float maxdist = (float)cimg_std::sqrt((float)dx*dx + dy*dy + dz*dz);
16038 cimg_forV(*this,k) {
16039 bool is_isophote = false;
16041 if (depth>1) { // 3D version
16042 { cimg_forYZ(*this,y,z) {
16043 if ((*this)(0,y,z,k)==isovalue) { is_isophote = true; res(0,y,z,k) = 0; } else res(0,y,z,k) = maxdist;
16044 for (int x = 1; x<dx; ++x) if ((*this)(x,y,z,k)==isovalue) { is_isophote = true; res(x,y,z,k) = 0; }
16045 else res(x,y,z,k) = res(x-1,y,z,k) + sizex;
16046 { for (int x = dx-2; x>=0; --x) if (res(x+1,y,z,k)<res(x,y,z,k)) res(x,y,z,k) = res(x+1,y,z,k) + sizex; }
16047 }}
16048 if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<float>::max()); continue; }
16049 CImg<floatT> tmp(cimg::max(dy,dz));
16050 CImg<intT> s(tmp.width), t(s.width);
16051 { cimg_forXZ(*this,x,z) {
16052 { cimg_forY(*this,y) tmp[y] = res(x,y,z,k); }
16053 int q = s[0] = t[0] = 0;
16054 { for (int y = 1; y<dy; ++y) {
16055 const float val = tmp[y], val2 = val*val;
16056 while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizey)>_distance_f(t[q],y,val2,sizey)) --q;
16057 if (q<0) { q = 0; s[0] = y; }
16058 else {
16059 const int w = 1 + _distance_sep(s[q],y,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizey);
16060 if (w<dy) { s[++q] = y; t[q] = w; }
16061 }
16062 }}
16063 { for (int y = dy - 1; y>=0; --y) {
16064 res(x,y,z,k) = _distance_f(y,s[q],cimg::sqr(tmp[s[q]]),sizey);
16065 if (y==t[q]) --q;
16066 }}
16067 }}
16068 { cimg_forXY(*this,x,y) {
16069 { cimg_forZ(*this,z) tmp[z] = res(x,y,z,k); }
16070 int q = s[0] = t[0] = 0;
16071 { for (int z = 1; z<dz; ++z) {
16072 const float val = tmp[z];
16073 while (q>=0 && _distance_f(t(q),s[q],tmp[s[q]],sizez)>_distance_f(t[q],z,tmp[z],sizez)) --q;
16074 if (q<0) { q = 0; s[0] = z; }
16075 else {
16076 const int w = 1 + _distance_sep(s[q],z,(int)tmp[s[q]],(int)val,sizez);
16077 if (w<dz) { s[++q] = z; t[q] = w; }
16078 }
16079 }}
16080 { for (int z = dz - 1; z>=0; --z) {
16081 const float val = _distance_f(z,s[q],tmp[s[q]],sizez);
16082 res(x,y,z,k) = compute_sqrt?(float)cimg_std::sqrt(val):val;
16083 if (z==t[q]) --q;
16084 }}
16085 }}
16086 } else { // 2D version (with small optimizations)
16087 cimg_forX(*this,x) {
16088 const T *ptrs = ptr(x,0,0,k);
16089 float *ptrd = res.ptr(x,0,0,k), d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:maxdist;
16090 for (int y = 1; y<dy; ++y) { ptrs+=width; ptrd+=width; d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:d+sizey; }
16091 { for (int y = dy - 2; y>=0; --y) { ptrd-=width; if (d<*ptrd) *ptrd = (d+=sizey); else d = *ptrd; }}
16092 }
16093 if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<float>::max()); continue; }
16094 CImg<floatT> tmp(dx);
16095 CImg<intT> s(dx), t(dx);
16096 cimg_forY(*this,y) {
16097 float *ptmp = tmp.ptr();
16098 cimg_std::memcpy(ptmp,res.ptr(0,y,0,k),sizeof(float)*dx);
16099 int q = s[0] = t[0] = 0;
16100 for (int x = 1; x<dx; ++x) {
16101 const float val = *(++ptmp), val2 = val*val;
16102 while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizex)>_distance_f(t[q],x,val2,sizex)) --q;
16103 if (q<0) { q = 0; s[0] = x; }
16104 else {
16105 const int w = 1 + _distance_sep(s[q],x,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizex);
16106 if (w<dx) { q++; s[q] = x; t[q] = w; }
16107 }
16108 }
16109 float *pres = res.ptr(0,y,0,k) + width;
16110 { for (int x = dx - 1; x>=0; --x) {
16111 const float val = _distance_f(x,s[q],cimg::sqr(tmp[s[q]]),sizex);
16112 *(--pres) = compute_sqrt?(float)cimg_std::sqrt(val):val;
16113 if (x==t[q]) --q;
16114 }}
16115 }
16116 }
16117 }
16118 return res;
16119 }
16121 static float _distance_f(const int x, const int i, const float gi2, const float fact) {
16122 const float xmi = fact*((float)x - i);
16123 return xmi*xmi + gi2;
16124 }
16125 static int _distance_sep(const int i, const int u, const int gi2, const int gu2, const float fact) {
16126 const float fact2 = fact*fact;
16127 return (int)(fact2*(u*u - i*i) + gu2 - gi2)/(int)(2*fact2*(u - i));
16128 }
16130 //! Compute minimal path in a graph, using the Dijkstra algorithm.
16131 /**
16132 \param distance An object having operator()(unsigned int i, unsigned int j) which returns distance between two nodes (i,j).
16133 \param nb_nodes Number of graph nodes.
16134 \param starting_node Indice of the starting node.
16135 \param ending_node Indice of the ending node (set to ~0U to ignore ending node).
16136 \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
16137 \return Array of distances of each node to the starting node.
16138 **/
16139 template<typename tf, typename t>
16140 static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
16141 const unsigned int starting_node, const unsigned int ending_node,
16142 CImg<t>& previous) {
16144 CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max());
16145 dist(starting_node) = 0;
16146 previous.assign(1,nb_nodes,1,1,(t)-1);
16147 previous(starting_node) = (t)starting_node;
16148 CImg<uintT> Q(nb_nodes);
16149 cimg_forX(Q,u) Q(u) = u;
16150 cimg::swap(Q(starting_node),Q(0));
16151 unsigned int sizeQ = nb_nodes;
16152 while (sizeQ) {
16153 // Update neighbors from minimal vertex
16154 const unsigned int umin = Q(0);
16155 if (umin==ending_node) sizeQ = 0;
16156 else {
16157 const T dmin = dist(umin);
16158 const T infty = cimg::type<T>::max();
16159 for (unsigned int q=1; q<sizeQ; ++q) {
16160 const unsigned int v = Q(q);
16161 const T d = (T)distance(v,umin);
16162 if (d<infty) {
16163 const T alt = dmin + d;
16164 if (alt<dist(v)) {
16165 dist(v) = alt;
16166 previous(v) = (t)umin;
16167 const T distpos = dist(Q(q));
16168 for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos+1)/2-1)); pos=par) cimg::swap(Q(pos),Q(par));
16169 }
16170 }
16171 }
16172 // Remove minimal vertex from queue
16173 Q(0) = Q(--sizeQ);
16174 const T distpos = dist(Q(0));
16175 for (unsigned int pos = 0, left = 0, right = 0;
16176 ((right=2*(pos+1),(left=right-1))<sizeQ && distpos>dist(Q(left))) || (right<sizeQ && distpos>dist(Q(right)));) {
16177 if (right<sizeQ) {
16178 if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; }
16179 else { cimg::swap(Q(pos),Q(right)); pos = right; }
16180 } else { cimg::swap(Q(pos),Q(left)); pos = left; }
16181 }
16182 }
16183 }
16184 return dist;
16185 }
16187 //! Return minimal path in a graph, using the Dijkstra algorithm.
16188 template<typename tf, typename t>
16189 static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
16190 const unsigned int starting_node, const unsigned int ending_node=~0U) {
16191 CImg<uintT> foo;
16192 return dijkstra(distance,nb_nodes,starting_node,ending_node,foo);
16193 }
16195 //! Return minimal path in a graph, using the Dijkstra algorithm.
16196 /**
16197 Instance image corresponds to the adjacency matrix of the graph.
16198 \param starting_node Indice of the starting node.
16199 \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
16200 \return Array of distances of each node to the starting node.
16201 **/
16202 template<typename t>
16203 CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) {
16204 return get_dijkstra(starting_node,ending_node,previous).transfer_to(*this);
16205 }
16207 template<typename t>
16208 CImg<T> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) const {
16209 if (width!=height || depth!=1 || dim!=1)
16210 throw CImgInstanceException("CImg<%s>::dijkstra() : Instance image (%u,%u,%u,%u,%p) is not a graph adjacency matrix",
16211 pixel_type(),width,height,depth,dim,data);
16212 return dijkstra(*this,width,starting_node,ending_node,previous);
16213 }
16215 //! Return minimal path in a graph, using the Dijkstra algorithm.
16216 CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) {
16217 return get_dijkstra(starting_node,ending_node).transfer_to(*this);
16218 }
16220 CImg<Tfloat> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const {
16221 CImg<uintT> foo;
16222 return get_dijkstra(starting_node,ending_node,foo);
16223 }
16225 //@}
16226 //-------------------------------------
16227 //
16228 //! \name Meshes and Triangulations
16229 //@{
16230 //-------------------------------------
16232 //! Return a 3D centered cube.
16233 template<typename tf>
16234 static CImg<floatT> cube3d(CImgList<tf>& primitives, const float size=100) {
16235 const double s = size/2.0;
16236 primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 0,1,5,4, 3,7,6,2, 0,4,7,3, 1,2,6,5);
16237 return CImg<floatT>(8,3,1,1,
16238 -s,s,s,-s,-s,s,s,-s,
16239 -s,-s,s,s,-s,-s,s,s,
16240 -s,-s,-s,-s,s,s,s,s);
16241 }
16243 //! Return a 3D centered cuboid.
16244 template<typename tf>
16245 static CImg<floatT> cuboid3d(CImgList<tf>& primitives, const float sizex=200,
16246 const float sizey=100, const float sizez=100) {
16247 const double sx = sizex/2.0, sy = sizey/2.0, sz = sizez/2.0;
16248 primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 0,1,5,4, 3,7,6,2, 0,4,7,3, 1,2,6,5);
16249 return CImg<floatT>(8,3,1,1,
16250 -sx,sx,sx,-sx,-sx,sx,sx,-sx,
16251 -sy,-sy,sy,sy,-sy,-sy,sy,sy,
16252 -sz,-sz,-sz,-sz,sz,sz,sz,sz);
16253 }
16255 //! Return a 3D centered cone.
16256 template<typename tf>
16257 static CImg<floatT> cone3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
16258 const unsigned int subdivisions=24, const bool symetrize=false) {
16259 primitives.assign();
16260 if (!subdivisions) return CImg<floatT>();
16261 const double r = (double)radius, h = (double)height/2;
16262 CImgList<floatT> points(2,1,3,1,1,
16263 0.0,0.0,h,
16264 0.0,0.0,-h);
16265 const float delta = 360.0f/subdivisions, nh = symetrize?0:-(float)h;
16266 for (float angle = 0; angle<360; angle+=delta) {
16267 const float a = (float)(angle*cimg::valuePI/180);
16268 points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),nh));
16269 }
16270 const unsigned int nbr = points.size-2;
16271 for (unsigned int p = 0; p<nbr; ++p) {
16272 const unsigned int curr = 2+p, next = 2+((p+1)%nbr);
16273 primitives.insert(CImg<tf>::vector(1,next,curr)).
16274 insert(CImg<tf>::vector(0,curr,next));
16275 }
16276 return points.get_append('x');
16277 }
16279 //! Return a 3D centered cylinder.
16280 template<typename tf>
16281 static CImg<floatT> cylinder3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
16282 const unsigned int subdivisions=24) {
16283 primitives.assign();
16284 if (!subdivisions) return CImg<floatT>();
16285 const double r = (double)radius, h = (double)height/2;
16286 CImgList<floatT> points(2,1,3,1,1,
16287 0.0,0.0,-h,
16288 0.0,0.0,h);
16290 const float delta = 360.0f/subdivisions;
16291 for (float angle = 0; angle<360; angle+=delta) {
16292 const float a = (float)(angle*cimg::valuePI/180);
16293 points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),-(float)h));
16294 points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),(float)h));
16295 }
16296 const unsigned int nbr = (points.size-2)/2;
16297 for (unsigned int p = 0; p<nbr; ++p) {
16298 const unsigned int curr = 2+2*p, next = 2+(2*((p+1)%nbr));
16299 primitives.insert(CImg<tf>::vector(0,next,curr)).
16300 insert(CImg<tf>::vector(1,curr+1,next+1)).
16301 insert(CImg<tf>::vector(curr,next,next+1,curr+1));
16302 }
16303 return points.get_append('x');
16304 }
16306 //! Return a 3D centered torus.
16307 template<typename tf>
16308 static CImg<floatT> torus3d(CImgList<tf>& primitives, const float radius1=100, const float radius2=30,
16309 const unsigned int subdivisions1=24, const unsigned int subdivisions2=12) {
16310 primitives.assign();
16311 if (!subdivisions1 || !subdivisions2) return CImg<floatT>();
16312 CImgList<floatT> points;
16313 for (unsigned int v = 0; v<subdivisions1; ++v) {
16314 const float
16315 beta = (float)(v*2*cimg::valuePI/subdivisions1),
16316 xc = radius1*(float)cimg_std::cos(beta),
16317 yc = radius1*(float)cimg_std::sin(beta);
16318 for (unsigned int u=0; u<subdivisions2; ++u) {
16319 const float
16320 alpha = (float)(u*2*cimg::valuePI/subdivisions2),
16321 x = xc + radius2*(float)(cimg_std::cos(alpha)*cimg_std::cos(beta)),
16322 y = yc + radius2*(float)(cimg_std::cos(alpha)*cimg_std::sin(beta)),
16323 z = radius2*(float)cimg_std::sin(alpha);
16324 points.insert(CImg<floatT>::vector(x,y,z));
16325 }
16326 }
16327 for (unsigned int vv = 0; vv<subdivisions1; ++vv) {
16328 const unsigned int nv = (vv+1)%subdivisions1;
16329 for (unsigned int uu = 0; uu<subdivisions2; ++uu) {
16330 const unsigned int nu = (uu+1)%subdivisions2, svv = subdivisions2*vv, snv = subdivisions2*nv;
16331 primitives.insert(CImg<tf>::vector(svv+nu,svv+uu,snv+uu));
16332 primitives.insert(CImg<tf>::vector(svv+nu,snv+uu,snv+nu));
16333 }
16334 }
16335 return points.get_append('x');
16336 }
16338 //! Return a 3D centered XY plane.
16339 template<typename tf>
16340 static CImg<floatT> plane3d(CImgList<tf>& primitives, const float sizex=100, const float sizey=100,
16341 const unsigned int subdivisionsx=3, const unsigned int subdivisionsy=3,
16342 const bool double_sided=false) {
16343 primitives.assign();
16344 if (!subdivisionsx || !subdivisionsy) return CImg<floatT>();
16345 CImgList<floatT> points;
16346 const unsigned int w = subdivisionsx + 1, h = subdivisionsy + 1;
16347 const float w2 = subdivisionsx/2.0f, h2 = subdivisionsy/2.0f, fx = (float)sizex/w, fy = (float)sizey/h;
16348 for (unsigned int yy = 0; yy<h; ++yy)
16349 for (unsigned int xx = 0; xx<w; ++xx)
16350 points.insert(CImg<floatT>::vector(fx*(xx-w2),fy*(yy-h2),0));
16351 for (unsigned int y = 0; y<subdivisionsy; ++y) for (unsigned int x = 0; x<subdivisionsx; ++x) {
16352 const int off1 = x+y*w, off2 = x+1+y*w, off3 = x+1+(y+1)*w, off4 = x+(y+1)*w;
16353 primitives.insert(CImg<tf>::vector(off1,off4,off3,off2));
16354 if (double_sided) primitives.insert(CImg<tf>::vector(off1,off2,off3,off4));
16355 }
16356 return points.get_append('x');
16357 }
16359 //! Return a 3D centered sphere.
16360 template<typename tf>
16361 static CImg<floatT> sphere3d(CImgList<tf>& primitives, const float radius=50, const unsigned int subdivisions=3) {
16363 // Create initial icosahedron
16364 primitives.assign();
16365 if (!subdivisions) return CImg<floatT>();
16366 const double tmp = (1+cimg_std::sqrt(5.0f))/2, a = 1.0/cimg_std::sqrt(1+tmp*tmp), b = tmp*a;
16367 CImgList<floatT> points(12,1,3,1,1, b,a,0.0, -b,a,0.0, -b,-a,0.0, b,-a,0.0, a,0.0,b, a,0.0,-b,
16368 -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a);
16369 primitives.assign(20,1,3,1,1, 4,8,7, 4,7,9, 5,6,11, 5,10,6, 0,4,3, 0,3,5, 2,7,1, 2,1,6,
16370 8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3,
16371 5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2);
16373 // Recurse subdivisions
16374 for (unsigned int i = 0; i<subdivisions; ++i) {
16375 const unsigned int L = primitives.size;
16376 for (unsigned int l = 0; l<L; ++l) {
16377 const unsigned int
16378 p0 = (unsigned int)primitives(0,0), p1 = (unsigned int)primitives(0,1), p2 = (unsigned int)primitives(0,2);
16379 const float
16380 x0 = points(p0,0), y0 = points(p0,1), z0 = points(p0,2),
16381 x1 = points(p1,0), y1 = points(p1,1), z1 = points(p1,2),
16382 x2 = points(p2,0), y2 = points(p2,1), z2 = points(p2,2),
16383 tnx0 = (x0+x1)/2, tny0 = (y0+y1)/2, tnz0 = (z0+z1)/2, nn0 = (float)cimg_std::sqrt(tnx0*tnx0+tny0*tny0+tnz0*tnz0),
16384 tnx1 = (x0+x2)/2, tny1 = (y0+y2)/2, tnz1 = (z0+z2)/2, nn1 = (float)cimg_std::sqrt(tnx1*tnx1+tny1*tny1+tnz1*tnz1),
16385 tnx2 = (x1+x2)/2, tny2 = (y1+y2)/2, tnz2 = (z1+z2)/2, nn2 = (float)cimg_std::sqrt(tnx2*tnx2+tny2*tny2+tnz2*tnz2),
16386 nx0 = tnx0/nn0, ny0 = tny0/nn0, nz0 = tnz0/nn0,
16387 nx1 = tnx1/nn1, ny1 = tny1/nn1, nz1 = tnz1/nn1,
16388 nx2 = tnx2/nn2, ny2 = tny2/nn2, nz2 = tnz2/nn2;
16389 int i0 = -1, i1 = -1, i2 = -1;
16390 cimglist_for(points,p) {
16391 const float x = (float)points(p,0), y = (float)points(p,1), z = (float)points(p,2);
16392 if (x==nx0 && y==ny0 && z==nz0) i0 = p;
16393 if (x==nx1 && y==ny1 && z==nz1) i1 = p;
16394 if (x==nx2 && y==ny2 && z==nz2) i2 = p;
16395 }
16396 if (i0<0) { points.insert(CImg<floatT>::vector(nx0,ny0,nz0)); i0 = points.size-1; }
16397 if (i1<0) { points.insert(CImg<floatT>::vector(nx1,ny1,nz1)); i1 = points.size-1; }
16398 if (i2<0) { points.insert(CImg<floatT>::vector(nx2,ny2,nz2)); i2 = points.size-1; }
16399 primitives.remove(0);
16400 primitives.insert(CImg<tf>::vector(p0,i0,i1)).
16401 insert(CImg<tf>::vector((tf)i0,(tf)p1,(tf)i2)).
16402 insert(CImg<tf>::vector((tf)i1,(tf)i2,(tf)p2)).
16403 insert(CImg<tf>::vector((tf)i1,(tf)i0,(tf)i2));
16404 }
16405 }
16406 return points.get_append('x')*=radius;
16407 }
16409 //! Return a 3D centered ellipsoid.
16410 template<typename tf, typename t>
16411 static CImg<floatT> ellipsoid3d(CImgList<tf>& primitives, const CImg<t>& tensor,
16412 const unsigned int subdivisions=3) {
16413 primitives.assign();
16414 if (!subdivisions) return CImg<floatT>();
16415 typedef typename cimg::superset<t,float>::type tfloat;
16416 CImg<tfloat> S,V;
16417 tensor.symmetric_eigen(S,V);
16418 const tfloat l0 = S[0], l1 = S[1], l2 = S[2];
16419 CImg<floatT> points = sphere(primitives,subdivisions);
16420 cimg_forX(points,p) {
16421 points(p,0) = (float)(points(p,0)*l0);
16422 points(p,1) = (float)(points(p,1)*l1);
16423 points(p,2) = (float)(points(p,2)*l2);
16424 }
16425 V.transpose();
16426 points = V*points;
16427 return points;
16428 }
16430 //! Return a 3D elevation object of the instance image.
16431 template<typename tf, typename tc, typename te>
16432 CImg<floatT> get_elevation3d(CImgList<tf>& primitives, CImgList<tc>& colors, const CImg<te>& elevation) const {
16433 primitives.assign();
16434 colors.assign();
16435 if (is_empty()) return *this;
16436 if (depth>1)
16437 throw CImgInstanceException("CImg<%s>::get_elevation3d() : Instance image (%u,%u,%u,%u,%p) is not a 2D image.",
16438 pixel_type(),width,height,depth,dim,data);
16439 if (!is_sameXY(elevation))
16440 throw CImgArgumentException("CImg<%s>::get_elevation3d() : Elevation image (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) "
16441 "have different sizes.",pixel_type(),
16442 elevation.width,elevation.height,elevation.depth,elevation.dim,elevation.data,
16443 width,height,depth,dim,data,pixel_type());
16444 float m, M = (float)maxmin(m);
16445 if (M==m) ++M;
16446 const unsigned int w = width + 1, h = height + 1;
16447 CImg<floatT> points(w*h,3);
16448 cimg_forXY(*this,x,y) {
16449 const int yw = y*w, xpyw = x + yw, xpyww = xpyw + w;
16450 points(xpyw,0) = points(xpyw+1,0) = points(xpyww+1,0) = points(xpyww,0) = (float)x;
16451 points(xpyw,1) = points(xpyw+1,1) = points(xpyww+1,1) = points(xpyww,1) = (float)y;
16452 points(xpyw,2) = points(xpyw+1,2) = points(xpyww+1,2) = points(xpyww,2) = (float)elevation(x,y);
16453 primitives.insert(CImg<tf>::vector(xpyw,xpyw+1,xpyww+1,xpyww));
16454 const unsigned char
16455 r = (unsigned char)(((*this)(x,y,0) - m)*255/(M-m)),
16456 g = dim>1?(unsigned char)(((*this)(x,y,1) - m)*255/(M-m)):r,
16457 b = dim>2?(unsigned char)(((*this)(x,y,2) - m)*255/(M-m)):(dim>1?0:r);
16458 colors.insert(CImg<tc>::vector((tc)r,(tc)g,(tc)b));
16459 }
16460 return points;
16461 }
16463 // Inner routine used by the Marching square algorithm.
16464 template<typename t>
16465 static int _marching_squares_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
16466 const unsigned int x, const unsigned int nx) {
16467 switch (edge) {
16468 case 0 : return (int)indices1(x,0);
16469 case 1 : return (int)indices1(nx,1);
16470 case 2 : return (int)indices2(x,0);
16471 case 3 : return (int)indices1(x,1);
16472 }
16473 return 0;
16474 }
16476 //! Polygonize an implicit 2D function by the marching squares algorithm.
16477 template<typename tf, typename tfunc>
16478 static CImg<floatT> marching_squares(CImgList<tf>& primitives, const tfunc& func, const float isovalue,
16479 const float x0, const float y0,
16480 const float x1, const float y1,
16481 const float resx, const float resy) {
16482 static unsigned int edges[16] = { 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc, 0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 };
16483 static int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 },
16484 { 1,2,-1,-1 }, { 0,1,2,3 }, { 0,2,-1,-1 }, { 2,3,-1,-1 },
16485 { 2,3,-1,-1 }, { 0,2,-1,-1}, { 0,3,1,2 }, { 1,2,-1,-1 },
16486 { 1,3,-1,-1 }, { 0,1,-1,-1}, { 0,3,-1,-1}, { -1,-1,-1,-1 } };
16487 const unsigned int
16488 nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1,
16489 ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1;
16490 if (!nxm1 || !nym1) return CImg<floatT>();
16492 primitives.assign();
16493 CImgList<floatT> points;
16494 CImg<intT> indices1(nx,1,1,2,-1), indices2(nx,1,1,2);
16495 CImg<floatT> values1(nx), values2(nx);
16496 float X = 0, Y = 0, nX = 0, nY = 0;
16498 // Fill first line with values
16499 cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=resx; }
16501 // Run the marching squares algorithm
16502 Y = y0; nY = Y + resy;
16503 for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y=nY, nY+=resy) {
16504 X = x0; nX = X + resx;
16505 indices2.fill(-1);
16506 for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X=nX, nX+=resx) {
16508 // Determine cube configuration
16509 const float
16510 val0 = values1(xi), val1 = values1(nxi),
16511 val2 = values2(nxi) = (float)func(nX,nY),
16512 val3 = values2(xi) = (float)func(X,nY);
16514 const unsigned int configuration = (val0<isovalue?1:0) | (val1<isovalue?2:0) | (val2<isovalue?4:0) | (val3<isovalue?8:0),
16515 edge = edges[configuration];
16517 // Compute intersection points
16518 if (edge) {
16519 if ((edge&1) && indices1(xi,0)<0) {
16520 const float Xi = X + (isovalue-val0)*resx/(val1-val0);
16521 indices1(xi,0) = points.size;
16522 points.insert(CImg<floatT>::vector(Xi,Y));
16523 }
16524 if ((edge&2) && indices1(nxi,1)<0) {
16525 const float Yi = Y + (isovalue-val1)*resy/(val2-val1);
16526 indices1(nxi,1) = points.size;
16527 points.insert(CImg<floatT>::vector(nX,Yi));
16528 }
16529 if ((edge&4) && indices2(xi,0)<0) {
16530 const float Xi = X + (isovalue-val3)*resx/(val2-val3);
16531 indices2(xi,0) = points.size;
16532 points.insert(CImg<floatT>::vector(Xi,nY));
16533 }
16534 if ((edge&8) && indices1(xi,1)<0) {
16535 const float Yi = Y + (isovalue-val0)*resy/(val3-val0);
16536 indices1(xi,1) = points.size;
16537 points.insert(CImg<floatT>::vector(X,Yi));
16538 }
16540 // Create segments
16541 for (int *segment = segments[configuration]; *segment!=-1; ) {
16542 const unsigned int p0 = *(segment++), p1 = *(segment++);
16543 const tf
16544 i0 = (tf)(_marching_squares_indice(p0,indices1,indices2,xi,nxi)),
16545 i1 = (tf)(_marching_squares_indice(p1,indices1,indices2,xi,nxi));
16546 primitives.insert(CImg<tf>::vector(i0,i1));
16547 }
16548 }
16549 }
16550 values1.swap(values2);
16551 indices1.swap(indices2);
16552 }
16553 return points.get_append('x');
16554 }
16556 // Inner routine used by the Marching cube algorithm.
16557 template<typename t>
16558 static int _marching_cubes_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
16559 const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny) {
16560 switch (edge) {
16561 case 0 : return indices1(x,y,0);
16562 case 1 : return indices1(nx,y,1);
16563 case 2 : return indices1(x,ny,0);
16564 case 3 : return indices1(x,y,1);
16565 case 4 : return indices2(x,y,0);
16566 case 5 : return indices2(nx,y,1);
16567 case 6 : return indices2(x,ny,0);
16568 case 7 : return indices2(x,y,1);
16569 case 8 : return indices1(x,y,2);
16570 case 9 : return indices1(nx,y,2);
16571 case 10 : return indices1(nx,ny,2);
16572 case 11 : return indices1(x,ny,2);
16573 }
16574 return 0;
16575 }
16577 //! Polygonize an implicit function
16578 // This function uses the Marching Cubes Tables published on the web page :
16579 // http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/
16580 template<typename tf, typename tfunc>
16581 static CImg<floatT> marching_cubes(CImgList<tf>& primitives,
16582 const tfunc& func, const float isovalue,
16583 const float x0, const float y0, const float z0,
16584 const float x1, const float y1, const float z1,
16585 const float resx, const float resy, const float resz,
16586 const bool invert_faces=false) {
16588 static unsigned int edges[256] = {
16589 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
16590 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
16591 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
16592 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
16593 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
16594 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
16595 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
16596 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
16597 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
16598 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
16599 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
16600 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
16601 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
16602 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
16603 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
16604 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 };
16606 static int triangles[256][16] =
16607 {{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16608 { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16609 { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16610 { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
16611 { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16612 { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
16613 { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
16614 { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16615 { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16616 { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
16617 { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 },
16618 { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
16619 { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
16620 { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 },
16621 { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 }, { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 },
16622 { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
16623 { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16624 { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
16625 { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
16626 { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 },
16627 { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
16628 { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 },
16629 { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 },
16630 { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
16631 { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
16632 { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16633 { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 }, { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 },
16634 { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 }, { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 },
16635 { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
16636 { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 }, { 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
16637 { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 }, { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 },
16638 { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 }, { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16639 { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16640 { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },
16641 { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 },
16642 { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 },
16643 { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },
16644 { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 },
16645 { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 },
16646 { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 }, { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
16647 { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 },
16648 { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, { 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
16649 { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 },
16650 { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 }, { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 },
16651 { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
16652 { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 }, { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 },
16653 { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 },
16654 { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 }, { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 },
16655 { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 },
16656 { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 },
16657 { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 },
16658 { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 },
16659 { 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 },
16660 { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 },
16661 { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 }, { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 },
16662 { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16663 { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 },
16664 { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 }, { 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
16665 { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 },
16666 { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16667 { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 },
16668 { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 }, { 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 },
16669 { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 }, { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16670 { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 }, { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16671 { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16672 { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
16673 { 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },
16674 { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 },
16675 { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
16676 { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 }, { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 },
16677 { 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 },
16678 { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 }, { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 },
16679 { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
16680 { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 },
16681 { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 },
16682 { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 }, { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 },
16683 { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16684 { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 }, { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
16685 { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 }, { 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
16686 { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 }, { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16687 { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
16688 { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 },
16689 { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 },
16690 { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 }, { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 },
16691 { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 },
16692 { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 }, { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 },
16693 { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 }, { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 },
16694 { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 }, { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 },
16695 { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 },
16696 { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 }, { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
16697 { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 }, { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 },
16698 { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 }, { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 },
16699 { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 }, { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 },
16700 { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 }, { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16701 { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 }, { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 },
16702 { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16703 { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 },
16704 { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 }, { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 },
16705 { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 },
16706 { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 }, { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 },
16707 { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 },
16708 { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 }, { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 },
16709 { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 },
16710 { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16711 { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 },
16712 { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 }, { 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 },
16713 { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 }, { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 },
16714 { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 }, { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16715 { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 }, { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
16716 { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 }, { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 },
16717 { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16718 { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 }, { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16719 { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 },
16720 { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 }, { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 },
16721 { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 }, { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 },
16722 { 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, { 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 },
16723 { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 }, { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 },
16724 { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 }, { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16725 { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 },
16726 { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16727 { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 },
16728 { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16729 { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 },
16730 { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16731 { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16732 { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 }, { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16733 { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
16734 { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }};
16736 const unsigned int
16737 nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1,
16738 ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1,
16739 nz = (unsigned int)((z1-z0+1)/resz), nzm1 = nz-1;
16740 if (!nxm1 || !nym1 || !nzm1) return CImg<floatT>();
16742 primitives.assign();
16743 CImgList<floatT> points;
16744 CImg<intT> indices1(nx,ny,1,3,-1), indices2(indices1);
16745 CImg<floatT> values1(nx,ny), values2(nx,ny);
16746 float X = 0, Y = 0, Z = 0, nX = 0, nY = 0, nZ = 0;
16748 // Fill the first plane with function values
16749 Y = y0;
16750 cimg_forY(values1,y) {
16751 X = x0;
16752 cimg_forX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=resx; }
16753 Y+=resy;
16754 }
16756 // Run Marching Cubes algorithm
16757 Z = z0; nZ = Z + resz;
16758 for (unsigned int zi = 0; zi<nzm1; ++zi, Z = nZ, nZ+=resz) {
16759 Y = y0; nY = Y + resy;
16760 indices2.fill(-1);
16761 for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y = nY, nY+=resy) {
16762 X = x0; nX = X + resx;
16763 for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X = nX, nX+=resx) {
16765 // Determine cube configuration
16766 const float
16767 val0 = values1(xi,yi), val1 = values1(nxi,yi), val2 = values1(nxi,nyi), val3 = values1(xi,nyi),
16768 val4 = values2(xi,yi) = (float)func(X,Y,nZ),
16769 val5 = values2(nxi,yi) = (float)func(nX,Y,nZ),
16770 val6 = values2(nxi,nyi) = (float)func(nX,nY,nZ),
16771 val7 = values2(xi,nyi) = (float)func(X,nY,nZ);
16773 const unsigned int configuration =
16774 (val0<isovalue?1:0) | (val1<isovalue?2:0) | (val2<isovalue?4:0) | (val3<isovalue?8:0) |
16775 (val4<isovalue?16:0) | (val5<isovalue?32:0) | (val6<isovalue?64:0) | (val7<isovalue?128:0),
16776 edge = edges[configuration];
16778 // Compute intersection points
16779 if (edge) {
16780 if ((edge&1) && indices1(xi,yi,0)<0) {
16781 const float Xi = X + (isovalue-val0)*resx/(val1-val0);
16782 indices1(xi,yi,0) = points.size;
16783 points.insert(CImg<floatT>::vector(Xi,Y,Z));
16784 }
16785 if ((edge&2) && indices1(nxi,yi,1)<0) {
16786 const float Yi = Y + (isovalue-val1)*resy/(val2-val1);
16787 indices1(nxi,yi,1) = points.size;
16788 points.insert(CImg<floatT>::vector(nX,Yi,Z));
16789 }
16790 if ((edge&4) && indices1(xi,nyi,0)<0) {
16791 const float Xi = X + (isovalue-val3)*resx/(val2-val3);
16792 indices1(xi,nyi,0) = points.size;
16793 points.insert(CImg<floatT>::vector(Xi,nY,Z));
16794 }
16795 if ((edge&8) && indices1(xi,yi,1)<0) {
16796 const float Yi = Y + (isovalue-val0)*resy/(val3-val0);
16797 indices1(xi,yi,1) = points.size;
16798 points.insert(CImg<floatT>::vector(X,Yi,Z));
16799 }
16800 if ((edge&16) && indices2(xi,yi,0)<0) {
16801 const float Xi = X + (isovalue-val4)*resx/(val5-val4);
16802 indices2(xi,yi,0) = points.size;
16803 points.insert(CImg<floatT>::vector(Xi,Y,nZ));
16804 }
16805 if ((edge&32) && indices2(nxi,yi,1)<0) {
16806 const float Yi = Y + (isovalue-val5)*resy/(val6-val5);
16807 indices2(nxi,yi,1) = points.size;
16808 points.insert(CImg<floatT>::vector(nX,Yi,nZ));
16809 }
16810 if ((edge&64) && indices2(xi,nyi,0)<0) {
16811 const float Xi = X + (isovalue-val7)*resx/(val6-val7);
16812 indices2(xi,nyi,0) = points.size;
16813 points.insert(CImg<floatT>::vector(Xi,nY,nZ));
16814 }
16815 if ((edge&128) && indices2(xi,yi,1)<0) {
16816 const float Yi = Y + (isovalue-val4)*resy/(val7-val4);
16817 indices2(xi,yi,1) = points.size;
16818 points.insert(CImg<floatT>::vector(X,Yi,nZ));
16819 }
16820 if ((edge&256) && indices1(xi,yi,2)<0) {
16821 const float Zi = Z+ (isovalue-val0)*resz/(val4-val0);
16822 indices1(xi,yi,2) = points.size;
16823 points.insert(CImg<floatT>::vector(X,Y,Zi));
16824 }
16825 if ((edge&512) && indices1(nxi,yi,2)<0) {
16826 const float Zi = Z + (isovalue-val1)*resz/(val5-val1);
16827 indices1(nxi,yi,2) = points.size;
16828 points.insert(CImg<floatT>::vector(nX,Y,Zi));
16829 }
16830 if ((edge&1024) && indices1(nxi,nyi,2)<0) {
16831 const float Zi = Z + (isovalue-val2)*resz/(val6-val2);
16832 indices1(nxi,nyi,2) = points.size;
16833 points.insert(CImg<floatT>::vector(nX,nY,Zi));
16834 }
16835 if ((edge&2048) && indices1(xi,nyi,2)<0) {
16836 const float Zi = Z + (isovalue-val3)*resz/(val7-val3);
16837 indices1(xi,nyi,2) = points.size;
16838 points.insert(CImg<floatT>::vector(X,nY,Zi));
16839 }
16841 // Create triangles
16842 for (int *triangle = triangles[configuration]; *triangle!=-1; ) {
16843 const unsigned int p0 = *(triangle++), p1 = *(triangle++), p2 = *(triangle++);
16844 const tf
16845 i0 = (tf)(_marching_cubes_indice(p0,indices1,indices2,xi,yi,nxi,nyi)),
16846 i1 = (tf)(_marching_cubes_indice(p1,indices1,indices2,xi,yi,nxi,nyi)),
16847 i2 = (tf)(_marching_cubes_indice(p2,indices1,indices2,xi,yi,nxi,nyi));
16848 if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2));
16849 else primitives.insert(CImg<tf>::vector(i0,i2,i1));
16850 }
16851 }
16852 }
16853 }
16854 cimg::swap(values1,values2);
16855 cimg::swap(indices1,indices2);
16856 }
16857 return points.get_append('x');
16858 }
16860 struct _marching_squares_func {
16861 const CImg<T>& ref;
16862 _marching_squares_func(const CImg<T>& pref):ref(pref) {}
16863 float operator()(const float x, const float y) const {
16864 return (float)ref((int)x,(int)y);
16865 }
16866 };
16868 struct _marching_cubes_func {
16869 const CImg<T>& ref;
16870 _marching_cubes_func(const CImg<T>& pref):ref(pref) {}
16871 float operator()(const float x, const float y, const float z) const {
16872 return (float)ref((int)x,(int)y,(int)z);
16873 }
16874 };
16876 struct _marching_squares_func_float {
16877 const CImg<T>& ref;
16878 _marching_squares_func_float(const CImg<T>& pref):ref(pref) {}
16879 float operator()(const float x, const float y) const {
16880 return (float)ref._linear_atXY(x,y);
16881 }
16882 };
16884 struct _marching_cubes_func_float {
16885 const CImg<T>& ref;
16886 _marching_cubes_func_float(const CImg<T>& pref):ref(pref) {}
16887 float operator()(const float x, const float y, const float z) const {
16888 return (float)ref._linear_atXYZ(x,y,z);
16889 }
16890 };
16892 //! Compute a vectorization of an implicit function.
16893 template<typename tf>
16894 CImg<floatT> get_isovalue3d(CImgList<tf>& primitives, const float isovalue,
16895 const float resx=1, const float resy=1, const float resz=1,
16896 const bool invert_faces=false) const {
16897 primitives.assign();
16898 if (is_empty()) return *this;
16899 if (dim>1)
16900 throw CImgInstanceException("CImg<%s>::get_isovalue3d() : Instance image (%u,%u,%u,%u,%p) is not a scalar image.",
16901 pixel_type(),width,height,depth,dim,data);
16902 CImg<floatT> points;
16903 if (depth>1) {
16904 if (resx==1 && resy==1 && resz==1) {
16905 const _marching_cubes_func func(*this);
16906 points = marching_cubes(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,resx,resy,resz,invert_faces);
16907 } else {
16908 const _marching_cubes_func_float func(*this);
16909 points = marching_cubes(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,resx,resy,resz,invert_faces);
16910 }
16911 } else {
16912 if (resx==1 && resy==1) {
16913 const _marching_squares_func func(*this);
16914 points = marching_squares(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,resx,resy);
16915 } else {
16916 const _marching_squares_func_float func(*this);
16917 points = marching_squares(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,resx,resy);
16918 }
16919 if (points) points.resize(-100,3,1,1,0);
16920 }
16921 return points;
16922 }
16924 //! Translate a 3D object.
16925 CImg<T>& translate_object3d(const float tx, const float ty=0, const float tz=0) {
16926 get_shared_line(0)+=tx; get_shared_line(1)+=ty; get_shared_line(2)+=tz;
16927 return *this;
16928 }
16930 CImg<Tfloat> get_translate_object3d(const float tx, const float ty=0, const float tz=0) const {
16931 return CImg<Tfloat>(*this,false).translate_object3d(tx,ty,tz);
16932 }
16934 //! Translate a 3D object so that it becomes centered.
16935 CImg<T>& translate_object3d() {
16936 CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
16937 float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
16938 xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2;
16939 return *this;
16940 }
16942 CImg<Tfloat> get_translate_object3d() const {
16943 return CImg<Tfloat>(*this,false).translate_object3d();
16944 }
16946 //! Resize a 3D object.
16947 CImg<T>& resize_object3d(const float sx, const float sy=-100, const float sz=-100) {
16948 CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
16949 float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
16950 if (xm<xM) { if (sx>0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; }
16951 if (ym<yM) { if (sy>0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; }
16952 if (zm<zM) { if (sz>0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; }
16953 return *this;
16954 }
16956 CImg<Tfloat> get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const {
16957 return CImg<Tfloat>(*this,false).resize_object3d(sx,sy,sz);
16958 }
16960 // Resize a 3D object so that its max dimension if one.
16961 CImg<T> resize_object3d() const {
16962 CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
16963 float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
16964 const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz);
16965 if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; }
16966 return *this;
16967 }
16969 CImg<Tfloat> get_resize_object3d() const {
16970 return CImg<Tfloat>(*this,false).resize_object3d();
16971 }
16973 //! Append a 3D object to another one.
16974 template<typename tf, typename tp, typename tff>
16975 CImg<T>& append_object3d(CImgList<tf>& primitives, const CImg<tp>& obj_points, const CImgList<tff>& obj_primitives) {
16976 const unsigned int P = width;
16977 append(obj_points,'x');
16978 const unsigned int N = primitives.size;
16979 primitives.insert(obj_primitives);
16980 for (unsigned int i = N; i<primitives.size; ++i) {
16981 CImg<tf> &p = primitives[i];
16982 if (p.size()!=5) p+=P;
16983 else { p[0]+=P; if (p[2]==0) p[1]+=P; }
16984 }
16985 return *this;
16986 }
16988 //@}
16989 //----------------------------
16990 //
16991 //! \name Color bases
16992 //@{
16993 //----------------------------
16995 //! Return a default indexed color palette with 256 (R,G,B) entries.
16996 /**
16997 The default color palette is used by %CImg when displaying images on 256 colors displays.
16998 It consists in the quantification of the (R,G,B) color space using 3:3:2 bits for color coding
16999 (i.e 8 levels for the Red and Green and 4 levels for the Blue).
17000 \return a 1x256x1x3 color image defining the palette entries.
17001 **/
17002 static CImg<Tuchar> default_LUT8() {
17003 static CImg<Tuchar> palette;
17004 if (!palette) {
17005 palette.assign(1,256,1,3);
17006 for (unsigned int index = 0, r = 16; r<256; r+=32)
17007 for (unsigned int g = 16; g<256; g+=32)
17008 for (unsigned int b = 32; b<256; b+=64) {
17009 palette(0,index,0) = (Tuchar)r;
17010 palette(0,index,1) = (Tuchar)g;
17011 palette(0,index++,2) = (Tuchar)b;
17012 }
17013 }
17014 return palette;
17015 }
17017 //! Return a rainbow color palette with 256 (R,G,B) entries.
17018 static CImg<Tuchar> rainbow_LUT8() {
17019 static CImg<Tuchar> palette;
17020 if (!palette) {
17021 CImg<Tint> tmp(1,256,1,3,1);
17022 tmp.get_shared_channel(0).sequence(0,359);
17023 palette = tmp.HSVtoRGB();
17024 }
17025 return palette;
17026 }
17028 //! Return a contrasted color palette with 256 (R,G,B) entries.
17029 static CImg<Tuchar> contrast_LUT8() {
17030 static const unsigned char pal[] = {
17031 217,62,88,75,1,237,240,12,56,160,165,116,1,1,204,2,15,248,148,185,133,141,46,246,222,116,16,5,207,226,
17032 17,114,247,1,214,53,238,0,95,55,233,235,109,0,17,54,33,0,90,30,3,0,94,27,19,0,68,212,166,130,0,15,7,119,
17033 238,2,246,198,0,3,16,10,13,2,25,28,12,6,2,99,18,141,30,4,3,140,12,4,30,233,7,10,0,136,35,160,168,184,20,
17034 233,0,1,242,83,90,56,180,44,41,0,6,19,207,5,31,214,4,35,153,180,75,21,76,16,202,218,22,17,2,136,71,74,
17035 81,251,244,148,222,17,0,234,24,0,200,16,239,15,225,102,230,186,58,230,110,12,0,7,129,249,22,241,37,219,
17036 1,3,254,210,3,212,113,131,197,162,123,252,90,96,209,60,0,17,0,180,249,12,112,165,43,27,229,77,40,195,12,
17037 87,1,210,148,47,80,5,9,1,137,2,40,57,205,244,40,8,252,98,0,40,43,206,31,187,0,180,1,69,70,227,131,108,0,
17038 223,94,228,35,248,243,4,16,0,34,24,2,9,35,73,91,12,199,51,1,249,12,103,131,20,224,2,70,32,
17039 233,1,165,3,8,154,246,233,196,5,0,6,183,227,247,195,208,36,0,0,226,160,210,198,69,153,210,1,23,8,192,2,4,
17040 137,1,0,52,2,249,241,129,0,0,234,7,238,71,7,32,15,157,157,252,158,2,250,6,13,30,11,162,0,199,21,11,27,224,
17041 4,157,20,181,111,187,218,3,0,11,158,230,196,34,223,22,248,135,254,210,157,219,0,117,239,3,255,4,227,5,247,
17042 11,4,3,188,111,11,105,195,2,0,14,1,21,219,192,0,183,191,113,241,1,12,17,248,0,48,7,19,1,254,212,0,239,246,
17043 0,23,0,250,165,194,194,17,3,253,0,24,6,0,141,167,221,24,212,2,235,243,0,0,205,1,251,133,204,28,4,6,1,10,
17044 141,21,74,12,236,254,228,19,1,0,214,1,186,13,13,6,13,16,27,209,6,216,11,207,251,59,32,9,155,23,19,235,143,
17045 116,6,213,6,75,159,23,6,0,228,4,10,245,249,1,7,44,234,4,102,174,0,19,239,103,16,15,18,8,214,22,4,47,244,
17046 255,8,0,251,173,1,212,252,250,251,252,6,0,29,29,222,233,246,5,149,0,182,180,13,151,0,203,183,0,35,149,0,
17047 235,246,254,78,9,17,203,73,11,195,0,3,5,44,0,0,237,5,106,6,130,16,214,20,168,247,168,4,207,11,5,1,232,251,
17048 129,210,116,231,217,223,214,27,45,38,4,177,186,249,7,215,172,16,214,27,249,230,236,2,34,216,217,0,175,30,
17049 243,225,244,182,20,212,2,226,21,255,20,0,2,13,62,13,191,14,76,64,20,121,4,118,0,216,1,147,0,2,210,1,215,
17050 95,210,236,225,184,46,0,248,24,11,1,9,141,250,243,9,221,233,160,11,147,2,55,8,23,12,253,9,0,54,0,231,6,3,
17051 141,8,2,246,9,180,5,11,8,227,8,43,110,242,1,130,5,97,36,10,6,219,86,133,11,108,6,1,5,244,67,19,28,0,174,
17052 154,16,127,149,252,188,196,196,228,244,9,249,0,0,0,37,170,32,250,0,73,255,23,3,224,234,38,195,198,0,255,87,
17053 33,221,174,31,3,0,189,228,6,153,14,144,14,108,197,0,9,206,245,254,3,16,253,178,248,0,95,125,8,0,3,168,21,
17054 23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 };
17055 static const CImg<Tuchar> palette(pal,1,256,1,3,false);
17056 return palette;
17057 }
17059 //! Convert (R,G,B) color image to indexed color image.
17060 template<typename t>
17061 CImg<T>& RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) {
17062 return get_RGBtoLUT(palette,dithering,indexing).transfer_to(*this);
17063 }
17065 template<typename t>
17066 CImg<t> get_RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) const {
17067 if (is_empty()) return CImg<t>();
17068 if (dim!=3)
17069 throw CImgInstanceException("CImg<%s>::RGBtoLUT() : Input image dimension is dim=%u, "
17070 "should be a (R,G,B) image.",
17071 pixel_type(),dim);
17072 if (palette.data && palette.dim!=3)
17073 throw CImgArgumentException("CImg<%s>::RGBtoLUT() : Given palette dimension is dim=%u, "
17074 "should be a (R,G,B) palette",
17075 pixel_type(),palette.dim);
17076 CImg<t> res(width,height,depth,indexing?1:3);
17077 float *line1 = new float[3*width], *line2 = new float[3*width];
17078 t *pRd = res.ptr(0,0,0,0), *pGd = indexing?pRd:res.ptr(0,0,0,1), *pBd = indexing?pRd:res.ptr(0,0,0,2);
17079 cimg_forZ(*this,z) {
17080 const T *pRs = ptr(0,0,z,0), *pGs = ptr(0,0,z,1), *pBs = ptr(0,0,z,2);
17081 float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
17082 cimg_forY(*this,y) {
17083 cimg::swap(line1,line2);
17084 if (y<dimy()-1) {
17085 const int ny = y + 1;
17086 const T *pRs = ptr(0,ny,z,0), *pGs = ptr(0,ny,z,1), *pBs = ptr(0,ny,z,2);
17087 float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
17088 }
17089 float *ptr1 = line1, *ptr2 = line2;
17090 cimg_forX(*this,x) {
17091 float R = *(ptr1++), G = *(ptr1++), B = *(ptr1++);
17092 R = R<0?0:(R>255?255:R); G = G<0?0:(G>255?255:G); B = B<0?0:(B>255?255:B);
17093 t Rbest = 0, Gbest = 0, Bbest = 0;
17094 int best_index = 0;
17095 if (palette) { // find best match in given color palette
17096 const t *pRs = palette.ptr(0,0,0,0), *pGs = palette.ptr(0,0,0,1), *pBs = palette.ptr(0,0,0,2);
17097 const unsigned int Npal = palette.width*palette.height*palette.depth;
17098 float min = cimg::type<float>::max();
17099 for (unsigned int off = 0; off<Npal; ++off) {
17100 const t Rp = *(pRs++), Gp = *(pGs++), Bp = *(pBs++);
17101 const float error = cimg::sqr((float)Rp-(float)R) + cimg::sqr((float)Gp-(float)G) + cimg::sqr((float)Bp-(float)B);
17102 if (error<min) { min = error; best_index = off; Rbest = Rp; Gbest = Gp; Bbest = Bp; }
17103 }
17104 } else {
17105 Rbest = (t)((unsigned char)R&0xe0); Gbest = (t)((unsigned char)G&0xe0); Bbest = (t)((unsigned char)B&0xc0);
17106 best_index = (unsigned char)Rbest | ((unsigned char)Gbest>>3) | ((unsigned char)Bbest>>6);
17107 }
17108 if (indexing) *(pRd++) = (t)best_index; else { *(pRd++) = Rbest; *(pGd++) = Gbest; *(pBd++) = Bbest; }
17109 if (dithering) { // apply dithering to neighborhood pixels if needed
17110 const float dR = (float)(R-Rbest), dG = (float)(G-Gbest), dB = (float)(B-Bbest);
17111 if (x<dimx()-1) { *(ptr1++)+= dR*7/16; *(ptr1++)+= dG*7/16; *(ptr1++)+= dB*7/16; ptr1-=3; }
17112 if (y<dimy()-1) {
17113 *(ptr2++)+= dR*5/16; *(ptr2++)+= dG*5/16; *ptr2+= dB*5/16; ptr2-=2;
17114 if (x>0) { *(--ptr2)+= dB*3/16; *(--ptr2)+= dG*3/16; *(--ptr2)+= dR*3/16; ptr2+=3; }
17115 if (x<dimx()-1) { ptr2+=3; *(ptr2++)+= dR/16; *(ptr2++)+= dG/16; *ptr2+= dB/16; ptr2-=5; }
17116 }
17117 }
17118 ptr2+=3;
17119 }
17120 }
17121 }
17122 delete[] line1; delete[] line2;
17123 return res;
17124 }
17126 //! Convert color pixels from (R,G,B) to match the default palette.
17127 CImg<T>& RGBtoLUT(const bool dithering=true, const bool indexing=false) {
17128 return get_RGBtoLUT(dithering,indexing).transfer_to(*this);
17129 }
17131 CImg<Tuchar> get_RGBtoLUT(const bool dithering=true, const bool indexing=false) const {
17132 static const CImg<Tuchar> empty;
17133 return get_RGBtoLUT(empty,dithering,indexing);
17134 }
17136 //! Convert an indexed image to a (R,G,B) image using the specified color palette.
17137 CImg<T>& LUTtoRGB(const CImg<T>& palette) {
17138 return get_LUTtoRGB(palette).transfer_to(*this);
17139 }
17141 template<typename t>
17142 CImg<t> get_LUTtoRGB(const CImg<t>& palette) const {
17143 if (is_empty()) return CImg<t>();
17144 if (dim!=1)
17145 throw CImgInstanceException("CImg<%s>::LUTtoRGB() : Input image dimension is dim=%u, "
17146 "should be a LUT image",
17147 pixel_type(),dim);
17148 if (palette.data && palette.dim!=3)
17149 throw CImgArgumentException("CImg<%s>::LUTtoRGB() : Given palette dimension is dim=%u, "
17150 "should be a (R,G,B) palette",
17151 pixel_type(),palette.dim);
17152 const CImg<t> pal = palette.data?palette:CImg<t>(default_LUT8());
17153 CImg<t> res(width,height,depth,3);
17154 const t *pRs = pal.ptr(0,0,0,0), *pGs = pal.ptr(0,0,0,1), *pBs = pal.ptr(0,0,0,2);
17155 t *pRd = res.ptr(0,0,0,1), *pGd = pRd + width*height*depth, *pBd = pGd + width*height*depth;
17156 const unsigned int Npal = palette.width*palette.height*palette.depth;
17157 cimg_for(*this,ptr,T) {
17158 const unsigned int index = ((unsigned int)*ptr)%Npal;
17159 *(--pRd) = pRs[index]; *(--pGd) = pGs[index]; *(--pBd) = pBs[index];
17160 }
17161 return res;
17162 }
17164 //! Convert an indexed image (with the default palette) to a (R,G,B) image.
17165 CImg<T>& LUTtoRGB() {
17166 return get_LUTtoRGB().transfer_to(*this);
17167 }
17169 CImg<Tuchar> get_LUTtoRGB() const {
17170 static const CImg<Tuchar> empty;
17171 return get_LUTtoRGB(empty);
17172 }
17174 //! Convert color pixels from (R,G,B) to (H,S,V).
17175 CImg<T>& RGBtoHSV() {
17176 if (is_empty()) return *this;
17177 if (dim!=3)
17178 throw CImgInstanceException("CImg<%s>::RGBtoHSV() : Input image dimension is dim=%u, "
17179 "should be a (R,G,B) image.",
17180 pixel_type(),dim);
17181 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17182 for (unsigned long N = width*height*depth; N; --N) {
17183 const Tfloat
17184 R = (Tfloat)*p1,
17185 G = (Tfloat)*p2,
17186 B = (Tfloat)*p3,
17187 nR = (R<0?0:(R>255?255:R))/255,
17188 nG = (G<0?0:(G>255?255:G))/255,
17189 nB = (B<0?0:(B>255?255:B))/255,
17190 m = cimg::min(nR,nG,nB),
17191 M = cimg::max(nR,nG,nB);
17192 Tfloat H = 0, S = 0;
17193 if (M!=m) {
17194 const Tfloat
17195 f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
17196 i = (Tfloat)((nR==m)?3:((nG==m)?5:1));
17197 H = (i-f/(M-m));
17198 if (H>=6) H-=6;
17199 H*=60;
17200 S = (M-m)/M;
17201 }
17202 *(p1++) = (T)H;
17203 *(p2++) = (T)S;
17204 *(p3++) = (T)M;
17205 }
17206 return *this;
17207 }
17209 CImg<Tfloat> get_RGBtoHSV() const {
17210 return CImg<Tfloat>(*this,false).RGBtoHSV();
17211 }
17213 //! Convert color pixels from (H,S,V) to (R,G,B).
17214 CImg<T>& HSVtoRGB() {
17215 if (is_empty()) return *this;
17216 if (dim!=3)
17217 throw CImgInstanceException("CImg<%s>::HSVtoRGB() : Input image dimension is dim=%u, "
17218 "should be a (H,S,V) image",
17219 pixel_type(),dim);
17220 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17221 for (unsigned long N = width*height*depth; N; --N) {
17222 Tfloat
17223 H = (Tfloat)*p1,
17224 S = (Tfloat)*p2,
17225 V = (Tfloat)*p3,
17226 R = 0, G = 0, B = 0;
17227 if (H==0 && S==0) R = G = B = V;
17228 else {
17229 H/=60;
17230 const int i = (int)cimg_std::floor(H);
17231 const Tfloat
17232 f = (i&1)?(H-i):(1-H+i),
17233 m = V*(1-S),
17234 n = V*(1-S*f);
17235 switch (i) {
17236 case 6 :
17237 case 0 : R = V; G = n; B = m; break;
17238 case 1 : R = n; G = V; B = m; break;
17239 case 2 : R = m; G = V; B = n; break;
17240 case 3 : R = m; G = n; B = V; break;
17241 case 4 : R = n; G = m; B = V; break;
17242 case 5 : R = V; G = m; B = n; break;
17243 }
17244 }
17245 R*=255; G*=255; B*=255;
17246 *(p1++) = (T)(R<0?0:(R>255?255:R));
17247 *(p2++) = (T)(G<0?0:(G>255?255:G));
17248 *(p3++) = (T)(B<0?0:(B>255?255:B));
17249 }
17250 return *this;
17251 }
17253 CImg<Tuchar> get_HSVtoRGB() const {
17254 return CImg<Tuchar>(*this,false).HSVtoRGB();
17255 }
17257 //! Convert color pixels from (R,G,B) to (H,S,L).
17258 CImg<T>& RGBtoHSL() {
17259 if (is_empty()) return *this;
17260 if (dim!=3)
17261 throw CImgInstanceException("CImg<%s>::RGBtoHSL() : Input image dimension is dim=%u, "
17262 "should be a (R,G,B) image.",
17263 pixel_type(),dim);
17264 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17265 for (unsigned long N = width*height*depth; N; --N) {
17266 const Tfloat
17267 R = (Tfloat)*p1,
17268 G = (Tfloat)*p2,
17269 B = (Tfloat)*p3,
17270 nR = (R<0?0:(R>255?255:R))/255,
17271 nG = (G<0?0:(G>255?255:G))/255,
17272 nB = (B<0?0:(B>255?255:B))/255,
17273 m = cimg::min(nR,nG,nB),
17274 M = cimg::max(nR,nG,nB),
17275 L = (m+M)/2;
17276 Tfloat H = 0, S = 0;
17277 if (M==m) H = S = 0;
17278 else {
17279 const Tfloat
17280 f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
17281 i = (nR==m)?3.0f:((nG==m)?5.0f:1.0f);
17282 H = (i-f/(M-m));
17283 if (H>=6) H-=6;
17284 H*=60;
17285 S = (2*L<=1)?((M-m)/(M+m)):((M-m)/(2-M-m));
17286 }
17287 *(p1++) = (T)H;
17288 *(p2++) = (T)S;
17289 *(p3++) = (T)L;
17290 }
17291 return *this;
17292 }
17294 CImg<Tfloat> get_RGBtoHSL() const {
17295 return CImg< Tfloat>(*this,false).RGBtoHSL();
17296 }
17298 //! Convert color pixels from (H,S,L) to (R,G,B).
17299 CImg<T>& HSLtoRGB() {
17300 if (is_empty()) return *this;
17301 if (dim!=3)
17302 throw CImgInstanceException("CImg<%s>::HSLtoRGB() : Input image dimension is dim=%u, "
17303 "should be a (H,S,V) image",
17304 pixel_type(),dim);
17305 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17306 for (unsigned long N = width*height*depth; N; --N) {
17307 const Tfloat
17308 H = (Tfloat)*p1,
17309 S = (Tfloat)*p2,
17310 L = (Tfloat)*p3,
17311 q = 2*L<1?L*(1+S):(L+S-L*S),
17312 p = 2*L-q,
17313 h = H/360,
17314 tr = h + 1.0f/3,
17315 tg = h,
17316 tb = h - 1.0f/3,
17317 ntr = tr<0?tr+1:(tr>1?tr-1:tr),
17318 ntg = tg<0?tg+1:(tg>1?tg-1:tg),
17319 ntb = tb<0?tb+1:(tb>1?tb-1:tb),
17320 R = 255*(6*ntr<1?p+(q-p)*6*ntr:(2*ntr<1?q:(3*ntr<2?p+(q-p)*6*(2.0f/3-ntr):p))),
17321 G = 255*(6*ntg<1?p+(q-p)*6*ntg:(2*ntg<1?q:(3*ntg<2?p+(q-p)*6*(2.0f/3-ntg):p))),
17322 B = 255*(6*ntb<1?p+(q-p)*6*ntb:(2*ntb<1?q:(3*ntb<2?p+(q-p)*6*(2.0f/3-ntb):p)));
17323 *(p1++) = (T)(R<0?0:(R>255?255:R));
17324 *(p2++) = (T)(G<0?0:(G>255?255:G));
17325 *(p3++) = (T)(B<0?0:(B>255?255:B));
17326 }
17327 return *this;
17328 }
17330 CImg<Tuchar> get_HSLtoRGB() const {
17331 return CImg<Tuchar>(*this,false).HSLtoRGB();
17332 }
17334 //! Convert color pixels from (R,G,B) to (H,S,I).
17335 //! Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002.
17336 CImg<T>& RGBtoHSI() {
17337 if (is_empty()) return *this;
17338 if (dim!=3)
17339 throw CImgInstanceException("CImg<%s>::RGBtoHSI() : Input image dimension is dim=%u, "
17340 "should be a (R,G,B) image.",
17341 pixel_type(),dim);
17342 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17343 for (unsigned long N = width*height*depth; N; --N) {
17344 const Tfloat
17345 R = (Tfloat)*p1,
17346 G = (Tfloat)*p2,
17347 B = (Tfloat)*p3,
17348 nR = (R<0?0:(R>255?255:R))/255,
17349 nG = (G<0?0:(G>255?255:G))/255,
17350 nB = (B<0?0:(B>255?255:B))/255,
17351 m = cimg::min(nR,nG,nB),
17352 theta = (Tfloat)(cimg_std::acos(0.5f*((nR-nG)+(nR-nB))/cimg_std::sqrt(cimg_std::pow(nR-nG,2)+(nR-nB)*(nG-nB)))*180/cimg::valuePI),
17353 sum = nR + nG + nB;
17354 Tfloat H = 0, S = 0, I = 0;
17355 if (theta>0) H = (nB<=nG)?theta:360-theta;
17356 if (sum>0) S = 1 - 3/sum*m;
17357 I = sum/3;
17358 *(p1++) = (T)H;
17359 *(p2++) = (T)S;
17360 *(p3++) = (T)I;
17361 }
17362 return *this;
17363 }
17365 CImg<Tfloat> get_RGBtoHSI() const {
17366 return CImg<Tfloat>(*this,false).RGBtoHSI();
17367 }
17369 //! Convert color pixels from (H,S,I) to (R,G,B).
17370 CImg<T>& HSItoRGB() {
17371 if (is_empty()) return *this;
17372 if (dim!=3)
17373 throw CImgInstanceException("CImg<%s>::HSItoRGB() : Input image dimension is dim=%u, "
17374 "should be a (H,S,I) image",
17375 pixel_type(),dim);
17376 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17377 for (unsigned long N = width*height*depth; N; --N) {
17378 Tfloat
17379 H = (Tfloat)*p1,
17380 S = (Tfloat)*p2,
17381 I = (Tfloat)*p3,
17382 a = I*(1-S),
17383 R = 0, G = 0, B = 0;
17384 if (H<120) {
17385 B = a;
17386 R = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
17387 G = 3*I-(R+B);
17388 } else if (H<240) {
17389 H-=120;
17390 R = a;
17391 G = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
17392 B = 3*I-(R+G);
17393 } else {
17394 H-=240;
17395 G = a;
17396 B = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
17397 R = 3*I-(G+B);
17398 }
17399 R*=255; G*=255; B*=255;
17400 *(p1++) = (T)(R<0?0:(R>255?255:R));
17401 *(p2++) = (T)(G<0?0:(G>255?255:G));
17402 *(p3++) = (T)(B<0?0:(B>255?255:B));
17403 }
17404 return *this;
17405 }
17407 CImg<Tfloat> get_HSItoRGB() const {
17408 return CImg< Tuchar>(*this,false).HSItoRGB();
17409 }
17411 //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
17412 CImg<T>& RGBtoYCbCr() {
17413 if (is_empty()) return *this;
17414 if (dim!=3)
17415 throw CImgInstanceException("CImg<%s>::RGBtoYCbCr() : Input image dimension is dim=%u, "
17416 "should be a (R,G,B) image (dim=3)",
17417 pixel_type(),dim);
17418 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17419 for (unsigned long N = width*height*depth; N; --N) {
17420 const Tfloat
17421 R = (Tfloat)*p1,
17422 G = (Tfloat)*p2,
17423 B = (Tfloat)*p3,
17424 Y = (66*R + 129*G + 25*B + 128)/256 + 16,
17425 Cb = (-38*R - 74*G + 112*B + 128)/256 + 128,
17426 Cr = (112*R - 94*G - 18*B + 128)/256 + 128;
17427 *(p1++) = (T)(Y<0?0:(Y>255?255:Y));
17428 *(p2++) = (T)(Cb<0?0:(Cb>255?255:Cb));
17429 *(p3++) = (T)(Cr<0?0:(Cr>255?255:Cr));
17430 }
17431 return *this;
17432 }
17434 CImg<Tuchar> get_RGBtoYCbCr() const {
17435 return CImg<Tuchar>(*this,false).RGBtoYCbCr();
17436 }
17438 //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
17439 CImg<T>& YCbCrtoRGB() {
17440 if (is_empty()) return *this;
17441 if (dim!=3)
17442 throw CImgInstanceException("CImg<%s>::YCbCrtoRGB() : Input image dimension is dim=%u, "
17443 "should be a (Y,Cb,Cr)_8 image (dim=3)",
17444 pixel_type(),dim);
17445 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17446 for (unsigned long N = width*height*depth; N; --N) {
17447 const Tfloat
17448 Y = (Tfloat)*p1 - 16,
17449 Cb = (Tfloat)*p2 - 128,
17450 Cr = (Tfloat)*p3 - 128,
17451 R = (298*Y + 409*Cr + 128)/256,
17452 G = (298*Y - 100*Cb - 208*Cr + 128)/256,
17453 B = (298*Y + 516*Cb + 128)/256;
17454 *(p1++) = (T)(R<0?0:(R>255?255:R));
17455 *(p2++) = (T)(G<0?0:(G>255?255:G));
17456 *(p3++) = (T)(B<0?0:(B>255?255:B));
17457 }
17458 return *this;
17459 }
17461 CImg<Tuchar> get_YCbCrtoRGB() const {
17462 return CImg<Tuchar>(*this,false).YCbCrtoRGB();
17463 }
17465 //! Convert color pixels from (R,G,B) to (Y,U,V).
17466 CImg<T>& RGBtoYUV() {
17467 if (is_empty()) return *this;
17468 if (dim!=3)
17469 throw CImgInstanceException("CImg<%s>::RGBtoYUV() : Input image dimension is dim=%u, "
17470 "should be a (R,G,B) image (dim=3)",
17471 pixel_type(),dim);
17472 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17473 for (unsigned long N = width*height*depth; N; --N) {
17474 const Tfloat
17475 R = (Tfloat)*p1/255,
17476 G = (Tfloat)*p2/255,
17477 B = (Tfloat)*p3/255,
17478 Y = 0.299f*R + 0.587f*G + 0.114f*B;
17479 *(p1++) = (T)Y;
17480 *(p2++) = (T)(0.492f*(B-Y));
17481 *(p3++) = (T)(0.877*(R-Y));
17482 }
17483 return *this;
17484 }
17486 CImg<Tfloat> get_RGBtoYUV() const {
17487 return CImg<Tfloat>(*this,false).RGBtoYUV();
17488 }
17490 //! Convert color pixels from (Y,U,V) to (R,G,B).
17491 CImg<T>& YUVtoRGB() {
17492 if (is_empty()) return *this;
17493 if (dim!=3)
17494 throw CImgInstanceException("CImg<%s>::YUVtoRGB() : Input image dimension is dim=%u, "
17495 "should be a (Y,U,V) image (dim=3)",
17496 pixel_type(),dim);
17497 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17498 for (unsigned long N = width*height*depth; N; --N) {
17499 const Tfloat
17500 Y = (Tfloat)*p1,
17501 U = (Tfloat)*p2,
17502 V = (Tfloat)*p3,
17503 R = (Y + 1.140f*V)*255,
17504 G = (Y - 0.395f*U - 0.581f*V)*255,
17505 B = (Y + 2.032f*U)*255;
17506 *(p1++) = (T)(R<0?0:(R>255?255:R));
17507 *(p2++) = (T)(G<0?0:(G>255?255:G));
17508 *(p3++) = (T)(B<0?0:(B>255?255:B));
17509 }
17510 return *this;
17511 }
17513 CImg<Tuchar> get_YUVtoRGB() const {
17514 return CImg< Tuchar>(*this,false).YUVtoRGB();
17515 }
17517 //! Convert color pixels from (R,G,B) to (C,M,Y).
17518 CImg<T>& RGBtoCMY() {
17519 if (is_empty()) return *this;
17520 if (dim!=3)
17521 throw CImgInstanceException("CImg<%s>::RGBtoCMY() : Input image dimension is dim=%u, "
17522 "should be a (R,G,B) image (dim=3)",
17523 pixel_type(),dim);
17524 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17525 for (unsigned long N = width*height*depth; N; --N) {
17526 const Tfloat
17527 R = (Tfloat)*p1/255,
17528 G = (Tfloat)*p2/255,
17529 B = (Tfloat)*p3/255;
17530 *(p1++) = (T)(1 - R);
17531 *(p2++) = (T)(1 - G);
17532 *(p3++) = (T)(1 - B);
17533 }
17534 return *this;
17535 }
17537 CImg<Tfloat> get_RGBtoCMY() const {
17538 return CImg<Tfloat>(*this,false).RGBtoCMY();
17539 }
17541 //! Convert (C,M,Y) pixels of a color image into the (R,G,B) color space.
17542 CImg<T>& CMYtoRGB() {
17543 if (is_empty()) return *this;
17544 if (dim!=3)
17545 throw CImgInstanceException("CImg<%s>::CMYtoRGB() : Input image dimension is dim=%u, "
17546 "should be a (C,M,Y) image (dim=3)",
17547 pixel_type(),dim);
17548 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17549 for (unsigned long N = width*height*depth; N; --N) {
17550 const Tfloat
17551 C = (Tfloat)*p1,
17552 M = (Tfloat)*p2,
17553 Y = (Tfloat)*p3,
17554 R = 255*(1 - C),
17555 G = 255*(1 - M),
17556 B = 255*(1 - Y);
17557 *(p1++) = (T)(R<0?0:(R>255?255:R));
17558 *(p2++) = (T)(G<0?0:(G>255?255:G));
17559 *(p3++) = (T)(B<0?0:(B>255?255:B));
17560 }
17561 return *this;
17562 }
17564 CImg<Tuchar> get_CMYtoRGB() const {
17565 return CImg<Tuchar>(*this,false).CMYtoRGB();
17566 }
17568 //! Convert color pixels from (C,M,Y) to (C,M,Y,K).
17569 CImg<T>& CMYtoCMYK() {
17570 return get_CMYtoCMYK().transfer_to(*this);
17571 }
17573 CImg<Tfloat> get_CMYtoCMYK() const {
17574 if (is_empty()) return *this;
17575 if (dim!=3)
17576 throw CImgInstanceException("CImg<%s>::CMYtoCMYK() : Input image dimension is dim=%u, "
17577 "should be a (C,M,Y) image (dim=3)",
17578 pixel_type(),dim);
17579 CImg<Tfloat> res(width,height,depth,4);
17580 const T *ps1 = ptr(0,0,0,0), *ps2 = ptr(0,0,0,1), *ps3 = ptr(0,0,0,2);
17581 Tfloat *pd1 = res.ptr(0,0,0,0), *pd2 = res.ptr(0,0,0,1), *pd3 = res.ptr(0,0,0,2), *pd4 = res.ptr(0,0,0,3);
17582 for (unsigned long N = width*height*depth; N; --N) {
17583 Tfloat
17584 C = (Tfloat)*(ps1++),
17585 M = (Tfloat)*(ps2++),
17586 Y = (Tfloat)*(ps3++),
17587 K = cimg::min(C,M,Y);
17588 if (K==1) C = M = Y = 0;
17589 else { const Tfloat K1 = 1 - K; C = (C - K)/K1; M = (M - K)/K1; Y = (Y - K)/K1; }
17590 *(pd1++) = C;
17591 *(pd2++) = M;
17592 *(pd3++) = Y;
17593 *(pd4++) = K;
17594 }
17595 return res;
17596 }
17598 //! Convert (C,M,Y,K) pixels of a color image into the (C,M,Y) color space.
17599 CImg<T>& CMYKtoCMY() {
17600 return get_CMYKtoCMY().transfer_to(*this);
17601 }
17603 CImg<Tfloat> get_CMYKtoCMY() const {
17604 if (is_empty()) return *this;
17605 if (dim!=4)
17606 throw CImgInstanceException("CImg<%s>::CMYKtoCMY() : Input image dimension is dim=%u, "
17607 "should be a (C,M,Y,K) image (dim=4)",
17608 pixel_type(),dim);
17609 CImg<Tfloat> res(width,height,depth,3);
17610 const T *ps1 = ptr(0,0,0,0), *ps2 = ptr(0,0,0,1), *ps3 = ptr(0,0,0,2), *ps4 = ptr(0,0,0,3);
17611 Tfloat *pd1 = res.ptr(0,0,0,0), *pd2 = res.ptr(0,0,0,1), *pd3 = res.ptr(0,0,0,2);
17612 for (unsigned long N = width*height*depth; N; --N) {
17613 const Tfloat
17614 C = (Tfloat)*ps1,
17615 M = (Tfloat)*ps2,
17616 Y = (Tfloat)*ps3,
17617 K = (Tfloat)*ps4,
17618 K1 = 1 - K;
17619 *(pd1++) = C*K1 + K;
17620 *(pd2++) = M*K1 + K;
17621 *(pd3++) = Y*K1 + K;
17622 }
17623 return res;
17624 }
17626 //! Convert color pixels from (R,G,B) to (X,Y,Z)_709.
17627 CImg<T>& RGBtoXYZ() {
17628 if (is_empty()) return *this;
17629 if (dim!=3)
17630 throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, "
17631 "should be a (R,G,B) image (dim=3)",
17632 pixel_type(),dim);
17633 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17634 for (unsigned long N = width*height*depth; N; --N) {
17635 const Tfloat
17636 R = (Tfloat)*p1/255,
17637 G = (Tfloat)*p2/255,
17638 B = (Tfloat)*p3/255;
17639 *(p1++) = (T)(0.412453f*R + 0.357580f*G + 0.180423f*B);
17640 *(p2++) = (T)(0.212671f*R + 0.715160f*G + 0.072169f*B);
17641 *(p3++) = (T)(0.019334f*R + 0.119193f*G + 0.950227f*B);
17642 }
17643 return *this;
17644 }
17646 CImg<Tfloat> get_RGBtoXYZ() const {
17647 return CImg<Tfloat>(*this,false).RGBtoXYZ();
17648 }
17650 //! Convert (X,Y,Z)_709 pixels of a color image into the (R,G,B) color space.
17651 CImg<T>& XYZtoRGB() {
17652 if (is_empty()) return *this;
17653 if (dim!=3)
17654 throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, "
17655 "should be a (X,Y,Z) image (dim=3)",
17656 pixel_type(),dim);
17657 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17658 for (unsigned long N = width*height*depth; N; --N) {
17659 const Tfloat
17660 X = (Tfloat)*p1*255,
17661 Y = (Tfloat)*p2*255,
17662 Z = (Tfloat)*p3*255,
17663 R = 3.240479f*X - 1.537150f*Y - 0.498535f*Z,
17664 G = -0.969256f*X + 1.875992f*Y + 0.041556f*Z,
17665 B = 0.055648f*X - 0.204043f*Y + 1.057311f*Z;
17666 *(p1++) = (T)(R<0?0:(R>255?255:R));
17667 *(p2++) = (T)(G<0?0:(G>255?255:G));
17668 *(p3++) = (T)(B<0?0:(B>255?255:B));
17669 }
17670 return *this;
17671 }
17673 CImg<Tuchar> get_XYZtoRGB() const {
17674 return CImg<Tuchar>(*this,false).XYZtoRGB();
17675 }
17677 //! Convert (X,Y,Z)_709 pixels of a color image into the (L*,a*,b*) color space.
17678 CImg<T>& XYZtoLab() {
17679 #define _cimg_Labf(x) ((x)>=0.008856f?(cimg_std::pow(x,(Tfloat)1/3)):(7.787f*(x)+16.0f/116))
17680 if (is_empty()) return *this;
17681 if (dim!=3)
17682 throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, "
17683 "should be a (X,Y,Z) image (dim=3)",
17684 pixel_type(),dim);
17685 const Tfloat
17686 Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
17687 Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
17688 Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
17689 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17690 for (unsigned long N = width*height*depth; N; --N) {
17691 const Tfloat
17692 X = (Tfloat)*p1,
17693 Y = (Tfloat)*p2,
17694 Z = (Tfloat)*p3,
17695 XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn,
17696 fX = (Tfloat)_cimg_Labf(XXn),
17697 fY = (Tfloat)_cimg_Labf(YYn),
17698 fZ = (Tfloat)_cimg_Labf(ZZn);
17699 *(p1++) = (T)(116*fY - 16);
17700 *(p2++) = (T)(500*(fX - fY));
17701 *(p3++) = (T)(200*(fY - fZ));
17702 }
17703 return *this;
17704 }
17706 CImg<Tfloat> get_XYZtoLab() const {
17707 return CImg<Tfloat>(*this,false).XYZtoLab();
17708 }
17710 //! Convert (L,a,b) pixels of a color image into the (X,Y,Z) color space.
17711 CImg<T>& LabtoXYZ() {
17712 #define _cimg_Labfi(x) ((x)>=0.206893f?((x)*(x)*(x)):(((x)-16.0f/116)/7.787f))
17713 if (is_empty()) return *this;
17714 if (dim!=3)
17715 throw CImgInstanceException("CImg<%s>::LabtoXYZ() : Input image dimension is dim=%u, "
17716 "should be a (X,Y,Z) image (dim=3)",
17717 pixel_type(),dim);
17718 const Tfloat
17719 Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
17720 Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
17721 Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
17722 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17723 for (unsigned long N = width*height*depth; N; --N) {
17724 const Tfloat
17725 L = (Tfloat)*p1,
17726 a = (Tfloat)*p2,
17727 b = (Tfloat)*p3,
17728 cY = (L + 16)/116,
17729 Y = (Tfloat)(Yn*_cimg_Labfi(cY)),
17730 pY = (Tfloat)cimg_std::pow(Y/Yn,(Tfloat)1/3),
17731 cX = a/500 + pY,
17732 X = Xn*cX*cX*cX,
17733 cZ = pY - b/200,
17734 Z = Zn*cZ*cZ*cZ;
17735 *(p1++) = (T)(X);
17736 *(p2++) = (T)(Y);
17737 *(p3++) = (T)(Z);
17738 }
17739 return *this;
17740 }
17742 CImg<Tfloat> get_LabtoXYZ() const {
17743 return CImg<Tfloat>(*this,false).LabtoXYZ();
17744 }
17746 //! Convert (X,Y,Z)_709 pixels of a color image into the (x,y,Y) color space.
17747 CImg<T>& XYZtoxyY() {
17748 if (is_empty()) return *this;
17749 if (dim!=3)
17750 throw CImgInstanceException("CImg<%s>::XYZtoxyY() : Input image dimension is dim=%u, "
17751 "should be a (X,Y,Z) image (dim=3)",
17752 pixel_type(),dim);
17753 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17754 for (unsigned long N = width*height*depth; N; --N) {
17755 const Tfloat
17756 X = (Tfloat)*p1,
17757 Y = (Tfloat)*p2,
17758 Z = (Tfloat)*p3,
17759 sum = (X+Y+Z),
17760 nsum = sum>0?sum:1;
17761 *(p1++) = (T)(X/nsum);
17762 *(p2++) = (T)(Y/nsum);
17763 *(p3++) = (T)Y;
17764 }
17765 return *this;
17766 }
17768 CImg<Tfloat> get_XYZtoxyY() const {
17769 return CImg<Tfloat>(*this,false).XYZtoxyY();
17770 }
17772 //! Convert (x,y,Y) pixels of a color image into the (X,Y,Z)_709 color space.
17773 CImg<T>& xyYtoXYZ() {
17774 if (is_empty()) return *this;
17775 if (dim!=3)
17776 throw CImgInstanceException("CImg<%s>::xyYtoXYZ() : Input image dimension is dim=%u, "
17777 "should be a (x,y,Y) image (dim=3)",
17778 pixel_type(),dim);
17779 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
17780 for (unsigned long N = width*height*depth; N; --N) {
17781 const Tfloat
17782 px = (Tfloat)*p1,
17783 py = (Tfloat)*p2,
17784 Y = (Tfloat)*p3,
17785 ny = py>0?py:1;
17786 *(p1++) = (T)(px*Y/ny);
17787 *(p2++) = (T)Y;
17788 *(p3++) = (T)((1-px-py)*Y/ny);
17789 }
17790 return *this;
17791 }
17793 CImg<Tfloat> get_xyYtoXYZ() const {
17794 return CImg<Tfloat>(*this,false).xyYtoXYZ();
17795 }
17797 //! Convert a (R,G,B) image to a (L,a,b) one.
17798 CImg<T>& RGBtoLab() {
17799 return RGBtoXYZ().XYZtoLab();
17800 }
17802 CImg<Tfloat> get_RGBtoLab() const {
17803 return CImg<Tfloat>(*this,false).RGBtoLab();
17804 }
17806 //! Convert a (L,a,b) image to a (R,G,B) one.
17807 CImg<T>& LabtoRGB() {
17808 return LabtoXYZ().XYZtoRGB();
17809 }
17811 CImg<Tuchar> get_LabtoRGB() const {
17812 return CImg<Tuchar>(*this,false).LabtoRGB();
17813 }
17815 //! Convert a (R,G,B) image to a (x,y,Y) one.
17816 CImg<T>& RGBtoxyY() {
17817 return RGBtoXYZ().XYZtoxyY();
17818 }
17820 CImg<Tfloat> get_RGBtoxyY() const {
17821 return CImg<Tfloat>(*this,false).RGBtoxyY();
17822 }
17824 //! Convert a (x,y,Y) image to a (R,G,B) one.
17825 CImg<T>& xyYtoRGB() {
17826 return xyYtoXYZ().XYZtoRGB();
17827 }
17829 CImg<Tuchar> get_xyYtoRGB() const {
17830 return CImg<Tuchar>(*this,false).xyYtoRGB();
17831 }
17833 //! Convert a (R,G,B) image to a (C,M,Y,K) one.
17834 CImg<T>& RGBtoCMYK() {
17835 return RGBtoCMY().CMYtoCMYK();
17836 }
17838 CImg<Tfloat> get_RGBtoCMYK() const {
17839 return CImg<Tfloat>(*this,false).RGBtoCMYK();
17840 }
17842 //! Convert a (C,M,Y,K) image to a (R,G,B) one.
17843 CImg<T>& CMYKtoRGB() {
17844 return CMYKtoCMY().CMYtoRGB();
17845 }
17847 CImg<Tuchar> get_CMYKtoRGB() const {
17848 return CImg<Tuchar>(*this,false).CMYKtoRGB();
17849 }
17851 //! Convert a (R,G,B) image to a Bayer-coded representation.
17852 /**
17853 \note First (upper-left) pixel if the red component of the pixel color.
17854 **/
17855 CImg<T>& RGBtoBayer() {
17856 return get_RGBtoBayer().transfer_to(*this);
17857 }
17859 CImg<T> get_RGBtoBayer() const {
17860 if (is_empty()) return *this;
17861 if (dim!=3)
17862 throw CImgInstanceException("CImg<%s>::RGBtoBayer() : Input image dimension is dim=%u, "
17863 "should be a (R,G,B) image (dim=3)",
17864 pixel_type(),dim);
17865 CImg<T> res(width,height,depth,1);
17866 const T *pR = ptr(0,0,0,0), *pG = ptr(0,0,0,1), *pB = ptr(0,0,0,2);
17867 T *ptrd = res.data;
17868 cimg_forXYZ(*this,x,y,z) {
17869 if (y%2) {
17870 if (x%2) *(ptrd++) = *pB;
17871 else *(ptrd++) = *pG;
17872 } else {
17873 if (x%2) *(ptrd++) = *pG;
17874 else *(ptrd++) = *pR;
17875 }
17876 ++pR; ++pG; ++pB;
17877 }
17878 return res;
17879 }
17881 //! Convert a Bayer-coded image to a (R,G,B) color image.
17882 CImg<T>& BayertoRGB(const unsigned int interpolation_type=3) {
17883 return get_BayertoRGB(interpolation_type).transfer_to(*this);
17884 }
17886 CImg<Tuchar> get_BayertoRGB(const unsigned int interpolation_type=3) const {
17887 if (is_empty()) return *this;
17888 if (dim!=1)
17889 throw CImgInstanceException("CImg<%s>::BayertoRGB() : Input image dimension is dim=%u, "
17890 "should be a Bayer image (dim=1)",
17891 pixel_type(),dim);
17892 CImg<Tuchar> res(width,height,depth,3);
17893 CImg_3x3(I,T);
17894 Tuchar *pR = res.ptr(0,0,0,0), *pG = res.ptr(0,0,0,1), *pB = res.ptr(0,0,0,2);
17895 switch (interpolation_type) {
17896 case 3 : { // Edge-directed
17897 CImg_3x3(R,T);
17898 CImg_3x3(G,T);
17899 CImg_3x3(B,T);
17900 cimg_forXYZ(*this,x,y,z) {
17901 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
17902 cimg_get3x3(*this,x,y,z,0,I);
17903 if (y%2) {
17904 if (x%2) {
17905 const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
17906 *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
17907 } else *pG = (Tuchar)Icc;
17908 } else {
17909 if (x%2) *pG = (Tuchar)Icc;
17910 else {
17911 const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
17912 *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
17913 }
17914 }
17915 ++pG;
17916 }
17917 cimg_forXYZ(*this,x,y,z) {
17918 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
17919 cimg_get3x3(*this,x,y,z,0,I);
17920 cimg_get3x3(res,x,y,z,1,G);
17921 if (y%2) {
17922 if (x%2) *pB = (Tuchar)Icc;
17923 else { *pR = (Tuchar)((Icn+Icp)/2); *pB = (Tuchar)((Inc+Ipc)/2); }
17924 } else {
17925 if (x%2) { *pR = (Tuchar)((Inc+Ipc)/2); *pB = (Tuchar)((Icn+Icp)/2); }
17926 else *pR = (Tuchar)Icc;
17927 }
17928 ++pR; ++pB;
17929 }
17930 pR = res.ptr(0,0,0,0);
17931 pG = res.ptr(0,0,0,1);
17932 pB = res.ptr(0,0,0,2);
17933 cimg_forXYZ(*this,x,y,z) {
17934 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
17935 cimg_get3x3(res,x,y,z,0,R);
17936 cimg_get3x3(res,x,y,z,1,G);
17937 cimg_get3x3(res,x,y,z,2,B);
17938 if (y%2) {
17939 if (x%2) {
17940 const float alpha = (float)cimg::sqr(Rnc-Rpc), beta = (float)cimg::sqr(Rcn-Rcp), cx = 1/(1+alpha), cy = 1/(1+beta);
17941 *pR = (Tuchar)((cx*(Rnc+Rpc) + cy*(Rcn+Rcp))/(2*(cx+cy)));
17942 }
17943 } else {
17944 if (!(x%2)) {
17945 const float alpha = (float)cimg::sqr(Bnc-Bpc), beta = (float)cimg::sqr(Bcn-Bcp), cx = 1/(1+alpha), cy = 1/(1+beta);
17946 *pB = (Tuchar)((cx*(Bnc+Bpc) + cy*(Bcn+Bcp))/(2*(cx+cy)));
17947 }
17948 }
17949 ++pR; ++pG; ++pB;
17950 }
17951 } break;
17952 case 2 : { // Linear interpolation
17953 cimg_forXYZ(*this,x,y,z) {
17954 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
17955 cimg_get3x3(*this,x,y,z,0,I);
17956 if (y%2) {
17957 if (x%2) { *pR = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)Icc; }
17958 else { *pR = (Tuchar)((Icp+Icn)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Inc+Ipc)/2); }
17959 } else {
17960 if (x%2) { *pR = (Tuchar)((Ipc+Inc)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Icn+Icp)/2); }
17961 else { *pR = (Tuchar)Icc; *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); }
17962 }
17963 ++pR; ++pG; ++pB;
17964 }
17965 } break;
17966 case 1 : { // Nearest neighbor interpolation
17967 cimg_forXYZ(*this,x,y,z) {
17968 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
17969 cimg_get3x3(*this,x,y,z,0,I);
17970 if (y%2) {
17971 if (x%2) { *pR = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)Icc; }
17972 else { *pR = (Tuchar)cimg::min(Icn,Icp); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Inc,Ipc); }
17973 } else {
17974 if (x%2) { *pR = (Tuchar)cimg::min(Inc,Ipc); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Icn,Icp); }
17975 else { *pR = (Tuchar)Icc; *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); }
17976 }
17977 ++pR; ++pG; ++pB;
17978 }
17979 } break;
17980 default : { // 0-filling interpolation
17981 const T *ptrs = data;
17982 res.fill(0);
17983 cimg_forXYZ(*this,x,y,z) {
17984 const T val = *(ptrs++);
17985 if (y%2) { if (x%2) *pB = val; else *pG = val; } else { if (x%2) *pG = val; else *pR = val; }
17986 ++pR; ++pG; ++pB;
17987 }
17988 }
17989 }
17990 return res;
17991 }
17993 //@}
17994 //-------------------
17995 //
17996 //! \name Drawing
17997 //@{
17998 //-------------------
18000 // The following _draw_scanline() routines are *non user-friendly functions*, used only for internal purpose.
18001 // Pre-requisites : x0<x1, y-coordinate is valid, col is valid.
18002 template<typename tc>
18003 CImg<T>& _draw_scanline(const int x0, const int x1, const int y,
18004 const tc *const color, const float opacity=1,
18005 const float brightness=1, const bool init=false) {
18006 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
18007 static float nopacity = 0, copacity = 0;
18008 static unsigned int whz = 0;
18009 static const tc *col = 0;
18010 if (init) {
18011 nopacity = cimg::abs(opacity);
18012 copacity = 1 - cimg::max(opacity,0);
18013 whz = width*height*depth;
18014 } else {
18015 const int nx0 = x0>0?x0:0, nx1 = x1<dimx()?x1:dimx()-1, dx = nx1 - nx0;
18016 if (dx>=0) {
18017 col = color;
18018 const unsigned int off = whz-dx-1;
18019 T *ptrd = ptr(nx0,y);
18020 if (opacity>=1) { // ** Opaque drawing **
18021 if (brightness==1) { // Brightness==1
18022 if (sizeof(T)!=1) cimg_forV(*this,k) {
18023 const T val = (T)*(col++);
18024 for (int x = dx; x>=0; --x) *(ptrd++) = val;
18025 ptrd+=off;
18026 } else cimg_forV(*this,k) {
18027 const T val = (T)*(col++);
18028 cimg_std::memset(ptrd,(int)val,dx+1);
18029 ptrd+=whz;
18030 }
18031 } else if (brightness<1) { // Brightness<1
18032 if (sizeof(T)!=1) cimg_forV(*this,k) {
18033 const T val = (T)(*(col++)*brightness);
18034 for (int x = dx; x>=0; --x) *(ptrd++) = val;
18035 ptrd+=off;
18036 } else cimg_forV(*this,k) {
18037 const T val = (T)(*(col++)*brightness);
18038 cimg_std::memset(ptrd,(int)val,dx+1);
18039 ptrd+=whz;
18040 }
18041 } else { // Brightness>1
18042 if (sizeof(T)!=1) cimg_forV(*this,k) {
18043 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
18044 for (int x = dx; x>=0; --x) *(ptrd++) = val;
18045 ptrd+=off;
18046 } else cimg_forV(*this,k) {
18047 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
18048 cimg_std::memset(ptrd,(int)val,dx+1);
18049 ptrd+=whz;
18050 }
18051 }
18052 } else { // ** Transparent drawing **
18053 if (brightness==1) { // Brightness==1
18054 cimg_forV(*this,k) {
18055 const T val = (T)*(col++);
18056 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
18057 ptrd+=off;
18058 }
18059 } else if (brightness<=1) { // Brightness<1
18060 cimg_forV(*this,k) {
18061 const T val = (T)(*(col++)*brightness);
18062 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
18063 ptrd+=off;
18064 }
18065 } else { // Brightness>1
18066 cimg_forV(*this,k) {
18067 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
18068 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
18069 ptrd+=off;
18070 }
18071 }
18072 }
18073 }
18074 }
18075 return *this;
18076 }
18078 template<typename tc>
18079 CImg<T>& _draw_scanline(const tc *const color, const float opacity=1) {
18080 return _draw_scanline(0,0,0,color,opacity,0,true);
18081 }
18083 //! Draw a 2D colored point (pixel).
18084 /**
18085 \param x0 X-coordinate of the point.
18086 \param y0 Y-coordinate of the point.
18087 \param color Pointer to \c dimv() consecutive values, defining the color values.
18088 \param opacity Drawing opacity (optional).
18089 \note
18090 - Clipping is supported.
18091 - To set pixel values without clipping needs, you should use the faster CImg::operator()() function.
18092 \par Example:
18093 \code
18094 CImg<unsigned char> img(100,100,1,3,0);
18095 const unsigned char color[] = { 255,128,64 };
18096 img.draw_point(50,50,color);
18097 \endcode
18098 **/
18099 template<typename tc>
18100 CImg<T>& draw_point(const int x0, const int y0,
18101 const tc *const color, const float opacity=1) {
18102 return draw_point(x0,y0,0,color,opacity);
18103 }
18105 //! Draw a 2D colored point (pixel).
18106 template<typename tc>
18107 CImg<T>& draw_point(const int x0, const int y0,
18108 const CImg<tc>& color, const float opacity=1) {
18109 return draw_point(x0,y0,color.data,opacity);
18110 }
18112 //! Draw a 3D colored point (voxel).
18113 template<typename tc>
18114 CImg<T>& draw_point(const int x0, const int y0, const int z0,
18115 const tc *const color, const float opacity=1) {
18116 if (is_empty()) return *this;
18117 if (!color)
18118 throw CImgArgumentException("CImg<%s>::draw_point() : Specified color is (null)",
18119 pixel_type());
18120 if (x0>=0 && y0>=0 && z0>=0 && x0<dimx() && y0<dimy() && z0<dimz()) {
18121 const unsigned int whz = width*height*depth;
18122 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18123 T *ptrd = ptr(x0,y0,z0,0);
18124 const tc *col = color;
18125 if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
18126 else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
18127 }
18128 return *this;
18129 }
18131 //! Draw a 3D colored point (voxel).
18132 template<typename tc>
18133 CImg<T>& draw_point(const int x0, const int y0, const int z0,
18134 const CImg<tc>& color, const float opacity=1) {
18135 return draw_point(x0,y0,z0,color.data,opacity);
18136 }
18138 // Draw a cloud of colored point (internal).
18139 template<typename t, typename tc>
18140 CImg<T>& _draw_point(const t& points, const unsigned int W, const unsigned int H,
18141 const tc *const color, const float opacity) {
18142 if (is_empty() || !points || !W) return *this;
18143 switch (H) {
18144 case 0 : case 1 :
18145 throw CImgArgumentException("CImg<%s>::draw_point() : Given list of points is not valid.",
18146 pixel_type());
18147 case 2 : {
18148 for (unsigned int i = 0; i<W; ++i) {
18149 const int x = (int)points(i,0), y = (int)points(i,1);
18150 draw_point(x,y,color,opacity);
18151 }
18152 } break;
18153 default : {
18154 for (unsigned int i = 0; i<W; ++i) {
18155 const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
18156 draw_point(x,y,z,color,opacity);
18157 }
18158 }
18159 }
18160 return *this;
18161 }
18163 //! Draw a cloud of colored points.
18164 /**
18165 \param points Coordinates of vertices, stored as a list of vectors.
18166 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
18167 \param opacity Drawing opacity (optional).
18168 \note
18169 - This function uses several call to the single CImg::draw_point() procedure,
18170 depending on the vectors size in \p points.
18171 \par Example:
18172 \code
18173 CImg<unsigned char> img(100,100,1,3,0);
18174 const unsigned char color[] = { 255,128,64 };
18175 CImgList<int> points;
18176 points.insert(CImg<int>::vector(0,0)).
18177 .insert(CImg<int>::vector(70,10)).
18178 .insert(CImg<int>::vector(80,60)).
18179 .insert(CImg<int>::vector(10,90));
18180 img.draw_point(points,color);
18181 \endcode
18182 **/
18183 template<typename t, typename tc>
18184 CImg<T>& draw_point(const CImgList<t>& points,
18185 const tc *const color, const float opacity=1) {
18186 unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
18187 return _draw_point(points,points.size,H,color,opacity);
18188 }
18190 //! Draw a cloud of colored points.
18191 template<typename t, typename tc>
18192 CImg<T>& draw_point(const CImgList<t>& points,
18193 const CImg<tc>& color, const float opacity=1) {
18194 return draw_point(points,color.data,opacity);
18195 }
18197 //! Draw a cloud of colored points.
18198 /**
18199 \note
18200 - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
18201 (sequence of vectors aligned along the x-axis).
18202 **/
18203 template<typename t, typename tc>
18204 CImg<T>& draw_point(const CImg<t>& points,
18205 const tc *const color, const float opacity=1) {
18206 return _draw_point(points,points.width,points.height,color,opacity);
18207 }
18209 //! Draw a cloud of colored points.
18210 template<typename t, typename tc>
18211 CImg<T>& draw_point(const CImg<t>& points,
18212 const CImg<tc>& color, const float opacity=1) {
18213 return draw_point(points,color.data,opacity);
18214 }
18216 //! Draw a 2D colored line.
18217 /**
18218 \param x0 X-coordinate of the starting line point.
18219 \param y0 Y-coordinate of the starting line point.
18220 \param x1 X-coordinate of the ending line point.
18221 \param y1 Y-coordinate of the ending line point.
18222 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
18223 \param opacity Drawing opacity (optional).
18224 \param pattern An integer whose bits describe the line pattern (optional).
18225 \param init_hatch Flag telling if a reinitialization of the hash state must be done (optional).
18226 \note
18227 - Clipping is supported.
18228 - Line routine uses Bresenham's algorithm.
18229 - Set \p init_hatch = false to draw consecutive hatched segments without breaking the line pattern.
18230 \par Example:
18231 \code
18232 CImg<unsigned char> img(100,100,1,3,0);
18233 const unsigned char color[] = { 255,128,64 };
18234 img.draw_line(40,40,80,70,color);
18235 \endcode
18236 **/
18237 template<typename tc>
18238 CImg<T>& draw_line(const int x0, const int y0,
18239 const int x1, const int y1,
18240 const tc *const color, const float opacity=1,
18241 const unsigned int pattern=~0U, const bool init_hatch=true) {
18242 if (is_empty()) return *this;
18243 if (!color)
18244 throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
18245 pixel_type());
18246 static unsigned int hatch = ~0U - (~0U>>1);
18247 if (init_hatch) hatch = ~0U - (~0U>>1);
18248 const bool xdir = x0<x1, ydir = y0<y1;
18249 int
18250 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
18251 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
18252 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
18253 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
18254 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
18255 if (xright<0 || xleft>=dimx()) return *this;
18256 if (xleft<0) { yleft-=xleft*(yright - yleft)/(xright - xleft); xleft = 0; }
18257 if (xright>=dimx()) { yright-=(xright - dimx())*(yright - yleft)/(xright - xleft); xright = dimx()-1; }
18258 if (ydown<0 || yup>=dimy()) return *this;
18259 if (yup<0) { xup-=yup*(xdown - xup)/(ydown - yup); yup = 0; }
18260 if (ydown>=dimy()) { xdown-=(ydown - dimy())*(xdown - xup)/(ydown - yup); ydown = dimy()-1; }
18261 T *ptrd0 = ptr(nx0,ny0);
18262 int dx = xright - xleft, dy = ydown - yup;
18263 const bool steep = dy>dx;
18264 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
18265 const int
18266 offx = (nx0<nx1?1:-1)*(steep?width:1),
18267 offy = (ny0<ny1?1:-1)*(steep?1:width),
18268 wh = width*height;
18269 if (opacity>=1) {
18270 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18271 if (pattern&hatch) { T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }}
18272 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18273 ptrd0+=offx;
18274 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18275 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18276 T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
18277 ptrd0+=offx;
18278 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18279 }
18280 } else {
18281 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18282 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18283 if (pattern&hatch) {
18284 T *ptrd = ptrd0; const tc* col = color;
18285 cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
18286 }
18287 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18288 ptrd0+=offx;
18289 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18290 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18291 T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
18292 ptrd0+=offx;
18293 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18294 }
18295 }
18296 return *this;
18297 }
18299 //! Draw a 2D colored line.
18300 template<typename tc>
18301 CImg<T>& draw_line(const int x0, const int y0,
18302 const int x1, const int y1,
18303 const CImg<tc>& color, const float opacity=1,
18304 const unsigned int pattern=~0U, const bool init_hatch=true) {
18305 return draw_line(x0,y0,x1,y1,color.data,opacity,pattern,init_hatch);
18306 }
18308 //! Draw a 2D colored line, with z-buffering.
18309 template<typename tc>
18310 CImg<T>& draw_line(float *const zbuffer,
18311 const int x0, const int y0, const float z0,
18312 const int x1, const int y1, const float z1,
18313 const tc *const color, const float opacity=1,
18314 const unsigned int pattern=~0U, const bool init_hatch=true) {
18315 if (!is_empty() && z0>0 && z1>0) {
18316 if (!color)
18317 throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null).",
18318 pixel_type());
18319 static unsigned int hatch = ~0U - (~0U>>1);
18320 if (init_hatch) hatch = ~0U - (~0U>>1);
18321 const bool xdir = x0<x1, ydir = y0<y1;
18322 int
18323 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
18324 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
18325 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
18326 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
18327 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
18328 float
18329 Z0 = 1/z0, Z1 = 1/z1, nz0 = Z0, nz1 = Z1, dz = Z1 - Z0,
18330 &zleft = xdir?nz0:nz1,
18331 &zright = xdir?nz1:nz0,
18332 &zup = ydir?nz0:nz1,
18333 &zdown = ydir?nz1:nz0;
18334 if (xright<0 || xleft>=dimx()) return *this;
18335 if (xleft<0) {
18336 const int D = xright - xleft;
18337 yleft-=xleft*(yright - yleft)/D;
18338 zleft-=xleft*(zright - zleft)/D;
18339 xleft = 0;
18340 }
18341 if (xright>=dimx()) {
18342 const int d = xright - dimx(), D = xright - xleft;
18343 yright-=d*(yright - yleft)/D;
18344 zright-=d*(zright - zleft)/D;
18345 xright = dimx()-1;
18346 }
18347 if (ydown<0 || yup>=dimy()) return *this;
18348 if (yup<0) {
18349 const int D = ydown - yup;
18350 xup-=yup*(xdown - xup)/D;
18351 zup-=yup*(zdown - zup)/D;
18352 yup = 0;
18353 }
18354 if (ydown>=dimy()) {
18355 const int d = ydown - dimy(), D = ydown - yup;
18356 xdown-=d*(xdown - xup)/D;
18357 zdown-=d*(zdown - zup)/D;
18358 ydown = dimy()-1;
18359 }
18360 T *ptrd0 = ptr(nx0,ny0);
18361 float *ptrz = zbuffer + nx0 + ny0*width;
18362 int dx = xright - xleft, dy = ydown - yup;
18363 const bool steep = dy>dx;
18364 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
18365 const int
18366 offx = (nx0<nx1?1:-1)*(steep?width:1),
18367 offy = (ny0<ny1?1:-1)*(steep?1:width),
18368 wh = width*height,
18369 ndx = dx>0?dx:1;
18370 if (opacity>=1) {
18371 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18372 const float z = Z0 + x*dz/ndx;
18373 if (z>*ptrz && pattern&hatch) {
18374 *ptrz = z;
18375 T *ptrd = ptrd0; const tc *col = color;
18376 cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
18377 }
18378 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18379 ptrd0+=offx; ptrz+=offx;
18380 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18381 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18382 const float z = Z0 + x*dz/ndx;
18383 if (z>*ptrz) {
18384 *ptrz = z;
18385 T *ptrd = ptrd0; const tc *col = color;
18386 cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
18387 }
18388 ptrd0+=offx; ptrz+=offx;
18389 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18390 }
18391 } else {
18392 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18393 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18394 const float z = Z0 + x*dz/ndx;
18395 if (z>*ptrz && pattern&hatch) {
18396 *ptrz = z;
18397 T *ptrd = ptrd0; const tc *col = color;
18398 cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
18399 }
18400 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18401 ptrd0+=offx; ptrz+=offx;
18402 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18403 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18404 const float z = Z0 + x*dz/ndx;
18405 if (z>*ptrz) {
18406 *ptrz = z;
18407 T *ptrd = ptrd0; const tc *col = color;
18408 cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
18409 }
18410 ptrd0+=offx; ptrz+=offx;
18411 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18412 }
18413 }
18414 }
18415 return *this;
18416 }
18418 //! Draw a 2D colored line, with z-buffering.
18419 template<typename tc>
18420 CImg<T>& draw_line(float *const zbuffer,
18421 const int x0, const int y0, const float z0,
18422 const int x1, const int y1, const float z1,
18423 const CImg<tc>& color, const float opacity=1,
18424 const unsigned int pattern=~0U, const bool init_hatch=true) {
18425 return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
18426 }
18428 //! Draw a 3D colored line.
18429 template<typename tc>
18430 CImg<T>& draw_line(const int x0, const int y0, const int z0,
18431 const int x1, const int y1, const int z1,
18432 const tc *const color, const float opacity=1,
18433 const unsigned int pattern=~0U, const bool init_hatch=true) {
18434 if (is_empty()) return *this;
18435 if (!color)
18436 throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
18437 pixel_type());
18438 static unsigned int hatch = ~0U - (~0U>>1);
18439 if (init_hatch) hatch = ~0U - (~0U>>1);
18440 int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1;
18441 if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
18442 if (nx1<0 || nx0>=dimx()) return *this;
18443 if (nx0<0) { const int D = 1 + nx1 - nx0; ny0-=nx0*(1 + ny1 - ny0)/D; nz0-=nx0*(1 + nz1 - nz0)/D; nx0 = 0; }
18444 if (nx1>=dimx()) { const int d = nx1-dimx(), D = 1 + nx1 - nx0; ny1+=d*(1 + ny0 - ny1)/D; nz1+=d*(1 + nz0 - nz1)/D; nx1 = dimx()-1; }
18445 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
18446 if (ny1<0 || ny0>=dimy()) return *this;
18447 if (ny0<0) { const int D = 1 + ny1 - ny0; nx0-=ny0*(1 + nx1 - nx0)/D; nz0-=ny0*(1 + nz1 - nz0)/D; ny0 = 0; }
18448 if (ny1>=dimy()) { const int d = ny1-dimy(), D = 1 + ny1 - ny0; nx1+=d*(1 + nx0 - nx1)/D; nz1+=d*(1 + nz0 - nz1)/D; ny1 = dimy()-1; }
18449 if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
18450 if (nz1<0 || nz0>=dimz()) return *this;
18451 if (nz0<0) { const int D = 1 + nz1 - nz0; nx0-=nz0*(1 + nx1 - nx0)/D; ny0-=nz0*(1 + ny1 - ny0)/D; nz0 = 0; }
18452 if (nz1>=dimz()) { const int d = nz1-dimz(), D = 1 + nz1 - nz0; nx1+=d*(1 + nx0 - nx1)/D; ny1+=d*(1 + ny0 - ny1)/D; nz1 = dimz()-1; }
18453 const unsigned int dmax = cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0), whz = width*height*depth;
18454 const float px = (nx1 - nx0)/(float)dmax, py = (ny1 - ny0)/(float)dmax, pz = (nz1 - nz0)/(float)dmax;
18455 float x = (float)nx0, y = (float)ny0, z = (float)nz0;
18456 if (opacity>=1) for (unsigned int t = 0; t<=dmax; ++t) {
18457 if (!(~pattern) || (~pattern && pattern&hatch)) {
18458 T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
18459 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
18460 }
18461 x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
18462 } else {
18463 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18464 for (unsigned int t = 0; t<=dmax; ++t) {
18465 if (!(~pattern) || (~pattern && pattern&hatch)) {
18466 T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
18467 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
18468 }
18469 x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
18470 }
18471 }
18472 return *this;
18473 }
18475 //! Draw a 3D colored line.
18476 template<typename tc>
18477 CImg<T>& draw_line(const int x0, const int y0, const int z0,
18478 const int x1, const int y1, const int z1,
18479 const CImg<tc>& color, const float opacity=1,
18480 const unsigned int pattern=~0U, const bool init_hatch=true) {
18481 return draw_line(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
18482 }
18484 //! Draw a 2D textured line.
18485 /**
18486 \param x0 X-coordinate of the starting line point.
18487 \param y0 Y-coordinate of the starting line point.
18488 \param x1 X-coordinate of the ending line point.
18489 \param y1 Y-coordinate of the ending line point.
18490 \param texture Texture image defining the pixel colors.
18491 \param tx0 X-coordinate of the starting texture point.
18492 \param ty0 Y-coordinate of the starting texture point.
18493 \param tx1 X-coordinate of the ending texture point.
18494 \param ty1 Y-coordinate of the ending texture point.
18495 \param opacity Drawing opacity (optional).
18496 \param pattern An integer whose bits describe the line pattern (optional).
18497 \param init_hatch Flag telling if the hash variable must be reinitialized (optional).
18498 \note
18499 - Clipping is supported but not for texture coordinates.
18500 - Line routine uses the well known Bresenham's algorithm.
18501 \par Example:
18502 \code
18503 CImg<unsigned char> img(100,100,1,3,0), texture("texture256x256.ppm");
18504 const unsigned char color[] = { 255,128,64 };
18505 img.draw_line(40,40,80,70,texture,0,0,255,255);
18506 \endcode
18507 **/
18508 template<typename tc>
18509 CImg<T>& draw_line(const int x0, const int y0,
18510 const int x1, const int y1,
18511 const CImg<tc>& texture,
18512 const int tx0, const int ty0,
18513 const int tx1, const int ty1,
18514 const float opacity=1,
18515 const unsigned int pattern=~0U, const bool init_hatch=true) {
18516 if (is_empty()) return *this;
18517 if (!texture || texture.dim<dim)
18518 throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
18519 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
18520 if (is_overlapped(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
18521 static unsigned int hatch = ~0U - (~0U>>1);
18522 if (init_hatch) hatch = ~0U - (~0U>>1);
18523 const bool xdir = x0<x1, ydir = y0<y1;
18524 int
18525 dtx = tx1-tx0, dty = ty1-ty0,
18526 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
18527 tnx0 = tx0, tnx1 = tx1, tny0 = ty0, tny1 = ty1,
18528 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
18529 &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
18530 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0,
18531 &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
18532 if (xright<0 || xleft>=dimx()) return *this;
18533 if (xleft<0) {
18534 const int D = xright - xleft;
18535 yleft-=xleft*(yright - yleft)/D;
18536 txleft-=xleft*(txright - txleft)/D;
18537 tyleft-=xleft*(tyright - tyleft)/D;
18538 xleft = 0;
18539 }
18540 if (xright>=dimx()) {
18541 const int d = xright - dimx(), D = xright - xleft;
18542 yright-=d*(yright - yleft)/D;
18543 txright-=d*(txright - txleft)/D;
18544 tyright-=d*(tyright - tyleft)/D;
18545 xright = dimx()-1;
18546 }
18547 if (ydown<0 || yup>=dimy()) return *this;
18548 if (yup<0) {
18549 const int D = ydown - yup;
18550 xup-=yup*(xdown - xup)/D;
18551 txup-=yup*(txdown - txup)/D;
18552 tyup-=yup*(tydown - tyup)/D;
18553 yup = 0;
18554 }
18555 if (ydown>=dimy()) {
18556 const int d = ydown - dimy(), D = ydown - yup;
18557 xdown-=d*(xdown - xup)/D;
18558 txdown-=d*(txdown - txup)/D;
18559 tydown-=d*(tydown - tyup)/D;
18560 ydown = dimy()-1;
18561 }
18562 T *ptrd0 = ptr(nx0,ny0);
18563 int dx = xright - xleft, dy = ydown - yup;
18564 const bool steep = dy>dx;
18565 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
18566 const int
18567 offx = (nx0<nx1?1:-1)*(steep?width:1),
18568 offy = (ny0<ny1?1:-1)*(steep?1:width),
18569 wh = width*height,
18570 ndx = dx>0?dx:1;
18571 if (opacity>=1) {
18572 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18573 if (pattern&hatch) {
18574 T *ptrd = ptrd0;
18575 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
18576 cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
18577 }
18578 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18579 ptrd0+=offx;
18580 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18581 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18582 T *ptrd = ptrd0;
18583 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
18584 cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
18585 ptrd0+=offx;
18586 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18587 }
18588 } else {
18589 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18590 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18591 T *ptrd = ptrd0;
18592 if (pattern&hatch) {
18593 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
18594 cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
18595 }
18596 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18597 ptrd0+=offx;
18598 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18599 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18600 T *ptrd = ptrd0;
18601 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
18602 cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
18603 ptrd0+=offx;
18604 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18605 }
18606 }
18607 return *this;
18608 }
18610 //! Draw a 2D textured line, with perspective correction.
18611 template<typename tc>
18612 CImg<T>& draw_line(const int x0, const int y0, const float z0,
18613 const int x1, const int y1, const float z1,
18614 const CImg<tc>& texture,
18615 const int tx0, const int ty0,
18616 const int tx1, const int ty1,
18617 const float opacity=1,
18618 const unsigned int pattern=~0U, const bool init_hatch=true) {
18619 if (is_empty() && z0<=0 && z1<=0) return *this;
18620 if (!texture || texture.dim<dim)
18621 throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
18622 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
18623 if (is_overlapped(texture)) return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
18624 static unsigned int hatch = ~0U - (~0U>>1);
18625 if (init_hatch) hatch = ~0U - (~0U>>1);
18626 const bool xdir = x0<x1, ydir = y0<y1;
18627 int
18628 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
18629 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
18630 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
18631 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
18632 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
18633 float
18634 Tx0 = tx0/z0, Tx1 = tx1/z1,
18635 Ty0 = ty0/z0, Ty1 = ty1/z1,
18636 Z0 = 1/z0, Z1 = 1/z1,
18637 dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
18638 tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
18639 &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
18640 &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
18641 &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
18642 &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
18643 if (xright<0 || xleft>=dimx()) return *this;
18644 if (xleft<0) {
18645 const int D = xright - xleft;
18646 yleft-=xleft*(yright - yleft)/D;
18647 zleft-=xleft*(zright - zleft)/D;
18648 txleft-=xleft*(txright - txleft)/D;
18649 tyleft-=xleft*(tyright - tyleft)/D;
18650 xleft = 0;
18651 }
18652 if (xright>=dimx()) {
18653 const int d = xright - dimx(), D = xright - xleft;
18654 yright-=d*(yright - yleft)/D;
18655 zright-=d*(zright - zleft)/D;
18656 txright-=d*(txright - txleft)/D;
18657 tyright-=d*(tyright - tyleft)/D;
18658 xright = dimx()-1;
18659 }
18660 if (ydown<0 || yup>=dimy()) return *this;
18661 if (yup<0) {
18662 const int D = ydown - yup;
18663 xup-=yup*(xdown - xup)/D;
18664 zup-=yup*(zdown - zup)/D;
18665 txup-=yup*(txdown - txup)/D;
18666 tyup-=yup*(tydown - tyup)/D;
18667 yup = 0;
18668 }
18669 if (ydown>=dimy()) {
18670 const int d = ydown - dimy(), D = ydown - yup;
18671 xdown-=d*(xdown - xup)/D;
18672 zdown-=d*(zdown - zup)/D;
18673 txdown-=d*(txdown - txup)/D;
18674 tydown-=d*(tydown - tyup)/D;
18675 ydown = dimy()-1;
18676 }
18677 T *ptrd0 = ptr(nx0,ny0);
18678 int dx = xright - xleft, dy = ydown - yup;
18679 const bool steep = dy>dx;
18680 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
18681 const int
18682 offx = (nx0<nx1?1:-1)*(steep?width:1),
18683 offy = (ny0<ny1?1:-1)*(steep?1:width),
18684 wh = width*height,
18685 ndx = dx>0?dx:1;
18686 if (opacity>=1) {
18687 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18688 if (pattern&hatch) {
18689 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18690 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
18691 }
18692 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18693 ptrd0+=offx;
18694 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18695 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18696 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18697 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
18698 ptrd0+=offx;
18699 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18700 }
18701 } else {
18702 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18703 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18704 if (pattern&hatch) {
18705 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18706 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
18707 }
18708 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18709 ptrd0+=offx;
18710 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18711 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18712 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18713 T *ptrd = ptrd0;
18714 cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
18715 ptrd0+=offx;
18716 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
18717 }
18718 }
18719 return *this;
18720 }
18722 //! Draw a 2D textured line, with z-buffering and perspective correction.
18723 template<typename tc>
18724 CImg<T>& draw_line(float *const zbuffer,
18725 const int x0, const int y0, const float z0,
18726 const int x1, const int y1, const float z1,
18727 const CImg<tc>& texture,
18728 const int tx0, const int ty0,
18729 const int tx1, const int ty1,
18730 const float opacity=1,
18731 const unsigned int pattern=~0U, const bool init_hatch=true) {
18732 if (!is_empty() && z0>0 && z1>0) {
18733 if (!texture || texture.dim<dim)
18734 throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
18735 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
18736 if (is_overlapped(texture)) return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
18737 static unsigned int hatch = ~0U - (~0U>>1);
18738 if (init_hatch) hatch = ~0U - (~0U>>1);
18739 const bool xdir = x0<x1, ydir = y0<y1;
18740 int
18741 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
18742 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
18743 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
18744 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
18745 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
18746 float
18747 Tx0 = tx0/z0, Tx1 = tx1/z1,
18748 Ty0 = ty0/z0, Ty1 = ty1/z1,
18749 Z0 = 1/z0, Z1 = 1/z1,
18750 dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
18751 tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
18752 &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
18753 &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
18754 &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
18755 &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
18756 if (xright<0 || xleft>=dimx()) return *this;
18757 if (xleft<0) {
18758 const int D = xright - xleft;
18759 yleft-=xleft*(yright - yleft)/D;
18760 zleft-=xleft*(zright - zleft)/D;
18761 txleft-=xleft*(txright - txleft)/D;
18762 tyleft-=xleft*(tyright - tyleft)/D;
18763 xleft = 0;
18764 }
18765 if (xright>=dimx()) {
18766 const int d = xright - dimx(), D = xright - xleft;
18767 yright-=d*(yright - yleft)/D;
18768 zright-=d*(zright - zleft)/D;
18769 txright-=d*(txright - txleft)/D;
18770 tyright-=d*(tyright - tyleft)/D;
18771 xright = dimx()-1;
18772 }
18773 if (ydown<0 || yup>=dimy()) return *this;
18774 if (yup<0) {
18775 const int D = ydown - yup;
18776 xup-=yup*(xdown - xup)/D;
18777 zup-=yup*(zdown - zup)/D;
18778 txup-=yup*(txdown - txup)/D;
18779 tyup-=yup*(tydown - tyup)/D;
18780 yup = 0;
18781 }
18782 if (ydown>=dimy()) {
18783 const int d = ydown - dimy(), D = ydown - yup;
18784 xdown-=d*(xdown - xup)/D;
18785 zdown-=d*(zdown - zup)/D;
18786 txdown-=d*(txdown - txup)/D;
18787 tydown-=d*(tydown - tyup)/D;
18788 ydown = dimy()-1;
18789 }
18790 T *ptrd0 = ptr(nx0,ny0);
18791 float *ptrz = zbuffer + nx0 + ny0*width;
18792 int dx = xright - xleft, dy = ydown - yup;
18793 const bool steep = dy>dx;
18794 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
18795 const int
18796 offx = (nx0<nx1?1:-1)*(steep?width:1),
18797 offy = (ny0<ny1?1:-1)*(steep?1:width),
18798 wh = width*height,
18799 ndx = dx>0?dx:1;
18800 if (opacity>=1) {
18801 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18802 if (pattern&hatch) {
18803 const float z = Z0 + x*dz/ndx;
18804 if (z>*ptrz) {
18805 *ptrz = z;
18806 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18807 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
18808 }
18809 }
18810 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18811 ptrd0+=offx; ptrz+=offx;
18812 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18813 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18814 const float z = Z0 + x*dz/ndx;
18815 if (z>*ptrz) {
18816 *ptrz = z;
18817 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18818 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
18819 }
18820 ptrd0+=offx; ptrz+=offx;
18821 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18822 }
18823 } else {
18824 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
18825 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
18826 if (pattern&hatch) {
18827 const float z = Z0 + x*dz/ndx;
18828 if (z>*ptrz) {
18829 *ptrz = z;
18830 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18831 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
18832 }
18833 }
18834 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
18835 ptrd0+=offx; ptrz+=offx;
18836 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
18837 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
18838 const float z = Z0 + x*dz/ndx;
18839 if (z>*ptrz) {
18840 *ptrz = z;
18841 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
18842 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
18843 }
18844 ptrd0+=offx; ptrz+=offx;
18845 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offx; error+=dx; }
18846 }
18847 }
18848 }
18849 return *this;
18850 }
18852 // Inner routine for drawing set of consecutive lines with generic type for coordinates.
18853 template<typename t, typename tc>
18854 CImg<T>& _draw_line(const t& points, const unsigned int W, const unsigned int H,
18855 const tc *const color, const float opacity,
18856 const unsigned int pattern, const bool init_hatch) {
18857 if (is_empty() || !points || W<2) return *this;
18858 bool ninit_hatch = init_hatch;
18859 switch (H) {
18860 case 0 : case 1 :
18861 throw CImgArgumentException("CImg<%s>::draw_line() : Given list of points is not valid.",
18862 pixel_type());
18863 case 2 : {
18864 const int x0 = (int)points(0,0), y0 = (int)points(0,1);
18865 int ox = x0, oy = y0;
18866 for (unsigned int i = 1; i<W; ++i) {
18867 const int x = (int)points(i,0), y = (int)points(i,1);
18868 draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
18869 ninit_hatch = false;
18870 ox = x; oy = y;
18871 }
18872 } break;
18873 default : {
18874 const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
18875 int ox = x0, oy = y0, oz = z0;
18876 for (unsigned int i = 1; i<W; ++i) {
18877 const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
18878 draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
18879 ninit_hatch = false;
18880 ox = x; oy = y; oz = z;
18881 }
18882 }
18883 }
18884 return *this;
18885 }
18887 //! Draw a set of consecutive colored lines in the instance image.
18888 /**
18889 \param points Coordinates of vertices, stored as a list of vectors.
18890 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
18891 \param opacity Drawing opacity (optional).
18892 \param pattern An integer whose bits describe the line pattern (optional).
18893 \param init_hatch If set to true, init hatch motif.
18894 \note
18895 - This function uses several call to the single CImg::draw_line() procedure,
18896 depending on the vectors size in \p points.
18897 \par Example:
18898 \code
18899 CImg<unsigned char> img(100,100,1,3,0);
18900 const unsigned char color[] = { 255,128,64 };
18901 CImgList<int> points;
18902 points.insert(CImg<int>::vector(0,0)).
18903 .insert(CImg<int>::vector(70,10)).
18904 .insert(CImg<int>::vector(80,60)).
18905 .insert(CImg<int>::vector(10,90));
18906 img.draw_line(points,color);
18907 \endcode
18908 **/
18909 template<typename t, typename tc>
18910 CImg<T>& draw_line(const CImgList<t>& points,
18911 const tc *const color, const float opacity=1,
18912 const unsigned int pattern=~0U, const bool init_hatch=true) {
18913 unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
18914 return _draw_line(points,points.size,H,color,opacity,pattern,init_hatch);
18915 }
18917 //! Draw a set of consecutive colored lines in the instance image.
18918 template<typename t, typename tc>
18919 CImg<T>& draw_line(const CImgList<t>& points,
18920 const CImg<tc>& color, const float opacity=1,
18921 const unsigned int pattern=~0U, const bool init_hatch=true) {
18922 return draw_line(points,color.data,opacity,pattern,init_hatch);
18923 }
18925 //! Draw a set of consecutive colored lines in the instance image.
18926 /**
18927 \note
18928 - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
18929 (sequence of vectors aligned along the x-axis).
18930 **/
18931 template<typename t, typename tc>
18932 CImg<T>& draw_line(const CImg<t>& points,
18933 const tc *const color, const float opacity=1,
18934 const unsigned int pattern=~0U, const bool init_hatch=true) {
18935 return _draw_line(points,points.width,points.height,color,opacity,pattern,init_hatch);
18936 }
18938 //! Draw a set of consecutive colored lines in the instance image.
18939 template<typename t, typename tc>
18940 CImg<T>& draw_line(const CImg<t>& points,
18941 const CImg<tc>& color, const float opacity=1,
18942 const unsigned int pattern=~0U, const bool init_hatch=true) {
18943 return draw_line(points,color.data,opacity,pattern,init_hatch);
18944 }
18946 // Inner routine for a drawing filled polygon with generic type for coordinates.
18947 template<typename t, typename tc>
18948 CImg<T>& _draw_polygon(const t& points, const unsigned int N,
18949 const tc *const color, const float opacity) {
18950 if (is_empty() || !points || N<3) return *this;
18951 if (!color)
18952 throw CImgArgumentException("CImg<%s>::draw_polygon() : Specified color is (null).",
18953 pixel_type());
18954 _draw_scanline(color,opacity);
18955 int xmin = (int)(~0U>>1), xmax = 0, ymin = (int)(~0U>>1), ymax = 0;
18956 { for (unsigned int p = 0; p<N; ++p) {
18957 const int x = (int)points(p,0), y = (int)points(p,1);
18958 if (x<xmin) xmin = x;
18959 if (x>xmax) xmax = x;
18960 if (y<ymin) ymin = y;
18961 if (y>ymax) ymax = y;
18962 }}
18963 if (xmax<0 || xmin>=dimx() || ymax<0 || ymin>=dimy()) return *this;
18964 const unsigned int
18965 nymin = ymin<0?0:(unsigned int)ymin,
18966 nymax = ymax>=dimy()?height-1:(unsigned int)ymax,
18967 dy = 1 + nymax - nymin;
18968 CImg<intT> X(1+2*N,dy,1,1,0), tmp;
18969 int cx = (int)points(0,0), cy = (int)points(0,1);
18970 for (unsigned int cp = 0, p = 0; p<N; ++p) {
18971 const unsigned int np = (p!=N-1)?p+1:0, ap = (np!=N-1)?np+1:0;
18972 const int
18973 nx = (int)points(np,0), ny = (int)points(np,1), ay = (int)points(ap,1),
18974 y0 = cy - nymin, y1 = ny - nymin;
18975 if (y0!=y1) {
18976 const int countermin = ((ny<ay && cy<ny) || (ny>ay && cy>ny))?1:0;
18977 for (int x = cx, y = y0, _sx = 1, _sy = 1,
18978 _dx = nx>cx?nx-cx:((_sx=-1),cx-nx),
18979 _dy = y1>y0?y1-y0:((_sy=-1),y0-y1),
18980 _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy),
18981 _err = _dx>>1,
18982 _rx = _dy?(nx-cx)/_dy:0;
18983 _counter>=countermin;
18984 --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0))
18985 if (y>=0 && y<(int)dy) X(++X(0,y),y) = x;
18986 cp = np; cx = nx; cy = ny;
18987 } else {
18988 const int pp = (cp?cp-1:N-1), py = (int)points(pp,1);
18989 if ((cy>py && ay>cy) || (cy<py && ay<cy)) X(++X(0,y0),y0) = nx;
18990 if (cy!=ay) { cp = np; cx = nx; cy = ny; }
18991 }
18992 }
18993 for (int y = 0; y<(int)dy; ++y) {
18994 tmp.assign(X.ptr(1,y),X(0,y),1,1,1,true).sort();
18995 for (int i = 1; i<=X(0,y); ) {
18996 const int xb = X(i++,y), xe = X(i++,y);
18997 _draw_scanline(xb,xe,nymin+y,color,opacity);
18998 }
18999 }
19000 return *this;
19001 }
19003 //! Draw a filled polygon in the instance image.
19004 template<typename t, typename tc>
19005 CImg<T>& draw_polygon(const CImgList<t>& points,
19006 const tc *const color, const float opacity=1) {
19007 if (!points.is_sameY(2))
19008 throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
19009 pixel_type());
19010 return _draw_polygon(points,points.size,color,opacity);
19011 }
19013 //! Draw a filled polygon in the instance image.
19014 template<typename t, typename tc>
19015 CImg<T>& draw_polygon(const CImgList<t>& points,
19016 const CImg<tc>& color, const float opacity=1) {
19017 return draw_polygon(points,color.data,opacity);
19018 }
19020 //! Draw a filled polygon in the instance image.
19021 template<typename t, typename tc>
19022 CImg<T>& draw_polygon(const CImg<t>& points,
19023 const tc *const color, const float opacity=1) {
19024 if (points.height<2)
19025 throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
19026 pixel_type());
19027 return _draw_polygon(points,points.width,color,opacity);
19028 }
19030 //! Draw a filled polygon in the instance image.
19031 template<typename t, typename tc>
19032 CImg<T>& draw_polygon(const CImg<t>& points,
19033 const CImg<tc>& color, const float opacity=1) {
19034 return draw_polygon(points,color.data,opacity);
19035 }
19037 // Inner routine for drawing an outlined polygon with generic point coordinates.
19038 template<typename t, typename tc>
19039 CImg<T>& _draw_polygon(const t& points, const unsigned int W, const unsigned int H,
19040 const tc *const color, const float opacity,
19041 const unsigned int pattern) {
19042 if (is_empty() || !points || W<3) return *this;
19043 bool ninit_hatch = true;
19044 switch (H) {
19045 case 0 : case 1 :
19046 throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
19047 pixel_type());
19048 case 2 : {
19049 const int x0 = (int)points(0,0), y0 = (int)points(0,1);
19050 int ox = x0, oy = y0;
19051 for (unsigned int i = 1; i<W; ++i) {
19052 const int x = (int)points(i,0), y = (int)points(i,1);
19053 draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
19054 ninit_hatch = false;
19055 ox = x; oy = y;
19056 }
19057 draw_line(ox,oy,x0,y0,color,opacity,pattern,false);
19058 } break;
19059 default : {
19060 const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
19061 int ox = x0, oy = y0, oz = z0;
19062 for (unsigned int i = 1; i<W; ++i) {
19063 const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
19064 draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
19065 ninit_hatch = false;
19066 ox = x; oy = y; oz = z;
19067 }
19068 draw_line(ox,oy,oz,x0,y0,z0,color,opacity,pattern,false);
19069 }
19070 }
19071 return *this;
19072 }
19074 //! Draw a polygon outline.
19075 template<typename t, typename tc>
19076 CImg<T>& draw_polygon(const CImgList<t>& points,
19077 const tc *const color, const float opacity,
19078 const unsigned int pattern) {
19079 unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
19080 return _draw_polygon(points,points.size,H,color,opacity,pattern);
19081 }
19083 //! Draw a polygon outline.
19084 template<typename t, typename tc>
19085 CImg<T>& draw_polygon(const CImgList<t>& points,
19086 const CImg<tc>& color, const float opacity,
19087 const unsigned int pattern) {
19088 return draw_polygon(points,color.data,opacity,pattern);
19089 }
19091 //! Draw a polygon outline.
19092 template<typename t, typename tc>
19093 CImg<T>& draw_polygon(const CImg<t>& points,
19094 const tc *const color, const float opacity,
19095 const unsigned int pattern) {
19096 return _draw_polygon(points,points.width,points.height,color,opacity,pattern);
19097 }
19099 //! Draw a polygon outline.
19100 template<typename t, typename tc>
19101 CImg<T>& draw_polygon(const CImg<t>& points,
19102 const CImg<tc>& color, const float opacity,
19103 const unsigned int pattern) {
19104 return draw_polygon(points,color.data,opacity,pattern);
19105 }
19107 //! Draw a cubic spline curve in the instance image.
19108 /**
19109 \param x0 X-coordinate of the starting curve point
19110 \param y0 Y-coordinate of the starting curve point
19111 \param u0 X-coordinate of the starting velocity
19112 \param v0 Y-coordinate of the starting velocity
19113 \param x1 X-coordinate of the ending curve point
19114 \param y1 Y-coordinate of the ending curve point
19115 \param u1 X-coordinate of the ending velocity
19116 \param v1 Y-coordinate of the ending velocity
19117 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
19118 \param precision Curve drawing precision (optional).
19119 \param opacity Drawing opacity (optional).
19120 \param pattern An integer whose bits describe the line pattern (optional).
19121 \param init_hatch If \c true, init hatch motif.
19122 \note
19123 - The curve is a 2D cubic Bezier spline, from the set of specified starting/ending points
19124 and corresponding velocity vectors.
19125 - The spline is drawn as a serie of connected segments. The \p precision parameter sets the
19126 average number of pixels in each drawn segment.
19127 - A cubic Bezier curve is sometimes defined by a set of 4 points { (\p x0,\p y0), (\p xa,\p ya), (\p xb,\p yb), (\p x1,\p y1) }
19128 where (\p x0,\p y0) is the starting point, (\p x1,\p y1) is the ending point and (\p xa,\p ya), (\p xb,\p yb) are two
19129 \e control points.
19130 The starting and ending velocities (\p u0,\p v0) and (\p u1,\p v1) can be deduced easily from the control points as
19131 \p u0 = (\p xa - \p x0), \p v0 = (\p ya - \p y0), \p u1 = (\p x1 - \p xb) and \p v1 = (\p y1 - \p yb).
19132 \par Example:
19133 \code
19134 CImg<unsigned char> img(100,100,1,3,0);
19135 const unsigned char color[] = { 255,255,255 };
19136 img.draw_spline(30,30,0,100,90,40,0,-100,color);
19137 \endcode
19138 **/
19139 template<typename tc>
19140 CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
19141 const int x1, const int y1, const float u1, const float v1,
19142 const tc *const color, const float opacity=1,
19143 const float precision=4, const unsigned int pattern=~0U,
19144 const bool init_hatch=true) {
19145 if (is_empty()) return *this;
19146 if (!color)
19147 throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
19148 pixel_type());
19149 bool ninit_hatch = init_hatch;
19150 const float
19151 dx = (float)(x1 - x0),
19152 dy = (float)(y1 - y0),
19153 dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
19154 ax = -2*dx + u0 + u1,
19155 bx = 3*dx - 2*u0 - u1,
19156 ay = -2*dy + v0 + v1,
19157 by = 3*dy - 2*v0 - v1,
19158 xprecision = dmax>0?precision/dmax:1.0f,
19159 tmax = 1 + (dmax>0?xprecision:0.0f);
19160 int ox = x0, oy = y0;
19161 for (float t = 0; t<tmax; t+=xprecision) {
19162 const float
19163 t2 = t*t,
19164 t3 = t2*t;
19165 const int
19166 nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
19167 ny = (int)(ay*t3 + by*t2 + v0*t + y0);
19168 draw_line(ox,oy,nx,ny,color,opacity,pattern,ninit_hatch);
19169 ninit_hatch = false;
19170 ox = nx; oy = ny;
19171 }
19172 return *this;
19173 }
19175 //! Draw a cubic spline curve in the instance image.
19176 template<typename tc>
19177 CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
19178 const int x1, const int y1, const float u1, const float v1,
19179 const CImg<tc>& color, const float opacity=1,
19180 const float precision=4, const unsigned int pattern=~0U,
19181 const bool init_hatch=true) {
19182 return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,color.data,opacity,precision,pattern,init_hatch);
19183 }
19185 //! Draw a cubic spline curve in the instance image (for volumetric images).
19186 /**
19187 \note
19188 - Similar to CImg::draw_spline() for a 3D spline in a volumetric image.
19189 **/
19190 template<typename tc>
19191 CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
19192 const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
19193 const tc *const color, const float opacity=1,
19194 const float precision=4, const unsigned int pattern=~0U,
19195 const bool init_hatch=true) {
19196 if (is_empty()) return *this;
19197 if (!color)
19198 throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
19199 pixel_type());
19200 bool ninit_hatch = init_hatch;
19201 const float
19202 dx = (float)(x1 - x0),
19203 dy = (float)(y1 - y0),
19204 dz = (float)(z1 - z0),
19205 dmax = cimg::max(cimg::abs(dx),cimg::abs(dy),cimg::abs(dz)),
19206 ax = -2*dx + u0 + u1,
19207 bx = 3*dx - 2*u0 - u1,
19208 ay = -2*dy + v0 + v1,
19209 by = 3*dy - 2*v0 - v1,
19210 az = -2*dz + w0 + w1,
19211 bz = 3*dz - 2*w0 - w1,
19212 xprecision = dmax>0?precision/dmax:1.0f,
19213 tmax = 1 + (dmax>0?xprecision:0.0f);
19214 int ox = x0, oy = y0, oz = z0;
19215 for (float t = 0; t<tmax; t+=xprecision) {
19216 const float
19217 t2 = t*t,
19218 t3 = t2*t;
19219 const int
19220 nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
19221 ny = (int)(ay*t3 + by*t2 + v0*t + y0),
19222 nz = (int)(az*t3 + bz*t2 + w0*t + z0);
19223 draw_line(ox,oy,oz,nx,ny,nz,color,opacity,pattern,ninit_hatch);
19224 ninit_hatch = false;
19225 ox = nx; oy = ny; oz = nz;
19226 }
19227 return *this;
19228 }
19230 //! Draw a cubic spline curve in the instance image (for volumetric images).
19231 template<typename tc>
19232 CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
19233 const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
19234 const CImg<tc>& color, const float opacity=1,
19235 const float precision=4, const unsigned int pattern=~0U,
19236 const bool init_hatch=true) {
19237 return draw_spline(x0,y0,z0,u0,v0,w0,x1,y1,z1,u1,v1,w1,color.data,opacity,precision,pattern,init_hatch);
19238 }
19240 //! Draw a cubic spline curve in the instance image.
19241 /**
19242 \param x0 X-coordinate of the starting curve point
19243 \param y0 Y-coordinate of the starting curve point
19244 \param u0 X-coordinate of the starting velocity
19245 \param v0 Y-coordinate of the starting velocity
19246 \param x1 X-coordinate of the ending curve point
19247 \param y1 Y-coordinate of the ending curve point
19248 \param u1 X-coordinate of the ending velocity
19249 \param v1 Y-coordinate of the ending velocity
19250 \param texture Texture image defining line pixel colors.
19251 \param tx0 X-coordinate of the starting texture point.
19252 \param ty0 Y-coordinate of the starting texture point.
19253 \param tx1 X-coordinate of the ending texture point.
19254 \param ty1 Y-coordinate of the ending texture point.
19255 \param precision Curve drawing precision (optional).
19256 \param opacity Drawing opacity (optional).
19257 \param pattern An integer whose bits describe the line pattern (optional).
19258 \param init_hatch if \c true, reinit hatch motif.
19259 **/
19260 template<typename t>
19261 CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
19262 const int x1, const int y1, const float u1, const float v1,
19263 const CImg<t>& texture,
19264 const int tx0, const int ty0, const int tx1, const int ty1,
19265 const float opacity=1,
19266 const float precision=4, const unsigned int pattern=~0U,
19267 const bool init_hatch=true) {
19268 if (is_empty()) return *this;
19269 if (!texture || texture.dim<dim)
19270 throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
19271 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
19272 if (is_overlapped(texture)) return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,+texture,tx0,ty0,tx1,ty1,precision,opacity,pattern,init_hatch);
19273 bool ninit_hatch = true;
19274 const float
19275 dx = (float)(x1 - x0),
19276 dy = (float)(y1 - y0),
19277 dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
19278 ax = -2*dx + u0 + u1,
19279 bx = 3*dx - 2*u0 - u1,
19280 ay = -2*dy + v0 + v1,
19281 by = 3*dy - 2*v0 - v1,
19282 xprecision = dmax>0?precision/dmax:1.0f,
19283 tmax = 1 + (dmax>0?xprecision:0.0f);
19284 int ox = x0, oy = y0, otx = tx0, oty = ty0;
19285 for (float t1 = 0; t1<tmax; t1+=xprecision) {
19286 const float
19287 t2 = t1*t1,
19288 t3 = t2*t1;
19289 const int
19290 nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0),
19291 ny = (int)(ay*t3 + by*t2 + v0*t1 + y0),
19292 ntx = tx0 + (int)((tx1-tx0)*t1/tmax),
19293 nty = ty0 + (int)((ty1-ty0)*t1/tmax);
19294 draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch);
19295 ninit_hatch = false;
19296 ox = nx; oy = ny; otx = ntx; oty = nty;
19297 }
19298 return *this;
19299 }
19301 // Draw a set of connected spline curves in the instance image (internal).
19302 template<typename tp, typename tt, typename tc>
19303 CImg<T>& _draw_spline(const tp& points, const tt& tangents, const unsigned int W, const unsigned int H,
19304 const tc *const color, const float opacity,
19305 const bool close_set, const float precision,
19306 const unsigned int pattern, const bool init_hatch) {
19307 if (is_empty() || !points || !tangents || W<2) return *this;
19308 bool ninit_hatch = init_hatch;
19309 switch (H) {
19310 case 0 : case 1 :
19311 throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
19312 pixel_type());
19313 case 2 : {
19314 const int x0 = (int)points(0,0), y0 = (int)points(0,1);
19315 const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1);
19316 int ox = x0, oy = y0;
19317 float ou = u0, ov = v0;
19318 for (unsigned int i = 1; i<W; ++i) {
19319 const int x = (int)points(i,0), y = (int)points(i,1);
19320 const float u = (float)tangents(i,0), v = (float)tangents(i,1);
19321 draw_spline(ox,oy,ou,ov,x,y,u,v,color,precision,opacity,pattern,ninit_hatch);
19322 ninit_hatch = false;
19323 ox = x; oy = y; ou = u; ov = v;
19324 }
19325 if (close_set) draw_spline(ox,oy,ou,ov,x0,y0,u0,v0,color,precision,opacity,pattern,false);
19326 } break;
19327 default : {
19328 const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
19329 const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1), w0 = (float)tangents(0,2);
19330 int ox = x0, oy = y0, oz = z0;
19331 float ou = u0, ov = v0, ow = w0;
19332 for (unsigned int i = 1; i<W; ++i) {
19333 const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
19334 const float u = (float)tangents(i,0), v = (float)tangents(i,1), w = (float)tangents(i,2);
19335 draw_spline(ox,oy,oz,ou,ov,ow,x,y,z,u,v,w,color,opacity,pattern,ninit_hatch);
19336 ninit_hatch = false;
19337 ox = x; oy = y; oz = z; ou = u; ov = v; ow = w;
19338 }
19339 if (close_set) draw_spline(ox,oy,oz,ou,ov,ow,x0,y0,z0,u0,v0,w0,color,precision,opacity,pattern,false);
19340 }
19341 }
19342 return *this;
19343 }
19345 // Draw a set of connected spline curves in the instance image (internal).
19346 template<typename tp, typename tc>
19347 CImg<T>& _draw_spline(const tp& points, const unsigned int W, const unsigned int H,
19348 const tc *const color, const float opacity,
19349 const bool close_set, const float precision,
19350 const unsigned int pattern, const bool init_hatch) {
19351 if (is_empty() || !points || W<2) return *this;
19352 CImg<Tfloat> tangents;
19353 switch (H) {
19354 case 0 : case 1 :
19355 throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
19356 pixel_type());
19357 case 2 : {
19358 tangents.assign(W,H);
19359 for (unsigned int p = 0; p<W; ++p) {
19360 const unsigned int
19361 p0 = close_set?(p+W-1)%W:(p?p-1:0),
19362 p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
19363 const float
19364 x = (float)points(p,0),
19365 y = (float)points(p,1),
19366 x0 = (float)points(p0,0),
19367 y0 = (float)points(p0,1),
19368 x1 = (float)points(p1,0),
19369 y1 = (float)points(p1,1),
19370 u0 = x - x0,
19371 v0 = y - y0,
19372 n0 = 1e-8f + (float)cimg_std::sqrt(u0*u0 + v0*v0),
19373 u1 = x1 - x,
19374 v1 = y1 - y,
19375 n1 = 1e-8f + (float)cimg_std::sqrt(u1*u1 + v1*v1),
19376 u = u0/n0 + u1/n1,
19377 v = v0/n0 + v1/n1,
19378 n = 1e-8f + (float)cimg_std::sqrt(u*u + v*v),
19379 fact = 0.5f*(n0 + n1);
19380 tangents(p,0) = (Tfloat)(fact*u/n);
19381 tangents(p,1) = (Tfloat)(fact*v/n);
19382 }
19383 } break;
19384 default : {
19385 tangents.assign(W,H);
19386 for (unsigned int p = 0; p<W; ++p) {
19387 const unsigned int
19388 p0 = close_set?(p+W-1)%W:(p?p-1:0),
19389 p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
19390 const float
19391 x = (float)points(p,0),
19392 y = (float)points(p,1),
19393 z = (float)points(p,2),
19394 x0 = (float)points(p0,0),
19395 y0 = (float)points(p0,1),
19396 z0 = (float)points(p0,2),
19397 x1 = (float)points(p1,0),
19398 y1 = (float)points(p1,1),
19399 z1 = (float)points(p1,2),
19400 u0 = x - x0,
19401 v0 = y - y0,
19402 w0 = z - z0,
19403 n0 = 1e-8f + (float)cimg_std::sqrt(u0*u0 + v0*v0 + w0*w0),
19404 u1 = x1 - x,
19405 v1 = y1 - y,
19406 w1 = z1 - z,
19407 n1 = 1e-8f + (float)cimg_std::sqrt(u1*u1 + v1*v1 + w1*w1),
19408 u = u0/n0 + u1/n1,
19409 v = v0/n0 + v1/n1,
19410 w = w0/n0 + w1/n1,
19411 n = 1e-8f + (float)cimg_std::sqrt(u*u + v*v + w*w),
19412 fact = 0.5f*(n0 + n1);
19413 tangents(p,0) = (Tfloat)(fact*u/n);
19414 tangents(p,1) = (Tfloat)(fact*v/n);
19415 tangents(p,2) = (Tfloat)(fact*w/n);
19416 }
19417 }
19418 }
19419 return _draw_spline(points,tangents,W,H,color,opacity,close_set,precision,pattern,init_hatch);
19420 }
19422 //! Draw a set of consecutive colored splines in the instance image.
19423 template<typename tp, typename tt, typename tc>
19424 CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
19425 const tc *const color, const float opacity=1,
19426 const bool close_set=false, const float precision=4,
19427 const unsigned int pattern=~0U, const bool init_hatch=true) {
19428 unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()),(unsigned int)(tangents[p].size()));
19429 return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.size,H);
19430 }
19432 //! Draw a set of consecutive colored splines in the instance image.
19433 template<typename tp, typename tt, typename tc>
19434 CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
19435 const CImg<tc>& color, const float opacity=1,
19436 const bool close_set=false, const float precision=4,
19437 const unsigned int pattern=~0U, const bool init_hatch=true) {
19438 return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
19439 }
19441 //! Draw a set of consecutive colored splines in the instance image.
19442 template<typename tp, typename tt, typename tc>
19443 CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
19444 const tc *const color, const float opacity=1,
19445 const bool close_set=false, const float precision=4,
19446 const unsigned int pattern=~0U, const bool init_hatch=true) {
19447 return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
19448 }
19450 //! Draw a set of consecutive colored splines in the instance image.
19451 template<typename tp, typename tt, typename tc>
19452 CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
19453 const CImg<tc>& color, const float opacity=1,
19454 const bool close_set=false, const float precision=4,
19455 const unsigned int pattern=~0U, const bool init_hatch=true) {
19456 return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
19457 }
19459 //! Draw a set of consecutive colored splines in the instance image.
19460 template<typename t, typename tc>
19461 CImg<T>& draw_spline(const CImgList<t>& points,
19462 const tc *const color, const float opacity=1,
19463 const bool close_set=false, const float precision=4,
19464 const unsigned int pattern=~0U, const bool init_hatch=true) {
19465 unsigned int H = ~0U;
19466 cimglist_for(points,p) { const unsigned int s = points[p].size(); if (s<H) H = s; }
19467 return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.size,H);
19468 }
19470 //! Draw a set of consecutive colored splines in the instance image.
19471 template<typename t, typename tc>
19472 CImg<T>& draw_spline(const CImgList<t>& points,
19473 CImg<tc>& color, const float opacity=1,
19474 const bool close_set=false, const float precision=4,
19475 const unsigned int pattern=~0U, const bool init_hatch=true) {
19476 return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
19477 }
19479 //! Draw a set of consecutive colored lines in the instance image.
19480 template<typename t, typename tc>
19481 CImg<T>& draw_spline(const CImg<t>& points,
19482 const tc *const color, const float opacity=1,
19483 const bool close_set=false, const float precision=4,
19484 const unsigned int pattern=~0U, const bool init_hatch=true) {
19485 return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
19486 }
19488 //! Draw a set of consecutive colored lines in the instance image.
19489 template<typename t, typename tc>
19490 CImg<T>& draw_spline(const CImg<t>& points,
19491 const CImg<tc>& color, const float opacity=1,
19492 const bool close_set=false, const float precision=4,
19493 const unsigned int pattern=~0U, const bool init_hatch=true) {
19494 return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
19495 }
19497 //! Draw a colored arrow in the instance image.
19498 /**
19499 \param x0 X-coordinate of the starting arrow point (tail).
19500 \param y0 Y-coordinate of the starting arrow point (tail).
19501 \param x1 X-coordinate of the ending arrow point (head).
19502 \param y1 Y-coordinate of the ending arrow point (head).
19503 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
19504 \param angle Aperture angle of the arrow head (optional).
19505 \param length Length of the arrow head. If negative, describes a percentage of the arrow length (optional).
19506 \param opacity Drawing opacity (optional).
19507 \param pattern An integer whose bits describe the line pattern (optional).
19508 \note
19509 - Clipping is supported.
19510 **/
19511 template<typename tc>
19512 CImg<T>& draw_arrow(const int x0, const int y0,
19513 const int x1, const int y1,
19514 const tc *const color, const float opacity=1,
19515 const float angle=30, const float length=-10,
19516 const unsigned int pattern=~0U) {
19517 if (is_empty()) return *this;
19518 const float u = (float)(x0 - x1), v = (float)(y0 - y1), sq = u*u + v*v,
19519 deg = (float)(angle*cimg::valuePI/180), ang = (sq>0)?(float)cimg_std::atan2(v,u):0.0f,
19520 l = (length>=0)?length:-length*(float)cimg_std::sqrt(sq)/100;
19521 if (sq>0) {
19522 const float
19523 cl = (float)cimg_std::cos(ang - deg), sl = (float)cimg_std::sin(ang - deg),
19524 cr = (float)cimg_std::cos(ang + deg), sr = (float)cimg_std::sin(ang + deg);
19525 const int
19526 xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl),
19527 xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr),
19528 xc = x1 + (int)((l+1)*(cl+cr))/2, yc = y1 + (int)((l+1)*(sl+sr))/2;
19529 draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);
19530 } else draw_point(x0,y0,color,opacity);
19531 return *this;
19532 }
19534 //! Draw a colored arrow in the instance image.
19535 template<typename tc>
19536 CImg<T>& draw_arrow(const int x0, const int y0,
19537 const int x1, const int y1,
19538 const CImg<tc>& color, const float opacity=1,
19539 const float angle=30, const float length=-10,
19540 const unsigned int pattern=~0U) {
19541 return draw_arrow(x0,y0,x1,y1,color.data,opacity,angle,length,pattern);
19542 }
19544 //! Draw an image.
19545 /**
19546 \param sprite Sprite image.
19547 \param x0 X-coordinate of the sprite position.
19548 \param y0 Y-coordinate of the sprite position.
19549 \param z0 Z-coordinate of the sprite position.
19550 \param v0 V-coordinate of the sprite position.
19551 \param opacity Drawing opacity (optional).
19552 \note
19553 - Clipping is supported.
19554 **/
19555 template<typename t>
19556 CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
19557 const CImg<t>& sprite, const float opacity=1) {
19558 if (is_empty()) return *this;
19559 if (!sprite)
19560 throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
19561 pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
19562 if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
19563 const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
19564 const int
19565 lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
19566 lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
19567 lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
19568 lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
19569 const t
19570 *ptrs = sprite.data -
19571 (bx?x0:0) -
19572 (by?y0*sprite.dimx():0) -
19573 (bz?z0*sprite.dimx()*sprite.dimy():0) -
19574 (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
19575 const unsigned int
19576 offX = width - lX, soffX = sprite.width - lX,
19577 offY = width*(height - lY), soffY = sprite.width*(sprite.height - lY),
19578 offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
19579 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
19580 if (lX>0 && lY>0 && lZ>0 && lV>0) {
19581 T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
19582 for (int v = 0; v<lV; ++v) {
19583 for (int z = 0; z<lZ; ++z) {
19584 for (int y = 0; y<lY; ++y) {
19585 if (opacity>=1) for (int x = 0; x<lX; ++x) *(ptrd++) = (T)*(ptrs++);
19586 else for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
19587 ptrd+=offX; ptrs+=soffX;
19588 }
19589 ptrd+=offY; ptrs+=soffY;
19590 }
19591 ptrd+=offZ; ptrs+=soffZ;
19592 }
19593 }
19594 return *this;
19595 }
19597 #ifndef cimg_use_visualcpp6
19598 // Otimized version (internal).
19599 CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
19600 const CImg<T>& sprite, const float opacity=1) {
19601 if (is_empty()) return *this;
19602 if (!sprite)
19603 throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
19604 pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
19605 if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
19606 const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
19607 const int
19608 lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
19609 lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
19610 lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
19611 lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
19612 const T
19613 *ptrs = sprite.data -
19614 (bx?x0:0) -
19615 (by?y0*sprite.dimx():0) -
19616 (bz?z0*sprite.dimx()*sprite.dimy():0) -
19617 (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
19618 const unsigned int
19619 offX = width - lX, soffX = sprite.width - lX,
19620 offY = width*(height - lY), soffY = sprite.width*(sprite.height - lY),
19621 offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ),
19622 slX = lX*sizeof(T);
19623 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
19624 if (lX>0 && lY>0 && lZ>0 && lV>0) {
19625 T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
19626 for (int v = 0; v<lV; ++v) {
19627 for (int z = 0; z<lZ; ++z) {
19628 if (opacity>=1) for (int y = 0; y<lY; ++y) { cimg_std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; }
19629 else for (int y = 0; y<lY; ++y) {
19630 for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
19631 ptrd+=offX; ptrs+=soffX;
19632 }
19633 ptrd+=offY; ptrs+=soffY;
19634 }
19635 ptrd+=offZ; ptrs+=soffZ;
19636 }
19637 }
19638 return *this;
19639 }
19640 #endif
19642 //! Draw an image.
19643 template<typename t>
19644 CImg<T>& draw_image(const int x0, const int y0, const int z0,
19645 const CImg<t>& sprite, const float opacity=1) {
19646 return draw_image(x0,y0,z0,0,sprite,opacity);
19647 }
19649 //! Draw an image.
19650 template<typename t>
19651 CImg<T>& draw_image(const int x0, const int y0,
19652 const CImg<t>& sprite, const float opacity=1) {
19653 return draw_image(x0,y0,0,sprite,opacity);
19654 }
19656 //! Draw an image.
19657 template<typename t>
19658 CImg<T>& draw_image(const int x0,
19659 const CImg<t>& sprite, const float opacity=1) {
19660 return draw_image(x0,0,sprite,opacity);
19661 }
19663 //! Draw an image.
19664 template<typename t>
19665 CImg<T>& draw_image(const CImg<t>& sprite, const float opacity=1) {
19666 return draw_image(0,sprite,opacity);
19667 }
19669 //! Draw a sprite image in the instance image (masked version).
19670 /**
19671 \param sprite Sprite image.
19672 \param mask Mask image.
19673 \param x0 X-coordinate of the sprite position in the instance image.
19674 \param y0 Y-coordinate of the sprite position in the instance image.
19675 \param z0 Z-coordinate of the sprite position in the instance image.
19676 \param v0 V-coordinate of the sprite position in the instance image.
19677 \param mask_valmax Maximum pixel value of the mask image \c mask (optional).
19678 \param opacity Drawing opacity.
19679 \note
19680 - Pixel values of \c mask set the opacity of the corresponding pixels in \c sprite.
19681 - Clipping is supported.
19682 - Dimensions along x,y and z of \p sprite and \p mask must be the same.
19683 **/
19684 template<typename ti, typename tm>
19685 CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
19686 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
19687 const float mask_valmax=1) {
19688 if (is_empty()) return *this;
19689 if (!sprite)
19690 throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
19691 pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
19692 if (!mask)
19693 throw CImgArgumentException("CImg<%s>::draw_image() : Specified mask image (%u,%u,%u,%u,%p) is empty.",
19694 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
19695 if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,mask,opacity,mask_valmax);
19696 if (is_overlapped(mask)) return draw_image(x0,y0,z0,v0,sprite,+mask,opacity,mask_valmax);
19697 if (mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
19698 throw CImgArgumentException("CImg<%s>::draw_image() : Mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)",
19699 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim);
19700 const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
19701 const int
19702 lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
19703 lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
19704 lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
19705 lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
19706 const int
19707 coff = -(bx?x0:0)-(by?y0*mask.dimx():0)-(bz?z0*mask.dimx()*mask.dimy():0)-(bv?v0*mask.dimx()*mask.dimy()*mask.dimz():0),
19708 ssize = mask.dimx()*mask.dimy()*mask.dimz();
19709 const ti *ptrs = sprite.data + coff;
19710 const tm *ptrm = mask.data + coff;
19711 const unsigned int
19712 offX = width - lX, soffX = sprite.width - lX,
19713 offY = width*(height - lY), soffY = sprite.width*(sprite.height - lY),
19714 offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
19715 if (lX>0 && lY>0 && lZ>0 && lV>0) {
19716 T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
19717 for (int v = 0; v<lV; ++v) {
19718 ptrm = mask.data + (ptrm - mask.data)%ssize;
19719 for (int z = 0; z<lZ; ++z) {
19720 for (int y = 0; y<lY; ++y) {
19721 for (int x=0; x<lX; ++x) {
19722 const float mopacity = (float)(*(ptrm++)*opacity),
19723 nopacity = cimg::abs(mopacity), copacity = mask_valmax - cimg::max(mopacity,0);
19724 *ptrd = (T)((nopacity*(*(ptrs++)) + *ptrd*copacity)/mask_valmax);
19725 ++ptrd;
19726 }
19727 ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
19728 }
19729 ptrd+=offY; ptrs+=soffY; ptrm+=soffY;
19730 }
19731 ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;
19732 }
19733 }
19734 return *this;
19735 }
19737 //! Draw an image.
19738 template<typename ti, typename tm>
19739 CImg<T>& draw_image(const int x0, const int y0, const int z0,
19740 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
19741 const float mask_valmax=1) {
19742 return draw_image(x0,y0,z0,0,sprite,mask,opacity,mask_valmax);
19743 }
19745 //! Draw an image.
19746 template<typename ti, typename tm>
19747 CImg<T>& draw_image(const int x0, const int y0,
19748 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
19749 const float mask_valmax=1) {
19750 return draw_image(x0,y0,0,sprite,mask,opacity,mask_valmax);
19751 }
19753 //! Draw an image.
19754 template<typename ti, typename tm>
19755 CImg<T>& draw_image(const int x0,
19756 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
19757 const float mask_valmax=1) {
19758 return draw_image(x0,0,sprite,mask,opacity,mask_valmax);
19759 }
19761 //! Draw an image.
19762 template<typename ti, typename tm>
19763 CImg<T>& draw_image(const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
19764 const float mask_valmax=1) {
19765 return draw_image(0,sprite,mask,opacity,mask_valmax);
19766 }
19768 //! Draw a 4D filled rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0,\c v0)-(\c x1,\c y1,\c z1,\c v1).
19769 /**
19770 \param x0 X-coordinate of the upper-left rectangle corner.
19771 \param y0 Y-coordinate of the upper-left rectangle corner.
19772 \param z0 Z-coordinate of the upper-left rectangle corner.
19773 \param v0 V-coordinate of the upper-left rectangle corner.
19774 \param x1 X-coordinate of the lower-right rectangle corner.
19775 \param y1 Y-coordinate of the lower-right rectangle corner.
19776 \param z1 Z-coordinate of the lower-right rectangle corner.
19777 \param v1 V-coordinate of the lower-right rectangle corner.
19778 \param val Scalar value used to fill the rectangle area.
19779 \param opacity Drawing opacity (optional).
19780 \note
19781 - Clipping is supported.
19782 **/
19783 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0, const int v0,
19784 const int x1, const int y1, const int z1, const int v1,
19785 const T val, const float opacity=1) {
19786 if (is_empty()) return *this;
19787 const bool bx = (x0<x1), by = (y0<y1), bz = (z0<z1), bv = (v0<v1);
19788 const int
19789 nx0 = bx?x0:x1, nx1 = bx?x1:x0,
19790 ny0 = by?y0:y1, ny1 = by?y1:y0,
19791 nz0 = bz?z0:z1, nz1 = bz?z1:z0,
19792 nv0 = bv?v0:v1, nv1 = bv?v1:v0;
19793 const int
19794 lX = (1 + nx1 - nx0) + (nx1>=dimx()?dimx() - 1 - nx1:0) + (nx0<0?nx0:0),
19795 lY = (1 + ny1 - ny0) + (ny1>=dimy()?dimy() - 1 - ny1:0) + (ny0<0?ny0:0),
19796 lZ = (1 + nz1 - nz0) + (nz1>=dimz()?dimz() - 1 - nz1:0) + (nz0<0?nz0:0),
19797 lV = (1 + nv1 - nv0) + (nv1>=dimv()?dimv() - 1 - nv1:0) + (nv0<0?nv0:0);
19798 const unsigned int offX = width - lX, offY = width*(height - lY), offZ = width*height*(depth - lZ);
19799 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
19800 T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0);
19801 if (lX>0 && lY>0 && lZ>0 && lV>0)
19802 for (int v = 0; v<lV; ++v) {
19803 for (int z = 0; z<lZ; ++z) {
19804 for (int y = 0; y<lY; ++y) {
19805 if (opacity>=1) {
19806 if (sizeof(T)!=1) { for (int x = 0; x<lX; ++x) *(ptrd++) = val; ptrd+=offX; }
19807 else { cimg_std::memset(ptrd,(int)val,lX); ptrd+=width; }
19808 } else { for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*val + *ptrd*copacity); ++ptrd; } ptrd+=offX; }
19809 }
19810 ptrd+=offY;
19811 }
19812 ptrd+=offZ;
19813 }
19814 return *this;
19815 }
19817 //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1).
19818 /**
19819 \param x0 X-coordinate of the upper-left rectangle corner.
19820 \param y0 Y-coordinate of the upper-left rectangle corner.
19821 \param z0 Z-coordinate of the upper-left rectangle corner.
19822 \param x1 X-coordinate of the lower-right rectangle corner.
19823 \param y1 Y-coordinate of the lower-right rectangle corner.
19824 \param z1 Z-coordinate of the lower-right rectangle corner.
19825 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
19826 \param opacity Drawing opacity (optional).
19827 \note
19828 - Clipping is supported.
19829 **/
19830 template<typename tc>
19831 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
19832 const int x1, const int y1, const int z1,
19833 const tc *const color, const float opacity=1) {
19834 if (!color)
19835 throw CImgArgumentException("CImg<%s>::draw_rectangle : specified color is (null)",
19836 pixel_type());
19837 cimg_forV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity);
19838 return *this;
19839 }
19841 //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1).
19842 template<typename tc>
19843 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
19844 const int x1, const int y1, const int z1,
19845 const CImg<tc>& color, const float opacity=1) {
19846 return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity);
19847 }
19849 //! Draw a 3D outlined colored rectangle in the instance image.
19850 template<typename tc>
19851 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
19852 const int x1, const int y1, const int z1,
19853 const tc *const color, const float opacity,
19854 const unsigned int pattern) {
19855 return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true).
19856 draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false).
19857 draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false).
19858 draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false).
19859 draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true).
19860 draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false).
19861 draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false).
19862 draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false).
19863 draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true).
19864 draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true).
19865 draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true).
19866 draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true);
19867 }
19869 //! Draw a 3D outlined colored rectangle in the instance image.
19870 template<typename tc>
19871 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
19872 const int x1, const int y1, const int z1,
19873 const CImg<tc>& color, const float opacity,
19874 const unsigned int pattern) {
19875 return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern);
19876 }
19878 //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
19879 /**
19880 \param x0 X-coordinate of the upper-left rectangle corner.
19881 \param y0 Y-coordinate of the upper-left rectangle corner.
19882 \param x1 X-coordinate of the lower-right rectangle corner.
19883 \param y1 Y-coordinate of the lower-right rectangle corner.
19884 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
19885 \param opacity Drawing opacity (optional).
19886 \note
19887 - Clipping is supported.
19888 **/
19889 template<typename tc>
19890 CImg<T>& draw_rectangle(const int x0, const int y0,
19891 const int x1, const int y1,
19892 const tc *const color, const float opacity=1) {
19893 return draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity);
19894 }
19896 //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
19897 template<typename tc>
19898 CImg<T>& draw_rectangle(const int x0, const int y0,
19899 const int x1, const int y1,
19900 const CImg<tc>& color, const float opacity=1) {
19901 return draw_rectangle(x0,y0,x1,y1,color.data,opacity);
19902 }
19904 //! Draw a 2D outlined colored rectangle.
19905 template<typename tc>
19906 CImg<T>& draw_rectangle(const int x0, const int y0,
19907 const int x1, const int y1,
19908 const tc *const color, const float opacity,
19909 const unsigned int pattern) {
19910 if (is_empty()) return *this;
19911 if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true);
19912 if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true);
19913 const bool bx = (x0<x1), by = (y0<y1);
19914 const int
19915 nx0 = bx?x0:x1, nx1 = bx?x1:x0,
19916 ny0 = by?y0:y1, ny1 = by?y1:y0;
19917 if (ny1==ny0+1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
19918 draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false);
19919 return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
19920 draw_line(nx1,ny0+1,nx1,ny1-1,color,opacity,pattern,false).
19921 draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false).
19922 draw_line(nx0,ny1-1,nx0,ny0+1,color,opacity,pattern,false);
19923 }
19925 //! Draw a 2D outlined colored rectangle.
19926 template<typename tc>
19927 CImg<T>& draw_rectangle(const int x0, const int y0,
19928 const int x1, const int y1,
19929 const CImg<tc>& color, const float opacity,
19930 const unsigned int pattern) {
19931 return draw_rectangle(x0,y0,x1,y1,color.data,opacity,pattern);
19932 }
19934 // Inner macro for drawing triangles.
19935 #define _cimg_for_triangle1(img,xl,xr,y,x0,y0,x1,y1,x2,y2) \
19936 for (int y = y0<0?0:y0, \
19937 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
19938 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
19939 _sxn=1, \
19940 _sxr=1, \
19941 _sxl=1, \
19942 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
19943 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
19944 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
19945 _dyn = y2-y1, \
19946 _dyr = y2-y0, \
19947 _dyl = y1-y0, \
19948 _counter = (_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
19949 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
19950 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
19951 cimg::min((int)(img).height-y-1,y2-y)), \
19952 _errn = _dyn/2, \
19953 _errr = _dyr/2, \
19954 _errl = _dyl/2, \
19955 _rxn = _dyn?(x2-x1)/_dyn:0, \
19956 _rxr = _dyr?(x2-x0)/_dyr:0, \
19957 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
19958 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn); \
19959 _counter>=0; --_counter, ++y, \
19960 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
19961 xl+=(y!=y1)?_rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0): \
19962 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
19964 #define _cimg_for_triangle2(img,xl,cl,xr,cr,y,x0,y0,c0,x1,y1,c1,x2,y2,c2) \
19965 for (int y = y0<0?0:y0, \
19966 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
19967 cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
19968 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
19969 cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
19970 _sxn=1, _scn=1, \
19971 _sxr=1, _scr=1, \
19972 _sxl=1, _scl=1, \
19973 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
19974 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
19975 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
19976 _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
19977 _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
19978 _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
19979 _dyn = y2-y1, \
19980 _dyr = y2-y0, \
19981 _dyl = y1-y0, \
19982 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
19983 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
19984 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
19985 _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
19986 _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
19987 _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
19988 cimg::min((int)(img).height-y-1,y2-y)), \
19989 _errn = _dyn/2, _errcn = _errn, \
19990 _errr = _dyr/2, _errcr = _errr, \
19991 _errl = _dyl/2, _errcl = _errl, \
19992 _rxn = _dyn?(x2-x1)/_dyn:0, \
19993 _rcn = _dyn?(c2-c1)/_dyn:0, \
19994 _rxr = _dyr?(x2-x0)/_dyr:0, \
19995 _rcr = _dyr?(c2-c0)/_dyr:0, \
19996 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
19997 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
19998 _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
19999 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ); \
20000 _counter>=0; --_counter, ++y, \
20001 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
20002 cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
20003 xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
20004 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
20005 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
20006 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
20008 #define _cimg_for_triangle3(img,xl,txl,tyl,xr,txr,tyr,y,x0,y0,tx0,ty0,x1,y1,tx1,ty1,x2,y2,tx2,ty2) \
20009 for (int y = y0<0?0:y0, \
20010 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
20011 txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
20012 tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
20013 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
20014 txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
20015 tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
20016 _sxn=1, _stxn=1, _styn=1, \
20017 _sxr=1, _stxr=1, _styr=1, \
20018 _sxl=1, _stxl=1, _styl=1, \
20019 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
20020 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
20021 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
20022 _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
20023 _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
20024 _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
20025 _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
20026 _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
20027 _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
20028 _dyn = y2-y1, \
20029 _dyr = y2-y0, \
20030 _dyl = y1-y0, \
20031 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
20032 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
20033 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
20034 _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
20035 _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
20036 _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
20037 _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
20038 _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
20039 _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
20040 cimg::min((int)(img).height-y-1,y2-y)), \
20041 _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, \
20042 _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, \
20043 _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, \
20044 _rxn = _dyn?(x2-x1)/_dyn:0, \
20045 _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
20046 _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
20047 _rxr = _dyr?(x2-x0)/_dyr:0, \
20048 _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
20049 _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
20050 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
20051 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
20052 _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
20053 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
20054 _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
20055 (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
20056 _counter>=0; --_counter, ++y, \
20057 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
20058 txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
20059 tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
20060 xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
20061 tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
20062 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
20063 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
20064 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1,\
20065 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
20067 #define _cimg_for_triangle4(img,xl,cl,txl,tyl,xr,cr,txr,tyr,y,x0,y0,c0,tx0,ty0,x1,y1,c1,tx1,ty1,x2,y2,c2,tx2,ty2) \
20068 for (int y = y0<0?0:y0, \
20069 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
20070 cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
20071 txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
20072 tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
20073 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
20074 cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
20075 txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
20076 tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
20077 _sxn=1, _scn=1, _stxn=1, _styn=1, \
20078 _sxr=1, _scr=1, _stxr=1, _styr=1, \
20079 _sxl=1, _scl=1, _stxl=1, _styl=1, \
20080 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
20081 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
20082 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
20083 _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
20084 _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
20085 _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
20086 _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
20087 _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
20088 _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
20089 _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
20090 _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
20091 _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
20092 _dyn = y2-y1, \
20093 _dyr = y2-y0, \
20094 _dyl = y1-y0, \
20095 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
20096 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
20097 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
20098 _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
20099 _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
20100 _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
20101 _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
20102 _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
20103 _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
20104 _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
20105 _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
20106 _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
20107 cimg::min((int)(img).height-y-1,y2-y)), \
20108 _errn = _dyn/2, _errcn = _errn, _errtxn = _errn, _errtyn = _errn, \
20109 _errr = _dyr/2, _errcr = _errr, _errtxr = _errr, _errtyr = _errr, \
20110 _errl = _dyl/2, _errcl = _errl, _errtxl = _errl, _errtyl = _errl, \
20111 _rxn = _dyn?(x2-x1)/_dyn:0, \
20112 _rcn = _dyn?(c2-c1)/_dyn:0, \
20113 _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
20114 _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
20115 _rxr = _dyr?(x2-x0)/_dyr:0, \
20116 _rcr = _dyr?(c2-c0)/_dyr:0, \
20117 _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
20118 _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
20119 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
20120 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
20121 _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
20122 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ), \
20123 _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
20124 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
20125 _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
20126 (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
20127 _counter>=0; --_counter, ++y, \
20128 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
20129 cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
20130 txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
20131 tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
20132 xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
20133 txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
20134 tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
20135 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
20136 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
20137 _errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
20138 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
20139 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
20141 #define _cimg_for_triangle5(img,xl,txl,tyl,lxl,lyl,xr,txr,tyr,lxr,lyr,y,x0,y0,tx0,ty0,lx0,ly0,x1,y1,tx1,ty1,lx1,ly1,x2,y2,tx2,ty2,lx2,ly2) \
20142 for (int y = y0<0?0:y0, \
20143 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
20144 txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
20145 tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
20146 lxr = y0>=0?lx0:(lx0-y0*(lx2-lx0)/(y2-y0)), \
20147 lyr = y0>=0?ly0:(ly0-y0*(ly2-ly0)/(y2-y0)), \
20148 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
20149 txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
20150 tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
20151 lxl = y1>=0?(y0>=0?(y0==y1?lx1:lx0):(lx0-y0*(lx1-lx0)/(y1-y0))):(lx1-y1*(lx2-lx1)/(y2-y1)), \
20152 lyl = y1>=0?(y0>=0?(y0==y1?ly1:ly0):(ly0-y0*(ly1-ly0)/(y1-y0))):(ly1-y1*(ly2-ly1)/(y2-y1)), \
20153 _sxn=1, _stxn=1, _styn=1, _slxn=1, _slyn=1, \
20154 _sxr=1, _stxr=1, _styr=1, _slxr=1, _slyr=1, \
20155 _sxl=1, _stxl=1, _styl=1, _slxl=1, _slyl=1, \
20156 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), _dyn = y2-y1, \
20157 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), _dyr = y2-y0, \
20158 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), _dyl = y1-y0, \
20159 _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
20160 _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
20161 _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
20162 _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
20163 _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
20164 _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
20165 _dlxn = lx2>lx1?lx2-lx1:(_slxn=-1,lx1-lx2), \
20166 _dlxr = lx2>lx0?lx2-lx0:(_slxr=-1,lx0-lx2), \
20167 _dlxl = lx1>lx0?lx1-lx0:(_slxl=-1,lx0-lx1), \
20168 _dlyn = ly2>ly1?ly2-ly1:(_slyn=-1,ly1-ly2), \
20169 _dlyr = ly2>ly0?ly2-ly0:(_slyr=-1,ly0-ly2), \
20170 _dlyl = ly1>ly0?ly1-ly0:(_slyl=-1,ly0-ly1), \
20171 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
20172 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
20173 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
20174 _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
20175 _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
20176 _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
20177 _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
20178 _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
20179 _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
20180 _dlxn-=_dyn?_dyn*(_dlxn/_dyn):0, \
20181 _dlxr-=_dyr?_dyr*(_dlxr/_dyr):0, \
20182 _dlxl-=_dyl?_dyl*(_dlxl/_dyl):0, \
20183 _dlyn-=_dyn?_dyn*(_dlyn/_dyn):0, \
20184 _dlyr-=_dyr?_dyr*(_dlyr/_dyr):0, \
20185 _dlyl-=_dyl?_dyl*(_dlyl/_dyl):0, \
20186 cimg::min((int)(img).height-y-1,y2-y)), \
20187 _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, _errlxn = _errn, _errlyn = _errn, \
20188 _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, _errlxr = _errr, _errlyr = _errr, \
20189 _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, _errlxl = _errl, _errlyl = _errl, \
20190 _rxn = _dyn?(x2-x1)/_dyn:0, \
20191 _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
20192 _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
20193 _rlxn = _dyn?(lx2-lx1)/_dyn:0, \
20194 _rlyn = _dyn?(ly2-ly1)/_dyn:0, \
20195 _rxr = _dyr?(x2-x0)/_dyr:0, \
20196 _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
20197 _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
20198 _rlxr = _dyr?(lx2-lx0)/_dyr:0, \
20199 _rlyr = _dyr?(ly2-ly0)/_dyr:0, \
20200 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
20201 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
20202 _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
20203 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
20204 _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
20205 (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ), \
20206 _rlxl = (y0!=y1 && y1>0)?(_dyl?(lx1-lx0)/_dyl:0): \
20207 (_errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxn ), \
20208 _rlyl = (y0!=y1 && y1>0)?(_dyl?(ly1-ly0)/_dyl:0): \
20209 (_errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyn ); \
20210 _counter>=0; --_counter, ++y, \
20211 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
20212 txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
20213 tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
20214 lxr+=_rlxr+((_errlxr-=_dlxr)<0?_errlxr+=_dyr,_slxr:0), \
20215 lyr+=_rlyr+((_errlyr-=_dlyr)<0?_errlyr+=_dyr,_slyr:0), \
20216 xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
20217 tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
20218 lxl+=_rlxl+((_errlxl-=_dlxl)<0?(_errlxl+=_dyl,_slxl):0), \
20219 lyl+=_rlyl+((_errlyl-=_dlyl)<0?(_errlyl+=_dyl,_slyl):0), \
20220 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
20221 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
20222 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
20223 _errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxl=_rlxn, lxl=lx1, \
20224 _errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyl=_rlyn, lyl=ly1, \
20225 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
20227 // Draw a colored triangle (inner routine, uses bresenham's algorithm).
20228 template<typename tc>
20229 CImg<T>& _draw_triangle(const int x0, const int y0,
20230 const int x1, const int y1,
20231 const int x2, const int y2,
20232 const tc *const color, const float opacity,
20233 const float brightness) {
20234 _draw_scanline(color,opacity);
20235 const float nbrightness = brightness<0?0:(brightness>2?2:brightness);
20236 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
20237 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
20238 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);
20239 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);
20240 if (ny0<dimy() && ny2>=0) {
20241 if ((nx1 - nx0)*(ny2 - ny0) - (nx2 - nx0)*(ny1 - ny0)<0)
20242 _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xl,xr,y,color,opacity,nbrightness);
20243 else
20244 _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xr,xl,y,color,opacity,nbrightness);
20245 }
20246 return *this;
20247 }
20249 //! Draw a 2D filled colored triangle.
20250 template<typename tc>
20251 CImg<T>& draw_triangle(const int x0, const int y0,
20252 const int x1, const int y1,
20253 const int x2, const int y2,
20254 const tc *const color, const float opacity=1) {
20255 if (is_empty()) return *this;
20256 if (!color)
20257 throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
20258 pixel_type());
20259 _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1);
20260 return *this;
20261 }
20263 //! Draw a 2D filled colored triangle.
20264 template<typename tc>
20265 CImg<T>& draw_triangle(const int x0, const int y0,
20266 const int x1, const int y1,
20267 const int x2, const int y2,
20268 const CImg<tc>& color, const float opacity=1) {
20269 return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity);
20270 }
20272 //! Draw a 2D outlined colored triangle.
20273 template<typename tc>
20274 CImg<T>& draw_triangle(const int x0, const int y0,
20275 const int x1, const int y1,
20276 const int x2, const int y2,
20277 const tc *const color, const float opacity,
20278 const unsigned int pattern) {
20279 if (is_empty()) return *this;
20280 if (!color)
20281 throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
20282 pixel_type());
20283 draw_line(x0,y0,x1,y1,color,opacity,pattern,true).
20284 draw_line(x1,y1,x2,y2,color,opacity,pattern,false).
20285 draw_line(x2,y2,x0,y0,color,opacity,pattern,false);
20286 return *this;
20287 }
20289 //! Draw a 2D outlined colored triangle.
20290 template<typename tc>
20291 CImg<T>& draw_triangle(const int x0, const int y0,
20292 const int x1, const int y1,
20293 const int x2, const int y2,
20294 const CImg<tc>& color, const float opacity,
20295 const unsigned int pattern) {
20296 return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity,pattern);
20297 }
20299 //! Draw a 2D filled colored triangle, with z-buffering.
20300 template<typename tc>
20301 CImg<T>& draw_triangle(float *const zbuffer,
20302 const int x0, const int y0, const float z0,
20303 const int x1, const int y1, const float z1,
20304 const int x2, const int y2, const float z2,
20305 const tc *const color, const float opacity=1,
20306 const float brightness=1) {
20307 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
20308 if (!color)
20309 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
20310 pixel_type());
20311 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20312 const float
20313 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
20314 nbrightness = brightness<0?0:(brightness>2?2:brightness);
20315 const int whz = width*height*depth, offx = dim*whz;
20316 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
20317 float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
20318 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
20319 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2);
20320 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2);
20321 if (ny0>=dimy() || ny2<0) return *this;
20322 float
20323 pzl = (nz1 - nz0)/(ny1 - ny0),
20324 pzr = (nz2 - nz0)/(ny2 - ny0),
20325 pzn = (nz2 - nz1)/(ny2 - ny1),
20326 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
20327 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
20328 _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
20329 if (y==ny1) { zl = nz1; pzl = pzn; }
20330 int xleft = xleft0, xright = xright0;
20331 float zleft = zl, zright = zr;
20332 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright);
20333 const int dx = xright - xleft;
20334 const float pentez = (zright - zleft)/dx;
20335 if (xleft<0 && dx) zleft-=xleft*(zright - zleft)/dx;
20336 if (xleft<0) xleft = 0;
20337 if (xright>=dimx()-1) xright = dimx()-1;
20338 T* ptrd = ptr(xleft,y,0,0);
20339 float *ptrz = zbuffer + xleft + y*width;
20340 if (opacity>=1) {
20341 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20342 if (zleft>*ptrz) {
20343 *ptrz = zleft;
20344 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
20345 ptrd-=offx;
20346 }
20347 zleft+=pentez;
20348 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20349 if (zleft>*ptrz) {
20350 *ptrz = zleft;
20351 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nbrightness*(*col++)); ptrd+=whz; }
20352 ptrd-=offx;
20353 }
20354 zleft+=pentez;
20355 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20356 if (zleft>*ptrz) {
20357 *ptrz = zleft;
20358 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); ptrd+=whz; }
20359 ptrd-=offx;
20360 }
20361 zleft+=pentez;
20362 }
20363 } else {
20364 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20365 if (zleft>*ptrz) {
20366 *ptrz = zleft;
20367 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=whz; }
20368 ptrd-=offx;
20369 }
20370 zleft+=pentez;
20371 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20372 if (zleft>*ptrz) {
20373 *ptrz = zleft;
20374 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity*nbrightness**(col++) + *ptrd*copacity); ptrd+=whz; }
20375 ptrd-=offx;
20376 }
20377 zleft+=pentez;
20378 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20379 if (zleft>*ptrz) {
20380 *ptrz = zleft;
20381 const tc *col = color;
20382 cimg_forV(*this,k) {
20383 const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
20384 *ptrd = (T)(nopacity*val + *ptrd*copacity);
20385 ptrd+=whz;
20386 }
20387 ptrd-=offx;
20388 }
20389 zleft+=pentez;
20390 }
20391 }
20392 zr+=pzr; zl+=pzl;
20393 }
20394 return *this;
20395 }
20397 //! Draw a 2D filled colored triangle, with z-buffering.
20398 template<typename tc>
20399 CImg<T>& draw_triangle(float *const zbuffer,
20400 const int x0, const int y0, const float z0,
20401 const int x1, const int y1, const float z1,
20402 const int x2, const int y2, const float z2,
20403 const CImg<tc>& color, const float opacity=1,
20404 const float brightness=1) {
20405 return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opacity,brightness);
20406 }
20408 //! Draw a 2D Gouraud-shaded colored triangle.
20409 /**
20410 \param x0 = X-coordinate of the first corner in the instance image.
20411 \param y0 = Y-coordinate of the first corner in the instance image.
20412 \param x1 = X-coordinate of the second corner in the instance image.
20413 \param y1 = Y-coordinate of the second corner in the instance image.
20414 \param x2 = X-coordinate of the third corner in the instance image.
20415 \param y2 = Y-coordinate of the third corner in the instance image.
20416 \param color = array of dimv() values of type \c T, defining the global drawing color.
20417 \param brightness0 = brightness of the first corner (in [0,2]).
20418 \param brightness1 = brightness of the second corner (in [0,2]).
20419 \param brightness2 = brightness of the third corner (in [0,2]).
20420 \param opacity = opacity of the drawing.
20421 \note Clipping is supported.
20422 **/
20423 template<typename tc>
20424 CImg<T>& draw_triangle(const int x0, const int y0,
20425 const int x1, const int y1,
20426 const int x2, const int y2,
20427 const tc *const color,
20428 const float brightness0,
20429 const float brightness1,
20430 const float brightness2,
20431 const float opacity=1) {
20432 if (is_empty()) return *this;
20433 if (!color)
20434 throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
20435 pixel_type());
20436 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20437 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
20438 const int whz = width*height*depth, offx = dim*whz-1;
20439 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
20440 nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
20441 nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
20442 nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
20443 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1);
20444 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2);
20445 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2);
20446 if (ny0>=dimy() || ny2<0) return *this;
20447 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
20448 int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
20449 if (xright<xleft) cimg::swap(xleft,xright,cleft,cright);
20450 const int
20451 dx = xright - xleft,
20452 dc = cright>cleft?cright - cleft:cleft - cright,
20453 rc = dx?(cright - cleft)/dx:0,
20454 sc = cright>cleft?1:-1,
20455 ndc = dc-(dx?dx*(dc/dx):0);
20456 int errc = dx>>1;
20457 if (xleft<0 && dx) cleft-=xleft*(cright - cleft)/dx;
20458 if (xleft<0) xleft = 0;
20459 if (xright>=dimx()-1) xright = dimx()-1;
20460 T* ptrd = ptr(xleft,y);
20461 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
20462 const tc *col = color;
20463 cimg_forV(*this,k) {
20464 *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
20465 ptrd+=whz;
20466 }
20467 ptrd-=offx;
20468 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
20469 } else for (int x = xleft; x<=xright; ++x) {
20470 const tc *col = color;
20471 cimg_forV(*this,k) {
20472 const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
20473 *ptrd = (T)(nopacity*val + *ptrd*copacity);
20474 ptrd+=whz;
20475 }
20476 ptrd-=offx;
20477 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
20478 }
20479 }
20480 return *this;
20481 }
20483 //! Draw a 2D Gouraud-shaded colored triangle.
20484 template<typename tc>
20485 CImg<T>& draw_triangle(const int x0, const int y0,
20486 const int x1, const int y1,
20487 const int x2, const int y2,
20488 const CImg<tc>& color,
20489 const float brightness0,
20490 const float brightness1,
20491 const float brightness2,
20492 const float opacity=1) {
20493 return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,brightness0,brightness1,brightness2,opacity);
20494 }
20496 //! Draw a 2D Gouraud-shaded colored triangle, with z-buffering.
20497 template<typename tc>
20498 CImg<T>& draw_triangle(float *const zbuffer,
20499 const int x0, const int y0, const float z0,
20500 const int x1, const int y1, const float z1,
20501 const int x2, const int y2, const float z2,
20502 const tc *const color,
20503 const float brightness0,
20504 const float brightness1,
20505 const float brightness2,
20506 const float opacity=1) {
20507 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
20508 if (!color)
20509 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
20510 pixel_type());
20511 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20512 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
20513 const int whz = width*height*depth, offx = dim*whz;
20514 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
20515 nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
20516 nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
20517 nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
20518 float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
20519 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1,nc0,nc1);
20520 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2,nc0,nc2);
20521 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2,nc1,nc2);
20522 if (ny0>=dimy() || ny2<0) return *this;
20523 float
20524 pzl = (nz1 - nz0)/(ny1 - ny0),
20525 pzr = (nz2 - nz0)/(ny2 - ny0),
20526 pzn = (nz2 - nz1)/(ny2 - ny1),
20527 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
20528 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
20529 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
20530 if (y==ny1) { zl = nz1; pzl = pzn; }
20531 int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
20532 float zleft = zl, zright = zr;
20533 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,cleft,cright);
20534 const int
20535 dx = xright - xleft,
20536 dc = cright>cleft?cright - cleft:cleft - cright,
20537 rc = dx?(cright-cleft)/dx:0,
20538 sc = cright>cleft?1:-1,
20539 ndc = dc-(dx?dx*(dc/dx):0);
20540 const float pentez = (zright - zleft)/dx;
20541 int errc = dx>>1;
20542 if (xleft<0 && dx) {
20543 cleft-=xleft*(cright - cleft)/dx;
20544 zleft-=xleft*(zright - zleft)/dx;
20545 }
20546 if (xleft<0) xleft = 0;
20547 if (xright>=dimx()-1) xright = dimx()-1;
20548 T *ptrd = ptr(xleft,y);
20549 float *ptrz = zbuffer + xleft + y*width;
20550 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
20551 if (zleft>*ptrz) {
20552 *ptrz = zleft;
20553 const tc *col = color;
20554 cimg_forV(*this,k) {
20555 *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
20556 ptrd+=whz;
20557 }
20558 ptrd-=offx;
20559 }
20560 zleft+=pentez;
20561 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
20562 } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
20563 if (zleft>*ptrz) {
20564 *ptrz = zleft;
20565 const tc *col = color;
20566 cimg_forV(*this,k) {
20567 const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
20568 *ptrd = (T)(nopacity*val + *ptrd*copacity);
20569 ptrd+=whz;
20570 }
20571 ptrd-=offx;
20572 }
20573 zleft+=pentez;
20574 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
20575 }
20576 zr+=pzr; zl+=pzl;
20577 }
20578 return *this;
20579 }
20581 //! Draw a Gouraud triangle with z-buffer consideration.
20582 template<typename tc>
20583 CImg<T>& draw_triangle(float *const zbuffer,
20584 const int x0, const int y0, const float z0,
20585 const int x1, const int y1, const float z1,
20586 const int x2, const int y2, const float z2,
20587 const CImg<tc>& color,
20588 const float brightness0,
20589 const float brightness1,
20590 const float brightness2,
20591 const float opacity=1) {
20592 return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,brightness0,brightness1,brightness2,opacity);
20593 }
20595 //! Draw a 2D textured triangle.
20596 /**
20597 \param x0 = X-coordinate of the first corner in the instance image.
20598 \param y0 = Y-coordinate of the first corner in the instance image.
20599 \param x1 = X-coordinate of the second corner in the instance image.
20600 \param y1 = Y-coordinate of the second corner in the instance image.
20601 \param x2 = X-coordinate of the third corner in the instance image.
20602 \param y2 = Y-coordinate of the third corner in the instance image.
20603 \param texture = texture image used to fill the triangle.
20604 \param tx0 = X-coordinate of the first corner in the texture image.
20605 \param ty0 = Y-coordinate of the first corner in the texture image.
20606 \param tx1 = X-coordinate of the second corner in the texture image.
20607 \param ty1 = Y-coordinate of the second corner in the texture image.
20608 \param tx2 = X-coordinate of the third corner in the texture image.
20609 \param ty2 = Y-coordinate of the third corner in the texture image.
20610 \param opacity = opacity of the drawing.
20611 \param brightness = brightness of the drawing (in [0,2]).
20612 \note Clipping is supported, but texture coordinates do not support clipping.
20613 **/
20614 template<typename tc>
20615 CImg<T>& draw_triangle(const int x0, const int y0,
20616 const int x1, const int y1,
20617 const int x2, const int y2,
20618 const CImg<tc>& texture,
20619 const int tx0, const int ty0,
20620 const int tx1, const int ty1,
20621 const int tx2, const int ty2,
20622 const float opacity=1,
20623 const float brightness=1) {
20624 if (is_empty()) return *this;
20625 if (!texture || texture.dim<dim)
20626 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
20627 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
20628 if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
20629 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20630 const float
20631 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
20632 nbrightness = brightness<0?0:(brightness>2?2:brightness);
20633 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
20634 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
20635 ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2;
20636 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
20637 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2);
20638 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2);
20639 if (ny0>=dimy() || ny2<0) return *this;
20640 _cimg_for_triangle3(*this,xleft0,txleft0,tyleft0,xright0,txright0,tyright0,y,
20641 nx0,ny0,ntx0,nty0,nx1,ny1,ntx1,nty1,nx2,ny2,ntx2,nty2) {
20642 int
20643 xleft = xleft0, xright = xright0,
20644 txleft = txleft0, txright = txright0,
20645 tyleft = tyleft0, tyright = tyright0;
20646 if (xright<xleft) cimg::swap(xleft,xright,txleft,txright,tyleft,tyright);
20647 const int
20648 dx = xright - xleft,
20649 dtx = txright>txleft?txright - txleft:txleft - txright,
20650 dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
20651 rtx = dx?(txright - txleft)/dx:0,
20652 rty = dx?(tyright - tyleft)/dx:0,
20653 stx = txright>txleft?1:-1,
20654 sty = tyright>tyleft?1:-1,
20655 ndtx = dtx - (dx?dx*(dtx/dx):0),
20656 ndty = dty - (dx?dx*(dty/dx):0);
20657 int errtx = dx>>1, errty = errtx;
20658 if (xleft<0 && dx) {
20659 txleft-=xleft*(txright - txleft)/dx;
20660 tyleft-=xleft*(tyright - tyleft)/dx;
20661 }
20662 if (xleft<0) xleft = 0;
20663 if (xright>=dimx()-1) xright = dimx()-1;
20664 T* ptrd = ptr(xleft,y,0,0);
20665 if (opacity>=1) {
20666 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
20667 const tc *col = texture.ptr(txleft,tyleft);
20668 cimg_forV(*this,k) {
20669 *ptrd = (T)*col;
20670 ptrd+=whz; col+=twhz;
20671 }
20672 ptrd-=offx;
20673 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20674 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20675 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
20676 const tc *col = texture.ptr(txleft,tyleft);
20677 cimg_forV(*this,k) {
20678 *ptrd = (T)(nbrightness**col);
20679 ptrd+=whz; col+=twhz;
20680 }
20681 ptrd-=offx;
20682 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20683 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20684 } else for (int x = xleft; x<=xright; ++x) {
20685 const tc *col = texture.ptr(txleft,tyleft);
20686 cimg_forV(*this,k) {
20687 *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
20688 ptrd+=whz; col+=twhz;
20689 }
20690 ptrd-=offx;
20691 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20692 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20693 }
20694 } else {
20695 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
20696 const tc *col = texture.ptr(txleft,tyleft);
20697 cimg_forV(*this,k) {
20698 *ptrd = (T)(nopacity**col + *ptrd*copacity);
20699 ptrd+=whz; col+=twhz;
20700 }
20701 ptrd-=offx;
20702 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20703 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20704 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
20705 const tc *col = texture.ptr(txleft,tyleft);
20706 cimg_forV(*this,k) {
20707 *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
20708 ptrd+=whz; col+=twhz;
20709 }
20710 ptrd-=offx;
20711 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20712 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20713 } else for (int x = xleft; x<=xright; ++x) {
20714 const tc *col = texture.ptr(txleft,tyleft);
20715 cimg_forV(*this,k) {
20716 const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
20717 *ptrd = (T)(nopacity*val + *ptrd*copacity);
20718 ptrd+=whz; col+=twhz;
20719 }
20720 ptrd-=offx;
20721 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
20722 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
20723 }
20724 }
20725 }
20726 return *this;
20727 }
20729 //! Draw a 2D textured triangle, with perspective correction.
20730 template<typename tc>
20731 CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
20732 const int x1, const int y1, const float z1,
20733 const int x2, const int y2, const float z2,
20734 const CImg<tc>& texture,
20735 const int tx0, const int ty0,
20736 const int tx1, const int ty1,
20737 const int tx2, const int ty2,
20738 const float opacity=1,
20739 const float brightness=1) {
20740 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
20741 if (!texture || texture.dim<dim)
20742 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
20743 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
20744 if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
20745 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20746 const float
20747 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
20748 nbrightness = brightness<0?0:(brightness>2?2:brightness);
20749 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
20750 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
20751 float
20752 ntx0 = tx0/z0, nty0 = ty0/z0,
20753 ntx1 = tx1/z1, nty1 = ty1/z1,
20754 ntx2 = tx2/z2, nty2 = ty2/z2,
20755 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
20756 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
20757 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
20758 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
20759 if (ny0>=dimy() || ny2<0) return *this;
20760 float
20761 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
20762 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
20763 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
20764 ptyl = (nty1 - nty0)/(ny1 - ny0),
20765 ptyr = (nty2 - nty0)/(ny2 - ny0),
20766 ptyn = (nty2 - nty1)/(ny2 - ny1),
20767 pzl = (nz1 - nz0)/(ny1 - ny0),
20768 pzr = (nz2 - nz0)/(ny2 - ny0),
20769 pzn = (nz2 - nz1)/(ny2 - ny1),
20770 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
20771 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
20772 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
20773 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
20774 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
20775 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
20776 _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
20777 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
20778 int xleft = xleft0, xright = xright0;
20779 float
20780 zleft = zl, zright = zr,
20781 txleft = txl, txright = txr,
20782 tyleft = tyl, tyright = tyr;
20783 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
20784 const int dx = xright - xleft;
20785 const float
20786 pentez = (zright - zleft)/dx,
20787 pentetx = (txright - txleft)/dx,
20788 pentety = (tyright - tyleft)/dx;
20789 if (xleft<0 && dx) {
20790 zleft-=xleft*(zright - zleft)/dx;
20791 txleft-=xleft*(txright - txleft)/dx;
20792 tyleft-=xleft*(tyright - tyleft)/dx;
20793 }
20794 if (xleft<0) xleft = 0;
20795 if (xright>=dimx()-1) xright = dimx()-1;
20796 T* ptrd = ptr(xleft,y,0,0);
20797 if (opacity>=1) {
20798 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
20799 const float invz = 1/zleft;
20800 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20801 cimg_forV(*this,k) {
20802 *ptrd = (T)*col;
20803 ptrd+=whz; col+=twhz;
20804 }
20805 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20806 } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) {
20807 const float invz = 1/zleft;
20808 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20809 cimg_forV(*this,k) {
20810 *ptrd = (T)(nbrightness**col);
20811 ptrd+=whz; col+=twhz;
20812 }
20813 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20814 } else for (int x = xleft; x<=xright; ++x) {
20815 const float invz = 1/zleft;
20816 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20817 cimg_forV(*this,k) {
20818 *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
20819 ptrd+=whz; col+=twhz;
20820 }
20821 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20822 }
20823 } else {
20824 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
20825 const float invz = 1/zleft;
20826 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20827 cimg_forV(*this,k) {
20828 *ptrd = (T)(nopacity**col + *ptrd*copacity);
20829 ptrd+=whz; col+=twhz;
20830 }
20831 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20832 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
20833 const float invz = 1/zleft;
20834 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20835 cimg_forV(*this,k) {
20836 *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
20837 ptrd+=whz; col+=twhz;
20838 }
20839 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20840 } else for (int x = xleft; x<=xright; ++x) {
20841 const float invz = 1/zleft;
20842 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20843 cimg_forV(*this,k) {
20844 const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
20845 *ptrd = (T)(nopacity*val + *ptrd*copacity);
20846 ptrd+=whz; col+=twhz;
20847 }
20848 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20849 }
20850 }
20851 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
20852 }
20853 return *this;
20854 }
20856 //! Draw a 2D textured triangle, with z-buffering and perspective correction.
20857 template<typename tc>
20858 CImg<T>& draw_triangle(float *const zbuffer,
20859 const int x0, const int y0, const float z0,
20860 const int x1, const int y1, const float z1,
20861 const int x2, const int y2, const float z2,
20862 const CImg<tc>& texture,
20863 const int tx0, const int ty0,
20864 const int tx1, const int ty1,
20865 const int tx2, const int ty2,
20866 const float opacity=1,
20867 const float brightness=1) {
20868 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
20869 if (!texture || texture.dim<dim)
20870 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
20871 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
20872 if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
20873 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
20874 const float
20875 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
20876 nbrightness = brightness<0?0:(brightness>2?2:brightness);
20877 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
20878 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
20879 float
20880 ntx0 = tx0/z0, nty0 = ty0/z0,
20881 ntx1 = tx1/z1, nty1 = ty1/z1,
20882 ntx2 = tx2/z2, nty2 = ty2/z2,
20883 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
20884 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
20885 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
20886 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
20887 if (ny0>=dimy() || ny2<0) return *this;
20888 float
20889 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
20890 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
20891 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
20892 ptyl = (nty1 - nty0)/(ny1 - ny0),
20893 ptyr = (nty2 - nty0)/(ny2 - ny0),
20894 ptyn = (nty2 - nty1)/(ny2 - ny1),
20895 pzl = (nz1 - nz0)/(ny1 - ny0),
20896 pzr = (nz2 - nz0)/(ny2 - ny0),
20897 pzn = (nz2 - nz1)/(ny2 - ny1),
20898 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
20899 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
20900 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
20901 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
20902 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
20903 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
20904 _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
20905 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
20906 int xleft = xleft0, xright = xright0;
20907 float
20908 zleft = zl, zright = zr,
20909 txleft = txl, txright = txr,
20910 tyleft = tyl, tyright = tyr;
20911 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
20912 const int dx = xright - xleft;
20913 const float
20914 pentez = (zright - zleft)/dx,
20915 pentetx = (txright - txleft)/dx,
20916 pentety = (tyright - tyleft)/dx;
20917 if (xleft<0 && dx) {
20918 zleft-=xleft*(zright - zleft)/dx;
20919 txleft-=xleft*(txright - txleft)/dx;
20920 tyleft-=xleft*(tyright - tyleft)/dx;
20921 }
20922 if (xleft<0) xleft = 0;
20923 if (xright>=dimx()-1) xright = dimx()-1;
20924 T *ptrd = ptr(xleft,y,0,0);
20925 float *ptrz = zbuffer + xleft + y*width;
20926 if (opacity>=1) {
20927 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20928 if (zleft>*ptrz) {
20929 *ptrz = zleft;
20930 const float invz = 1/zleft;
20931 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20932 cimg_forV(*this,k) {
20933 *ptrd = (T)*col;
20934 ptrd+=whz; col+=twhz;
20935 }
20936 ptrd-=offx;
20937 }
20938 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20939 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20940 if (zleft>*ptrz) {
20941 *ptrz = zleft;
20942 const float invz = 1/zleft;
20943 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20944 cimg_forV(*this,k) {
20945 *ptrd = (T)(nbrightness**col);
20946 ptrd+=whz; col+=twhz;
20947 }
20948 ptrd-=offx;
20949 }
20950 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20951 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20952 if (zleft>*ptrz) {
20953 *ptrz = zleft;
20954 const float invz = 1/zleft;
20955 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20956 cimg_forV(*this,k) {
20957 *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
20958 ptrd+=whz; col+=twhz;
20959 }
20960 ptrd-=offx;
20961 }
20962 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20963 }
20964 } else {
20965 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20966 if (zleft>*ptrz) {
20967 *ptrz = zleft;
20968 const float invz = 1/zleft;
20969 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20970 cimg_forV(*this,k) {
20971 *ptrd = (T)(nopacity**col + *ptrd*copacity);
20972 ptrd+=whz; col+=twhz;
20973 }
20974 ptrd-=offx;
20975 }
20976 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20977 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20978 if (zleft>*ptrz) {
20979 *ptrz = zleft;
20980 const float invz = 1/zleft;
20981 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20982 cimg_forV(*this,k) {
20983 *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
20984 ptrd+=whz; col+=twhz;
20985 }
20986 ptrd-=offx;
20987 }
20988 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
20989 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
20990 if (zleft>*ptrz) {
20991 *ptrz = zleft;
20992 const float invz = 1/zleft;
20993 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
20994 cimg_forV(*this,k) {
20995 const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
20996 *ptrd = (T)(nopacity*val + *ptrd*copacity);
20997 ptrd+=whz; col+=twhz;
20998 }
20999 ptrd-=offx;
21000 }
21001 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21002 }
21003 }
21004 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
21005 }
21006 return *this;
21007 }
21009 //! Draw a 2D Pseudo-Phong-shaded triangle.
21010 /**
21011 \param x0 = X-coordinate of the first corner in the instance image.
21012 \param y0 = Y-coordinate of the first corner in the instance image.
21013 \param x1 = X-coordinate of the second corner in the instance image.
21014 \param y1 = Y-coordinate of the second corner in the instance image.
21015 \param x2 = X-coordinate of the third corner in the instance image.
21016 \param y2 = Y-coordinate of the third corner in the instance image.
21017 \param color = array of dimv() values of type \c T, defining the global drawing color.
21018 \param light = light image.
21019 \param lx0 = X-coordinate of the first corner in the light image.
21020 \param ly0 = Y-coordinate of the first corner in the light image.
21021 \param lx1 = X-coordinate of the second corner in the light image.
21022 \param ly1 = Y-coordinate of the second corner in the light image.
21023 \param lx2 = X-coordinate of the third corner in the light image.
21024 \param ly2 = Y-coordinate of the third corner in the light image.
21025 \param opacity = opacity of the drawing.
21026 \note Clipping is supported, but texture coordinates do not support clipping.
21027 **/
21028 template<typename tc, typename tl>
21029 CImg<T>& draw_triangle(const int x0, const int y0,
21030 const int x1, const int y1,
21031 const int x2, const int y2,
21032 const tc *const color,
21033 const CImg<tl>& light,
21034 const int lx0, const int ly0,
21035 const int lx1, const int ly1,
21036 const int lx2, const int ly2,
21037 const float opacity=1) {
21038 if (is_empty()) return *this;
21039 if (!color)
21040 throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
21041 pixel_type());
21042 if (!light)
21043 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
21044 pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
21045 if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,color,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21046 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21047 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21048 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21049 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
21050 const int whz = width*height*depth, offx = dim*whz-1;
21051 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1);
21052 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2);
21053 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2);
21054 if (ny0>=dimy() || ny2<0) return *this;
21055 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
21056 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
21057 int
21058 xleft = xleft0, xright = xright0,
21059 lxleft = lxleft0, lxright = lxright0,
21060 lyleft = lyleft0, lyright = lyright0;
21061 if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright);
21062 const int
21063 dx = xright - xleft,
21064 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
21065 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
21066 rlx = dx?(lxright - lxleft)/dx:0,
21067 rly = dx?(lyright - lyleft)/dx:0,
21068 slx = lxright>lxleft?1:-1,
21069 sly = lyright>lyleft?1:-1,
21070 ndlx = dlx - (dx?dx*(dlx/dx):0),
21071 ndly = dly - (dx?dx*(dly/dx):0);
21072 int errlx = dx>>1, errly = errlx;
21073 if (xleft<0 && dx) {
21074 lxleft-=xleft*(lxright - lxleft)/dx;
21075 lyleft-=xleft*(lyright - lyleft)/dx;
21076 }
21077 if (xleft<0) xleft = 0;
21078 if (xright>=dimx()-1) xright = dimx()-1;
21079 T* ptrd = ptr(xleft,y,0,0);
21080 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
21081 const tl l = light(lxleft,lyleft);
21082 const tc *col = color;
21083 cimg_forV(*this,k) {
21084 *ptrd = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
21085 ptrd+=whz;
21086 }
21087 ptrd-=offx;
21088 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21089 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21090 } else for (int x = xleft; x<=xright; ++x) {
21091 const tl l = light(lxleft,lyleft);
21092 const tc *col = color;
21093 cimg_forV(*this,k) {
21094 const T val = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
21095 *ptrd = (T)(nopacity*val + *ptrd*copacity);
21096 ptrd+=whz;
21097 }
21098 ptrd-=offx;
21099 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21100 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21101 }
21102 }
21103 return *this;
21104 }
21106 //! Draw a 2D Pseudo-Phong-shaded triangle.
21107 template<typename tc, typename tl>
21108 CImg<T>& draw_triangle(const int x0, const int y0,
21109 const int x1, const int y1,
21110 const int x2, const int y2,
21111 const CImg<tc>& color,
21112 const CImg<tl>& light,
21113 const int lx0, const int ly0,
21114 const int lx1, const int ly1,
21115 const int lx2, const int ly2,
21116 const float opacity=1) {
21117 return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21118 }
21120 //! Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
21121 template<typename tc, typename tl>
21122 CImg<T>& draw_triangle(float *const zbuffer,
21123 const int x0, const int y0, const float z0,
21124 const int x1, const int y1, const float z1,
21125 const int x2, const int y2, const float z2,
21126 const tc *const color,
21127 const CImg<tl>& light,
21128 const int lx0, const int ly0,
21129 const int lx1, const int ly1,
21130 const int lx2, const int ly2,
21131 const float opacity=1) {
21132 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
21133 if (!color)
21134 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
21135 pixel_type());
21136 if (!light)
21137 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
21138 pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
21139 if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,
21140 +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21141 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21142 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21143 const int whz = width*height*depth, offx = dim*whz;
21144 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21145 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
21146 float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
21147 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1,nz0,nz1);
21148 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2,nz0,nz2);
21149 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2,nz1,nz2);
21150 if (ny0>=dimy() || ny2<0) return *this;
21151 float
21152 pzl = (nz1 - nz0)/(ny1 - ny0),
21153 pzr = (nz2 - nz0)/(ny2 - ny0),
21154 pzn = (nz2 - nz1)/(ny2 - ny1),
21155 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
21156 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
21157 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
21158 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
21159 if (y==ny1) { zl = nz1; pzl = pzn; }
21160 int
21161 xleft = xleft0, xright = xright0,
21162 lxleft = lxleft0, lxright = lxright0,
21163 lyleft = lyleft0, lyright = lyright0;
21164 float zleft = zl, zright = zr;
21165 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,lxleft,lxright,lyleft,lyright);
21166 const int
21167 dx = xright - xleft,
21168 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
21169 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
21170 rlx = dx?(lxright - lxleft)/dx:0,
21171 rly = dx?(lyright - lyleft)/dx:0,
21172 slx = lxright>lxleft?1:-1,
21173 sly = lyright>lyleft?1:-1,
21174 ndlx = dlx - (dx?dx*(dlx/dx):0),
21175 ndly = dly - (dx?dx*(dly/dx):0);
21176 const float pentez = (zright - zleft)/dx;
21177 int errlx = dx>>1, errly = errlx;
21178 if (xleft<0 && dx) {
21179 zleft-=xleft*(zright - zleft)/dx;
21180 lxleft-=xleft*(lxright - lxleft)/dx;
21181 lyleft-=xleft*(lyright - lyleft)/dx;
21182 }
21183 if (xleft<0) xleft = 0;
21184 if (xright>=dimx()-1) xright = dimx()-1;
21185 T *ptrd = ptr(xleft,y,0,0);
21186 float *ptrz = zbuffer + xleft + y*width;
21187 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
21188 if (zleft>*ptrz) {
21189 *ptrz = zleft;
21190 const tl l = light(lxleft,lyleft);
21191 const tc *col = color;
21192 cimg_forV(*this,k) {
21193 const tc cval = *(col++);
21194 *ptrd = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
21195 ptrd+=whz;
21196 }
21197 ptrd-=offx;
21198 }
21199 zleft+=pentez;
21200 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21201 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21202 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
21203 if (zleft>*ptrz) {
21204 *ptrz = zleft;
21205 const tl l = light(lxleft,lyleft);
21206 const tc *col = color;
21207 cimg_forV(*this,k) {
21208 const tc cval = *(col++);
21209 const T val = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
21210 *ptrd = (T)(nopacity*val + *ptrd*copacity);
21211 ptrd+=whz;
21212 }
21213 ptrd-=offx;
21214 }
21215 zleft+=pentez;
21216 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21217 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21218 }
21219 zr+=pzr; zl+=pzl;
21220 }
21221 return *this;
21222 }
21224 //! Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
21225 template<typename tc, typename tl>
21226 CImg<T>& draw_triangle(float *const zbuffer,
21227 const int x0, const int y0, const float z0,
21228 const int x1, const int y1, const float z1,
21229 const int x2, const int y2, const float z2,
21230 const CImg<tc>& color,
21231 const CImg<tl>& light,
21232 const int lx0, const int ly0,
21233 const int lx1, const int ly1,
21234 const int lx2, const int ly2,
21235 const float opacity=1) {
21236 return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21237 }
21239 //! Draw a 2D Gouraud-shaded textured triangle.
21240 /**
21241 \param x0 = X-coordinate of the first corner in the instance image.
21242 \param y0 = Y-coordinate of the first corner in the instance image.
21243 \param x1 = X-coordinate of the second corner in the instance image.
21244 \param y1 = Y-coordinate of the second corner in the instance image.
21245 \param x2 = X-coordinate of the third corner in the instance image.
21246 \param y2 = Y-coordinate of the third corner in the instance image.
21247 \param texture = texture image used to fill the triangle.
21248 \param tx0 = X-coordinate of the first corner in the texture image.
21249 \param ty0 = Y-coordinate of the first corner in the texture image.
21250 \param tx1 = X-coordinate of the second corner in the texture image.
21251 \param ty1 = Y-coordinate of the second corner in the texture image.
21252 \param tx2 = X-coordinate of the third corner in the texture image.
21253 \param ty2 = Y-coordinate of the third corner in the texture image.
21254 \param brightness0 = brightness value of the first corner.
21255 \param brightness1 = brightness value of the second corner.
21256 \param brightness2 = brightness value of the third corner.
21257 \param opacity = opacity of the drawing.
21258 \note Clipping is supported, but texture coordinates do not support clipping.
21259 **/
21260 template<typename tc>
21261 CImg<T>& draw_triangle(const int x0, const int y0,
21262 const int x1, const int y1,
21263 const int x2, const int y2,
21264 const CImg<tc>& texture,
21265 const int tx0, const int ty0,
21266 const int tx1, const int ty1,
21267 const int tx2, const int ty2,
21268 const float brightness0,
21269 const float brightness1,
21270 const float brightness2,
21271 const float opacity=1) {
21272 if (is_empty()) return *this;
21273 if (!texture || texture.dim<dim)
21274 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21275 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21276 if (is_overlapped(texture))
21277 return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,brightness0,brightness1,brightness2,opacity);
21278 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21279 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21280 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
21281 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21282 ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
21283 nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
21284 nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
21285 nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
21286 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1);
21287 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2);
21288 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2);
21289 if (ny0>=dimy() || ny2<0) return *this;
21290 _cimg_for_triangle4(*this,xleft0,cleft0,txleft0,tyleft0,xright0,cright0,txright0,tyright0,y,
21291 nx0,ny0,nc0,ntx0,nty0,nx1,ny1,nc1,ntx1,nty1,nx2,ny2,nc2,ntx2,nty2) {
21292 int
21293 xleft = xleft0, xright = xright0,
21294 cleft = cleft0, cright = cright0,
21295 txleft = txleft0, txright = txright0,
21296 tyleft = tyleft0, tyright = tyright0;
21297 if (xright<xleft) cimg::swap(xleft,xright,cleft,cright,txleft,txright,tyleft,tyright);
21298 const int
21299 dx = xright - xleft,
21300 dc = cright>cleft?cright - cleft:cleft - cright,
21301 dtx = txright>txleft?txright - txleft:txleft - txright,
21302 dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
21303 rc = dx?(cright - cleft)/dx:0,
21304 rtx = dx?(txright - txleft)/dx:0,
21305 rty = dx?(tyright - tyleft)/dx:0,
21306 sc = cright>cleft?1:-1,
21307 stx = txright>txleft?1:-1,
21308 sty = tyright>tyleft?1:-1,
21309 ndc = dc - (dx?dx*(dc/dx):0),
21310 ndtx = dtx - (dx?dx*(dtx/dx):0),
21311 ndty = dty - (dx?dx*(dty/dx):0);
21312 int errc = dx>>1, errtx = errc, errty = errc;
21313 if (xleft<0 && dx) {
21314 cleft-=xleft*(cright - cleft)/dx;
21315 txleft-=xleft*(txright - txleft)/dx;
21316 tyleft-=xleft*(tyright - tyleft)/dx;
21317 }
21318 if (xleft<0) xleft = 0;
21319 if (xright>=dimx()-1) xright = dimx()-1;
21320 T* ptrd = ptr(xleft,y,0,0);
21321 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
21322 const tc *col = texture.ptr(txleft,tyleft);
21323 cimg_forV(*this,k) {
21324 *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21325 ptrd+=whz; col+=twhz;
21326 }
21327 ptrd-=offx;
21328 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21329 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
21330 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
21331 } else for (int x = xleft; x<=xright; ++x) {
21332 const tc *col = texture.ptr(txleft,tyleft);
21333 cimg_forV(*this,k) {
21334 const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21335 *ptrd = (T)(nopacity*val + *ptrd*copacity);
21336 ptrd+=whz; col+=twhz;
21337 }
21338 ptrd-=offx;
21339 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21340 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
21341 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
21342 }
21343 }
21344 return *this;
21345 }
21347 //! Draw a 2D Gouraud-shaded textured triangle, with perspective correction.
21348 template<typename tc>
21349 CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
21350 const int x1, const int y1, const float z1,
21351 const int x2, const int y2, const float z2,
21352 const CImg<tc>& texture,
21353 const int tx0, const int ty0,
21354 const int tx1, const int ty1,
21355 const int tx2, const int ty2,
21356 const float brightness0,
21357 const float brightness1,
21358 const float brightness2,
21359 const float opacity=1) {
21360 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
21361 if (!texture || texture.dim<dim)
21362 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21363 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21364 if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
21365 brightness0,brightness1,brightness2,opacity);
21366 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21367 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21368 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
21369 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21370 nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
21371 nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
21372 nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
21373 float
21374 ntx0 = tx0/z0, nty0 = ty0/z0,
21375 ntx1 = tx1/z1, nty1 = ty1/z1,
21376 ntx2 = tx2/z2, nty2 = ty2/z2,
21377 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
21378 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
21379 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
21380 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
21381 if (ny0>=dimy() || ny2<0) return *this;
21382 float
21383 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
21384 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
21385 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
21386 ptyl = (nty1 - nty0)/(ny1 - ny0),
21387 ptyr = (nty2 - nty0)/(ny2 - ny0),
21388 ptyn = (nty2 - nty1)/(ny2 - ny1),
21389 pzl = (nz1 - nz0)/(ny1 - ny0),
21390 pzr = (nz2 - nz0)/(ny2 - ny0),
21391 pzn = (nz2 - nz1)/(ny2 - ny1),
21392 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
21393 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
21394 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
21395 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
21396 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
21397 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
21398 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
21399 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
21400 int
21401 xleft = xleft0, xright = xright0,
21402 cleft = cleft0, cright = cright0;
21403 float
21404 zleft = zl, zright = zr,
21405 txleft = txl, txright = txr,
21406 tyleft = tyl, tyright = tyr;
21407 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
21408 const int
21409 dx = xright - xleft,
21410 dc = cright>cleft?cright - cleft:cleft - cright,
21411 rc = dx?(cright - cleft)/dx:0,
21412 sc = cright>cleft?1:-1,
21413 ndc = dc - (dx?dx*(dc/dx):0);
21414 const float
21415 pentez = (zright - zleft)/dx,
21416 pentetx = (txright - txleft)/dx,
21417 pentety = (tyright - tyleft)/dx;
21418 int errc = dx>>1;
21419 if (xleft<0 && dx) {
21420 cleft-=xleft*(cright - cleft)/dx;
21421 zleft-=xleft*(zright - zleft)/dx;
21422 txleft-=xleft*(txright - txleft)/dx;
21423 tyleft-=xleft*(tyright - tyleft)/dx;
21424 }
21425 if (xleft<0) xleft = 0;
21426 if (xright>=dimx()-1) xright = dimx()-1;
21427 T* ptrd = ptr(xleft,y,0,0);
21428 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
21429 const float invz = 1/zleft;
21430 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21431 cimg_forV(*this,k) {
21432 *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21433 ptrd+=whz; col+=twhz;
21434 }
21435 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21436 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21437 } else for (int x = xleft; x<=xright; ++x) {
21438 const float invz = 1/zleft;
21439 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21440 cimg_forV(*this,k) {
21441 const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21442 *ptrd = (T)(nopacity*val + *ptrd*copacity);
21443 ptrd+=whz; col+=twhz;
21444 }
21445 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21446 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21447 }
21448 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
21449 }
21450 return *this;
21451 }
21453 //! Draw a 2D Gouraud-shaded textured triangle, with z-buffering and perspective correction.
21454 template<typename tc>
21455 CImg<T>& draw_triangle(float *const zbuffer,
21456 const int x0, const int y0, const float z0,
21457 const int x1, const int y1, const float z1,
21458 const int x2, const int y2, const float z2,
21459 const CImg<tc>& texture,
21460 const int tx0, const int ty0,
21461 const int tx1, const int ty1,
21462 const int tx2, const int ty2,
21463 const float brightness0,
21464 const float brightness1,
21465 const float brightness2,
21466 const float opacity=1) {
21467 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
21468 if (!texture || texture.dim<dim)
21469 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21470 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21471 if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
21472 brightness0,brightness1,brightness2,opacity);
21473 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21474 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21475 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
21476 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21477 nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
21478 nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
21479 nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
21480 float
21481 ntx0 = tx0/z0, nty0 = ty0/z0,
21482 ntx1 = tx1/z1, nty1 = ty1/z1,
21483 ntx2 = tx2/z2, nty2 = ty2/z2,
21484 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
21485 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
21486 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
21487 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
21488 if (ny0>=dimy() || ny2<0) return *this;
21489 float
21490 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
21491 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
21492 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
21493 ptyl = (nty1 - nty0)/(ny1 - ny0),
21494 ptyr = (nty2 - nty0)/(ny2 - ny0),
21495 ptyn = (nty2 - nty1)/(ny2 - ny1),
21496 pzl = (nz1 - nz0)/(ny1 - ny0),
21497 pzr = (nz2 - nz0)/(ny2 - ny0),
21498 pzn = (nz2 - nz1)/(ny2 - ny1),
21499 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
21500 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
21501 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
21502 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
21503 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
21504 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
21505 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
21506 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
21507 int
21508 xleft = xleft0, xright = xright0,
21509 cleft = cleft0, cright = cright0;
21510 float
21511 zleft = zl, zright = zr,
21512 txleft = txl, txright = txr,
21513 tyleft = tyl, tyright = tyr;
21514 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
21515 const int
21516 dx = xright - xleft,
21517 dc = cright>cleft?cright - cleft:cleft - cright,
21518 rc = dx?(cright - cleft)/dx:0,
21519 sc = cright>cleft?1:-1,
21520 ndc = dc - (dx?dx*(dc/dx):0);
21521 const float
21522 pentez = (zright - zleft)/dx,
21523 pentetx = (txright - txleft)/dx,
21524 pentety = (tyright - tyleft)/dx;
21525 int errc = dx>>1;
21526 if (xleft<0 && dx) {
21527 cleft-=xleft*(cright - cleft)/dx;
21528 zleft-=xleft*(zright - zleft)/dx;
21529 txleft-=xleft*(txright - txleft)/dx;
21530 tyleft-=xleft*(tyright - tyleft)/dx;
21531 }
21532 if (xleft<0) xleft = 0;
21533 if (xright>=dimx()-1) xright = dimx()-1;
21534 T* ptrd = ptr(xleft,y);
21535 float *ptrz = zbuffer + xleft + y*width;
21536 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
21537 if (zleft>*ptrz) {
21538 *ptrz = zleft;
21539 const float invz = 1/zleft;
21540 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21541 cimg_forV(*this,k) {
21542 *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21543 ptrd+=whz; col+=twhz;
21544 }
21545 ptrd-=offx;
21546 }
21547 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21548 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21549 } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
21550 if (zleft>*ptrz) {
21551 *ptrz = zleft;
21552 const float invz = 1/zleft;
21553 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21554 cimg_forV(*this,k) {
21555 const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
21556 *ptrd = (T)(nopacity*val + *ptrd*copacity);
21557 ptrd+=whz; col+=twhz;
21558 }
21559 ptrd-=offx;
21560 }
21561 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21562 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
21563 }
21564 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
21565 }
21566 return *this;
21567 }
21569 //! Draw a 2D Pseudo-Phong-shaded textured triangle.
21570 /**
21571 \param x0 = X-coordinate of the first corner in the instance image.
21572 \param y0 = Y-coordinate of the first corner in the instance image.
21573 \param x1 = X-coordinate of the second corner in the instance image.
21574 \param y1 = Y-coordinate of the second corner in the instance image.
21575 \param x2 = X-coordinate of the third corner in the instance image.
21576 \param y2 = Y-coordinate of the third corner in the instance image.
21577 \param texture = texture image used to fill the triangle.
21578 \param tx0 = X-coordinate of the first corner in the texture image.
21579 \param ty0 = Y-coordinate of the first corner in the texture image.
21580 \param tx1 = X-coordinate of the second corner in the texture image.
21581 \param ty1 = Y-coordinate of the second corner in the texture image.
21582 \param tx2 = X-coordinate of the third corner in the texture image.
21583 \param ty2 = Y-coordinate of the third corner in the texture image.
21584 \param light = light image.
21585 \param lx0 = X-coordinate of the first corner in the light image.
21586 \param ly0 = Y-coordinate of the first corner in the light image.
21587 \param lx1 = X-coordinate of the second corner in the light image.
21588 \param ly1 = Y-coordinate of the second corner in the light image.
21589 \param lx2 = X-coordinate of the third corner in the light image.
21590 \param ly2 = Y-coordinate of the third corner in the light image.
21591 \param opacity = opacity of the drawing.
21592 \note Clipping is supported, but texture coordinates do not support clipping.
21593 **/
21594 template<typename tc, typename tl>
21595 CImg<T>& draw_triangle(const int x0, const int y0,
21596 const int x1, const int y1,
21597 const int x2, const int y2,
21598 const CImg<tc>& texture,
21599 const int tx0, const int ty0,
21600 const int tx1, const int ty1,
21601 const int tx2, const int ty2,
21602 const CImg<tl>& light,
21603 const int lx0, const int ly0,
21604 const int lx1, const int ly1,
21605 const int lx2, const int ly2,
21606 const float opacity=1) {
21607 if (is_empty()) return *this;
21608 if (!texture || texture.dim<dim)
21609 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21610 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21611 if (!light)
21612 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
21613 pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
21614 if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21615 if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21616 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21617 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21618 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
21619 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21620 ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
21621 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
21622 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1);
21623 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2);
21624 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2);
21625 if (ny0>=dimy() || ny2<0) return *this;
21626 _cimg_for_triangle5(*this,xleft0,lxleft0,lyleft0,txleft0,tyleft0,xright0,lxright0,lyright0,txright0,tyright0,y,
21627 nx0,ny0,nlx0,nly0,ntx0,nty0,nx1,ny1,nlx1,nly1,ntx1,nty1,nx2,ny2,nlx2,nly2,ntx2,nty2) {
21628 int
21629 xleft = xleft0, xright = xright0,
21630 lxleft = lxleft0, lxright = lxright0,
21631 lyleft = lyleft0, lyright = lyright0,
21632 txleft = txleft0, txright = txright0,
21633 tyleft = tyleft0, tyright = tyright0;
21634 if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright,txleft,txright,tyleft,tyright);
21635 const int
21636 dx = xright - xleft,
21637 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
21638 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
21639 dtx = txright>txleft?txright - txleft:txleft - txright,
21640 dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
21641 rlx = dx?(lxright - lxleft)/dx:0,
21642 rly = dx?(lyright - lyleft)/dx:0,
21643 rtx = dx?(txright - txleft)/dx:0,
21644 rty = dx?(tyright - tyleft)/dx:0,
21645 slx = lxright>lxleft?1:-1,
21646 sly = lyright>lyleft?1:-1,
21647 stx = txright>txleft?1:-1,
21648 sty = tyright>tyleft?1:-1,
21649 ndlx = dlx - (dx?dx*(dlx/dx):0),
21650 ndly = dly - (dx?dx*(dly/dx):0),
21651 ndtx = dtx - (dx?dx*(dtx/dx):0),
21652 ndty = dty - (dx?dx*(dty/dx):0);
21653 int errlx = dx>>1, errly = errlx, errtx = errlx, errty = errlx;
21654 if (xleft<0 && dx) {
21655 lxleft-=xleft*(lxright - lxleft)/dx;
21656 lyleft-=xleft*(lyright - lyleft)/dx;
21657 txleft-=xleft*(txright - txleft)/dx;
21658 tyleft-=xleft*(tyright - tyleft)/dx;
21659 }
21660 if (xleft<0) xleft = 0;
21661 if (xright>=dimx()-1) xright = dimx()-1;
21662 T* ptrd = ptr(xleft,y,0,0);
21663 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
21664 const tl l = light(lxleft,lyleft);
21665 const tc *col = texture.ptr(txleft,tyleft);
21666 cimg_forV(*this,k) {
21667 *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21668 ptrd+=whz; col+=twhz;
21669 }
21670 ptrd-=offx;
21671 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21672 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21673 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
21674 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
21675 } else for (int x = xleft; x<=xright; ++x) {
21676 const tl l = light(lxleft,lyleft);
21677 const tc *col = texture.ptr(txleft,tyleft);
21678 cimg_forV(*this,k) {
21679 const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21680 *ptrd = (T)(nopacity*val + *ptrd*copacity);
21681 ptrd+=whz; col+=twhz;
21682 }
21683 ptrd-=offx;
21684 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21685 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21686 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
21687 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
21688 }
21689 }
21690 return *this;
21691 }
21693 //! Draw a 2D Pseudo-Phong-shaded textured triangle, with perspective correction.
21694 template<typename tc, typename tl>
21695 CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
21696 const int x1, const int y1, const float z1,
21697 const int x2, const int y2, const float z2,
21698 const CImg<tc>& texture,
21699 const int tx0, const int ty0,
21700 const int tx1, const int ty1,
21701 const int tx2, const int ty2,
21702 const CImg<tl>& light,
21703 const int lx0, const int ly0,
21704 const int lx1, const int ly1,
21705 const int lx2, const int ly2,
21706 const float opacity=1) {
21707 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
21708 if (!texture || texture.dim<dim)
21709 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21710 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21711 if (!light)
21712 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
21713 pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
21714 if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21715 if (is_overlapped(light)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21716 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21717 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21718 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
21719 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21720 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
21721 float
21722 ntx0 = tx0/z0, nty0 = ty0/z0,
21723 ntx1 = tx1/z1, nty1 = ty1/z1,
21724 ntx2 = tx2/z2, nty2 = ty2/z2,
21725 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
21726 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
21727 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
21728 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
21729 if (ny0>=dimy() || ny2<0) return *this;
21730 float
21731 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
21732 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
21733 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
21734 ptyl = (nty1 - nty0)/(ny1 - ny0),
21735 ptyr = (nty2 - nty0)/(ny2 - ny0),
21736 ptyn = (nty2 - nty1)/(ny2 - ny1),
21737 pzl = (nz1 - nz0)/(ny1 - ny0),
21738 pzr = (nz2 - nz0)/(ny2 - ny0),
21739 pzn = (nz2 - nz1)/(ny2 - ny1),
21740 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
21741 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
21742 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
21743 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
21744 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
21745 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
21746 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
21747 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
21748 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
21749 int
21750 xleft = xleft0, xright = xright0,
21751 lxleft = lxleft0, lxright = lxright0,
21752 lyleft = lyleft0, lyright = lyright0;
21753 float
21754 zleft = zl, zright = zr,
21755 txleft = txl, txright = txr,
21756 tyleft = tyl, tyright = tyr;
21757 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
21758 const int
21759 dx = xright - xleft,
21760 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
21761 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
21762 rlx = dx?(lxright - lxleft)/dx:0,
21763 rly = dx?(lyright - lyleft)/dx:0,
21764 slx = lxright>lxleft?1:-1,
21765 sly = lyright>lyleft?1:-1,
21766 ndlx = dlx - (dx?dx*(dlx/dx):0),
21767 ndly = dly - (dx?dx*(dly/dx):0);
21768 const float
21769 pentez = (zright - zleft)/dx,
21770 pentetx = (txright - txleft)/dx,
21771 pentety = (tyright - tyleft)/dx;
21772 int errlx = dx>>1, errly = errlx;
21773 if (xleft<0 && dx) {
21774 zleft-=xleft*(zright - zleft)/dx;
21775 lxleft-=xleft*(lxright - lxleft)/dx;
21776 lyleft-=xleft*(lyright - lyleft)/dx;
21777 txleft-=xleft*(txright - txleft)/dx;
21778 tyleft-=xleft*(tyright - tyleft)/dx;
21779 }
21780 if (xleft<0) xleft = 0;
21781 if (xright>=dimx()-1) xright = dimx()-1;
21782 T* ptrd = ptr(xleft,y,0,0);
21783 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
21784 const float invz = 1/zleft;
21785 const tl l = light(lxleft,lyleft);
21786 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21787 cimg_forV(*this,k) {
21788 *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21789 ptrd+=whz; col+=twhz;
21790 }
21791 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21792 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21793 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21794 } else for (int x = xleft; x<=xright; ++x) {
21795 const float invz = 1/zleft;
21796 const tl l = light(lxleft,lyleft);
21797 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21798 cimg_forV(*this,k) {
21799 const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21800 *ptrd = (T)(nopacity*val + *ptrd*copacity);
21801 ptrd+=whz; col+=twhz;
21802 }
21803 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21804 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21805 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21806 }
21807 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
21808 }
21809 return *this;
21810 }
21812 //! Draw a 2D Pseudo-Phong-shaded textured triangle, with z-buffering and perspective correction.
21813 template<typename tc, typename tl>
21814 CImg<T>& draw_triangle(float *const zbuffer,
21815 const int x0, const int y0, const float z0,
21816 const int x1, const int y1, const float z1,
21817 const int x2, const int y2, const float z2,
21818 const CImg<tc>& texture,
21819 const int tx0, const int ty0,
21820 const int tx1, const int ty1,
21821 const int tx2, const int ty2,
21822 const CImg<tl>& light,
21823 const int lx0, const int ly0,
21824 const int lx1, const int ly1,
21825 const int lx2, const int ly2,
21826 const float opacity=1) {
21827 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
21828 if (!texture || texture.dim<dim)
21829 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
21830 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
21831 if (!light)
21832 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
21833 pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
21834 if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
21835 +texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21836 if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
21837 texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
21838 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
21839 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
21840 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
21841 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
21842 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
21843 float
21844 ntx0 = tx0/z0, nty0 = ty0/z0,
21845 ntx1 = tx1/z1, nty1 = ty1/z1,
21846 ntx2 = tx2/z2, nty2 = ty2/z2,
21847 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
21848 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
21849 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
21850 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
21851 if (ny0>=dimy() || ny2<0) return *this;
21852 float
21853 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
21854 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
21855 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
21856 ptyl = (nty1 - nty0)/(ny1 - ny0),
21857 ptyr = (nty2 - nty0)/(ny2 - ny0),
21858 ptyn = (nty2 - nty1)/(ny2 - ny1),
21859 pzl = (nz1 - nz0)/(ny1 - ny0),
21860 pzr = (nz2 - nz0)/(ny2 - ny0),
21861 pzn = (nz2 - nz1)/(ny2 - ny1),
21862 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
21863 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
21864 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
21865 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
21866 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
21867 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
21868 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
21869 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
21870 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
21871 int
21872 xleft = xleft0, xright = xright0,
21873 lxleft = lxleft0, lxright = lxright0,
21874 lyleft = lyleft0, lyright = lyright0;
21875 float
21876 zleft = zl, zright = zr,
21877 txleft = txl, txright = txr,
21878 tyleft = tyl, tyright = tyr;
21879 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
21880 const int
21881 dx = xright - xleft,
21882 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
21883 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
21884 rlx = dx?(lxright - lxleft)/dx:0,
21885 rly = dx?(lyright - lyleft)/dx:0,
21886 slx = lxright>lxleft?1:-1,
21887 sly = lyright>lyleft?1:-1,
21888 ndlx = dlx - (dx?dx*(dlx/dx):0),
21889 ndly = dly - (dx?dx*(dly/dx):0);
21890 const float
21891 pentez = (zright - zleft)/dx,
21892 pentetx = (txright - txleft)/dx,
21893 pentety = (tyright - tyleft)/dx;
21894 int errlx = dx>>1, errly = errlx;
21895 if (xleft<0 && dx) {
21896 zleft-=xleft*(zright - zleft)/dx;
21897 lxleft-=xleft*(lxright - lxleft)/dx;
21898 lyleft-=xleft*(lyright - lyleft)/dx;
21899 txleft-=xleft*(txright - txleft)/dx;
21900 tyleft-=xleft*(tyright - tyleft)/dx;
21901 }
21902 if (xleft<0) xleft = 0;
21903 if (xright>=dimx()-1) xright = dimx()-1;
21904 T* ptrd = ptr(xleft,y);
21905 float *ptrz = zbuffer + xleft + y*width;
21906 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
21907 if (zleft>*ptrz) {
21908 *ptrz = zleft;
21909 const float invz = 1/zleft;
21910 const tl l = light(lxleft,lyleft);
21911 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21912 cimg_forV(*this,k) {
21913 *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21914 ptrd+=whz; col+=twhz;
21915 }
21916 ptrd-=offx;
21917 }
21918 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21919 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21920 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21921 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
21922 if (zleft>*ptrz) {
21923 *ptrz = zleft;
21924 const float invz = 1/zleft;
21925 const tl l = light(lxleft,lyleft);
21926 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
21927 cimg_forV(*this,k) {
21928 const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
21929 *ptrd = (T)(nopacity*val + *ptrd*copacity);
21930 ptrd+=whz; col+=twhz;
21931 }
21932 ptrd-=offx;
21933 }
21934 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
21935 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
21936 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
21937 }
21938 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
21939 }
21940 return *this;
21941 }
21943 // Draw a 2D ellipse (inner routine).
21944 template<typename tc>
21945 CImg<T>& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
21946 const tc *const color, const float opacity,
21947 const unsigned int pattern) {
21948 if (is_empty()) return *this;
21949 if (!color)
21950 throw CImgArgumentException("CImg<%s>::draw_ellipse : Specified color is (null).",
21951 pixel_type());
21952 _draw_scanline(color,opacity);
21953 const float
21954 nr1 = cimg::abs(r1), nr2 = cimg::abs(r2),
21955 norm = (float)cimg_std::sqrt(ru*ru+rv*rv),
21956 u = norm>0?ru/norm:1,
21957 v = norm>0?rv/norm:0,
21958 rmax = cimg::max(nr1,nr2),
21959 l1 = (float)cimg_std::pow(rmax/(nr1>0?nr1:1e-6),2),
21960 l2 = (float)cimg_std::pow(rmax/(nr2>0?nr2:1e-6),2),
21961 a = l1*u*u + l2*v*v,
21962 b = u*v*(l1-l2),
21963 c = l1*v*v + l2*u*u;
21964 const int
21965 yb = (int)cimg_std::sqrt(a*rmax*rmax/(a*c-b*b)),
21966 tymin = y0 - yb - 1,
21967 tymax = y0 + yb + 1,
21968 ymin = tymin<0?0:tymin,
21969 ymax = tymax>=dimy()?height-1:tymax;
21970 int oxmin = 0, oxmax = 0;
21971 bool first_line = true;
21972 for (int y = ymin; y<=ymax; ++y) {
21973 const float
21974 Y = y-y0 + (y<y0?0.5f:-0.5f),
21975 delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax),
21976 sdelta = delta>0?(float)cimg_std::sqrt(delta)/a:0.0f,
21977 bY = b*Y/a,
21978 fxmin = x0-0.5f-bY-sdelta,
21979 fxmax = x0+0.5f-bY+sdelta;
21980 const int xmin = (int)fxmin, xmax = (int)fxmax;
21981 if (!pattern) _draw_scanline(xmin,xmax,y,color,opacity);
21982 else {
21983 if (first_line) {
21984 if (y0-yb>=0) _draw_scanline(xmin,xmax,y,color,opacity);
21985 else draw_point(xmin,y,color,opacity).draw_point(xmax,y,color,opacity);
21986 first_line = false;
21987 } else {
21988 if (xmin<oxmin) _draw_scanline(xmin,oxmin-1,y,color,opacity);
21989 else _draw_scanline(oxmin+(oxmin==xmin?0:1),xmin,y,color,opacity);
21990 if (xmax<oxmax) _draw_scanline(xmax,oxmax-1,y,color,opacity);
21991 else _draw_scanline(oxmax+(oxmax==xmax?0:1),xmax,y,color,opacity);
21992 if (y==tymax) _draw_scanline(xmin+1,xmax-1,y,color,opacity);
21993 }
21994 }
21995 oxmin = xmin; oxmax = xmax;
21996 }
21997 return *this;
21998 }
22000 //! Draw a filled ellipse.
22001 /**
22002 \param x0 = X-coordinate of the ellipse center.
22003 \param y0 = Y-coordinate of the ellipse center.
22004 \param r1 = First radius of the ellipse.
22005 \param r2 = Second radius of the ellipse.
22006 \param ru = X-coordinate of the orientation vector related to the first radius.
22007 \param rv = Y-coordinate of the orientation vector related to the first radius.
22008 \param color = array of dimv() values of type \c T, defining the drawing color.
22009 \param opacity = opacity of the drawing.
22010 **/
22011 template<typename tc>
22012 CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
22013 const tc *const color, const float opacity=1) {
22014 return _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,0U);
22015 }
22017 //! Draw a filled ellipse.
22018 template<typename tc>
22019 CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
22020 const CImg<tc>& color, const float opacity=1) {
22021 return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity);
22022 }
22024 //! Draw a filled ellipse.
22025 /**
22026 \param x0 = X-coordinate of the ellipse center.
22027 \param y0 = Y-coordinate of the ellipse center.
22028 \param tensor = Diffusion tensor describing the ellipse.
22029 \param color = array of dimv() values of type \c T, defining the drawing color.
22030 \param opacity = opacity of the drawing.
22031 **/
22032 template<typename t, typename tc>
22033 CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
22034 const tc *const color, const float opacity=1) {
22035 CImgList<t> eig = tensor.get_symmetric_eigen();
22036 const CImg<t> &val = eig[0], &vec = eig[1];
22037 return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity);
22038 }
22040 //! Draw a filled ellipse.
22041 template<typename t, typename tc>
22042 CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
22043 const CImg<tc>& color, const float opacity=1) {
22044 return draw_ellipse(x0,y0,tensor,color.data,opacity);
22045 }
22047 //! Draw an outlined ellipse.
22048 /**
22049 \param x0 = X-coordinate of the ellipse center.
22050 \param y0 = Y-coordinate of the ellipse center.
22051 \param r1 = First radius of the ellipse.
22052 \param r2 = Second radius of the ellipse.
22053 \param ru = X-coordinate of the orientation vector related to the first radius.
22054 \param rv = Y-coordinate of the orientation vector related to the first radius.
22055 \param color = array of dimv() values of type \c T, defining the drawing color.
22056 \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
22057 \param opacity = opacity of the drawing.
22058 **/
22059 template<typename tc>
22060 CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
22061 const tc *const color, const float opacity,
22062 const unsigned int pattern) {
22063 if (pattern) _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,pattern);
22064 return *this;
22065 }
22067 //! Draw an outlined ellipse.
22068 template<typename tc>
22069 CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
22070 const CImg<tc>& color, const float opacity,
22071 const unsigned int pattern) {
22072 return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity,pattern);
22073 }
22075 //! Draw an outlined ellipse.
22076 /**
22077 \param x0 = X-coordinate of the ellipse center.
22078 \param y0 = Y-coordinate of the ellipse center.
22079 \param tensor = Diffusion tensor describing the ellipse.
22080 \param color = array of dimv() values of type \c T, defining the drawing color.
22081 \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
22082 \param opacity = opacity of the drawing.
22083 **/
22084 template<typename t, typename tc>
22085 CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
22086 const tc *const color, const float opacity,
22087 const unsigned int pattern) {
22088 CImgList<t> eig = tensor.get_symmetric_eigen();
22089 const CImg<t> &val = eig[0], &vec = eig[1];
22090 return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity,pattern);
22091 }
22093 //! Draw an outlined ellipse.
22094 template<typename t, typename tc>
22095 CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
22096 const CImg<tc>& color, const float opacity,
22097 const unsigned int pattern) {
22098 return draw_ellipse(x0,y0,tensor,color.data,opacity,pattern);
22099 }
22101 //! Draw a filled circle.
22102 /**
22103 \param x0 X-coordinate of the circle center.
22104 \param y0 Y-coordinate of the circle center.
22105 \param radius Circle radius.
22106 \param color Array of dimv() values of type \c T, defining the drawing color.
22107 \param opacity Drawing opacity.
22108 \note
22109 - Circle version of the Bresenham's algorithm is used.
22110 **/
22111 template<typename tc>
22112 CImg<T>& draw_circle(const int x0, const int y0, int radius,
22113 const tc *const color, const float opacity=1) {
22114 if (!is_empty()) {
22115 if (!color)
22116 throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
22117 pixel_type());
22118 _draw_scanline(color,opacity);
22119 if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
22120 if (y0>=0 && y0<dimy()) _draw_scanline(x0-radius,x0+radius,y0,color,opacity);
22121 for (int f=1-radius, ddFx=0, ddFy=-(radius<<1), x=0, y=radius; x<y; ) {
22122 if (f>=0) {
22123 const int x1 = x0-x, x2 = x0+x, y1 = y0-y, y2 = y0+y;
22124 if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
22125 if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
22126 f+=(ddFy+=2); --y;
22127 }
22128 const bool no_diag = y!=(x++);
22129 ++(f+=(ddFx+=2));
22130 const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x;
22131 if (no_diag) {
22132 if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
22133 if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
22134 }
22135 }
22136 }
22137 return *this;
22138 }
22140 //! Draw a filled circle.
22141 template<typename tc>
22142 CImg<T>& draw_circle(const int x0, const int y0, int radius,
22143 const CImg<tc>& color, const float opacity=1) {
22144 return draw_circle(x0,y0,radius,color.data,opacity);
22145 }
22147 //! Draw an outlined circle.
22148 /**
22149 \param x0 X-coordinate of the circle center.
22150 \param y0 Y-coordinate of the circle center.
22151 \param radius Circle radius.
22152 \param color Array of dimv() values of type \c T, defining the drawing color.
22153 \param opacity Drawing opacity.
22154 **/
22155 template<typename tc>
22156 CImg<T>& draw_circle(const int x0, const int y0, int radius,
22157 const tc *const color, const float opacity,
22158 const unsigned int) {
22159 if (!is_empty()) {
22160 if (!color)
22161 throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
22162 pixel_type());
22163 if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
22164 if (!radius) return draw_point(x0,y0,color,opacity);
22165 draw_point(x0-radius,y0,color,opacity).draw_point(x0+radius,y0,color,opacity).
22166 draw_point(x0,y0-radius,color,opacity).draw_point(x0,y0+radius,color,opacity);
22167 if (radius==1) return *this;
22168 for (int f=1-radius, ddFx=0, ddFy=-(radius<<1), x=0, y=radius; x<y; ) {
22169 if (f>=0) { f+=(ddFy+=2); --y; }
22170 ++x; ++(f+=(ddFx+=2));
22171 if (x!=y+1) {
22172 const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x, x3 = x0-x, x4 = x0+x, y3 = y0-y, y4 = y0+y;
22173 draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity).
22174 draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity);
22175 if (x!=y)
22176 draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity).
22177 draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity);
22178 }
22179 }
22180 }
22181 return *this;
22182 }
22184 //! Draw an outlined circle.
22185 template<typename tc>
22186 CImg<T>& draw_circle(const int x0, const int y0, int radius, const CImg<tc>& color,
22187 const float opacity,
22188 const unsigned int pattern) {
22189 return draw_circle(x0,y0,radius,color.data,opacity,pattern);
22190 }
22192 // Draw a text (internal).
22193 template<typename tc1, typename tc2, typename t>
22194 CImg<T>& _draw_text(const int x0, const int y0, const char *const text,
22195 const tc1 *const foreground_color, const tc2 *const background_color,
22196 const float opacity, const CImgList<t>& font) {
22197 if (!text) return *this;
22198 if (!font)
22199 throw CImgArgumentException("CImg<%s>::draw_text() : Specified font (%u,%p) is empty.",
22200 pixel_type(),font.size,font.data);
22201 const int text_length = cimg::strlen(text);
22203 if (is_empty()) {
22204 // If needed, pre-compute necessary size of the image
22205 int x = 0, y = 0, w = 0;
22206 unsigned char c = 0;
22207 for (int i = 0; i<text_length; ++i) {
22208 c = text[i];
22209 switch (c) {
22210 case '\n' : y+=font[' '].height; if (x>w) w = x; x = 0; break;
22211 case '\t' : x+=4*font[' '].width; break;
22212 default : if (c<font.size) x+=font[c].width;
22213 }
22214 }
22215 if (x!=0 || c=='\n') {
22216 if (x>w) w=x;
22217 y+=font[' '].height;
22218 }
22219 assign(x0+w,y0+y,1,font[' '].dim,0);
22220 if (background_color) cimg_forV(*this,k) get_shared_channel(k).fill((T)background_color[k]);
22221 }
22223 int x = x0, y = y0;
22224 CImg<T> letter;
22225 for (int i = 0; i<text_length; ++i) {
22226 const unsigned char c = text[i];
22227 switch (c) {
22228 case '\n' : y+=font[' '].height; x = x0; break;
22229 case '\t' : x+=4*font[' '].width; break;
22230 default : if (c<font.size) {
22231 letter = font[c];
22232 const CImg<T>& mask = (c+256)<(int)font.size?font[c+256]:font[c];
22233 if (foreground_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
22234 if (mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)(letter(p,0,0,k)*foreground_color[k]);
22235 if (background_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
22236 if (!mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)background_color[k];
22237 if (!background_color && font.size>=512) draw_image(x,y,letter,mask,opacity,(T)1);
22238 else draw_image(x,y,letter,opacity);
22239 x+=letter.width;
22240 }
22241 }
22242 }
22243 return *this;
22244 }
22246 //! Draw a text.
22247 /**
22248 \param x0 X-coordinate of the text in the instance image.
22249 \param y0 Y-coordinate of the text in the instance image.
22250 \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
22251 \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
22252 \param font Font used for drawing text.
22253 \param opacity Drawing opacity.
22254 \param format 'printf'-style format string, followed by arguments.
22255 \note Clipping is supported.
22256 **/
22257 template<typename tc1, typename tc2, typename t>
22258 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22259 const tc1 *const foreground_color, const tc2 *const background_color,
22260 const float opacity, const CImgList<t>& font, ...) {
22261 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
22262 cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22263 return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
22264 }
22266 //! Draw a text.
22267 template<typename tc1, typename tc2, typename t>
22268 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22269 const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
22270 const float opacity, const CImgList<t>& font, ...) {
22271 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
22272 cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22273 return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
22274 }
22276 //! Draw a text.
22277 template<typename tc, typename t>
22278 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22279 const tc *const foreground_color, const int background_color,
22280 const float opacity, const CImgList<t>& font, ...) {
22281 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
22282 cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22283 return _draw_text(x0,y0,tmp,foreground_color,(tc*)background_color,opacity,font);
22284 }
22286 //! Draw a text.
22287 template<typename tc, typename t>
22288 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22289 const int foreground_color, const tc *const background_color,
22290 const float opacity, const CImgList<t>& font, ...) {
22291 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
22292 cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22293 return _draw_text(x0,y0,tmp,(tc*)foreground_color,background_color,opacity,font);
22294 }
22296 //! Draw a text.
22297 /**
22298 \param x0 X-coordinate of the text in the instance image.
22299 \param y0 Y-coordinate of the text in the instance image.
22300 \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
22301 \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
22302 \param font_size Size of the font (nearest match).
22303 \param opacity Drawing opacity.
22304 \param format 'printf'-style format string, followed by arguments.
22305 \note Clipping is supported.
22306 **/
22307 template<typename tc1, typename tc2>
22308 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22309 const tc1 *const foreground_color, const tc2 *const background_color,
22310 const float opacity=1, const unsigned int font_size=11, ...) {
22311 static CImgList<T> font;
22312 static unsigned int fsize = 0;
22313 if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
22314 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22315 return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
22316 }
22318 //! Draw a text.
22319 template<typename tc1, typename tc2>
22320 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22321 const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
22322 const float opacity=1, const unsigned int font_size=11, ...) {
22323 static CImgList<T> font;
22324 static unsigned int fsize = 0;
22325 if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
22326 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22327 return _draw_text(x0,y0,tmp,foreground_color.data,background_color.data,opacity,font);
22328 }
22330 //! Draw a text.
22331 template<typename tc>
22332 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22333 const tc *const foreground_color, const int background_color=0,
22334 const float opacity=1, const unsigned int font_size=11, ...) {
22335 static CImgList<T> font;
22336 static unsigned int fsize = 0;
22337 if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
22338 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22339 return _draw_text(x0,y0,tmp,foreground_color,(const tc*)background_color,opacity,font);
22340 }
22342 //! Draw a text.
22343 template<typename tc>
22344 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
22345 const int foreground_color, const tc *const background_color,
22346 const float opacity=1, const unsigned int font_size=11, ...) {
22347 static CImgList<T> font;
22348 static unsigned int fsize = 0;
22349 if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
22350 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
22351 return _draw_text(x0,y0,tmp,(tc*)foreground_color,background_color,opacity,font);
22352 }
22354 //! Draw a vector field in the instance image, using a colormap.
22355 /**
22356 \param flow Image of 2d vectors used as input data.
22357 \param color Image of dimv()-D vectors corresponding to the color of each arrow.
22358 \param sampling Length (in pixels) between each arrow.
22359 \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
22360 \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
22361 \param opacity Opacity of the drawing.
22362 \param pattern Used pattern to draw lines.
22363 \note Clipping is supported.
22364 **/
22365 template<typename t1, typename t2>
22366 CImg<T>& draw_quiver(const CImg<t1>& flow,
22367 const t2 *const color, const float opacity=1,
22368 const unsigned int sampling=25, const float factor=-20,
22369 const int quiver_type=0, const unsigned int pattern=~0U) {
22370 return draw_quiver(flow,CImg<t2>(color,dim,1,1,1,true),opacity,sampling,factor,quiver_type,pattern);
22371 }
22373 //! Draw a vector field in the instance image, using a colormap.
22374 /**
22375 \param flow Image of 2d vectors used as input data.
22376 \param color Image of dimv()-D vectors corresponding to the color of each arrow.
22377 \param sampling Length (in pixels) between each arrow.
22378 \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
22379 \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
22380 \param opacity Opacity of the drawing.
22381 \param pattern Used pattern to draw lines.
22382 \note Clipping is supported.
22383 **/
22384 template<typename t1, typename t2>
22385 CImg<T>& draw_quiver(const CImg<t1>& flow,
22386 const CImg<t2>& color, const float opacity=1,
22387 const unsigned int sampling=25, const float factor=-20,
22388 const int quiver_type=0, const unsigned int pattern=~0U) {
22389 if (!is_empty()) {
22390 if (!flow || flow.dim!=2)
22391 throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.",
22392 pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data);
22393 if (sampling<=0)
22394 throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g",
22395 pixel_type(),sampling);
22396 const bool colorfield = (color.width==flow.width && color.height==flow.height && color.depth==1 && color.dim==dim);
22397 if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,quiver_type,pattern);
22399 float vmax,fact;
22400 if (factor<=0) {
22401 float m, M = (float)flow.get_pointwise_norm(2).maxmin(m);
22402 vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
22403 fact = -factor;
22404 } else { fact = factor; vmax = 1; }
22406 for (unsigned int y=sampling/2; y<height; y+=sampling)
22407 for (unsigned int x=sampling/2; x<width; x+=sampling) {
22408 const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
22409 float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
22410 if (!quiver_type) {
22411 const int xx = x+(int)u, yy = y+(int)v;
22412 if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y).data,opacity,45,sampling/5.0f,pattern);
22413 else draw_arrow(x,y,xx,yy,color,opacity,45,sampling/5.0f,pattern);
22414 } else {
22415 if (colorfield) draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color.get_vector_at(X,Y),opacity,pattern);
22416 else draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color,opacity,pattern);
22417 }
22418 }
22419 }
22420 return *this;
22421 }
22423 //! Draw a 1D graph on the instance image.
22424 /**
22425 \param data Image containing the graph values I = f(x).
22426 \param color Array of dimv() values of type \c T, defining the drawing color.
22427 \param gtype Define the type of the plot :
22428 - 0 = Plot using points clouds.
22429 - 1 = Plot using linear interpolation (segments).
22430 - 2 = Plot with bars.
22431 - 3 = Plot using cubic interpolation (3-polynomials).
22432 - 4 = Plot using cross clouds.
22433 \param ymin Lower bound of the y-range.
22434 \param ymax Upper bound of the y-range.
22435 \param opacity Drawing opacity.
22436 \param pattern Drawing pattern.
22437 \note
22438 - if \c ymin==ymax==0, the y-range is computed automatically from the input sample.
22439 **/
22440 template<typename t, typename tc>
22441 CImg<T>& draw_graph(const CImg<t>& data,
22442 const tc *const color, const float opacity=1,
22443 const unsigned int plot_type=1, const unsigned int vertex_type=1,
22444 const double ymin=0, const double ymax=0,
22445 const unsigned int pattern=~0U) {
22446 if (is_empty() || height<=1) return *this;;
22447 const unsigned long siz = data.size();
22448 if (!color)
22449 throw CImgArgumentException("CImg<%s>::draw_graph() : Specified color is (null)",
22450 pixel_type());
22451 tc *color1 = 0, *color2 = 0;
22452 if (plot_type==3) {
22453 color1 = new tc[dim]; color2 = new tc[dim];
22454 cimg_forV(*this,k) { color1[k] = (tc)(color[k]*0.6f); color2[k] = (tc)(color[k]*0.3f); }
22455 }
22457 double m = ymin, M = ymax;
22458 if (ymin==ymax) m = (double)data.maxmin(M);
22459 if (m==M) { --m; ++M; }
22460 const float ca = (float)(M-m)/(height-1);
22461 bool init_hatch = true;
22463 // Draw graph edges
22464 switch (plot_type%4) {
22465 case 1 : { // Segments
22466 int oX = 0, oY = (int)((data[0]-m)/ca);
22467 for (unsigned long off = 1; off<siz; ++off) {
22468 const int
22469 X = (int)(off*width/siz),
22470 Y = (int)((data[off]-m)/ca);
22471 draw_line(oX,oY,X,Y,color,opacity,pattern,init_hatch);
22472 oX = X; oY = Y;
22473 init_hatch = false;
22474 }
22475 } break;
22476 case 2 : { // Spline
22477 const CImg<t> ndata = data.get_shared_points(0,siz-1);
22478 int oY = (int)((data[0]-m)/ca);
22479 cimg_forX(*this,x) {
22480 const int Y = (int)((ndata._cubic_atX((float)x*ndata.width/width)-m)/ca);
22481 if (x>0) draw_line(x,oY,x+1,Y,color,opacity,pattern,init_hatch);
22482 init_hatch = false;
22483 oY = Y;
22484 }
22485 } break;
22486 case 3 : { // Bars
22487 const int Y0 = (int)(-m/ca);
22488 int oX = 0;
22489 cimg_foroff(data,off) {
22490 const int
22491 X = (off+1)*width/siz-1,
22492 Y = (int)((data[off]-m)/ca);
22493 draw_rectangle(oX,Y0,X,Y,color1,opacity).
22494 draw_line(oX,Y,oX,Y0,color2,opacity).
22495 draw_line(oX,Y0,X,Y0,Y<=Y0?color2:color,opacity).
22496 draw_line(X,Y,X,Y0,color,opacity).
22497 draw_line(oX,Y,X,Y,Y<=Y0?color:color2,opacity);
22498 oX = X+1;
22499 }
22500 } break;
22501 default : break; // No edges
22502 }
22504 // Draw graph points
22505 switch (vertex_type%8) {
22506 case 1 : { // Point
22507 cimg_foroff(data,off) {
22508 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22509 draw_point(X,Y,color,opacity);
22510 }
22511 } break;
22512 case 2 : { // Standard Cross
22513 cimg_foroff(data,off) {
22514 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22515 draw_line(X-3,Y,X+3,Y,color,opacity).draw_line(X,Y-3,X,Y+3,color,opacity);
22516 }
22517 } break;
22518 case 3 : { // Rotated Cross
22519 cimg_foroff(data,off) {
22520 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22521 draw_line(X-3,Y-3,X+3,Y+3,color,opacity).draw_line(X-3,Y+3,X+3,Y-3,color,opacity);
22522 }
22523 } break;
22524 case 4 : { // Filled Circle
22525 cimg_foroff(data,off) {
22526 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22527 draw_circle(X,Y,3,color,opacity);
22528 }
22529 } break;
22530 case 5 : { // Outlined circle
22531 cimg_foroff(data,off) {
22532 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22533 draw_circle(X,Y,3,color,opacity,0U);
22534 }
22535 } break;
22536 case 6 : { // Square
22537 cimg_foroff(data,off) {
22538 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22539 draw_rectangle(X-3,Y-3,X+3,Y+3,color,opacity,~0U);
22540 }
22541 } break;
22542 case 7 : { // Diamond
22543 cimg_foroff(data,off) {
22544 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
22545 draw_line(X,Y-4,X+4,Y,color,opacity).
22546 draw_line(X+4,Y,X,Y+4,color,opacity).
22547 draw_line(X,Y+4,X-4,Y,color,opacity).
22548 draw_line(X-4,Y,X,Y-4,color,opacity);
22549 }
22550 } break;
22551 default : break; // No vertices
22552 }
22554 if (color1) delete[] color1; if (color2) delete[] color2;
22555 return *this;
22556 }
22558 //! Draw a 1D graph on the instance image.
22559 template<typename t, typename tc>
22560 CImg<T>& draw_graph(const CImg<t>& data,
22561 const CImg<tc>& color, const float opacity=1,
22562 const unsigned int plot_type=1, const unsigned int vertex_type=1,
22563 const double ymin=0, const double ymax=0,
22564 const unsigned int pattern=~0U) {
22565 return draw_graph(data,color.data,opacity,plot_type,vertex_type,ymin,ymax,pattern);
22566 }
22568 //! Draw a labeled horizontal axis on the instance image.
22569 /**
22570 \param xvalues Lower bound of the x-range.
22571 \param y Y-coordinate of the horizontal axis in the instance image.
22572 \param color Array of dimv() values of type \c T, defining the drawing color.
22573 \param opacity Drawing opacity.
22574 \param pattern Drawing pattern.
22575 \param opacity_out Drawing opacity of 'outside' axes.
22576 \note if \c precision==0, precision of the labels is automatically computed.
22577 **/
22578 template<typename t, typename tc>
22579 CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
22580 const tc *const color, const float opacity=1,
22581 const unsigned int pattern=~0U) {
22582 if (!is_empty()) {
22583 int siz = (int)xvalues.size()-1;
22584 if (siz<=0) draw_line(0,y,width-1,y,color,opacity,pattern);
22585 else {
22586 if (xvalues[0]<xvalues[siz]) draw_arrow(0,y,width-1,y,color,opacity,30,5,pattern);
22587 else draw_arrow(width-1,y,0,y,color,opacity,30,5,pattern);
22588 const int yt = (y+14)<dimy()?(y+3):(y-14);
22589 char txt[32];
22590 cimg_foroff(xvalues,x) {
22591 cimg_std::sprintf(txt,"%g",(double)xvalues(x));
22592 const int xi = (int)(x*(width-1)/siz), xt = xi-(int)cimg::strlen(txt)*3;
22593 draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity).
22594 draw_text(xt<0?0:xt,yt,txt,color,(tc*)0,opacity,11);
22595 }
22596 }
22597 }
22598 return *this;
22599 }
22601 //! Draw a labeled horizontal axis on the instance image.
22602 template<typename t, typename tc>
22603 CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
22604 const CImg<tc>& color, const float opacity=1,
22605 const unsigned int pattern=~0U) {
22606 return draw_axis(xvalues,y,color.data,opacity,pattern);
22607 }
22609 //! Draw a labeled vertical axis on the instance image.
22610 template<typename t, typename tc>
22611 CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
22612 const tc *const color, const float opacity=1,
22613 const unsigned int pattern=~0U) {
22614 if (!is_empty()) {
22615 int siz = (int)yvalues.size()-1;
22616 if (siz<=0) draw_line(x,0,x,height-1,color,opacity,pattern);
22617 else {
22618 if (yvalues[0]<yvalues[siz]) draw_arrow(x,0,x,height-1,color,opacity,30,5,pattern);
22619 else draw_arrow(x,height-1,x,0,color,opacity,30,5,pattern);
22620 char txt[32];
22621 cimg_foroff(yvalues,y) {
22622 cimg_std::sprintf(txt,"%g",(double)yvalues(y));
22623 const int
22624 yi = (int)(y*(height-1)/siz),
22625 tmp = yi-5,
22626 nyi = tmp<0?0:(tmp>=dimy()-11?dimy()-11:tmp),
22627 xt = x-(int)cimg::strlen(txt)*7;
22628 draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity);
22629 if (xt>0) draw_text(xt,nyi,txt,color,(tc*)0,opacity,11);
22630 else draw_text(x+3,nyi,txt,color,(tc*)0,opacity,11);
22631 }
22632 }
22633 }
22634 return *this;
22635 }
22637 //! Draw a labeled vertical axis on the instance image.
22638 template<typename t, typename tc>
22639 CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
22640 const CImg<tc>& color, const float opacity=1,
22641 const unsigned int pattern=~0U) {
22642 return draw_axis(x,yvalues,color.data,opacity,pattern);
22643 }
22645 //! Draw a labeled horizontal+vertical axis on the instance image.
22646 template<typename tx, typename ty, typename tc>
22647 CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
22648 const tc *const color, const float opacity=1,
22649 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22650 if (!is_empty()) {
22651 const CImg<tx> nxvalues(xvalues.data,xvalues.size(),1,1,1,true);
22652 const int sizx = (int)xvalues.size()-1, wm1 = (int)(width)-1;
22653 if (sizx>0) {
22654 float ox = (float)nxvalues[0];
22655 for (unsigned int x = 1; x<width; ++x) {
22656 const float nx = (float)nxvalues._linear_atX((float)x*sizx/wm1);
22657 if (nx*ox<=0) { draw_axis(nx==0?x:x-1,yvalues,color,opacity,patterny); break; }
22658 ox = nx;
22659 }
22660 }
22661 const CImg<ty> nyvalues(yvalues.data,yvalues.size(),1,1,1,true);
22662 const int sizy = (int)yvalues.size()-1, hm1 = (int)(height)-1;
22663 if (sizy>0) {
22664 float oy = (float)nyvalues[0];
22665 for (unsigned int y = 1; y<height; ++y) {
22666 const float ny = (float)nyvalues._linear_atX((float)y*sizy/hm1);
22667 if (ny*oy<=0) { draw_axis(xvalues,ny==0?y:y-1,color,opacity,patternx); break; }
22668 oy = ny;
22669 }
22670 }
22671 }
22672 return *this;
22673 }
22675 //! Draw a labeled horizontal+vertical axis on the instance image.
22676 template<typename tx, typename ty, typename tc>
22677 CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
22678 const CImg<tc>& color, const float opacity=1,
22679 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22680 return draw_axis(xvalues,yvalues,color.data,opacity,patternx,patterny);
22681 }
22683 //! Draw a labeled horizontal+vertical axis on the instance image.
22684 template<typename tc>
22685 CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
22686 const tc *const color, const float opacity=1,
22687 const int subdivisionx=-60, const int subdivisiony=-60,
22688 const float precisionx=0, const float precisiony=0,
22689 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22690 if (!is_empty()) {
22691 const float
22692 dx = cimg::abs(x1-x0), dy = cimg::abs(y1-y0),
22693 px = (precisionx==0)?(float)cimg_std::pow(10.0,(int)cimg_std::log10(dx)-2.0):precisionx,
22694 py = (precisiony==0)?(float)cimg_std::pow(10.0,(int)cimg_std::log10(dy)-2.0):precisiony;
22695 draw_axis(CImg<floatT>::sequence(subdivisionx>0?subdivisionx:1-dimx()/subdivisionx,x0,x1).round(px),
22696 CImg<floatT>::sequence(subdivisiony>0?subdivisiony:1-dimy()/subdivisiony,y0,y1).round(py),
22697 color,opacity,patternx,patterny);
22698 }
22699 return *this;
22700 }
22702 //! Draw a labeled horizontal+vertical axis on the instance image.
22703 template<typename tc>
22704 CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
22705 const CImg<tc>& color, const float opacity=1,
22706 const int subdivisionx=-60, const int subdivisiony=-60,
22707 const float precisionx=0, const float precisiony=0,
22708 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22709 return draw_axis(x0,x1,y0,y1,color.data,opacity,subdivisionx,subdivisiony,precisionx,precisiony,patternx,patterny);
22710 }
22712 //! Draw grid.
22713 template<typename tx, typename ty, typename tc>
22714 CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
22715 const tc *const color, const float opacity=1,
22716 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22717 if (!is_empty()) {
22718 if (xvalues) cimg_foroff(xvalues,x) {
22719 const int xi = (int)xvalues[x];
22720 if (xi>=0 && xi<dimx()) draw_line(xi,0,xi,height-1,color,opacity,patternx);
22721 }
22722 if (yvalues) cimg_foroff(yvalues,y) {
22723 const int yi = (int)yvalues[y];
22724 if (yi>=0 && yi<dimy()) draw_line(0,yi,width-1,yi,color,opacity,patterny);
22725 }
22726 }
22727 return *this;
22728 }
22730 //! Draw grid.
22731 template<typename tx, typename ty, typename tc>
22732 CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
22733 const CImg<tc>& color, const float opacity=1,
22734 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22735 return draw_grid(xvalues,yvalues,color.data,opacity,patternx,patterny);
22736 }
22738 //! Draw grid.
22739 template<typename tc>
22740 CImg<T>& draw_grid(const float deltax, const float deltay,
22741 const float offsetx, const float offsety,
22742 const bool invertx, const bool inverty,
22743 const tc *const color, const float opacity=1,
22744 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22745 CImg<uintT> seqx, seqy;
22746 if (deltax!=0) {
22747 const float dx = deltax>0?deltax:width*-deltax/100;
22748 const unsigned int nx = (unsigned int)(width/dx);
22749 seqx = CImg<uintT>::sequence(1+nx,0,(unsigned int)(dx*nx));
22750 if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x)+offsetx,(float)width);
22751 if (invertx) cimg_foroff(seqx,x) seqx(x) = width-1-seqx(x);
22752 }
22754 if (deltay!=0) {
22755 const float dy = deltay>0?deltay:height*-deltay/100;
22756 const unsigned int ny = (unsigned int)(height/dy);
22757 seqy = CImg<uintT>::sequence(1+ny,0,(unsigned int)(dy*ny));
22758 if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y)+offsety,(float)height);
22759 if (inverty) cimg_foroff(seqy,y) seqy(y) = height-1-seqy(y);
22760 }
22761 return draw_grid(seqx,seqy,color,opacity,patternx,patterny);
22762 }
22764 //! Draw grid.
22765 template<typename tc>
22766 CImg<T>& draw_grid(const float deltax, const float deltay,
22767 const float offsetx, const float offsety,
22768 const bool invertx, const bool inverty,
22769 const CImg<tc>& color, const float opacity=1,
22770 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
22771 return draw_grid(deltax,deltay,offsetx,offsety,invertx,inverty,color.data,opacity,patternx,patterny);
22772 }
22774 //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
22775 /**
22776 \param x X-coordinate of the starting point of the region to fill.
22777 \param y Y-coordinate of the starting point of the region to fill.
22778 \param z Z-coordinate of the starting point of the region to fill.
22779 \param color An array of dimv() values of type \c T, defining the drawing color.
22780 \param region Image that will contain the mask of the filled region mask, as an output.
22781 \param sigma Tolerance concerning neighborhood values.
22782 \param opacity Opacity of the drawing.
22783 \param high_connexity Tells if 8-connexity must be used (only for 2D images).
22784 \return \p region is initialized with the binary mask of the filled region.
22785 **/
22786 template<typename tc, typename t>
22787 CImg<T>& draw_fill(const int x, const int y, const int z,
22788 const tc *const color, const float opacity,
22789 CImg<t>& region, const float sigma=0,
22790 const bool high_connexity=false) {
22792 #define _cimg_draw_fill_test(x,y,z,res) if (region(x,y,z)) res = false; else { \
22793 res = true; \
22794 const T *reference_col = reference_color.ptr() + dim, *ptrs = ptr(x,y,z) + siz; \
22795 for (unsigned int i = dim; res && i; --i) { ptrs-=whz; res = (cimg::abs(*ptrs - *(--reference_col))<=sigma); } \
22796 region(x,y,z) = (t)(res?1:noregion); \
22797 }
22799 #define _cimg_draw_fill_set(x,y,z) { \
22800 const tc *col = color; \
22801 T *ptrd = ptr(x,y,z); \
22802 if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; } \
22803 else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; } \
22804 }
22806 #define _cimg_draw_fill_insert(x,y,z) { \
22807 if (posr1>=remaining.height) remaining.resize(3,remaining.height<<1,1,1,0); \
22808 unsigned int *ptrr = remaining.ptr(0,posr1); \
22809 *(ptrr++) = x; *(ptrr++) = y; *(ptrr++) = z; ++posr1; \
22810 }
22812 #define _cimg_draw_fill_test_neighbor(x,y,z,cond) if (cond) { \
22813 const unsigned int tx = x, ty = y, tz = z; \
22814 _cimg_draw_fill_test(tx,ty,tz,res); if (res) _cimg_draw_fill_insert(tx,ty,tz); \
22815 }
22817 if (!color)
22818 throw CImgArgumentException("CImg<%s>::draw_fill() : Specified color is (null).",
22819 pixel_type());
22820 region.assign(width,height,depth,1,(t)0);
22821 if (x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz()) {
22822 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
22823 const unsigned int whz = width*height*depth, siz = dim*whz, W1 = width-1, H1 = height-1, D1 = depth-1;
22824 const bool threed = depth>1;
22825 const CImg<T> reference_color = get_vector_at(x,y,z);
22826 CImg<uintT> remaining(3,512,1,1,0);
22827 remaining(0,0) = x; remaining(1,0) = y; remaining(2,0) = z;
22828 unsigned int posr0 = 0, posr1 = 1;
22829 region(x,y,z) = (t)1;
22830 const t noregion = ((t)1==(t)2)?(t)0:(t)(-1);
22831 if (threed) do { // 3D version of the filling algorithm
22832 const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++), zc = *(pcurr++);
22833 if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
22834 bool cont, res;
22835 unsigned int nxc = xc;
22836 do { // X-backward
22837 _cimg_draw_fill_set(nxc,yc,zc);
22838 _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
22839 _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
22840 _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
22841 _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
22842 if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
22843 } while (cont);
22844 nxc = xc;
22845 do { // X-forward
22846 if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
22847 if (cont) {
22848 _cimg_draw_fill_set(nxc,yc,zc);
22849 _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
22850 _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
22851 _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
22852 _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
22853 }
22854 } while (cont);
22855 unsigned int nyc = yc;
22856 do { // Y-backward
22857 if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
22858 if (cont) {
22859 _cimg_draw_fill_set(xc,nyc,zc);
22860 _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
22861 _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
22862 _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
22863 _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
22864 }
22865 } while (cont);
22866 nyc = yc;
22867 do { // Y-forward
22868 if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
22869 if (cont) {
22870 _cimg_draw_fill_set(xc,nyc,zc);
22871 _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
22872 _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
22873 _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
22874 _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
22875 }
22876 } while (cont);
22877 unsigned int nzc = zc;
22878 do { // Z-backward
22879 if (nzc) { --nzc; _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
22880 if (cont) {
22881 _cimg_draw_fill_set(xc,yc,nzc);
22882 _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
22883 _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
22884 _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
22885 _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
22886 }
22887 } while (cont);
22888 nzc = zc;
22889 do { // Z-forward
22890 if ((++nzc)<=D1) { _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
22891 if (cont) {
22892 _cimg_draw_fill_set(xc,nyc,zc);
22893 _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
22894 _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
22895 _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
22896 _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
22897 }
22898 } while (cont);
22899 } while (posr1>posr0);
22900 else do { // 2D version of the filling algorithm
22901 const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++);
22902 if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
22903 bool cont, res;
22904 unsigned int nxc = xc;
22905 do { // X-backward
22906 _cimg_draw_fill_set(nxc,yc,0);
22907 _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
22908 _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
22909 if (high_connexity) {
22910 _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
22911 _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
22912 _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
22913 _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
22914 }
22915 if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
22916 } while (cont);
22917 nxc = xc;
22918 do { // X-forward
22919 if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
22920 if (cont) {
22921 _cimg_draw_fill_set(nxc,yc,0);
22922 _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
22923 _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
22924 if (high_connexity) {
22925 _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
22926 _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
22927 _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
22928 _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
22929 }
22930 }
22931 } while (cont);
22932 unsigned int nyc = yc;
22933 do { // Y-backward
22934 if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
22935 if (cont) {
22936 _cimg_draw_fill_set(xc,nyc,0);
22937 _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
22938 _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
22939 if (high_connexity) {
22940 _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
22941 _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
22942 _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
22943 _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
22944 }
22945 }
22946 } while (cont);
22947 nyc = yc;
22948 do { // Y-forward
22949 if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
22950 if (cont) {
22951 _cimg_draw_fill_set(xc,nyc,0);
22952 _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
22953 _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
22954 if (high_connexity) {
22955 _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
22956 _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
22957 _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
22958 _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
22959 }
22960 }
22961 } while (cont);
22962 } while (posr1>posr0);
22963 if (noregion) cimg_for(region,ptr,t) if (*ptr==noregion) *ptr = (t)0;
22964 }
22965 return *this;
22966 }
22968 //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
22969 template<typename tc, typename t>
22970 CImg<T>& draw_fill(const int x, const int y, const int z,
22971 const CImg<tc>& color, const float opacity,
22972 CImg<t>& region, const float sigma=0, const bool high_connexity=false) {
22973 return draw_fill(x,y,z,color.data,opacity,region,sigma,high_connexity);
22974 }
22976 //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
22977 /**
22978 \param x = X-coordinate of the starting point of the region to fill.
22979 \param y = Y-coordinate of the starting point of the region to fill.
22980 \param z = Z-coordinate of the starting point of the region to fill.
22981 \param color = an array of dimv() values of type \c T, defining the drawing color.
22982 \param sigma = tolerance concerning neighborhood values.
22983 \param opacity = opacity of the drawing.
22984 **/
22985 template<typename tc>
22986 CImg<T>& draw_fill(const int x, const int y, const int z,
22987 const tc *const color, const float opacity=1,
22988 const float sigma=0, const bool high_connexity=false) {
22989 CImg<boolT> tmp;
22990 return draw_fill(x,y,z,color,opacity,tmp,sigma,high_connexity);
22991 }
22993 //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
22994 template<typename tc>
22995 CImg<T>& draw_fill(const int x, const int y, const int z,
22996 const CImg<tc>& color, const float opacity=1,
22997 const float sigma=0, const bool high_connexity=false) {
22998 return draw_fill(x,y,z,color.data,opacity,sigma,high_connexity);
22999 }
23001 //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
23002 /**
23003 \param x = X-coordinate of the starting point of the region to fill.
23004 \param y = Y-coordinate of the starting point of the region to fill.
23005 \param color = an array of dimv() values of type \c T, defining the drawing color.
23006 \param sigma = tolerance concerning neighborhood values.
23007 \param opacity = opacity of the drawing.
23008 **/
23009 template<typename tc>
23010 CImg<T>& draw_fill(const int x, const int y,
23011 const tc *const color, const float opacity=1,
23012 const float sigma=0, const bool high_connexity=false) {
23013 CImg<boolT> tmp;
23014 return draw_fill(x,y,0,color,opacity,tmp,sigma,high_connexity);
23015 }
23017 //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
23018 template<typename tc>
23019 CImg<T>& draw_fill(const int x, const int y,
23020 const CImg<tc>& color, const float opacity=1,
23021 const float sigma=0, const bool high_connexity=false) {
23022 return draw_fill(x,y,color.data,opacity,sigma,high_connexity);
23023 }
23025 //! Draw a plasma random texture.
23026 /**
23027 \param x0 = X-coordinate of the upper-left corner of the plasma.
23028 \param y0 = Y-coordinate of the upper-left corner of the plasma.
23029 \param x1 = X-coordinate of the lower-right corner of the plasma.
23030 \param y1 = Y-coordinate of the lower-right corner of the plasma.
23031 \param alpha = Alpha-parameter of the plasma.
23032 \param beta = Beta-parameter of the plasma.
23033 \param opacity = opacity of the drawing.
23034 **/
23035 CImg<T>& draw_plasma(const int x0, const int y0, const int x1, const int y1,
23036 const float alpha=1, const float beta=1,
23037 const float opacity=1) {
23038 if (!is_empty()) {
23039 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
23040 int nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1;
23041 if (nx1<nx0) cimg::swap(nx0,nx1);
23042 if (ny1<ny0) cimg::swap(ny0,ny1);
23043 if (nx0<0) nx0 = 0;
23044 if (nx1>=dimx()) nx1 = width-1;
23045 if (ny0<0) ny0 = 0;
23046 if (ny1>=dimy()) ny1 = height-1;
23047 const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx = (xc-nx0), dy = (yc-ny0);
23048 const Tfloat dc = (Tfloat)(cimg_std::sqrt((float)(dx*dx+dy*dy))*alpha + beta);
23049 Tfloat val = 0;
23050 cimg_forV(*this,k) {
23051 if (opacity>=1) {
23052 const Tfloat
23053 val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
23054 val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
23055 (*this)(xc,ny0,0,k) = (T)((val0+val1)/2);
23056 (*this)(xc,ny1,0,k) = (T)((val2+val3)/2);
23057 (*this)(nx0,yc,0,k) = (T)((val0+val2)/2);
23058 (*this)(nx1,yc,0,k) = (T)((val1+val3)/2);
23059 do {
23060 val = (Tfloat)(0.25f*((Tfloat)((*this)(nx0,ny0,0,k)) +
23061 (Tfloat)((*this)(nx1,ny0,0,k)) +
23062 (Tfloat)((*this)(nx1,ny1,0,k)) +
23063 (Tfloat)((*this)(nx0,ny1,0,k))) +
23064 dc*cimg::grand());
23065 } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
23066 (*this)(xc,yc,0,k) = (T)val;
23067 } else {
23068 const Tfloat
23069 val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
23070 val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
23071 (*this)(xc,ny0,0,k) = (T)(((val0+val1)*nopacity + copacity*(*this)(xc,ny0,0,k))/2);
23072 (*this)(xc,ny1,0,k) = (T)(((val2+val3)*nopacity + copacity*(*this)(xc,ny1,0,k))/2);
23073 (*this)(nx0,yc,0,k) = (T)(((val0+val2)*nopacity + copacity*(*this)(nx0,yc,0,k))/2);
23074 (*this)(nx1,yc,0,k) = (T)(((val1+val3)*nopacity + copacity*(*this)(nx1,yc,0,k))/2);
23075 do {
23076 val = (Tfloat)(0.25f*(((Tfloat)((*this)(nx0,ny0,0,k)) +
23077 (Tfloat)((*this)(nx1,ny0,0,k)) +
23078 (Tfloat)((*this)(nx1,ny1,0,k)) +
23079 (Tfloat)((*this)(nx0,ny1,0,k))) +
23080 dc*cimg::grand())*nopacity + copacity*(*this)(xc,yc,0,k));
23081 } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
23082 (*this)(xc,yc,0,k) = (T)val;
23083 }
23084 }
23085 if (xc!=nx0 || yc!=ny0) {
23086 draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity);
23087 draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity);
23088 draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity);
23089 draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity);
23090 }
23091 }
23092 return *this;
23093 }
23095 //! Draw a plasma random texture.
23096 /**
23097 \param alpha = Alpha-parameter of the plasma.
23098 \param beta = Beta-parameter of the plasma.
23099 \param opacity = opacity of the drawing.
23100 **/
23101 CImg<T>& draw_plasma(const float alpha=1, const float beta=1,
23102 const float opacity=1) {
23103 return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity);
23104 }
23106 //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
23107 template<typename tc>
23108 CImg<T>& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1,
23109 const CImg<tc>& color_palette, const float opacity=1,
23110 const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
23111 const unsigned int itermax=255,
23112 const bool normalized_iteration=false,
23113 const bool julia_set=false,
23114 const double paramr=0, const double parami=0) {
23115 if (is_empty()) return *this;
23116 CImg<tc> palette;
23117 if (color_palette) palette.assign(color_palette.data,color_palette.size()/color_palette.dim,1,1,color_palette.dim,true);
23118 if (palette && palette.dim!=dim)
23119 throw CImgArgumentException("CImg<%s>::draw_mandelbrot() : Specified color palette (%u,%u,%u,%u,%p) is not \n"
23120 "compatible with instance image (%u,%u,%u,%u,%p).",
23121 pixel_type(),color_palette.width,color_palette.height,color_palette.depth,color_palette.dim,
23122 color_palette.data,width,height,depth,dim,data);
23123 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), ln2 = (float)cimg_std::log(2.0);
23124 unsigned int iter = 0;
23125 cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
23126 const double x = z0r + p*(z1r-z0r)/width, y = z0i + q*(z1i-z0i)/height;
23127 double zr, zi, cr, ci;
23128 if (julia_set) { zr = x; zi = y; cr = paramr; ci = parami; }
23129 else { zr = paramr; zi = parami; cr = x; ci = y; }
23130 for (iter=1; zr*zr + zi*zi<=4 && iter<=itermax; ++iter) {
23131 const double temp = zr*zr - zi*zi + cr;
23132 zi = 2*zr*zi + ci;
23133 zr = temp;
23134 }
23135 if (iter>itermax) {
23136 if (palette) {
23137 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette(0,k);
23138 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(0,k)*nopacity + (*this)(p,q,0,k)*copacity);
23139 } else {
23140 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)0;
23141 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)((*this)(p,q,0,k)*copacity);
23142 }
23143 } else if (normalized_iteration) {
23144 const float
23145 normz = (float)cimg::abs(zr*zr+zi*zi),
23146 niter = (float)(iter + 1 - cimg_std::log(cimg_std::log(normz))/ln2);
23147 if (palette) {
23148 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._linear_atX(niter,k);
23149 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette._linear_atX(niter,k)*nopacity + (*this)(p,q,0,k)*copacity);
23150 } else {
23151 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)niter;
23152 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(niter*nopacity + (*this)(p,q,0,k)*copacity);
23153 }
23154 } else {
23155 if (palette) {
23156 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._atX(iter,k);
23157 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(iter,k)*nopacity + (*this)(p,q,0,k)*copacity);
23158 } else {
23159 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)iter;
23160 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(iter*nopacity + (*this)(p,q,0,k)*copacity);
23161 }
23162 }
23163 }
23164 return *this;
23165 }
23167 //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
23168 template<typename tc>
23169 CImg<T>& draw_mandelbrot(const CImg<tc>& color_palette, const float opacity=1,
23170 const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
23171 const unsigned int itermax=255,
23172 const bool normalized_iteration=false,
23173 const bool julia_set=false,
23174 const double paramr=0, const double parami=0) {
23175 return draw_mandelbrot(0,0,width-1,height-1,color_palette,opacity,z0r,z0i,z1r,z1i,itermax,normalized_iteration,julia_set,paramr,parami);
23176 }
23178 //! Draw a 1D gaussian function in the instance image.
23179 /**
23180 \param xc = X-coordinate of the gaussian center.
23181 \param sigma = Standard variation of the gaussian distribution.
23182 \param color = array of dimv() values of type \c T, defining the drawing color.
23183 \param opacity = opacity of the drawing.
23184 **/
23185 template<typename tc>
23186 CImg<T>& draw_gaussian(const float xc, const float sigma,
23187 const tc *const color, const float opacity=1) {
23188 if (is_empty()) return *this;
23189 if (!color)
23190 throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
23191 pixel_type());
23192 const float sigma2 = 2*sigma*sigma, nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
23193 const unsigned int whz = width*height*depth;
23194 const tc *col = color;
23195 cimg_forX(*this,x) {
23196 const float dx = (x - xc), val = (float)cimg_std::exp(-dx*dx/sigma2);
23197 T *ptrd = ptr(x,0,0,0);
23198 if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
23199 else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
23200 col-=dim;
23201 }
23202 return *this;
23203 }
23205 //! Draw a 1D gaussian function in the instance image.
23206 template<typename tc>
23207 CImg<T>& draw_gaussian(const float xc, const float sigma,
23208 const CImg<tc>& color, const float opacity=1) {
23209 return draw_gaussian(xc,sigma,color.data,opacity);
23210 }
23212 //! Draw an anisotropic 2D gaussian function.
23213 /**
23214 \param xc = X-coordinate of the gaussian center.
23215 \param yc = Y-coordinate of the gaussian center.
23216 \param tensor = 2x2 covariance matrix.
23217 \param color = array of dimv() values of type \c T, defining the drawing color.
23218 \param opacity = opacity of the drawing.
23219 **/
23220 template<typename t, typename tc>
23221 CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
23222 const tc *const color, const float opacity=1) {
23223 if (is_empty()) return *this;
23224 typedef typename cimg::superset<t,float>::type tfloat;
23225 if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1)
23226 throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 2x2 matrix.",
23227 pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
23228 if (!color)
23229 throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
23230 pixel_type());
23231 const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
23232 const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1);
23233 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
23234 const unsigned int whz = width*height*depth;
23235 const tc *col = color;
23236 float dy = -yc;
23237 cimg_forY(*this,y) {
23238 float dx = -xc;
23239 cimg_forX(*this,x) {
23240 const float val = (float)cimg_std::exp(a*dx*dx + b*dx*dy + c*dy*dy);
23241 T *ptrd = ptr(x,y,0,0);
23242 if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
23243 else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
23244 col-=dim;
23245 ++dx;
23246 }
23247 ++dy;
23248 }
23249 return *this;
23250 }
23252 //! Draw an anisotropic 2D gaussian function.
23253 template<typename t, typename tc>
23254 CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
23255 const CImg<tc>& color, const float opacity=1) {
23256 return draw_gaussian(xc,yc,tensor,color.data,opacity);
23257 }
23259 //! Draw an anisotropic 2D gaussian function.
23260 template<typename tc>
23261 CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
23262 const tc *const color, const float opacity=1) {
23263 const double
23264 a = r1*ru*ru + r2*rv*rv,
23265 b = (r1-r2)*ru*rv,
23266 c = r1*rv*rv + r2*ru*ru;
23267 const CImg<Tfloat> tensor(2,2,1,1, a,b,b,c);
23268 return draw_gaussian(xc,yc,tensor,color,opacity);
23269 }
23271 //! Draw an anisotropic 2D gaussian function.
23272 template<typename tc>
23273 CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
23274 const CImg<tc>& color, const float opacity=1) {
23275 return draw_gaussian(xc,yc,r1,r2,ru,rv,color.data,opacity);
23276 }
23278 //! Draw an isotropic 2D gaussian function.
23279 /**
23280 \param xc = X-coordinate of the gaussian center.
23281 \param yc = Y-coordinate of the gaussian center.
23282 \param sigma = standard variation of the gaussian distribution.
23283 \param color = array of dimv() values of type \c T, defining the drawing color.
23284 \param opacity = opacity of the drawing.
23285 **/
23286 template<typename tc>
23287 CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
23288 const tc *const color, const float opacity=1) {
23289 return draw_gaussian(xc,yc,CImg<floatT>::diagonal(sigma,sigma),color,opacity);
23290 }
23292 //! Draw an isotropic 2D gaussian function.
23293 template<typename tc>
23294 CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
23295 const CImg<tc>& color, const float opacity=1) {
23296 return draw_gaussian(xc,yc,sigma,color.data,opacity);
23297 }
23299 //! Draw an anisotropic 3D gaussian function.
23300 /**
23301 \param xc = X-coordinate of the gaussian center.
23302 \param yc = Y-coordinate of the gaussian center.
23303 \param zc = Z-coordinate of the gaussian center.
23304 \param tensor = 3x3 covariance matrix.
23305 \param color = array of dimv() values of type \c T, defining the drawing color.
23306 \param opacity = opacity of the drawing.
23307 **/
23308 template<typename t, typename tc>
23309 CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
23310 const tc *const color, const float opacity=1) {
23311 if (is_empty()) return *this;
23312 typedef typename cimg::superset<t,float>::type tfloat;
23313 if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1)
23314 throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 3x3 matrix.",
23315 pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
23316 const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
23317 const tfloat a = invT(0,0), b = 2*invT(1,0), c = 2*invT(2,0), d = invT(1,1), e = 2*invT(2,1), f = invT(2,2);
23318 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
23319 const unsigned int whz = width*height*depth;
23320 const tc *col = color;
23321 cimg_forXYZ(*this,x,y,z) {
23322 const float
23323 dx = (x - xc), dy = (y - yc), dz = (z - zc),
23324 val = (float)cimg_std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz);
23325 T *ptrd = ptr(x,y,z,0);
23326 if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
23327 else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
23328 col-=dim;
23329 }
23330 return *this;
23331 }
23333 //! Draw an anisotropic 3D gaussian function.
23334 template<typename t, typename tc>
23335 CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
23336 const CImg<tc>& color, const float opacity=1) {
23337 return draw_gaussian(xc,yc,zc,tensor,color.data,opacity);
23338 }
23340 //! Draw an isotropic 3D gaussian function.
23341 /**
23342 \param xc = X-coordinate of the gaussian center.
23343 \param yc = Y-coordinate of the gaussian center.
23344 \param zc = Z-coordinate of the gaussian center.
23345 \param sigma = standard variation of the gaussian distribution.
23346 \param color = array of dimv() values of type \c T, defining the drawing color.
23347 \param opacity = opacity of the drawing.
23348 **/
23349 template<typename tc>
23350 CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
23351 const tc *const color, const float opacity=1) {
23352 return draw_gaussian(xc,yc,zc,CImg<floatT>::diagonal(sigma,sigma,sigma),color,opacity);
23353 }
23355 //! Draw an isotropic 3D gaussian function.
23356 template<typename tc>
23357 CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
23358 const CImg<tc>& color, const float opacity=1) {
23359 return draw_gaussian(xc,yc,zc,sigma,color.data,opacity);
23360 }
23362 // Draw a 3D object (internal)
23363 template<typename tc, typename to>
23364 void _draw_object3d_sprite(const int x, const int y,
23365 const CImg<tc>& color, const CImg<to>& opacity, const CImg<T>& sprite) {
23366 if (opacity.width==color.width && opacity.height==color.height)
23367 draw_image(x,y,sprite,opacity.get_resize(sprite.width,sprite.height,1,sprite.dim,1));
23368 else
23369 draw_image(x,y,sprite,opacity(0));
23370 }
23372 template<typename tc>
23373 void _draw_object3d_sprite(const int x, const int y,
23374 const CImg<tc>& color, const float opacity, const CImg<T>& sprite) {
23375 if (color) draw_image(x,y,sprite,opacity);
23376 }
23378 template<typename tp, typename tf, typename tc, typename to>
23379 CImg<T>& _draw_object3d(void *const pboard, float *const zbuffer,
23380 const float X, const float Y, const float Z,
23381 const tp& points, const unsigned int nb_points,
23382 const CImgList<tf>& primitives,
23383 const CImgList<tc>& colors,
23384 const to& opacities, const unsigned int nb_opacities,
23385 const unsigned int render_type,
23386 const bool double_sided, const float focale,
23387 const float lightx, const float lighty, const float lightz,
23388 const float specular_light, const float specular_shine) {
23389 if (is_empty()) return *this;
23390 #ifndef cimg_use_board
23391 if (pboard) return *this;
23392 #endif
23393 const float
23394 nspec = 1-(specular_light<0?0:(specular_light>1?1:specular_light)),
23395 nspec2 = 1+(specular_shine<0?0:specular_shine),
23396 nsl1 = (nspec2-1)/cimg::sqr(nspec-1),
23397 nsl2 = (1-2*nsl1*nspec),
23398 nsl3 = nspec2-nsl1-nsl2;
23400 // Create light texture for phong-like rendering
23401 static CImg<floatT> light_texture;
23402 if (render_type==5) {
23403 if (colors.size>primitives.size) light_texture.assign(colors[primitives.size])/=255;
23404 else {
23405 static float olightx = 0, olighty = 0, olightz = 0, ospecular_shine = 0;
23406 if (!light_texture || lightx!=olightx || lighty!=olighty || lightz!=olightz || specular_shine!=ospecular_shine) {
23407 light_texture.assign(512,512);
23408 const float white[] = { 1 },
23409 dlx = lightx-X, dly = lighty-Y, dlz = lightz-Z,
23410 nl = (float)cimg_std::sqrt(dlx*dlx+dly*dly+dlz*dlz),
23411 nlx = light_texture.width/2*(1+dlx/nl),
23412 nly = light_texture.height/2*(1+dly/nl);
23413 light_texture.draw_gaussian(nlx,nly,light_texture.width/3.0f,white);
23414 cimg_forXY(light_texture,x,y) {
23415 const float factor = light_texture(x,y);
23416 if (factor>nspec) light_texture(x,y) = cimg::min(2,nsl1*factor*factor+nsl2*factor+nsl3);
23417 }
23418 olightx = lightx; olighty = lighty; olightz = lightz; ospecular_shine = specular_shine;
23419 }
23420 }
23421 }
23423 // Compute 3D to 2D projection
23424 CImg<floatT> projections(nb_points,2);
23425 cimg_forX(projections,l) {
23426 const float
23427 x = (float)points(l,0),
23428 y = (float)points(l,1),
23429 z = (float)points(l,2);
23430 const float projectedz = z + Z + focale;
23431 projections(l,1) = Y + focale*y/projectedz;
23432 projections(l,0) = X + focale*x/projectedz;
23433 }
23435 // Compute and sort visible primitives
23436 CImg<uintT> visibles(primitives.size);
23437 CImg<floatT> zrange(primitives.size);
23438 unsigned int nb_visibles = 0;
23439 const float zmin = -focale+1.5f;
23440 { cimglist_for(primitives,l) {
23441 const CImg<tf>& primitive = primitives[l];
23442 switch (primitive.size()) {
23444 case 1 : { // Point
23445 const unsigned int i0 = (unsigned int)primitive(0);
23446 const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2));
23447 if (z0>zmin && x0>=0 && x0<width && y0>=0 && y0<height) {
23448 visibles(nb_visibles) = (unsigned int)l;
23449 zrange(nb_visibles++) = z0;
23450 }
23451 } break;
23452 case 5 : { // Sphere
23453 const unsigned int
23454 i0 = (unsigned int)primitive(0),
23455 i1 = (unsigned int)primitive(1),
23456 i2 = (unsigned int)primitive(2);
23457 const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2));
23458 int radius;
23459 if (i2) radius = (int)(i2*focale/(z0+focale));
23460 else {
23461 const float x1 = projections(i1,0), y1 = projections(i1,1);
23462 const int deltax = (int)(x1-x0), deltay = (int)(y1-y0);
23463 radius = (int)cimg_std::sqrt((float)(deltax*deltax + deltay*deltay));
23464 }
23465 if (z0>zmin && x0+radius>=0 && x0-radius<width && y0+radius>=0 && y0-radius<height) {
23466 visibles(nb_visibles) = (unsigned int)l;
23467 zrange(nb_visibles++) = z0;
23468 }
23469 } break;
23470 case 2 : // Line
23471 case 6 : {
23472 const unsigned int
23473 i0 = (unsigned int)primitive(0),
23474 i1 = (unsigned int)primitive(1);
23475 const float
23476 x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
23477 x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2));
23478 float xm, xM, ym, yM;
23479 if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
23480 if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
23481 if (z0>zmin && z1>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
23482 visibles(nb_visibles) = (unsigned int)l;
23483 zrange(nb_visibles++) = 0.5f*(z0+z1);
23484 }
23485 } break;
23486 case 3 : // Triangle
23487 case 9 : {
23488 const unsigned int
23489 i0 = (unsigned int)primitive(0),
23490 i1 = (unsigned int)primitive(1),
23491 i2 = (unsigned int)primitive(2);
23492 const float
23493 x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
23494 x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)),
23495 x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2));
23496 float xm, xM, ym, yM;
23497 if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
23498 if (x2<xm) xm = x2;
23499 if (x2>xM) xM = x2;
23500 if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
23501 if (y2<ym) ym = y2;
23502 if (y2>yM) yM = y2;
23503 if (z0>zmin && z1>zmin && z2>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
23504 const float d = (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);
23505 if (double_sided || d<0) {
23506 visibles(nb_visibles) = (unsigned int)l;
23507 zrange(nb_visibles++) = (z0+z1+z2)/3;
23508 }
23509 }
23510 } break;
23511 case 4 : // Rectangle
23512 case 12 : {
23513 const unsigned int
23514 i0 = (unsigned int)primitive(0),
23515 i1 = (unsigned int)primitive(1),
23516 i2 = (unsigned int)primitive(2),
23517 i3 = (unsigned int)primitive(3);
23518 const float
23519 x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
23520 x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)),
23521 x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2)),
23522 x3 = projections(i3,0), y3 = projections(i3,1), z3 = (float)(Z+points(i3,2));
23523 float xm, xM, ym, yM;
23524 if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
23525 if (x2<xm) xm = x2;
23526 if (x2>xM) xM = x2;
23527 if (x3<xm) xm = x3;
23528 if (x3>xM) xM = x3;
23529 if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
23530 if (y2<ym) ym = y2;
23531 if (y2>yM) yM = y2;
23532 if (y3<ym) ym = y3;
23533 if (y3>yM) yM = y3;
23534 if (z0>zmin && z1>zmin && z2>zmin && z3>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
23535 const float d = (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0);
23536 if (double_sided || d<0) {
23537 visibles(nb_visibles) = (unsigned int)l;
23538 zrange(nb_visibles++) = (z0 + z1 + z2 + z3)/4;
23539 }
23540 }
23541 } break;
23542 default :
23543 throw CImgArgumentException("CImg<%s>::draw_object3d() : Primitive %u is invalid (size = %u, can be 1,2,3,4,5,6,9 or 12)",
23544 pixel_type(),l,primitive.size());
23545 }}
23546 }
23547 if (nb_visibles<=0) return *this;
23548 CImg<uintT> permutations;
23549 CImg<floatT>(zrange.data,nb_visibles,1,1,1,true).sort(permutations,false);
23551 // Compute light properties
23552 CImg<floatT> lightprops;
23553 switch (render_type) {
23554 case 3 : { // Flat Shading
23555 lightprops.assign(nb_visibles);
23556 cimg_forX(lightprops,l) {
23557 const CImg<tf>& primitive = primitives(visibles(permutations(l)));
23558 const unsigned int psize = primitive.size();
23559 if (psize==3 || psize==4 || psize==9 || psize==12) {
23560 const unsigned int
23561 i0 = (unsigned int)primitive(0),
23562 i1 = (unsigned int)primitive(1),
23563 i2 = (unsigned int)primitive(2);
23564 const float
23565 x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2),
23566 x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2),
23567 x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2),
23568 dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
23569 dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
23570 nx = dy1*dz2 - dz1*dy2,
23571 ny = dz1*dx2 - dx1*dz2,
23572 nz = dx1*dy2 - dy1*dx2,
23573 norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
23574 lx = X + (x0 + x1 + x2)/3 - lightx,
23575 ly = Y + (y0 + y1 + y2)/3 - lighty,
23576 lz = Z + (z0 + z1 + z2)/3 - lightz,
23577 nl = (float)cimg_std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
23578 factor = cimg::max(cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
23579 lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
23580 } else lightprops[l] = 1;
23581 }
23582 } break;
23584 case 4 : // Gouraud Shading
23585 case 5 : { // Phong-Shading
23586 CImg<floatT> points_normals(nb_points,3,1,1,0);
23587 for (unsigned int l=0; l<nb_visibles; ++l) {
23588 const CImg<tf>& primitive = primitives[visibles(l)];
23589 const unsigned int psize = primitive.size();
23590 const bool
23591 triangle_flag = (psize==3) || (psize==9),
23592 rectangle_flag = (psize==4) || (psize==12);
23593 if (triangle_flag || rectangle_flag) {
23594 const unsigned int
23595 i0 = (unsigned int)primitive(0),
23596 i1 = (unsigned int)primitive(1),
23597 i2 = (unsigned int)primitive(2),
23598 i3 = rectangle_flag?(unsigned int)primitive(3):0;
23599 const float
23600 x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2),
23601 x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2),
23602 x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2),
23603 dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
23604 dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
23605 nnx = dy1*dz2 - dz1*dy2,
23606 nny = dz1*dx2 - dx1*dz2,
23607 nnz = dx1*dy2 - dy1*dx2,
23608 norm = 1e-5f + (float)cimg_std::sqrt(nnx*nnx + nny*nny + nnz*nnz),
23609 nx = nnx/norm,
23610 ny = nny/norm,
23611 nz = nnz/norm;
23612 points_normals(i0,0)+=nx; points_normals(i0,1)+=ny; points_normals(i0,2)+=nz;
23613 points_normals(i1,0)+=nx; points_normals(i1,1)+=ny; points_normals(i1,2)+=nz;
23614 points_normals(i2,0)+=nx; points_normals(i2,1)+=ny; points_normals(i2,2)+=nz;
23615 if (rectangle_flag) { points_normals(i3,0)+=nx; points_normals(i3,1)+=ny; points_normals(i3,2)+=nz; }
23616 }
23617 }
23619 if (double_sided) cimg_forX(points_normals,p) if (points_normals(p,2)>0) {
23620 points_normals(p,0) = -points_normals(p,0);
23621 points_normals(p,1) = -points_normals(p,1);
23622 points_normals(p,2) = -points_normals(p,2);
23623 }
23625 if (render_type==4) {
23626 lightprops.assign(nb_points);
23627 cimg_forX(lightprops,ll) {
23628 const float
23629 nx = points_normals(ll,0),
23630 ny = points_normals(ll,1),
23631 nz = points_normals(ll,2),
23632 norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
23633 lx = (float)(X + points(ll,0) - lightx),
23634 ly = (float)(Y + points(ll,1) - lighty),
23635 lz = (float)(Z + points(ll,2) - lightz),
23636 nl = (float)cimg_std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
23637 factor = cimg::max((-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
23638 lightprops[ll] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
23639 }
23640 } else {
23641 const unsigned int
23642 lw2 = light_texture.width/2 - 1,
23643 lh2 = light_texture.height/2 - 1;
23644 lightprops.assign(nb_points,2);
23645 cimg_forX(lightprops,ll) {
23646 const float
23647 nx = points_normals(ll,0),
23648 ny = points_normals(ll,1),
23649 nz = points_normals(ll,2),
23650 norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
23651 nnx = nx/norm,
23652 nny = ny/norm;
23653 lightprops(ll,0) = lw2*(1 + nnx);
23654 lightprops(ll,1) = lh2*(1 + nny);
23655 }
23656 }
23657 } break;
23658 }
23660 // Draw visible primitives
23661 const CImg<tc> default_color(1,dim,1,1,(tc)200);
23662 { for (unsigned int l = 0; l<nb_visibles; ++l) {
23663 const unsigned int n_primitive = visibles(permutations(l));
23664 const CImg<tf>& primitive = primitives[n_primitive];
23665 const CImg<tc>& color = n_primitive<colors.size?colors[n_primitive]:default_color;
23666 const float opac = n_primitive<nb_opacities?opacities(n_primitive,0):1.0f;
23667 #ifdef cimg_use_board
23668 BoardLib::Board &board = *(BoardLib::Board*)pboard;
23669 #endif
23671 switch (primitive.size()) {
23672 case 1 : { // Colored point or sprite
23673 const unsigned int n0 = (unsigned int)primitive[0];
23674 const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
23675 if (color.size()==dim) {
23676 draw_point(x0,y0,color,opac);
23677 #ifdef cimg_use_board
23678 if (pboard) {
23679 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23680 board.fillCircle((float)x0,dimy()-(float)y0,0);
23681 }
23682 #endif
23683 } else {
23684 const float z = Z + points(n0,2);
23685 const int
23686 factor = (int)(focale*100/(z+focale)),
23687 sw = color.width*factor/200,
23688 sh = color.height*factor/200;
23689 if (x0+sw>=0 && x0-sw<dimx() && y0+sh>=0 && y0-sh<dimy()) {
23690 const CImg<T> sprite = color.get_resize(-factor,-factor,1,-100,render_type<=3?1:3);
23691 _draw_object3d_sprite(x0-sw,y0-sh,color,opacities[n_primitive%nb_opacities],sprite);
23692 #ifdef cimg_use_board
23693 if (pboard) {
23694 board.setPenColorRGBi(128,128,128);
23695 board.setFillColor(BoardLib::Color::none);
23696 board.drawRectangle((float)x0-sw,dimy()-(float)y0+sh,sw,sh);
23697 }
23698 #endif
23699 }
23700 }
23701 } break;
23702 case 2 : { // Colored line
23703 const unsigned int
23704 n0 = (unsigned int)primitive[0],
23705 n1 = (unsigned int)primitive[1];
23706 const int
23707 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
23708 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
23709 const float
23710 z0 = points(n0,2) + Z + focale,
23711 z1 = points(n1,2) + Z + focale;
23712 if (render_type) {
23713 if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac);
23714 else draw_line(x0,y0,x1,y1,color,opac);
23715 #ifdef cimg_use_board
23716 if (pboard) {
23717 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23718 board.drawLine((float)x0,dimy()-(float)y0,x1,dimy()-(float)y1);
23719 }
23720 #endif
23721 } else {
23722 draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac);
23723 #ifdef cimg_use_board
23724 if (pboard) {
23725 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23726 board.drawCircle((float)x0,dimy()-(float)y0,0);
23727 board.drawCircle((float)x1,dimy()-(float)y1,0);
23728 }
23729 #endif
23730 }
23731 } break;
23732 case 5 : { // Colored sphere
23733 const unsigned int
23734 n0 = (unsigned int)primitive[0],
23735 n1 = (unsigned int)primitive[1],
23736 n2 = (unsigned int)primitive[2];
23737 const int
23738 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
23739 int radius;
23740 if (n2) radius = (int)(n2*focale/(Z+points(n0,2)+focale));
23741 else {
23742 const int
23743 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
23744 deltax = x1-x0, deltay = y1-y0;
23745 radius = (int)cimg_std::sqrt((float)(deltax*deltax + deltay*deltay));
23746 }
23747 switch (render_type) {
23748 case 0 :
23749 draw_point(x0,y0,color,opac);
23750 #ifdef cimg_use_board
23751 if (pboard) {
23752 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23753 board.fillCircle((float)x0,dimy()-(float)y0,0);
23754 }
23755 #endif
23756 break;
23757 case 1 :
23758 draw_circle(x0,y0,radius,color,opac,~0U);
23759 #ifdef cimg_use_board
23760 if (pboard) {
23761 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23762 board.setFillColor(BoardLib::Color::none);
23763 board.drawCircle((float)x0,dimy()-(float)y0,(float)radius);
23764 }
23765 #endif
23766 break;
23767 default :
23768 draw_circle(x0,y0,radius,color,opac);
23769 #ifdef cimg_use_board
23770 if (pboard) {
23771 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23772 board.fillCircle((float)x0,dimy()-(float)y0,(float)radius);
23773 }
23774 #endif
23775 break;
23776 }
23777 } break;
23778 case 6 : { // Textured line
23779 const unsigned int
23780 n0 = (unsigned int)primitive[0],
23781 n1 = (unsigned int)primitive[1],
23782 tx0 = (unsigned int)primitive[2],
23783 ty0 = (unsigned int)primitive[3],
23784 tx1 = (unsigned int)primitive[4],
23785 ty1 = (unsigned int)primitive[5];
23786 const int
23787 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
23788 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
23789 const float
23790 z0 = points(n0,2) + Z + focale,
23791 z1 = points(n1,2) + Z + focale;
23792 if (render_type) {
23793 if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac);
23794 else draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opac);
23795 #ifdef cimg_use_board
23796 if (pboard) {
23797 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
23798 board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
23799 }
23800 #endif
23801 } else {
23802 draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
23803 draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac);
23804 #ifdef cimg_use_board
23805 if (pboard) {
23806 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
23807 board.drawCircle((float)x0,dimy()-(float)y0,0);
23808 board.drawCircle((float)x1,dimy()-(float)y1,0);
23809 }
23810 #endif
23811 }
23812 } break;
23813 case 3 : { // Colored triangle
23814 const unsigned int
23815 n0 = (unsigned int)primitive[0],
23816 n1 = (unsigned int)primitive[1],
23817 n2 = (unsigned int)primitive[2];
23818 const int
23819 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
23820 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
23821 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
23822 const float
23823 z0 = points(n0,2) + Z + focale,
23824 z1 = points(n1,2) + Z + focale,
23825 z2 = points(n2,2) + Z + focale;
23826 switch (render_type) {
23827 case 0 :
23828 draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).draw_point(x2,y2,color,opac);
23829 #ifdef cimg_use_board
23830 if (pboard) {
23831 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23832 board.drawCircle((float)x0,dimy()-(float)y0,0);
23833 board.drawCircle((float)x1,dimy()-(float)y1,0);
23834 board.drawCircle((float)x2,dimy()-(float)y2,0);
23835 }
23836 #endif
23837 break;
23838 case 1 :
23839 if (zbuffer)
23840 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,opac).
23841 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac);
23842 else
23843 draw_line(x0,y0,x1,y1,color,opac).draw_line(x0,y0,x2,y2,color,opac).
23844 draw_line(x1,y1,x2,y2,color,opac);
23845 #ifdef cimg_use_board
23846 if (pboard) {
23847 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23848 board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
23849 board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
23850 board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
23851 }
23852 #endif
23853 break;
23854 case 2 :
23855 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,opac);
23856 else draw_triangle(x0,y0,x1,y1,x2,y2,color,opac);
23857 #ifdef cimg_use_board
23858 if (pboard) {
23859 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23860 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
23861 }
23862 #endif
23863 break;
23864 case 3 :
23865 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l));
23866 else _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l));
23867 #ifdef cimg_use_board
23868 if (pboard) {
23869 const float lp = cimg::min(lightprops(l),1);
23870 board.setPenColorRGBi((unsigned char)(color[0]*lp),
23871 (unsigned char)(color[1]*lp),
23872 (unsigned char)(color[2]*lp),
23873 (unsigned char)(opac*255));
23874 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
23875 }
23876 #endif
23877 break;
23878 case 4 :
23879 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
23880 else draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
23881 #ifdef cimg_use_board
23882 if (pboard) {
23883 board.setPenColorRGBi((unsigned char)(color[0]),
23884 (unsigned char)(color[1]),
23885 (unsigned char)(color[2]),
23886 (unsigned char)(opac*255));
23887 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
23888 (float)x1,dimy()-(float)y1,lightprops(n1),
23889 (float)x2,dimy()-(float)y2,lightprops(n2));
23890 }
23891 #endif
23892 break;
23893 case 5 : {
23894 const unsigned int
23895 lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
23896 lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
23897 lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1);
23898 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
23899 else draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
23900 #ifdef cimg_use_board
23901 if (pboard) {
23902 const float
23903 l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
23904 l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
23905 l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
23906 board.setPenColorRGBi((unsigned char)(color[0]),
23907 (unsigned char)(color[1]),
23908 (unsigned char)(color[2]),
23909 (unsigned char)(opac*255));
23910 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
23911 (float)x1,dimy()-(float)y1,l1,
23912 (float)x2,dimy()-(float)y2,l2);
23913 }
23914 #endif
23915 } break;
23916 }
23917 } break;
23918 case 4 : { // Colored rectangle
23919 const unsigned int
23920 n0 = (unsigned int)primitive[0],
23921 n1 = (unsigned int)primitive[1],
23922 n2 = (unsigned int)primitive[2],
23923 n3 = (unsigned int)primitive[3];
23924 const int
23925 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
23926 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
23927 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
23928 x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
23929 const float
23930 z0 = points(n0,2) + Z + focale,
23931 z1 = points(n1,2) + Z + focale,
23932 z2 = points(n2,2) + Z + focale,
23933 z3 = points(n3,2) + Z + focale;
23934 switch (render_type) {
23935 case 0 :
23936 draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).
23937 draw_point(x2,y2,color,opac).draw_point(x3,y3,color,opac);
23938 #ifdef cimg_use_board
23939 if (pboard) {
23940 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23941 board.drawCircle((float)x0,dimy()-(float)y0,0);
23942 board.drawCircle((float)x1,dimy()-(float)y1,0);
23943 board.drawCircle((float)x2,dimy()-(float)y2,0);
23944 board.drawCircle((float)x3,dimy()-(float)y3,0);
23945 }
23946 #endif
23947 break;
23948 case 1 :
23949 if (zbuffer)
23950 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac).
23951 draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,opac).draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,opac);
23952 else
23953 draw_line(x0,y0,x1,y1,color,opac).draw_line(x1,y1,x2,y2,color,opac).
23954 draw_line(x2,y2,x3,y3,color,opac).draw_line(x3,y3,x0,y0,color,opac);
23955 #ifdef cimg_use_board
23956 if (pboard) {
23957 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23958 board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
23959 board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
23960 board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
23961 board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
23962 }
23963 #endif
23964 break;
23965 case 2 :
23966 if (zbuffer)
23967 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,opac).draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,opac);
23968 else
23969 draw_triangle(x0,y0,x1,y1,x2,y2,color,opac).draw_triangle(x0,y0,x2,y2,x3,y3,color,opac);
23970 #ifdef cimg_use_board
23971 if (pboard) {
23972 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
23973 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
23974 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
23975 }
23976 #endif
23977 break;
23978 case 3 :
23979 if (zbuffer)
23980 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l)).
23981 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color.data,opac,lightprops(l));
23982 else
23983 _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l)).
23984 _draw_triangle(x0,y0,x2,y2,x3,y3,color.data,opac,lightprops(l));
23985 #ifdef cimg_use_board
23986 if (pboard) {
23987 const float lp = cimg::min(lightprops(l),1);
23988 board.setPenColorRGBi((unsigned char)(color[0]*lp),
23989 (unsigned char)(color[1]*lp),
23990 (unsigned char)(color[2]*lp),(unsigned char)(opac*255));
23991 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
23992 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
23993 }
23994 #endif
23995 break;
23996 case 4 : {
23997 const float
23998 lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
23999 lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
24000 if (zbuffer)
24001 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprop0,lightprop1,lightprop2,opac).
24002 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,lightprop0,lightprop2,lightprop3,opac);
24003 else
24004 draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprop0,lightprop1,lightprop2,opac).
24005 draw_triangle(x0,y0,x2,y2,x3,y3,color,lightprop0,lightprop2,lightprop3,opac);
24006 #ifdef cimg_use_board
24007 if (pboard) {
24008 board.setPenColorRGBi((unsigned char)(color[0]),
24009 (unsigned char)(color[1]),
24010 (unsigned char)(color[2]),
24011 (unsigned char)(opac*255));
24012 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
24013 (float)x1,dimy()-(float)y1,lightprop1,
24014 (float)x2,dimy()-(float)y2,lightprop2);
24015 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
24016 (float)x2,dimy()-(float)y2,lightprop2,
24017 (float)x3,dimy()-(float)y3,lightprop3);
24018 }
24019 #endif
24020 } break;
24021 case 5 : {
24022 const unsigned int
24023 lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
24024 lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
24025 lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
24026 lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
24027 if (zbuffer)
24028 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
24029 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
24030 else
24031 draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
24032 draw_triangle(x0,y0,x2,y2,x3,y3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
24033 #ifdef cimg_use_board
24034 if (pboard) {
24035 const float
24036 l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
24037 l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
24038 l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
24039 l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
24040 board.setPenColorRGBi((unsigned char)(color[0]),
24041 (unsigned char)(color[1]),
24042 (unsigned char)(color[2]),
24043 (unsigned char)(opac*255));
24044 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
24045 (float)x1,dimy()-(float)y1,l1,
24046 (float)x2,dimy()-(float)y2,l2);
24047 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
24048 (float)x2,dimy()-(float)y2,l2,
24049 (float)x3,dimy()-(float)y3,l3);
24050 }
24051 #endif
24052 } break;
24053 }
24054 } break;
24055 case 9 : { // Textured triangle
24056 const unsigned int
24057 n0 = (unsigned int)primitive[0],
24058 n1 = (unsigned int)primitive[1],
24059 n2 = (unsigned int)primitive[2],
24060 tx0 = (unsigned int)primitive[3],
24061 ty0 = (unsigned int)primitive[4],
24062 tx1 = (unsigned int)primitive[5],
24063 ty1 = (unsigned int)primitive[6],
24064 tx2 = (unsigned int)primitive[7],
24065 ty2 = (unsigned int)primitive[8];
24066 const int
24067 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
24068 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
24069 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
24070 const float
24071 z0 = points(n0,2) + Z + focale,
24072 z1 = points(n1,2) + Z + focale,
24073 z2 = points(n2,2) + Z + focale;
24074 switch (render_type) {
24075 case 0 :
24076 draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
24077 draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
24078 draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac);
24079 #ifdef cimg_use_board
24080 if (pboard) {
24081 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24082 board.drawCircle((float)x0,dimy()-(float)y0,0);
24083 board.drawCircle((float)x1,dimy()-(float)y1,0);
24084 board.drawCircle((float)x2,dimy()-(float)y2,0);
24085 }
24086 #endif
24087 break;
24088 case 1 :
24089 if (zbuffer)
24090 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
24091 draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
24092 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
24093 else
24094 draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
24095 draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
24096 draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
24097 #ifdef cimg_use_board
24098 if (pboard) {
24099 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24100 board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
24101 board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
24102 board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24103 }
24104 #endif
24105 break;
24106 case 2 :
24107 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
24108 else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
24109 #ifdef cimg_use_board
24110 if (pboard) {
24111 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24112 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24113 }
24114 #endif
24115 break;
24116 case 3 :
24117 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
24118 else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
24119 #ifdef cimg_use_board
24120 if (pboard) {
24121 const float lp = cimg::min(lightprops(l),1);
24122 board.setPenColorRGBi((unsigned char)(128*lp),
24123 (unsigned char)(128*lp),
24124 (unsigned char)(128*lp),
24125 (unsigned char)(opac*255));
24126 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24127 }
24128 #endif
24129 break;
24130 case 4 :
24131 if (zbuffer)
24132 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprops(n0),lightprops(n1),lightprops(n2),opac);
24133 else
24134 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprops(n0),lightprops(n1),lightprops(n2),opac);
24135 #ifdef cimg_use_board
24136 if (pboard) {
24137 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24138 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
24139 (float)x1,dimy()-(float)y1,lightprops(n1),
24140 (float)x2,dimy()-(float)y2,lightprops(n2));
24141 }
24142 #endif
24143 break;
24144 case 5 :
24145 if (zbuffer)
24146 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
24147 (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
24148 (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
24149 (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
24150 opac);
24151 else
24152 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
24153 (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
24154 (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
24155 (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
24156 opac);
24157 #ifdef cimg_use_board
24158 if (pboard) {
24159 const float
24160 l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
24161 l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
24162 l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
24163 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24164 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,(float)x1,dimy()-(float)y1,l1,(float)x2,dimy()-(float)y2,l2);
24165 }
24166 #endif
24167 break;
24168 }
24169 } break;
24170 case 12 : { // Textured rectangle
24171 const unsigned int
24172 n0 = (unsigned int)primitive[0],
24173 n1 = (unsigned int)primitive[1],
24174 n2 = (unsigned int)primitive[2],
24175 n3 = (unsigned int)primitive[3],
24176 tx0 = (unsigned int)primitive[4],
24177 ty0 = (unsigned int)primitive[5],
24178 tx1 = (unsigned int)primitive[6],
24179 ty1 = (unsigned int)primitive[7],
24180 tx2 = (unsigned int)primitive[8],
24181 ty2 = (unsigned int)primitive[9],
24182 tx3 = (unsigned int)primitive[10],
24183 ty3 = (unsigned int)primitive[11];
24184 const int
24185 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
24186 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
24187 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
24188 x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
24189 const float
24190 z0 = points(n0,2) + Z + focale,
24191 z1 = points(n1,2) + Z + focale,
24192 z2 = points(n2,2) + Z + focale,
24193 z3 = points(n3,2) + Z + focale;
24194 switch (render_type) {
24195 case 0 :
24196 draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
24197 draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
24198 draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac).
24199 draw_point(x3,y3,color.get_vector_at(tx3,ty3),opac);
24200 #ifdef cimg_use_board
24201 if (pboard) {
24202 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24203 board.drawCircle((float)x0,dimy()-(float)y0,0);
24204 board.drawCircle((float)x1,dimy()-(float)y1,0);
24205 board.drawCircle((float)x2,dimy()-(float)y2,0);
24206 board.drawCircle((float)x3,dimy()-(float)y3,0);
24207 }
24208 #endif
24209 break;
24210 case 1 :
24211 if (zbuffer)
24212 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
24213 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
24214 draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
24215 draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
24216 else
24217 draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
24218 draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
24219 draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
24220 draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
24221 #ifdef cimg_use_board
24222 if (pboard) {
24223 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24224 board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
24225 board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24226 board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
24227 board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
24228 }
24229 #endif
24230 break;
24231 case 2 :
24232 if (zbuffer)
24233 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
24234 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
24235 else
24236 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
24237 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
24238 #ifdef cimg_use_board
24239 if (pboard) {
24240 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24241 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24242 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
24243 }
24244 #endif
24245 break;
24246 case 3 :
24247 if (zbuffer)
24248 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
24249 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
24250 else
24251 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
24252 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
24253 #ifdef cimg_use_board
24254 if (pboard) {
24255 const float lp = cimg::min(lightprops(l),1);
24256 board.setPenColorRGBi((unsigned char)(128*lp),
24257 (unsigned char)(128*lp),
24258 (unsigned char)(128*lp),
24259 (unsigned char)(opac*255));
24260 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
24261 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
24262 }
24263 #endif
24264 break;
24265 case 4 : {
24266 const float
24267 lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
24268 lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
24269 if (zbuffer)
24270 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
24271 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
24272 else
24273 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
24274 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
24275 #ifdef cimg_use_board
24276 if (pboard) {
24277 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24278 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
24279 (float)x1,dimy()-(float)y1,lightprop1,
24280 (float)x2,dimy()-(float)y2,lightprop2);
24281 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
24282 (float)x2,dimy()-(float)y2,lightprop2,
24283 (float)x3,dimy()-(float)y3,lightprop3);
24284 }
24285 #endif
24286 } break;
24287 case 5 : {
24288 const unsigned int
24289 lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
24290 lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
24291 lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
24292 lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
24293 if (zbuffer)
24294 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
24295 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
24296 else
24297 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
24298 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
24299 #ifdef cimg_use_board
24300 if (pboard) {
24301 const float
24302 l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
24303 l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
24304 l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
24305 l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
24306 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
24307 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
24308 (float)x1,dimy()-(float)y1,l1,
24309 (float)x2,dimy()-(float)y2,l2);
24310 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
24311 (float)x2,dimy()-(float)y2,l2,
24312 (float)x3,dimy()-(float)y3,l3);
24313 }
24314 #endif
24315 } break;
24316 }
24317 } break;
24318 }
24319 }
24320 }
24321 return *this;
24322 }
24324 //! Draw a 3D object.
24325 /**
24326 \param X = X-coordinate of the 3d object position
24327 \param Y = Y-coordinate of the 3d object position
24328 \param Z = Z-coordinate of the 3d object position
24329 \param points = Image N*3 describing 3D point coordinates
24330 \param primitives = List of P primitives
24331 \param colors = List of P color (or textures)
24332 \param opacities = Image of P opacities
24333 \param render_type = Render type (0=Points, 1=Lines, 2=Faces (no light), 3=Faces (flat), 4=Faces(Gouraud)
24334 \param double_sided = Tell if object faces have two sides or are oriented.
24335 \param focale = length of the focale
24336 \param lightx = X-coordinate of the light
24337 \param lighty = Y-coordinate of the light
24338 \param lightz = Z-coordinate of the light
24339 \param specular_shine = Shininess of the object
24340 **/
24341 template<typename tp, typename tf, typename tc, typename to>
24342 CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
24343 const CImg<tp>& points, const CImgList<tf>& primitives,
24344 const CImgList<tc>& colors, const CImgList<to>& opacities,
24345 const unsigned int render_type=4,
24346 const bool double_sided=false, const float focale=500,
24347 const float lightx=0, const float lighty=0, const float lightz=-5000,
24348 const float specular_light=0.2f, const float specular_shine=0.1f,
24349 float *const zbuffer=0) {
24350 if (!points) return *this;
24351 return _draw_object3d(0,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
24352 primitives,colors,opacities,opacities.size,
24353 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24354 }
24356 #ifdef cimg_use_board
24357 template<typename tp, typename tf, typename tc, typename to>
24358 CImg<T>& draw_object3d(BoardLib::Board& board,
24359 const float x0, const float y0, const float z0,
24360 const CImg<tp>& points, const CImgList<tf>& primitives,
24361 const CImgList<tc>& colors, const CImgList<to>& opacities,
24362 const unsigned int render_type=4,
24363 const bool double_sided=false, const float focale=500,
24364 const float lightx=0, const float lighty=0, const float lightz=-5000,
24365 const float specular_light=0.2f, const float specular_shine=0.1f,
24366 float *const zbuffer=0) {
24367 if (!points) return *this;
24368 return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
24369 primitives,colors,opacities,opacities.size,
24370 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24371 }
24372 #endif
24374 //! Draw a 3D object.
24375 template<typename tp, typename tf, typename tc, typename to>
24376 CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
24377 const CImgList<tp>& points, const CImgList<tf>& primitives,
24378 const CImgList<tc>& colors, const CImgList<to>& opacities,
24379 const unsigned int render_type=4,
24380 const bool double_sided=false, const float focale=500,
24381 const float lightx=0, const float lighty=0, const float lightz=-5000,
24382 const float specular_light=0.2f, const float specular_shine=0.1f,
24383 float *const zbuffer=0) {
24384 if (!points) return *this;
24385 return _draw_object3d(0,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size,
24386 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24387 }
24389 #ifdef cimg_use_board
24390 template<typename tp, typename tf, typename tc, typename to>
24391 CImg<T>& draw_object3d(BoardLib::Board& board,
24392 const float x0, const float y0, const float z0,
24393 const CImgList<tp>& points, const CImgList<tf>& primitives,
24394 const CImgList<tc>& colors, const CImgList<to>& opacities,
24395 const unsigned int render_type=4,
24396 const bool double_sided=false, const float focale=500,
24397 const float lightx=0, const float lighty=0, const float lightz=-5000,
24398 const float specular_light=0.2f, const float specular_shine=0.1f,
24399 float *const zbuffer=0) {
24400 if (!points) return *this;
24401 return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size,
24402 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24403 }
24404 #endif
24406 //! Draw a 3D object.
24407 template<typename tp, typename tf, typename tc, typename to>
24408 CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
24409 const CImg<tp>& points, const CImgList<tf>& primitives,
24410 const CImgList<tc>& colors, const CImg<to>& opacities,
24411 const unsigned int render_type=4,
24412 const bool double_sided=false, const float focale=500,
24413 const float lightx=0, const float lighty=0, const float lightz=-5000,
24414 const float specular_light=0.2f, const float specular_shine=0.1f,
24415 float *const zbuffer=0) {
24416 if (!points) return *this;
24417 return _draw_object3d(0,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
24418 primitives,colors,opacities,opacities.size(),
24419 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24420 }
24422 #ifdef cimg_use_board
24423 template<typename tp, typename tf, typename tc, typename to>
24424 CImg<T>& draw_object3d(BoardLib::Board& board,
24425 const float x0, const float y0, const float z0,
24426 const CImg<tp>& points, const CImgList<tf>& primitives,
24427 const CImgList<tc>& colors, const CImg<to>& opacities,
24428 const unsigned int render_type=4,
24429 const bool double_sided=false, const float focale=500,
24430 const float lightx=0, const float lighty=0, const float lightz=-5000,
24431 const float specular_light=0.2f, const float specular_shine=0.1f,
24432 float *const zbuffer=0) {
24433 if (!points) return *this;
24434 return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width
24435 ,primitives,colors,opacities,opacities.size(),
24436 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24437 }
24438 #endif
24440 //! Draw a 3D object.
24441 template<typename tp, typename tf, typename tc, typename to>
24442 CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
24443 const CImgList<tp>& points, const CImgList<tf>& primitives,
24444 const CImgList<tc>& colors, const CImg<to>& opacities,
24445 const unsigned int render_type=4,
24446 const bool double_sided=false, const float focale=500,
24447 const float lightx=0, const float lighty=0, const float lightz=-5000,
24448 const float specular_light=0.2f, const float specular_shine=0.1f,
24449 float *const zbuffer=0) {
24450 if (!points) return *this;
24451 return _draw_object3d(0,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size(),
24452 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24453 }
24455 #ifdef cimg_use_board
24456 template<typename tp, typename tf, typename tc, typename to>
24457 CImg<T>& draw_object3d(BoardLib::Board& board,
24458 const float x0, const float y0, const float z0,
24459 const CImgList<tp>& points, const CImgList<tf>& primitives,
24460 const CImgList<tc>& colors, const CImg<to>& opacities,
24461 const unsigned int render_type=4,
24462 const bool double_sided=false, const float focale=500,
24463 const float lightx=0, const float lighty=0, const float lightz=-5000,
24464 const float specular_light=0.2f, const float specular_shine=0.1f,
24465 float *const zbuffer=0) {
24466 if (!points) return *this;
24467 return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size(),
24468 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
24469 }
24470 #endif
24472 //! Draw a 3D object.
24473 template<typename tp, typename tf, typename tc>
24474 CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
24475 const tp& points, const CImgList<tf>& primitives,
24476 const CImgList<tc>& colors,
24477 const unsigned int render_type=4,
24478 const bool double_sided=false, const float focale=500,
24479 const float lightx=0, const float lighty=0, const float lightz=-5000,
24480 const float specular_light=0.2f, const float specular_shine=0.1f,
24481 float *const zbuffer=0) {
24482 static const CImg<floatT> opacities;
24483 return draw_object3d(x0,y0,z0,points,primitives,colors,opacities,
24484 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
24485 }
24487 #ifdef cimg_use_board
24488 template<typename tp, typename tf, typename tc, typename to>
24489 CImg<T>& draw_object3d(BoardLib::Board& board,
24490 const float x0, const float y0, const float z0,
24491 const tp& points, const CImgList<tf>& primitives,
24492 const CImgList<tc>& colors,
24493 const unsigned int render_type=4,
24494 const bool double_sided=false, const float focale=500,
24495 const float lightx=0, const float lighty=0, const float lightz=-5000,
24496 const float specular_light=0.2f, const float specular_shine=0.1f,
24497 float *const zbuffer=0) {
24498 static const CImg<floatT> opacities;
24499 return draw_object3d(x0,y0,z0,points,primitives,colors,opacities,
24500 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
24501 }
24502 #endif
24504 //@}
24505 //----------------------------
24506 //
24507 //! \name Image Filtering
24508 //@{
24509 //----------------------------
24511 //! Compute the correlation of the instance image by a mask.
24512 /**
24513 The correlation of the instance image \p *this by the mask \p mask is defined to be :
24515 res(x,y,z) = sum_{i,j,k} (*this)(x+i,y+j,z+k)*mask(i,j,k)
24517 \param mask = the correlation kernel.
24518 \param cond = the border condition type (0=zero, 1=dirichlet)
24519 \param weighted_correl = enable local normalization.
24520 **/
24521 template<typename t>
24522 CImg<T>& correlate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_correl=false) {
24523 return get_correlate(mask,cond,weighted_correl).transfer_to(*this);
24524 }
24526 template<typename t>
24527 CImg<typename cimg::superset2<T,t,float>::type> get_correlate(const CImg<t>& mask, const unsigned int cond=1,
24528 const bool weighted_correl=false) const {
24529 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
24530 if (is_empty()) return *this;
24531 if (!mask || mask.dim!=1)
24532 throw CImgArgumentException("CImg<%s>::correlate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
24533 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
24534 CImg<Ttfloat> dest(width,height,depth,dim);
24535 if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) {
24536 // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with cond=1)
24537 switch (mask.depth) {
24538 case 3 : {
24539 T I[27] = { 0 };
24540 cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24541 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] +
24542 I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
24543 I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] +
24544 I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
24545 I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
24546 I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
24547 I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] +
24548 I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
24549 I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26]);
24550 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) {
24551 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] +
24552 I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +
24553 I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] +
24554 I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
24555 I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
24556 I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
24557 I[18]*I[18] + I[19]*I[19] + I[20]*I[20] +
24558 I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
24559 I[24]*I[24] + I[25]*I[25] + I[26]*I[26]);
24560 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24561 }
24562 } break;
24563 case 2 : {
24564 T I[8] = { 0 };
24565 cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24566 (I[0]*mask[0] + I[1]*mask[1] +
24567 I[2]*mask[2] + I[3]*mask[3] +
24568 I[4]*mask[4] + I[5]*mask[5] +
24569 I[6]*mask[6] + I[7]*mask[7]);
24570 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) {
24571 const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
24572 I[2]*I[2] + I[3]*I[3] +
24573 I[4]*I[4] + I[5]*I[5] +
24574 I[6]*I[6] + I[7]*I[7]);
24575 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24576 }
24577 } break;
24578 default :
24579 case 1 :
24580 switch (mask.width) {
24581 case 6 : {
24582 T I[36] = { 0 };
24583 cimg_forZV(*this,z,v) cimg_for6x6(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24584 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
24585 I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
24586 I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
24587 I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
24588 I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26] + I[27]*mask[27] + I[28]*mask[28] + I[29]*mask[29] +
24589 I[30]*mask[30] + I[31]*mask[31] + I[32]*mask[32] + I[33]*mask[33] + I[34]*mask[34] + I[35]*mask[35]);
24590 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
24591 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +
24592 I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
24593 I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
24594 I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
24595 I[24]*I[24] + I[25]*I[25] + I[26]*I[26] + I[27]*I[27] + I[28]*I[28] + I[29]*I[29] +
24596 I[30]*I[30] + I[31]*I[31] + I[32]*I[32] + I[33]*I[33] + I[34]*I[34] + I[35]*I[35]);
24597 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24598 }
24599 } break;
24600 case 5 : {
24601 T I[25] = { 0 };
24602 cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24603 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] +
24604 I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] +
24605 I[10]*mask[10] + I[11]*mask[11] + I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
24606 I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] + I[18]*mask[18] + I[19]*mask[19] +
24607 I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] + I[24]*mask[24]);
24608 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
24609 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] +
24610 I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] +
24611 I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
24612 I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] +
24613 I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24]);
24614 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24615 }
24616 } break;
24617 case 4 : {
24618 T I[16] = { 0 };
24619 cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24620 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] +
24621 I[ 4]*mask[ 4] + I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] +
24622 I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
24623 I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15]);
24624 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) {
24625 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] +
24626 I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] +
24627 I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
24628 I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15]);
24629 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24630 }
24631 } break;
24632 case 3 : {
24633 T I[9] = { 0 };
24634 cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24635 (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
24636 I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
24637 I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
24638 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) {
24639 const double weight = (double)(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] +
24640 I[3]*I[3] + I[4]*I[4] + I[5]*I[5] +
24641 I[6]*I[6] + I[7]*I[7] + I[8]*I[8]);
24642 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24643 }
24644 } break;
24645 case 2 : {
24646 T I[4] = { 0 };
24647 cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
24648 (I[0]*mask[0] + I[1]*mask[1] +
24649 I[2]*mask[2] + I[3]*mask[3]);
24650 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) {
24651 const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
24652 I[2]*I[2] + I[3]*I[3]);
24653 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
24654 }
24655 } break;
24656 case 1 : (dest.assign(*this))*=mask(0); break;
24657 }
24658 }
24659 } else { // Generic version for other masks
24660 const int
24661 mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
24662 mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
24663 mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
24664 cimg_forV(*this,v)
24665 if (!weighted_correl) { // Classical correlation
24666 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24667 Ttfloat val = 0;
24668 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
24669 val+=(*this)(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
24670 dest(x,y,z,v) = (Ttfloat)val;
24671 }
24672 if (cond)
24673 cimg_forYZV(*this,y,z,v)
24674 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24675 Ttfloat val = 0;
24676 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
24677 val+=_atXYZ(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
24678 dest(x,y,z,v) = (Ttfloat)val;
24679 }
24680 else
24681 cimg_forYZV(*this,y,z,v)
24682 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24683 Ttfloat val = 0;
24684 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
24685 val+=atXYZ(x+xm,y+ym,z+zm,v,0)*mask(mx1+xm,my1+ym,mz1+zm);
24686 dest(x,y,z,v) = (Ttfloat)val;
24687 }
24688 } else { // Weighted correlation
24689 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24690 Ttfloat val = 0, weight = 0;
24691 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24692 const Ttfloat cval = (Ttfloat)(*this)(x+xm,y+ym,z+zm,v);
24693 val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
24694 weight+=cval*cval;
24695 }
24696 dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
24697 }
24698 if (cond)
24699 cimg_forYZV(*this,y,z,v)
24700 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24701 Ttfloat val = 0, weight = 0;
24702 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24703 const Ttfloat cval = (Ttfloat)_atXYZ(x+xm,y+ym,z+zm,v);
24704 val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
24705 weight+=cval*cval;
24706 }
24707 dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
24708 }
24709 else
24710 cimg_forYZV(*this,y,z,v)
24711 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24712 Ttfloat val = 0, weight = 0;
24713 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24714 const Ttfloat cval = (Ttfloat)atXYZ(x+xm,y+ym,z+zm,v,0);
24715 val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
24716 weight+=cval*cval;
24717 }
24718 dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
24719 }
24720 }
24721 }
24722 return dest;
24723 }
24725 //! Compute the convolution of the image by a mask.
24726 /**
24727 The result \p res of the convolution of an image \p img by a mask \p mask is defined to be :
24729 res(x,y,z) = sum_{i,j,k} img(x-i,y-j,z-k)*mask(i,j,k)
24731 \param mask = the correlation kernel.
24732 \param cond = the border condition type (0=zero, 1=dirichlet)
24733 \param weighted_convol = enable local normalization.
24734 **/
24735 template<typename t>
24736 CImg<T>& convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) {
24737 return get_convolve(mask,cond,weighted_convol).transfer_to(*this);
24738 }
24740 template<typename t>
24741 CImg<typename cimg::superset2<T,t,float>::type> get_convolve(const CImg<t>& mask, const unsigned int cond=1,
24742 const bool weighted_convol=false) const {
24743 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
24744 if (is_empty()) return *this;
24745 if (!mask || mask.dim!=1)
24746 throw CImgArgumentException("CImg<%s>::convolve() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
24747 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
24748 return get_correlate(CImg<t>(mask.ptr(),mask.size(),1,1,1,true).get_mirror('x').resize(mask,-1),cond,weighted_convol);
24749 }
24751 //! Return the erosion of the image by a structuring element.
24752 template<typename t>
24753 CImg<T>& erode(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) {
24754 return get_erode(mask,cond,weighted_erosion).transfer_to(*this);
24755 }
24757 template<typename t>
24758 CImg<typename cimg::superset<T,t>::type> get_erode(const CImg<t>& mask, const unsigned int cond=1,
24759 const bool weighted_erosion=false) const {
24760 typedef typename cimg::superset<T,t>::type Tt;
24761 if (is_empty()) return *this;
24762 if (!mask || mask.dim!=1)
24763 throw CImgArgumentException("CImg<%s>::erode() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
24764 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
24765 CImg<Tt> dest(width,height,depth,dim);
24766 const int
24767 mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
24768 mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
24769 mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
24770 cimg_forV(*this,v)
24771 if (!weighted_erosion) { // Classical erosion
24772 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24773 Tt min_val = cimg::type<Tt>::max();
24774 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24775 const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
24776 if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
24777 }
24778 dest(x,y,z,v) = min_val;
24779 }
24780 if (cond)
24781 cimg_forYZV(*this,y,z,v)
24782 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24783 Tt min_val = cimg::type<Tt>::max();
24784 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24785 const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
24786 if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
24787 }
24788 dest(x,y,z,v) = min_val;
24789 }
24790 else
24791 cimg_forYZV(*this,y,z,v)
24792 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24793 Tt min_val = cimg::type<Tt>::max();
24794 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24795 const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
24796 if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
24797 }
24798 dest(x,y,z,v) = min_val;
24799 }
24800 } else { // Weighted erosion
24801 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24802 Tt min_val = cimg::type<Tt>::max();
24803 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24804 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24805 const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) + mval);
24806 if (mval && cval<min_val) min_val = cval;
24807 }
24808 dest(x,y,z,v) = min_val;
24809 }
24810 if (cond)
24811 cimg_forYZV(*this,y,z,v)
24812 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24813 Tt min_val = cimg::type<Tt>::max();
24814 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24815 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24816 const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) + mval);
24817 if (mval && cval<min_val) min_val = cval;
24818 }
24819 dest(x,y,z,v) = min_val;
24820 }
24821 else
24822 cimg_forYZV(*this,y,z,v)
24823 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24824 Tt min_val = cimg::type<Tt>::max();
24825 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24826 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24827 const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) + mval);
24828 if (mval && cval<min_val) min_val = cval;
24829 }
24830 dest(x,y,z,v) = min_val;
24831 }
24832 }
24833 return dest;
24834 }
24836 //! Erode the image by a square structuring element of size n.
24837 CImg<T>& erode(const unsigned int n, const unsigned int cond=1) {
24838 if (n<2) return *this;
24839 return get_erode(n,cond).transfer_to(*this);
24840 }
24842 CImg<T> get_erode(const unsigned int n, const unsigned int cond=1) const {
24843 static CImg<T> mask;
24844 if (n<2) return *this;
24845 if (mask.width!=n) mask.assign(n,n,1,1,1);
24846 const CImg<T> res = get_erode(mask,cond,false);
24847 if (n>20) mask.assign();
24848 return res;
24849 }
24851 //! Dilate the image by a structuring element.
24852 template<typename t>
24853 CImg<T>& dilate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) {
24854 return get_dilate(mask,cond,weighted_dilatation).transfer_to(*this);
24855 }
24857 template<typename t>
24858 CImg<typename cimg::superset<T,t>::type> get_dilate(const CImg<t>& mask, const unsigned int cond=1,
24859 const bool weighted_dilatation=false) const {
24860 typedef typename cimg::superset<T,t>::type Tt;
24861 if (is_empty()) return *this;
24862 if (!mask || mask.dim!=1)
24863 throw CImgArgumentException("CImg<%s>::dilate() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
24864 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
24865 CImg<Tt> dest(width,height,depth,dim);
24866 const int
24867 mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
24868 mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
24869 mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
24870 cimg_forV(*this,v)
24871 if (!weighted_dilatation) { // Classical dilatation
24872 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24873 Tt max_val = cimg::type<Tt>::min();
24874 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24875 const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
24876 if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
24877 }
24878 dest(x,y,z,v) = max_val;
24879 }
24880 if (cond)
24881 cimg_forYZV(*this,y,z,v)
24882 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24883 Tt max_val = cimg::type<Tt>::min();
24884 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24885 const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
24886 if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
24887 }
24888 dest(x,y,z,v) = max_val;
24889 }
24890 else
24891 cimg_forYZV(*this,y,z,v)
24892 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24893 Tt max_val = cimg::type<Tt>::min();
24894 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24895 const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
24896 if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
24897 }
24898 dest(x,y,z,v) = max_val;
24899 }
24900 } else { // Weighted dilatation
24901 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
24902 Tt max_val = cimg::type<Tt>::min();
24903 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24904 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24905 const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) - mval);
24906 if (mval && cval>max_val) max_val = cval;
24907 }
24908 dest(x,y,z,v) = max_val;
24909 }
24910 if (cond)
24911 cimg_forYZV(*this,y,z,v)
24912 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24913 Tt max_val = cimg::type<Tt>::min();
24914 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24915 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24916 const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) - mval);
24917 if (mval && cval>max_val) max_val = cval;
24918 }
24919 dest(x,y,z,v) = max_val;
24920 }
24921 else
24922 cimg_forYZV(*this,y,z,v)
24923 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
24924 Tt max_val = cimg::type<Tt>::min();
24925 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
24926 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
24927 const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) - mval);
24928 if (mval && cval>max_val) max_val = cval;
24929 }
24930 dest(x,y,z,v) = max_val;
24931 }
24932 }
24933 return dest;
24934 }
24936 //! Dilate the image by a square structuring element of size n.
24937 CImg<T>& dilate(const unsigned int n, const unsigned int cond=1) {
24938 if (n<2) return *this;
24939 return get_dilate(n,cond).transfer_to(*this);
24940 }
24942 CImg<T> get_dilate(const unsigned int n, const unsigned int cond=1) const {
24943 static CImg<T> mask;
24944 if (n<2) return *this;
24945 if (mask.width!=n) mask.assign(n,n,1,1,1);
24946 const CImg<T> res = get_dilate(mask,cond,false);
24947 if (n>20) mask.assign();
24948 return res;
24949 }
24951 //! Add noise to the image.
24952 /**
24953 \param sigma = power of the noise. if sigma<0, it corresponds to the percentage of the maximum image value.
24954 \param ntype = noise type. can be 0=gaussian, 1=uniform or 2=Salt and Pepper, 3=Poisson, 4=Rician.
24955 \return A noisy version of the instance image.
24956 **/
24957 CImg<T>& noise(const double sigma, const unsigned int noise_type=0) {
24958 if (!is_empty()) {
24959 double nsigma = sigma, max = (double)cimg::type<T>::max(), min = (double)cimg::type<T>::min();
24960 Tfloat m = 0, M = 0;
24961 if (nsigma==0 && noise_type!=3) return *this;
24962 if (nsigma<0 || noise_type==2) m = (Tfloat)minmax(M);
24963 if (nsigma<0) nsigma = -nsigma*(M-m)/100.0;
24964 switch (noise_type) {
24965 case 0 : { // Gaussian noise
24966 cimg_for(*this,ptr,T) {
24967 double val = *ptr + nsigma*cimg::grand();
24968 if (val>max) val = max;
24969 if (val<min) val = min;
24970 *ptr = (T)val;
24971 }
24972 } break;
24973 case 1 : { // Uniform noise
24974 cimg_for(*this,ptr,T) {
24975 double val = *ptr + nsigma*cimg::crand();
24976 if (val>max) val = max;
24977 if (val<min) val = min;
24978 *ptr = (T)val;
24979 }
24980 } break;
24981 case 2 : { // Salt & Pepper noise
24982 if (nsigma<0) nsigma = -nsigma;
24983 if (M==m) { m = 0; M = (float)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); }
24984 cimg_for(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr = (T)(cimg::rand()<0.5?M:m);
24985 } break;
24987 case 3 : { // Poisson Noise
24988 cimg_for(*this,ptr,T) *ptr = (T)cimg::prand(*ptr);
24989 } break;
24991 case 4 : { // Rice noise
24992 const double sqrt2 = (double)cimg_std::sqrt(2.0);
24993 cimg_for(*this,ptr,T) {
24994 const double
24995 val0 = (double)*ptr/sqrt2,
24996 re = val0 + nsigma*cimg::grand(),
24997 im = val0 + nsigma*cimg::grand();
24998 double val = cimg_std::sqrt(re*re + im*im);
24999 if (val>max) val = max;
25000 if (val<min) val = min;
25001 *ptr = (T)val;
25002 }
25003 } break;
25004 default :
25005 throw CImgArgumentException("CImg<%s>::noise() : Invalid noise type %d "
25006 "(should be {0=Gaussian, 1=Uniform, 2=Salt&Pepper, 3=Poisson}).",pixel_type(),noise_type);
25007 }
25008 }
25009 return *this;
25010 }
25012 CImg<T> get_noise(const double sigma, const unsigned int noise_type=0) const {
25013 return (+*this).noise(sigma,noise_type);
25014 }
25016 //! Compute the result of the Deriche filter.
25017 /**
25018 The Canny-Deriche filter is a recursive algorithm allowing to compute blurred derivatives of
25019 order 0,1 or 2 of an image.
25020 **/
25021 CImg<T>& deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) {
25022 #define _cimg_deriche2_apply \
25023 Tfloat *ptrY = Y.data, yb = 0, yp = 0; \
25024 T xp = (T)0; \
25025 if (cond) { xp = *ptrX; yb = yp = (Tfloat)(coefp*xp); } \
25026 for (int m=0; m<N; ++m) { \
25027 const T xc = *ptrX; ptrX+=off; \
25028 const Tfloat yc = *(ptrY++) = (Tfloat)(a0*xc + a1*xp - b1*yp - b2*yb); \
25029 xp = xc; yb = yp; yp = yc; \
25030 } \
25031 T xn = (T)0, xa = (T)0; \
25032 Tfloat yn = 0, ya = 0; \
25033 if (cond) { xn = xa = *(ptrX-off); yn = ya = (Tfloat)coefn*xn; } \
25034 for (int n=N-1; n>=0; --n) { \
25035 const T xc = *(ptrX-=off); \
25036 const Tfloat yc = (Tfloat)(a2*xn + a3*xa - b1*yn - b2*ya); \
25037 xa = xn; xn = xc; ya = yn; yn = yc; \
25038 *ptrX = (T)(*(--ptrY)+yc); \
25039 }
25040 if (sigma<0)
25041 throw CImgArgumentException("CImg<%s>::deriche() : Given filter variance (sigma = %g) is negative",
25042 pixel_type(),sigma);
25043 if (is_empty() || (sigma<0.1 && !order)) return *this;
25044 const float
25045 nsigma = sigma<0.1f?0.1f:sigma,
25046 alpha = 1.695f/nsigma,
25047 ema = (float)cimg_std::exp(-alpha),
25048 ema2 = (float)cimg_std::exp(-2*alpha),
25049 b1 = -2*ema,
25050 b2 = ema2;
25051 float a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0;
25052 switch (order) {
25053 case 0 : {
25054 const float k = (1-ema)*(1-ema)/(1+2*alpha*ema-ema2);
25055 a0 = k;
25056 a1 = k*(alpha-1)*ema;
25057 a2 = k*(alpha+1)*ema;
25058 a3 = -k*ema2;
25059 } break;
25060 case 1 : {
25061 const float k = (1-ema)*(1-ema)/ema;
25062 a0 = k*ema;
25063 a1 = a3 = 0;
25064 a2 = -a0;
25065 } break;
25066 case 2 : {
25067 const float
25068 ea = (float)cimg_std::exp(-alpha),
25069 k = -(ema2-1)/(2*alpha*ema),
25070 kn = (-2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea));
25071 a0 = kn;
25072 a1 = -kn*(1+k*alpha)*ema;
25073 a2 = kn*(1-k*alpha)*ema;
25074 a3 = -kn*ema2;
25075 } break;
25076 default :
25077 throw CImgArgumentException("CImg<%s>::deriche() : Given filter order (order = %u) must be 0,1 or 2",
25078 pixel_type(),order);
25079 }
25080 coefp = (a0+a1)/(1+b1+b2);
25081 coefn = (a2+a3)/(1+b1+b2);
25082 switch (cimg::uncase(axis)) {
25083 case 'x' : {
25084 const int N = width, off = 1;
25085 CImg<Tfloat> Y(N);
25086 cimg_forYZV(*this,y,z,v) { T *ptrX = ptr(0,y,z,v); _cimg_deriche2_apply; }
25087 } break;
25088 case 'y' : {
25089 const int N = height, off = width;
25090 CImg<Tfloat> Y(N);
25091 cimg_forXZV(*this,x,z,v) { T *ptrX = ptr(x,0,z,v); _cimg_deriche2_apply; }
25092 } break;
25093 case 'z' : {
25094 const int N = depth, off = width*height;
25095 CImg<Tfloat> Y(N);
25096 cimg_forXYV(*this,x,y,v) { T *ptrX = ptr(x,y,0,v); _cimg_deriche2_apply; }
25097 } break;
25098 case 'v' : {
25099 const int N = dim, off = width*height*depth;
25100 CImg<Tfloat> Y(N);
25101 cimg_forXYZ(*this,x,y,z) { T *ptrX = ptr(x,y,z,0); _cimg_deriche2_apply; }
25102 } break;
25103 }
25104 return *this;
25105 }
25107 CImg<Tfloat> get_deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) const {
25108 return CImg<Tfloat>(*this,false).deriche(sigma,order,axis,cond);
25109 }
25111 //! Return a blurred version of the image, using a Canny-Deriche filter.
25112 /**
25113 Blur the image with an anisotropic exponential filter (Deriche filter of order 0).
25114 **/
25115 CImg<T>& blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) {
25116 if (!is_empty()) {
25117 if (width>1 && sigmax>0) deriche(sigmax,0,'x',cond);
25118 if (height>1 && sigmay>0) deriche(sigmay,0,'y',cond);
25119 if (depth>1 && sigmaz>0) deriche(sigmaz,0,'z',cond);
25120 }
25121 return *this;
25122 }
25124 CImg<Tfloat> get_blur(const float sigmax, const float sigmay, const float sigmaz,
25125 const bool cond=true) const {
25126 return CImg<Tfloat>(*this,false).blur(sigmax,sigmay,sigmaz,cond);
25127 }
25129 //! Return a blurred version of the image, using a Canny-Deriche filter.
25130 CImg<T>& blur(const float sigma, const bool cond=true) {
25131 return blur(sigma,sigma,sigma,cond);
25132 }
25134 CImg<Tfloat> get_blur(const float sigma, const bool cond=true) const {
25135 return CImg<Tfloat>(*this,false).blur(sigma,cond);
25136 }
25138 //! Blur the image anisotropically following a field of diffusion tensors.
25139 /**
25140 \param G = Field of square roots of diffusion tensors used to drive the smoothing.
25141 \param amplitude = amplitude of the smoothing.
25142 \param dl = spatial discretization.
25143 \param da = angular discretization.
25144 \param gauss_prec = precision of the gaussian function.
25145 \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
25146 \param fast_approx = Tell to use the fast approximation or not.
25147 **/
25148 template<typename t>
25149 CImg<T>& blur_anisotropic(const CImg<t>& G, const float amplitude=60, const float dl=0.8f, const float da=30,
25150 const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true) {
25151 #define _cimg_valign2d(i,j) \
25152 { Tfloat &u = W(i,j,0,0), &v = W(i,j,0,1); \
25153 if (u*curru + v*currv<0) { u=-u; v=-v; }}
25154 #define _cimg_valign3d(i,j,k) \
25155 { Tfloat &u = W(i,j,k,0), &v = W(i,j,k,1), &w = W(i,j,k,2); \
25156 if (u*curru + v*currv + w*currw<0) { u=-u; v=-v; w=-w; }}
25158 // Check arguments and init variables
25159 if (!is_empty() && amplitude>0) {
25160 if (!G || (G.dim!=3 && G.dim!=6) || G.width!=width || G.height!=height || G.depth!=depth)
25161 throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Specified tensor field (%u,%u,%u,%u) is not valid.",
25162 pixel_type(),G.width,G.height,G.depth,G.dim);
25164 const float sqrt2amplitude = (float)cimg_std::sqrt(2*amplitude);
25165 const bool threed = (G.dim>=6);
25166 const int
25167 dx1 = dimx()-1,
25168 dy1 = dimy()-1,
25169 dz1 = dimz()-1;
25170 CImg<Tfloat>
25171 dest(width,height,depth,dim,0),
25172 W(width,height,depth,threed?4:3),
25173 tmp(dim);
25174 int N = 0;
25176 if (threed)
25177 // 3D version of the algorithm
25178 for (float phi=(180%(int)da)/2.0f; phi<=180; phi+=da) {
25179 const float
25180 phir = (float)(phi*cimg::valuePI/180),
25181 datmp = (float)(da/cimg_std::cos(phir)),
25182 da2 = datmp<1?360.0f:datmp;
25184 for (float theta=0; theta<360; (theta+=da2),++N) {
25185 const float
25186 thetar = (float)(theta*cimg::valuePI/180),
25187 vx = (float)(cimg_std::cos(thetar)*cimg_std::cos(phir)),
25188 vy = (float)(cimg_std::sin(thetar)*cimg_std::cos(phir)),
25189 vz = (float)cimg_std::sin(phir);
25190 const t
25191 *pa = G.ptr(0,0,0,0),
25192 *pb = G.ptr(0,0,0,1),
25193 *pc = G.ptr(0,0,0,2),
25194 *pd = G.ptr(0,0,0,3),
25195 *pe = G.ptr(0,0,0,4),
25196 *pf = G.ptr(0,0,0,5);
25197 Tfloat
25198 *pd0 = W.ptr(0,0,0,0),
25199 *pd1 = W.ptr(0,0,0,1),
25200 *pd2 = W.ptr(0,0,0,2),
25201 *pd3 = W.ptr(0,0,0,3);
25202 cimg_forXYZ(G,xg,yg,zg) {
25203 const t
25204 a = *(pa++), b = *(pb++), c = *(pc++),
25205 d = *(pd++), e = *(pe++), f = *(pf++);
25206 const float
25207 u = (float)(a*vx + b*vy + c*vz),
25208 v = (float)(b*vx + d*vy + e*vz),
25209 w = (float)(c*vx + e*vy + f*vz),
25210 n = (float)cimg_std::sqrt(1e-5+u*u+v*v+w*w),
25211 dln = dl/n;
25212 *(pd0++) = (Tfloat)(u*dln);
25213 *(pd1++) = (Tfloat)(v*dln);
25214 *(pd2++) = (Tfloat)(w*dln);
25215 *(pd3++) = (Tfloat)n;
25216 }
25218 cimg_forXYZ(*this,x,y,z) {
25219 tmp.fill(0);
25220 const float
25221 cu = (float)W(x,y,z,0),
25222 cv = (float)W(x,y,z,1),
25223 cw = (float)W(x,y,z,2),
25224 n = (float)W(x,y,z,3),
25225 fsigma = (float)(n*sqrt2amplitude),
25226 length = gauss_prec*fsigma,
25227 fsigma2 = 2*fsigma*fsigma;
25228 float
25229 S = 0,
25230 pu = cu,
25231 pv = cv,
25232 pw = cw,
25233 X = (float)x,
25234 Y = (float)y,
25235 Z = (float)z;
25237 switch (interpolation_type) {
25238 case 0 : {
25239 // Nearest neighbor
25240 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
25241 const int
25242 cx = (int)(X+0.5f),
25243 cy = (int)(Y+0.5f),
25244 cz = (int)(Z+0.5f);
25245 float
25246 u = (float)W(cx,cy,cz,0),
25247 v = (float)W(cx,cy,cz,1),
25248 w = (float)W(cx,cy,cz,2);
25249 if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
25250 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,cz,k); ++S; }
25251 else {
25252 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25253 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,cz,k));
25254 S+=coef;
25255 }
25256 X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
25257 }
25258 } break;
25260 case 1 : {
25261 // Linear interpolation
25262 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
25263 const int
25264 cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
25265 cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
25266 cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
25267 const float
25268 curru = (float)W(cx,cy,cz,0),
25269 currv = (float)W(cx,cy,cz,1),
25270 currw = (float)W(cx,cy,cz,2);
25271 _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
25272 _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
25273 _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
25274 _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
25275 _cimg_valign3d(px,cy,cz); _cimg_valign3d(nx,cy,cz);
25276 _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
25277 _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
25278 _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
25279 _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
25280 float
25281 u = (float)(W._linear_atXYZ(X,Y,Z,0)),
25282 v = (float)(W._linear_atXYZ(X,Y,Z,1)),
25283 w = (float)(W._linear_atXYZ(X,Y,Z,2));
25284 if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
25285 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
25286 else {
25287 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25288 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
25289 S+=coef;
25290 }
25291 X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
25292 }
25293 } break;
25295 default : {
25296 // 2nd order Runge Kutta
25297 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
25298 const int
25299 cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
25300 cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
25301 cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
25302 const float
25303 curru = (float)W(cx,cy,cz,0),
25304 currv = (float)W(cx,cy,cz,1),
25305 currw = (float)W(cx,cy,cz,2);
25306 _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
25307 _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
25308 _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
25309 _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
25310 _cimg_valign3d(px,cy,cz); _cimg_valign3d(nx,cy,cz);
25311 _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
25312 _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
25313 _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
25314 _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
25315 const float
25316 u0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,0)),
25317 v0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,1)),
25318 w0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,2));
25319 float
25320 u = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,0)),
25321 v = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,1)),
25322 w = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,2));
25323 if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
25324 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
25325 else {
25326 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25327 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
25328 S+=coef;
25329 }
25330 X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
25331 }
25332 } break;
25333 }
25334 if (S>0) cimg_forV(dest,k) dest(x,y,z,k)+=tmp[k]/S;
25335 else cimg_forV(dest,k) dest(x,y,z,k)+=(Tfloat)((*this)(x,y,z,k));
25336 cimg_plugin_greycstoration_count;
25337 }
25338 }
25339 } else
25340 // 2D version of the algorithm
25341 for (float theta=(360%(int)da)/2.0f; theta<360; (theta+=da),++N) {
25342 const float
25343 thetar = (float)(theta*cimg::valuePI/180),
25344 vx = (float)(cimg_std::cos(thetar)),
25345 vy = (float)(cimg_std::sin(thetar));
25346 const t
25347 *pa = G.ptr(0,0,0,0),
25348 *pb = G.ptr(0,0,0,1),
25349 *pc = G.ptr(0,0,0,2);
25350 Tfloat
25351 *pd0 = W.ptr(0,0,0,0),
25352 *pd1 = W.ptr(0,0,0,1),
25353 *pd2 = W.ptr(0,0,0,2);
25354 cimg_forXY(G,xg,yg) {
25355 const t a = *(pa++), b = *(pb++), c = *(pc++);
25356 const float
25357 u = (float)(a*vx + b*vy),
25358 v = (float)(b*vx + c*vy),
25359 n = (float)cimg_std::sqrt(1e-5+u*u+v*v),
25360 dln = dl/n;
25361 *(pd0++) = (Tfloat)(u*dln);
25362 *(pd1++) = (Tfloat)(v*dln);
25363 *(pd2++) = (Tfloat)n;
25364 }
25366 cimg_forXY(*this,x,y) {
25367 tmp.fill(0);
25368 const float
25369 cu = (float)W(x,y,0,0),
25370 cv = (float)W(x,y,0,1),
25371 n = (float)W(x,y,0,2),
25372 fsigma = (float)(n*sqrt2amplitude),
25373 length = gauss_prec*fsigma,
25374 fsigma2 = 2*fsigma*fsigma;
25375 float
25376 S = 0,
25377 pu = cu,
25378 pv = cv,
25379 X = (float)x,
25380 Y = (float)y;
25382 switch (interpolation_type) {
25384 case 0 : {
25385 // Nearest-neighbor interpolation for 2D images
25386 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
25387 const int
25388 cx = (int)(X+0.5f),
25389 cy = (int)(Y+0.5f);
25390 float
25391 u = (float)W(cx,cy,0,0),
25392 v = (float)W(cx,cy,0,1);
25393 if ((pu*u + pv*v)<0) { u=-u; v=-v; }
25394 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,0,k); ++S; }
25395 else {
25396 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25397 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,0,k));
25398 S+=coef;
25399 }
25400 X+=(pu=u); Y+=(pv=v);
25401 }
25402 } break;
25404 case 1 : {
25405 // Linear interpolation for 2D images
25406 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
25407 const int
25408 cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
25409 cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
25410 const float
25411 curru = (float)W(cx,cy,0,0),
25412 currv = (float)W(cx,cy,0,1);
25413 _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
25414 _cimg_valign2d(px,cy); _cimg_valign2d(nx,cy);
25415 _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
25416 float
25417 u = (float)(W._linear_atXY(X,Y,0,0)),
25418 v = (float)(W._linear_atXY(X,Y,0,1));
25419 if ((pu*u + pv*v)<0) { u=-u; v=-v; }
25420 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
25421 else {
25422 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25423 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
25424 S+=coef;
25425 }
25426 X+=(pu=u); Y+=(pv=v);
25427 }
25428 } break;
25430 default : {
25431 // 2nd-order Runge-kutta interpolation for 2D images
25432 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
25433 const int
25434 cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
25435 cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
25436 const float
25437 curru = (float)W(cx,cy,0,0),
25438 currv = (float)W(cx,cy,0,1);
25439 _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
25440 _cimg_valign2d(px,cy); _cimg_valign2d(nx,cy);
25441 _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
25442 const float
25443 u0 = (float)(0.5f*W._linear_atXY(X,Y,0,0)),
25444 v0 = (float)(0.5f*W._linear_atXY(X,Y,0,1));
25445 float
25446 u = (float)(W._linear_atXY(X+u0,Y+v0,0,0)),
25447 v = (float)(W._linear_atXY(X+u0,Y+v0,0,1));
25448 if ((pu*u + pv*v)<0) { u=-u; v=-v; }
25449 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
25450 else {
25451 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
25452 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
25453 S+=coef;
25454 }
25455 X+=(pu=u); Y+=(pv=v);
25456 }
25457 }
25458 }
25459 if (S>0) cimg_forV(dest,k) dest(x,y,0,k)+=tmp[k]/S;
25460 else cimg_forV(dest,k) dest(x,y,0,k)+=(Tfloat)((*this)(x,y,0,k));
25461 cimg_plugin_greycstoration_count;
25462 }
25463 }
25464 const Tfloat *ptrs = dest.data+dest.size();
25465 const T m = cimg::type<T>::min(), M = cimg::type<T>::max();
25466 cimg_for(*this,ptrd,T) { const Tfloat val = *(--ptrs)/N; *ptrd = val<m?m:(val>M?M:(T)val); }
25467 }
25468 return *this;
25469 }
25471 template<typename t>
25472 CImg<T> get_blur_anisotropic(const CImg<t>& G, const float amplitude=60, const float dl=0.8f, const float da=30,
25473 const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true) const {
25474 return (+*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
25475 }
25477 //! Blur an image in an anisotropic way.
25478 /**
25479 \param mask Binary mask.
25480 \param amplitude Amplitude of the anisotropic blur.
25481 \param sharpness Contour preservation.
25482 \param anisotropy Smoothing anisotropy.
25483 \param alpha Image pre-blurring (gaussian).
25484 \param sigma Regularity of the tensor-valued geometry.
25485 \param dl Spatial discretization.
25486 \param da Angular discretization.
25487 \param gauss_prec Precision of the gaussian function.
25488 \param interpolation_type Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
25489 \param fast_approx Tell to use the fast approximation or not
25490 \param geom_factor Geometry factor.
25491 **/
25492 template<typename tm>
25493 CImg<T>& blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
25494 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,
25495 const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true,
25496 const float geom_factor=1) {
25497 if (!is_empty() && amplitude>0) {
25498 if (amplitude==0) return *this;
25499 if (amplitude<0 || sharpness<0 || anisotropy<0 || anisotropy>1 || alpha<0 || sigma<0 || dl<0 || da<0 || gauss_prec<0)
25500 throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Given parameters are amplitude(%g), sharpness(%g), "
25501 "anisotropy(%g), alpha(%g), sigma(%g), dl(%g), da(%g), gauss_prec(%g).\n"
25502 "Admissible parameters are in the range : amplitude>0, sharpness>0, anisotropy in [0,1], "
25503 "alpha>0, sigma>0, dl>0, da>0, gauss_prec>0.",
25504 pixel_type(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec);
25505 const bool threed = (depth>1), no_mask = mask.is_empty();
25506 const float nsharpness = cimg::max(sharpness,1e-5f), power1 = 0.5f*nsharpness, power2 = power1/(1e-7f+1-anisotropy);
25507 CImg<floatT> blurred = CImg<floatT>(*this,false).blur(alpha);
25508 if (geom_factor>0) blurred*=geom_factor;
25509 else blurred.normalize(0,-geom_factor);
25511 if (threed) { // Field for 3D volumes
25512 cimg_plugin_greycstoration_lock;
25513 CImg<floatT> val(3), vec(3,3), G(blurred.get_structure_tensor());
25514 if (sigma>0) G.blur(sigma);
25515 cimg_forXYZ(*this,x,y,z) {
25516 if (no_mask || mask(x,y,z)) {
25517 G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
25518 const float l1 = val[2], l2 = val[1], l3 = val[0],
25519 ux = vec(0,0), uy = vec(0,1), uz = vec(0,2),
25520 vx = vec(1,0), vy = vec(1,1), vz = vec(1,2),
25521 wx = vec(2,0), wy = vec(2,1), wz = vec(2,2),
25522 n1 = (float)cimg_std::pow(1+l1+l2+l3,-power1),
25523 n2 = (float)cimg_std::pow(1+l1+l2+l3,-power2);
25524 G(x,y,z,0) = n1*(ux*ux + vx*vx) + n2*wx*wx;
25525 G(x,y,z,1) = n1*(ux*uy + vx*vy) + n2*wx*wy;
25526 G(x,y,z,2) = n1*(ux*uz + vx*vz) + n2*wx*wz;
25527 G(x,y,z,3) = n1*(uy*uy + vy*vy) + n2*wy*wy;
25528 G(x,y,z,4) = n1*(uy*uz + vy*vz) + n2*wy*wz;
25529 G(x,y,z,5) = n1*(uz*uz + vz*vz) + n2*wz*wz;
25530 } else G(x,y,z,0) = G(x,y,z,1) = G(x,y,z,2) = G(x,y,z,3) = G(x,y,z,4) = G(x,y,z,5) = 0;
25531 cimg_plugin_greycstoration_count;
25532 }
25533 cimg_plugin_greycstoration_unlock;
25534 blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
25535 } else { // Field for 2D images
25536 cimg_plugin_greycstoration_lock;
25537 CImg<floatT> val(2), vec(2,2), G(blurred.get_structure_tensor());
25538 if (sigma>0) G.blur(sigma);
25539 cimg_forXY(*this,x,y) {
25540 if (no_mask || mask(x,y)) {
25541 G.get_tensor_at(x,y).symmetric_eigen(val,vec);
25542 const float l1 = val[1], l2 = val[0],
25543 ux = vec(1,0), uy = vec(1,1),
25544 vx = vec(0,0), vy = vec(0,1),
25545 n1 = (float)cimg_std::pow(1+l1+l2,-power1),
25546 n2 = (float)cimg_std::pow(1+l1+l2,-power2);
25547 G(x,y,0,0) = n1*ux*ux + n2*vx*vx;
25548 G(x,y,0,1) = n1*ux*uy + n2*vx*vy;
25549 G(x,y,0,2) = n1*uy*uy + n2*vy*vy;
25550 } else G(x,y,0,0) = G(x,y,0,1) = G(x,y,0,2) = 0;
25551 cimg_plugin_greycstoration_count;
25552 }
25553 cimg_plugin_greycstoration_unlock;
25554 blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
25555 }
25556 }
25557 return *this;
25558 }
25560 template<typename tm>
25561 CImg<T> get_blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
25562 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
25563 const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0,
25564 const bool fast_approx=true, const float geom_factor=1) const {
25565 return (+*this).blur_anisotropic(mask,amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
25566 }
25568 //! Blur an image following in an anisotropic way.
25569 CImg<T>& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
25570 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,
25571 const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true,
25572 const float geom_factor=1) {
25573 return blur_anisotropic(CImg<T>(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
25574 }
25576 CImg<T> get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
25577 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
25578 const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0,
25579 const bool fast_approx=true, const float geom_factor=1) const {
25580 return (+*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
25581 }
25583 //! Blur an image using the bilateral filter.
25584 /**
25585 \param sigmax Amount of blur along the X-axis.
25586 \param sigmay Amount of blur along the Y-axis.
25587 \param sigmaz Amount of blur along the Z-axis.
25588 \param sigmar Amount of blur along the range axis.
25589 \param bgridx Size of the bilateral grid along the X-axis.
25590 \param bgridy Size of the bilateral grid along the Y-axis.
25591 \param bgridz Size of the bilateral grid along the Z-axis.
25592 \param bgridr Size of the bilateral grid along the range axis.
25593 \param interpolation_type Use interpolation for image slicing.
25594 \note This algorithm uses the optimisation technique proposed by S. Paris and F. Durand, in ECCV'2006
25595 (extended for 3D volumetric images).
25596 **/
25597 CImg<T>& blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
25598 const int bgridx, const int bgridy, const int bgridz, const int bgridr,
25599 const bool interpolation_type=true) {
25600 T m, M = maxmin(m);
25601 const float range = (float)(1.0f+M-m);
25602 const unsigned int
25603 bx0 = bgridx>=0?bgridx:width*(-bgridx)/100,
25604 by0 = bgridy>=0?bgridy:height*(-bgridy)/100,
25605 bz0 = bgridz>=0?bgridz:depth*(-bgridz)/100,
25606 br0 = bgridr>=0?bgridr:(int)(-range*bgridr/100),
25607 bx = bx0>0?bx0:1,
25608 by = by0>0?by0:1,
25609 bz = bz0>0?bz0:1,
25610 br = br0>0?br0:1;
25611 const float
25612 nsigmax = sigmax*bx/width,
25613 nsigmay = sigmay*by/height,
25614 nsigmaz = sigmaz*bz/depth,
25615 nsigmar = sigmar*br/range;
25616 if (nsigmax>0 || nsigmay>0 || nsigmaz>0 || nsigmar>0) {
25617 const bool threed = depth>1;
25618 if (threed) { // 3d version of the algorithm
25619 CImg<floatT> bgrid(bx,by,bz,br), bgridw(bx,by,bz,br);
25620 cimg_forV(*this,k) {
25621 bgrid.fill(0); bgridw.fill(0);
25622 cimg_forXYZ(*this,x,y,z) {
25623 const T val = (*this)(x,y,z,k);
25624 const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
25625 bgrid(X,Y,Z,R) = (float)val;
25626 bgridw(X,Y,Z,R) = 1;
25627 }
25628 bgrid.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
25629 bgridw.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
25630 if (interpolation_type) cimg_forXYZ(*this,x,y,z) {
25631 const T val = (*this)(x,y,z,k);
25632 const float X = (float)x*bx/width, Y = (float)y*by/height, Z = (float)z*bz/depth, R = (float)((val-m)*br/range),
25633 bval0 = bgrid._linear_atXYZV(X,Y,Z,R), bval1 = bgridw._linear_atXYZV(X,Y,Z,R);
25634 (*this)(x,y,z,k) = (T)(bval0/bval1);
25635 } else cimg_forXYZ(*this,x,y,z) {
25636 const T val = (*this)(x,y,z,k);
25637 const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
25638 const float bval0 = bgrid(X,Y,Z,R), bval1 = bgridw(X,Y,Z,R);
25639 (*this)(x,y,z,k) = (T)(bval0/bval1);
25640 }
25641 }
25642 } else { // 2d version of the algorithm
25643 CImg<floatT> bgrid(bx,by,br,2);
25644 cimg_forV(*this,k) {
25645 bgrid.fill(0);
25646 cimg_forXY(*this,x,y) {
25647 const T val = (*this)(x,y,k);
25648 const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
25649 bgrid(X,Y,R,0) = (float)val;
25650 bgrid(X,Y,R,1) = 1;
25651 }
25652 bgrid.blur(nsigmax,nsigmay,0,true).blur(0,0,nsigmar,false);
25653 if (interpolation_type) cimg_forXY(*this,x,y) {
25654 const T val = (*this)(x,y,k);
25655 const float X = (float)x*bx/width, Y = (float)y*by/height, R = (float)((val-m)*br/range),
25656 bval0 = bgrid._linear_atXYZ(X,Y,R,0), bval1 = bgrid._linear_atXYZ(X,Y,R,1);
25657 (*this)(x,y,k) = (T)(bval0/bval1);
25658 } else cimg_forXY(*this,x,y) {
25659 const T val = (*this)(x,y,k);
25660 const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
25661 const float bval0 = bgrid(X,Y,R,0), bval1 = bgrid(X,Y,R,1);
25662 (*this)(x,y,k) = (T)(bval0/bval1);
25663 }
25664 }
25665 }
25666 }
25667 return *this;
25668 }
25670 CImg<T> get_blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
25671 const int bgridx, const int bgridy, const int bgridz, const int bgridr,
25672 const bool interpolation_type=true) const {
25673 return (+*this).blur_bilateral(sigmax,sigmay,sigmaz,sigmar,bgridx,bgridy,bgridz,bgridr,interpolation_type);
25674 }
25676 //! Blur an image using the bilateral filter.
25677 CImg<T>& blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
25678 const bool interpolation_type=true) {
25679 return blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
25680 }
25682 CImg<T> get_blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
25683 const bool interpolation_type=true) const {
25684 return (+*this).blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
25685 }
25687 //! Blur an image in its patch-based space.
25688 CImg<T>& blur_patch(const unsigned int patch_size, const float sigma_p, const float sigma_s=10,
25689 const unsigned int lookup_size=4, const bool fast_approx=true) {
25691 #define _cimg_blur_patch_fastfunc(x) ((x)>3?0:1)
25692 #define _cimg_blur_patch_slowfunc(x) cimg_std::exp(-(x))
25693 #define _cimg_blur_patch3d(N,func) { \
25694 const unsigned int N3 = N*N*N; \
25695 cimg_for##N##XYZ(*this,x,y,z) { \
25696 cimg_plugin_greycstoration_count; \
25697 cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,x,y,z,k,P.ptr(N3*k)); \
25698 const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \
25699 float sum_weights = 0; \
25700 cimg_for_in##N##XYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) { \
25701 cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,p,q,r,k,Q.ptr(N3*k)); \
25702 float distance2 = 0; \
25703 const T *pQ = Q.end(); \
25704 cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(--pQ); distance2+=dI*dI; } \
25705 distance2/=Pnorm; \
25706 const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \
25707 alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = (float)func(alldist); \
25708 sum_weights+=weight; \
25709 { cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k); } \
25710 } \
25711 if (sum_weights>0) cimg_forV(*this,k) res(x,y,z,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,z,k) = (Tfloat)((*this)(x,y,z,k)); \
25712 }}
25713 #define _cimg_blur_patch2d(N,func) { \
25714 const unsigned int N2 = N*N; \
25715 cimg_for##N##XY(*this,x,y) { \
25716 cimg_plugin_greycstoration_count; \
25717 cimg_forV(*this,k) cimg_get##N##x##N(*this,x,y,0,k,P.ptr(N2*k)); \
25718 const int x0 = x-rsize1, y0 = y-rsize1, x1 = x+rsize2, y1 = y+rsize2; \
25719 float sum_weights = 0; \
25720 cimg_for_in##N##XY(*this,x0,y0,x1,y1,p,q) { \
25721 cimg_forV(*this,k) cimg_get##N##x##N(*this,p,q,0,k,Q.ptr(N2*k)); \
25722 float distance2 = 0; \
25723 const T *pQ = Q.end(); \
25724 cimg_for(P,pP,T) { const float dI = (float)*pP-(float)*(--pQ); distance2+=dI*dI; } \
25725 distance2/=Pnorm; \
25726 const float dx = (float)p-x, dy = (float)q-y, \
25727 alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = (float)func(alldist); \
25728 sum_weights+=weight; \
25729 { cimg_forV(*this,k) res(x,y,k)+=weight*(*this)(p,q,k); } \
25730 } \
25731 if (sum_weights>0) cimg_forV(*this,k) res(x,y,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,k) = (Tfloat)((*this)(x,y,k)); \
25732 }}
25734 CImg<Tfloat> res(width,height,depth,dim,0);
25735 CImg<T> P(patch_size*patch_size*dim), Q(P);
25736 const float sigma_s2 = sigma_s*sigma_s, sigma_p2 = sigma_p*sigma_p, Pnorm = P.size()*sigma_p2;
25737 const int rsize2 = (int)lookup_size/2, rsize1 = rsize2-1+(lookup_size%2);
25738 if (depth>1) switch (patch_size) { // 3D version
25739 case 2 :
25740 if (fast_approx) { _cimg_blur_patch3d(2,_cimg_blur_patch_fastfunc); }
25741 else { _cimg_blur_patch3d(2,_cimg_blur_patch_slowfunc); }
25742 break;
25743 case 3 :
25744 if (fast_approx) { _cimg_blur_patch3d(3,_cimg_blur_patch_fastfunc); }
25745 else { _cimg_blur_patch3d(3,_cimg_blur_patch_slowfunc); }
25746 break;
25747 default : {
25748 const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
25749 cimg_forXYZ(*this,x,y,z) {
25750 cimg_plugin_greycstoration_count;
25751 P = get_crop(x - psize0,y - psize0,z - psize0,x + psize1,y + psize1,z + psize1,true);
25752 const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2;
25753 float sum_weights = 0;
25754 cimg_for_inXYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) {
25755 (Q = get_crop(p - psize0,q - psize0,r - psize0,p + psize1,q + psize1,r + psize1,true))-=P;
25756 const float
25757 dx = (float)x - p, dy = (float)y - q, dz = (float)z - r,
25758 distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),
25759 weight = (float)cimg_std::exp(-distance2);
25760 sum_weights+=weight;
25761 cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k);
25762 }
25763 if (sum_weights>0) cimg_forV(*this,k) res(x,y,z,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,z,k) = (Tfloat)((*this)(x,y,z,k));
25764 }
25765 }
25766 } else switch (patch_size) { // 2D version
25767 case 2 :
25768 if (fast_approx) { _cimg_blur_patch2d(2,_cimg_blur_patch_fastfunc); }
25769 else { _cimg_blur_patch2d(2,_cimg_blur_patch_slowfunc); }
25770 break;
25771 case 3 :
25772 if (fast_approx) { _cimg_blur_patch2d(3,_cimg_blur_patch_fastfunc); }
25773 else { _cimg_blur_patch2d(3,_cimg_blur_patch_slowfunc); }
25774 break;
25775 case 4 :
25776 if (fast_approx) { _cimg_blur_patch2d(4,_cimg_blur_patch_fastfunc); }
25777 else { _cimg_blur_patch2d(4,_cimg_blur_patch_slowfunc); }
25778 break;
25779 case 5 :
25780 if (fast_approx) { _cimg_blur_patch2d(5,_cimg_blur_patch_fastfunc); }
25781 else { _cimg_blur_patch2d(5,_cimg_blur_patch_slowfunc); }
25782 break;
25783 case 6 :
25784 if (fast_approx) { _cimg_blur_patch2d(6,_cimg_blur_patch_fastfunc); }
25785 else { _cimg_blur_patch2d(6,_cimg_blur_patch_slowfunc); }
25786 break;
25787 case 7 :
25788 if (fast_approx) { _cimg_blur_patch2d(7,_cimg_blur_patch_fastfunc); }
25789 else { _cimg_blur_patch2d(7,_cimg_blur_patch_slowfunc); }
25790 break;
25791 case 8 :
25792 if (fast_approx) { _cimg_blur_patch2d(8,_cimg_blur_patch_fastfunc); }
25793 else { _cimg_blur_patch2d(8,_cimg_blur_patch_slowfunc); }
25794 break;
25795 case 9 :
25796 if (fast_approx) { _cimg_blur_patch2d(9,_cimg_blur_patch_fastfunc); }
25797 else { _cimg_blur_patch2d(9,_cimg_blur_patch_slowfunc); }
25798 break;
25799 default : {
25800 const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
25801 cimg_forXY(*this,x,y) {
25802 cimg_plugin_greycstoration_count;
25803 P = get_crop(x - psize0,y - psize0,x + psize1,y + psize1,true);
25804 const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2;
25805 float sum_weights = 0;
25806 cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
25807 (Q = get_crop(p - psize0,q - psize0,p + psize1,q + psize1,true))-=P;
25808 const float
25809 dx = (float)x - p, dy = (float)y - q,
25810 distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),
25811 weight = (float)cimg_std::exp(-distance2);
25812 sum_weights+=weight;
25813 cimg_forV(*this,k) res(x,y,0,k)+=weight*(*this)(p,q,0,k);
25814 }
25815 if (sum_weights>0) cimg_forV(*this,k) res(x,y,0,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,0,k) = (Tfloat)((*this)(x,y,0,k));
25816 }
25817 }
25818 }
25819 return res.transfer_to(*this);
25820 }
25822 CImg<T> get_blur_patch(const unsigned int patch_size, const float sigma_p, const float sigma_s=10,
25823 const unsigned int lookup_size=4, const bool fast_approx=true) const {
25824 return (+*this).blur_patch(patch_size,sigma_p,sigma_s,lookup_size,fast_approx);
25825 }
25827 //! Compute the Fast Fourier Transform of an image (along a specified axis).
25828 CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
25829 return CImgList<Tfloat>(*this).FFT(axis,invert);
25830 }
25832 //! Compute the Fast Fourier Transform on an image.
25833 CImgList<Tfloat> get_FFT(const bool invert=false) const {
25834 return CImgList<Tfloat>(*this).FFT(invert);
25835 }
25837 //! Apply a median filter.
25838 CImg<T>& blur_median(const unsigned int n) {
25839 return get_blur_median(n).transfer_to(*this);
25840 }
25842 CImg<T> get_blur_median(const unsigned int n) {
25843 CImg<T> res(width,height,depth,dim);
25844 if (!n || n==1) return *this;
25845 const int hl=n/2, hr=hl-1+n%2;
25846 if (res.depth!=1) { // 3D median filter
25847 CImg<T> vois;
25848 cimg_forXYZV(*this,x,y,z,k) {
25849 const int
25850 x0 = x - hl, y0 = y - hl, z0 = z-hl, x1 = x + hr, y1 = y + hr, z1 = z+hr,
25851 nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,
25852 nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1, nz1 = z1>=dimz()?dimz()-1:z1;
25853 vois = get_crop(nx0,ny0,nz0,k,nx1,ny1,nz1,k);
25854 res(x,y,z,k) = vois.median();
25855 }
25856 } else {
25857 #define _cimg_median_sort(a,b) if ((a)>(b)) cimg::swap(a,b)
25858 if (res.height!=1) switch (n) { // 2D median filter
25859 case 3 : {
25860 T I[9] = { 0 };
25861 CImg_3x3(J,T);
25862 cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
25863 cimg_std::memcpy(J,I,9*sizeof(T));
25864 _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
25865 _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jpn, Jcn);
25866 _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
25867 _cimg_median_sort(Jpp, Jpc); _cimg_median_sort(Jnc, Jnn); _cimg_median_sort(Jcc, Jcn);
25868 _cimg_median_sort(Jpc, Jpn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jnp, Jnc);
25869 _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcc, Jnp); _cimg_median_sort(Jpn, Jcc);
25870 _cimg_median_sort(Jcc, Jnp);
25871 res(x,y,0,k) = Jcc;
25872 }
25873 } break;
25874 case 5 : {
25875 T I[25] = { 0 };
25876 CImg_5x5(J,T);
25877 cimg_forV(*this,k) cimg_for5x5(*this,x,y,0,k,I) {
25878 cimg_std::memcpy(J,I,25*sizeof(T));
25879 _cimg_median_sort(Jbb, Jpb); _cimg_median_sort(Jnb, Jab); _cimg_median_sort(Jcb, Jab); _cimg_median_sort(Jcb, Jnb);
25880 _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbp, Jcp); _cimg_median_sort(Jbp, Jpp); _cimg_median_sort(Jap, Jbc);
25881 _cimg_median_sort(Jnp, Jbc); _cimg_median_sort(Jnp, Jap); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jpc, Jnc);
25882 _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jbn, Jpn); _cimg_median_sort(Jac, Jpn); _cimg_median_sort(Jac, Jbn);
25883 _cimg_median_sort(Jnn, Jan); _cimg_median_sort(Jcn, Jan); _cimg_median_sort(Jcn, Jnn); _cimg_median_sort(Jpa, Jca);
25884 _cimg_median_sort(Jba, Jca); _cimg_median_sort(Jba, Jpa); _cimg_median_sort(Jna, Jaa); _cimg_median_sort(Jcb, Jbp);
25885 _cimg_median_sort(Jnb, Jpp); _cimg_median_sort(Jbb, Jpp); _cimg_median_sort(Jbb, Jnb); _cimg_median_sort(Jab, Jcp);
25886 _cimg_median_sort(Jpb, Jcp); _cimg_median_sort(Jpb, Jab); _cimg_median_sort(Jpc, Jac); _cimg_median_sort(Jnp, Jac);
25887 _cimg_median_sort(Jnp, Jpc); _cimg_median_sort(Jcc, Jbn); _cimg_median_sort(Jap, Jbn); _cimg_median_sort(Jap, Jcc);
25888 _cimg_median_sort(Jnc, Jpn); _cimg_median_sort(Jbc, Jpn); _cimg_median_sort(Jbc, Jnc); _cimg_median_sort(Jba, Jna);
25889 _cimg_median_sort(Jcn, Jna); _cimg_median_sort(Jcn, Jba); _cimg_median_sort(Jpa, Jaa); _cimg_median_sort(Jnn, Jaa);
25890 _cimg_median_sort(Jnn, Jpa); _cimg_median_sort(Jan, Jca); _cimg_median_sort(Jnp, Jcn); _cimg_median_sort(Jap, Jnn);
25891 _cimg_median_sort(Jbb, Jnn); _cimg_median_sort(Jbb, Jap); _cimg_median_sort(Jbc, Jan); _cimg_median_sort(Jpb, Jan);
25892 _cimg_median_sort(Jpb, Jbc); _cimg_median_sort(Jpc, Jba); _cimg_median_sort(Jcb, Jba); _cimg_median_sort(Jcb, Jpc);
25893 _cimg_median_sort(Jcc, Jpa); _cimg_median_sort(Jnb, Jpa); _cimg_median_sort(Jnb, Jcc); _cimg_median_sort(Jnc, Jca);
25894 _cimg_median_sort(Jab, Jca); _cimg_median_sort(Jab, Jnc); _cimg_median_sort(Jac, Jna); _cimg_median_sort(Jbp, Jna);
25895 _cimg_median_sort(Jbp, Jac); _cimg_median_sort(Jbn, Jaa); _cimg_median_sort(Jpp, Jaa); _cimg_median_sort(Jpp, Jbn);
25896 _cimg_median_sort(Jcp, Jpn); _cimg_median_sort(Jcp, Jan); _cimg_median_sort(Jnc, Jpa); _cimg_median_sort(Jbn, Jna);
25897 _cimg_median_sort(Jcp, Jnc); _cimg_median_sort(Jcp, Jbn); _cimg_median_sort(Jpb, Jap); _cimg_median_sort(Jnb, Jpc);
25898 _cimg_median_sort(Jbp, Jcn); _cimg_median_sort(Jpc, Jcn); _cimg_median_sort(Jap, Jcn); _cimg_median_sort(Jab, Jbc);
25899 _cimg_median_sort(Jpp, Jcc); _cimg_median_sort(Jcp, Jac); _cimg_median_sort(Jab, Jpp); _cimg_median_sort(Jab, Jcp);
25900 _cimg_median_sort(Jcc, Jac); _cimg_median_sort(Jbc, Jac); _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbc, Jcc);
25901 _cimg_median_sort(Jpp, Jbc); _cimg_median_sort(Jpp, Jcn); _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcp, Jcn);
25902 _cimg_median_sort(Jcp, Jbc); _cimg_median_sort(Jcc, Jnn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jbc, Jnn);
25903 _cimg_median_sort(Jcc, Jba); _cimg_median_sort(Jbc, Jba); _cimg_median_sort(Jbc, Jcc);
25904 res(x,y,0,k) = Jcc;
25905 }
25906 } break;
25907 default : {
25908 CImg<T> vois;
25909 cimg_forXYV(*this,x,y,k) {
25910 const int
25911 x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,
25912 nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,
25913 nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1;
25914 vois = get_crop(nx0,ny0,0,k,nx1,ny1,0,k);
25915 res(x,y,0,k) = vois.median();
25916 }
25917 }
25918 } else switch (n) { // 1D median filter
25919 case 2 : {
25920 T I[4] = { 0 };
25921 cimg_forV(*this,k) cimg_for2x2(*this,x,y,0,k,I) res(x,0,0,k) = (T)(0.5f*(I[0]+I[1]));
25922 } break;
25923 case 3 : {
25924 T I[9] = { 0 };
25925 cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
25926 res(x,0,0,k) = I[3]<I[4]?
25927 (I[4]<I[5]?I[4]:
25928 (I[3]<I[5]?I[5]:I[3])):
25929 (I[3]<I[5]?I[3]:
25930 (I[4]<I[5]?I[5]:I[4]));
25931 }
25932 } break;
25933 default : {
25934 CImg<T> vois;
25935 cimg_forXV(*this,x,k) {
25936 const int
25937 x0 = x - hl, x1 = x + hr,
25938 nx0 = x0<0?0:x0, nx1 = x1>=dimx()?dimx()-1:x1;
25939 vois = get_crop(nx0,0,0,k,nx1,0,0,k);
25940 res(x,0,0,k) = vois.median();
25941 }
25942 }
25943 }
25944 }
25945 return res;
25946 }
25948 //! Sharpen image using anisotropic shock filters or inverse diffusion.
25949 CImg<T>& sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) {
25950 if (is_empty()) return *this;
25951 T valm, valM = maxmin(valm);
25952 const bool threed = (depth>1);
25953 const float nedge = 0.5f*edge;
25954 CImg<Tfloat> val, vec, veloc(width,height,depth,dim);
25956 if (threed) {
25957 CImg_3x3x3(I,T);
25958 if (sharpen_type) { // 3D Shock filter.
25959 CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
25960 if (sigma>0) G.blur(sigma);
25962 cimg_forXYZ(G,x,y,z) {
25963 G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
25964 G(x,y,z,0) = vec(0,0);
25965 G(x,y,z,1) = vec(0,1);
25966 G(x,y,z,2) = vec(0,2);
25967 G(x,y,z,3) = 1 - (Tfloat)cimg_std::pow(1+val[0]+val[1]+val[2],-(Tfloat)nedge);
25968 }
25969 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
25970 const Tfloat
25971 u = G(x,y,z,0),
25972 v = G(x,y,z,1),
25973 w = G(x,y,z,2),
25974 amp = G(x,y,z,3),
25975 ixx = (Tfloat)Incc + Ipcc - 2*Iccc,
25976 ixy = 0.25f*((Tfloat)Innc + Ippc - Inpc - Ipnc),
25977 ixz = 0.25f*((Tfloat)Incn + Ipcp - Incp - Ipcn),
25978 iyy = (Tfloat)Icnc + Icpc - 2*Iccc,
25979 iyz = 0.25f*((Tfloat)Icnn + Icpp - Icnp - Icpn),
25980 izz = (Tfloat)Iccn + Iccp - 2*Iccc,
25981 ixf = (Tfloat)Incc - Iccc,
25982 ixb = (Tfloat)Iccc - Ipcc,
25983 iyf = (Tfloat)Icnc - Iccc,
25984 iyb = (Tfloat)Iccc - Icpc,
25985 izf = (Tfloat)Iccn - Iccc,
25986 izb = (Tfloat)Iccc - Iccp,
25987 itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz,
25988 it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb);
25989 veloc(x,y,z,k) = -amp*cimg::sign(itt)*cimg::abs(it);
25990 }
25991 } else cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) veloc(x,y,z,k) = -(Tfloat)Ipcc-Incc-Icpc-Icnc-Iccp-Iccn+6*Iccc; // 3D Inverse diffusion.
25992 } else {
25993 CImg_3x3(I,T);
25994 if (sharpen_type) { // 2D Shock filter.
25995 CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
25996 if (sigma>0) G.blur(sigma);
25997 cimg_forXY(G,x,y) {
25998 G.get_tensor_at(x,y).symmetric_eigen(val,vec);
25999 G(x,y,0) = vec(0,0);
26000 G(x,y,1) = vec(0,1);
26001 G(x,y,2) = 1 - (Tfloat)cimg_std::pow(1+val[0]+val[1],-(Tfloat)nedge);
26002 }
26003 cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
26004 const Tfloat
26005 u = G(x,y,0),
26006 v = G(x,y,1),
26007 amp = G(x,y,2),
26008 ixx = (Tfloat)Inc + Ipc - 2*Icc,
26009 ixy = 0.25f*((Tfloat)Inn + Ipp - Inp - Ipn),
26010 iyy = (Tfloat)Icn + Icp - 2*Icc,
26011 ixf = (Tfloat)Inc - Icc,
26012 ixb = (Tfloat)Icc - Ipc,
26013 iyf = (Tfloat)Icn - Icc,
26014 iyb = (Tfloat)Icc - Icp,
26015 itt = u*u*ixx + v*v*iyy + 2*u*v*ixy,
26016 it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb);
26017 veloc(x,y,k) = -amp*cimg::sign(itt)*cimg::abs(it);
26018 }
26019 } else cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) veloc(x,y,k) = -(Tfloat)Ipc-Inc-Icp-Icn+4*Icc; // 3D Inverse diffusion.
26020 }
26021 float m, M = (float)veloc.maxmin(m);
26022 const float vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
26023 if (vmax!=0) { veloc*=amplitude/vmax; (*this)+=veloc; }
26024 return cut(valm,valM);
26025 }
26027 CImg<T> get_sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) const {
26028 return (+*this).sharpen(amplitude,sharpen_type,edge,alpha,sigma);
26029 }
26031 //! Compute the Haar multiscale wavelet transform (monodimensional version).
26032 /**
26033 \param axis Axis considered for the transform.
26034 \param invert Set inverse of direct transform.
26035 \param nb_scales Number of scales used for the transform.
26036 **/
26037 CImg<T>& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) {
26038 return get_haar(axis,invert,nb_scales).transfer_to(*this);
26039 }
26041 CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const {
26042 if (is_empty() || !nb_scales) return *this;
26043 CImg<Tfloat> res;
26045 if (nb_scales==1) {
26046 switch (cimg::uncase(axis)) { // Single scale transform
26047 case 'x' : {
26048 const unsigned int w = width/2;
26049 if (w) {
26050 if (w%2)
26051 throw CImgInstanceException("CImg<%s>::haar() : Sub-image width = %u is not even at a particular scale (=%u).",
26052 pixel_type(),w);
26053 res.assign(width,height,depth,dim);
26054 if (invert) cimg_forYZV(*this,y,z,v) { // Inverse transform along X
26055 for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
26056 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(xw,y,z,v);
26057 res(x2++,y,z,v) = val0 - val1;
26058 res(x2++,y,z,v) = val0 + val1;
26059 }
26060 } else cimg_forYZV(*this,y,z,v) { // Direct transform along X
26061 for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
26062 const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,v), val1 = (Tfloat)(*this)(x2++,y,z,v);
26063 res(x,y,z,v) = (val0 + val1)/2;
26064 res(xw,y,z,v) = (val1 - val0)/2;
26065 }
26066 }
26067 } else return *this;
26068 } break;
26069 case 'y' : {
26070 const unsigned int h = height/2;
26071 if (h) {
26072 if (h%2)
26073 throw CImgInstanceException("CImg<%s>::haar() : Sub-image height = %u is not even at a particular scale.",
26074 pixel_type(),h);
26075 res.assign(width,height,depth,dim);
26076 if (invert) cimg_forXZV(*this,x,z,v) { // Inverse transform along Y
26077 for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) {
26078 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,yh,z,v);
26079 res(x,y2++,z,v) = val0 - val1;
26080 res(x,y2++,z,v) = val0 + val1;
26081 }
26082 } else cimg_forXZV(*this,x,z,v) {
26083 for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) { // Direct transform along Y
26084 const Tfloat val0 = (Tfloat)(*this)(x,y2++,z,v), val1 = (Tfloat)(*this)(x,y2++,z,v);
26085 res(x,y,z,v) = (val0 + val1)/2;
26086 res(x,yh,z,v) = (val1 - val0)/2;
26087 }
26088 }
26089 } else return *this;
26090 } break;
26091 case 'z' : {
26092 const unsigned int d = depth/2;
26093 if (d) {
26094 if (d%2)
26095 throw CImgInstanceException("CImg<%s>::haar() : Sub-image depth = %u is not even at a particular scale.",
26096 pixel_type(),d);
26097 res.assign(width,height,depth,dim);
26098 if (invert) cimg_forXYV(*this,x,y,v) { // Inverse transform along Z
26099 for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) {
26100 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,y,zd,v);
26101 res(x,y,z2++,v) = val0 - val1;
26102 res(x,y,z2++,v) = val0 + val1;
26103 }
26104 } else cimg_forXYV(*this,x,y,v) {
26105 for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) { // Direct transform along Z
26106 const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,v), val1 = (Tfloat)(*this)(x,y,z2++,v);
26107 res(x,y,z,v) = (val0 + val1)/2;
26108 res(x,y,zd,v) = (val1 - val0)/2;
26109 }
26110 }
26111 } else return *this;
26112 } break;
26113 default :
26114 throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
26115 pixel_type(),axis);
26116 }
26117 } else { // Multi-scale version
26118 if (invert) {
26119 res.assign(*this);
26120 switch (cimg::uncase(axis)) {
26121 case 'x' : {
26122 unsigned int w = width;
26123 for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
26124 for (w=w?w:1; w<=width; w*=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',true,1));
26125 } break;
26126 case 'y' : {
26127 unsigned int h = width;
26128 for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
26129 for (h=h?h:1; h<=height; h*=2) res.draw_image(res.get_crop(0,0,width-1,h-1).get_haar('y',true,1));
26130 } break;
26131 case 'z' : {
26132 unsigned int d = depth;
26133 for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
26134 for (d=d?d:1; d<=depth; d*=2) res.draw_image(res.get_crop(0,0,0,width-1,height-1,d-1).get_haar('z',true,1));
26135 } break;
26136 default :
26137 throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
26138 pixel_type(),axis);
26139 }
26140 } else { // Direct transform
26141 res = get_haar(axis,false,1);
26142 switch (cimg::uncase(axis)) {
26143 case 'x' : {
26144 for (unsigned int s=1, w=width/2; w && s<nb_scales; ++s, w/=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',false,1));
26145 } break;
26146 case 'y' : {
26147 for (unsigned int s=1, h=height/2; h && s<nb_scales; ++s, h/=2) res.draw_image(res.get_crop(0,0,width-1,h-1).get_haar('y',false,1));
26148 } break;
26149 case 'z' : {
26150 for (unsigned int s=1, d=depth/2; d && s<nb_scales; ++s, d/=2) res.draw_image(res.get_crop(0,0,0,width-1,height-1,d-1).get_haar('z',false,1));
26151 } break;
26152 default :
26153 throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
26154 pixel_type(),axis);
26155 }
26156 }
26157 }
26158 return res;
26159 }
26161 //! Compute the Haar multiscale wavelet transform.
26162 /**
26163 \param invert Set inverse of direct transform.
26164 \param nb_scales Number of scales used for the transform.
26165 **/
26166 CImg<T>& haar(const bool invert=false, const unsigned int nb_scales=1) {
26167 return get_haar(invert,nb_scales).transfer_to(*this);
26168 }
26170 CImg<Tfloat> get_haar(const bool invert=false, const unsigned int nb_scales=1) const {
26171 CImg<Tfloat> res;
26173 if (nb_scales==1) { // Single scale transform
26174 if (width>1) get_haar('x',invert,1).transfer_to(res);
26175 if (height>1) { if (res) res.get_haar('y',invert,1).transfer_to(res); else get_haar('y',invert,1).transfer_to(res); }
26176 if (depth>1) { if (res) res.get_haar('z',invert,1).transfer_to(res); else get_haar('z',invert,1).transfer_to(res); }
26177 if (res) return res;
26178 } else { // Multi-scale transform
26179 if (invert) { // Inverse transform
26180 res.assign(*this);
26181 if (width>1) {
26182 if (height>1) {
26183 if (depth>1) {
26184 unsigned int w = width, h = height, d = depth; for (unsigned int s=1; w && h && d && s<nb_scales; ++s) { w/=2; h/=2; d/=2; }
26185 for (w=w?w:1, h=h?h:1, d=d?d:1; w<=width && h<=height && d<=depth; w*=2, h*=2, d*=2)
26186 res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).get_haar(true,1));
26187 } else {
26188 unsigned int w = width, h = height; for (unsigned int s=1; w && h && s<nb_scales; ++s) { w/=2; h/=2; }
26189 for (w=w?w:1, h=h?h:1; w<=width && h<=height; w*=2, h*=2)
26190 res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).get_haar(true,1));
26191 }
26192 } else {
26193 if (depth>1) {
26194 unsigned int w = width, d = depth; for (unsigned int s=1; w && d && s<nb_scales; ++s) { w/=2; d/=2; }
26195 for (w=w?w:1, d=d?d:1; w<=width && d<=depth; w*=2, d*=2)
26196 res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).get_haar(true,1));
26197 } else {
26198 unsigned int w = width; for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
26199 for (w=w?w:1; w<=width; w*=2)
26200 res.draw_image(res.get_crop(0,0,0,w-1,0,0).get_haar(true,1));
26201 }
26202 }
26203 } else {
26204 if (height>1) {
26205 if (depth>1) {
26206 unsigned int h = height, d = depth; for (unsigned int s=1; h && d && s<nb_scales; ++s) { h/=2; d/=2; }
26207 for (h=h?h:1, d=d?d:1; h<=height && d<=depth; h*=2, d*=2)
26208 res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).get_haar(true,1));
26209 } else {
26210 unsigned int h = height; for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
26211 for (h=h?h:1; h<=height; h*=2)
26212 res.draw_image(res.get_crop(0,0,0,0,h-1,0).get_haar(true,1));
26213 }
26214 } else {
26215 if (depth>1) {
26216 unsigned int d = depth; for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
26217 for (d=d?d:1; d<=depth; d*=2)
26218 res.draw_image(res.get_crop(0,0,0,0,0,d-1).get_haar(true,1));
26219 } else return *this;
26220 }
26221 }
26222 } else { // Direct transform
26223 res = get_haar(false,1);
26224 if (width>1) {
26225 if (height>1) {
26226 if (depth>1) for (unsigned int s=1, w=width/2, h=height/2, d=depth/2; w && h && d && s<nb_scales; ++s, w/=2, h/=2, d/=2)
26227 res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).haar(false,1));
26228 else for (unsigned int s=1, w=width/2, h=height/2; w && h && s<nb_scales; ++s, w/=2, h/=2)
26229 res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).haar(false,1));
26230 } else {
26231 if (depth>1) for (unsigned int s=1, w=width/2, d=depth/2; w && d && s<nb_scales; ++s, w/=2, d/=2)
26232 res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).haar(false,1));
26233 else for (unsigned int s=1, w=width/2; w && s<nb_scales; ++s, w/=2)
26234 res.draw_image(res.get_crop(0,0,0,w-1,0,0).haar(false,1));
26235 }
26236 } else {
26237 if (height>1) {
26238 if (depth>1) for (unsigned int s=1, h=height/2, d=depth/2; h && d && s<nb_scales; ++s, h/=2, d/=2)
26239 res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).haar(false,1));
26240 else for (unsigned int s=1, h=height/2; h && s<nb_scales; ++s, h/=2)
26241 res.draw_image(res.get_crop(0,0,0,0,h-1,0).haar(false,1));
26242 } else {
26243 if (depth>1) for (unsigned int s=1, d=depth/2; d && s<nb_scales; ++s, d/=2)
26244 res.draw_image(res.get_crop(0,0,0,0,0,d-1).haar(false,1));
26245 else return *this;
26246 }
26247 }
26248 }
26249 return res;
26250 }
26251 return *this;
26252 }
26254 //! Estimate a displacement field between instance image and given target image.
26255 CImg<T>& displacement_field(const CImg<T>& target, const float smooth=0.1f, const float precision=0.1f,
26256 const unsigned int nb_scales=0, const unsigned int itermax=10000) {
26257 return get_displacement_field(target,smooth,precision,nb_scales,itermax).transfer_to(*this);
26258 }
26260 CImg<Tfloat> get_displacement_field(const CImg<T>& target,
26261 const float smoothness=0.1f, const float precision=0.1f,
26262 const unsigned int nb_scales=0, const unsigned int itermax=10000) const {
26263 if (is_empty() || !target) return *this;
26264 if (!is_sameXYZV(target))
26265 throw CImgArgumentException("CImg<%s>::displacement_field() : Instance image (%u,%u,%u,%u,%p) and target image (%u,%u,%u,%u,%p) "
26266 "have different size.",
26267 pixel_type(),width,height,depth,dim,data,
26268 target.width,target.height,target.depth,target.dim,target.data);
26269 if (smoothness<0)
26270 throw CImgArgumentException("CImg<%s>::displacement_field() : Smoothness parameter %g is negative.",
26271 pixel_type(),smoothness);
26272 if (precision<0)
26273 throw CImgArgumentException("CImg<%s>::displacement_field() : Precision parameter %g is negative.",
26274 pixel_type(),precision);
26276 const unsigned int nscales = nb_scales>0?nb_scales:(unsigned int)(2*cimg_std::log((double)(cimg::max(width,height,depth))));
26277 Tfloat m1, M1 = (Tfloat)maxmin(m1), m2, M2 = (Tfloat)target.maxmin(m2);
26278 const Tfloat factor = cimg::max(cimg::abs(m1),cimg::abs(M1),cimg::abs(m2),cimg::abs(M2));
26279 CImg<Tfloat> U0;
26280 const bool threed = (depth>1);
26282 // Begin multi-scale motion estimation
26283 for (int scale = (int)nscales-1; scale>=0; --scale) {
26284 const float sfactor = (float)cimg_std::pow(1.5f,(float)scale), sprecision = (float)(precision/cimg_std::pow(2.25,1+scale));
26285 const int
26286 sw = (int)(width/sfactor), sh = (int)(height/sfactor), sd = (int)(depth/sfactor),
26287 swidth = sw?sw:1, sheight = sh?sh:1, sdepth = sd?sd:1;
26288 CImg<Tfloat>
26289 I1 = get_resize(swidth,sheight,sdepth,-100,2),
26290 I2 = target.get_resize(swidth,sheight,sdepth,-100,2);
26291 I1/=factor; I2/=factor;
26292 CImg<Tfloat> U;
26293 if (U0) U = (U0*=1.5f).get_resize(I1.dimx(),I1.dimy(),I1.dimz(),-100,3);
26294 else U.assign(I1.dimx(),I1.dimy(),I1.dimz(),threed?3:2,0);
26296 // Begin single-scale motion estimation
26297 CImg<Tfloat> veloc(U);
26298 float dt = 2, Energy = cimg::type<float>::max();
26299 const CImgList<Tfloat> dI = I2.get_gradient();
26300 for (unsigned int iter=0; iter<itermax; iter++) {
26301 veloc.fill(0);
26302 float nEnergy = 0;
26303 if (threed) {
26304 cimg_for3XYZ(U,x,y,z) {
26305 const float X = (float)(x + U(x,y,z,0)), Y = (float)(y + U(x,y,z,1)), Z = (float)(z + U(x,y,z,2));
26306 cimg_forV(U,k) {
26307 const Tfloat
26308 Ux = 0.5f*(U(_n1x,y,z,k) - U(_p1x,y,z,k)),
26309 Uy = 0.5f*(U(x,_n1y,z,k) - U(x,_p1y,z,k)),
26310 Uz = 0.5f*(U(x,y,_n1z,k) - U(x,y,_p1z,k)),
26311 Uxx = U(_n1x,y,z,k) + U(_p1x,y,z,k) - 2*U(x,y,z,k),
26312 Uyy = U(x,_n1y,z,k) + U(x,_p1y,z,k) - 2*U(x,y,z,k),
26313 Uzz = U(x,y,_n1z,k) + U(x,y,_n1z,k) - 2*U(x,y,z,k);
26314 nEnergy += (float)(smoothness*(Ux*Ux + Uy*Uy + Uz*Uz));
26315 Tfloat deltaIgrad = 0;
26316 cimg_forV(I1,i) {
26317 const Tfloat deltaIi = (float)(I2._linear_atXYZ(X,Y,Z,i) - I1(x,y,z,i));
26318 nEnergy += (float)(deltaIi*deltaIi/2);
26319 deltaIgrad+=-deltaIi*dI[k]._linear_atXYZ(X,Y,Z,i);
26320 }
26321 veloc(x,y,z,k) = deltaIgrad + smoothness*(Uxx + Uyy + Uzz);
26322 }
26323 }
26324 } else {
26325 cimg_for3XY(U,x,y) {
26326 const float X = (float)(x + U(x,y,0)), Y = (float)(y + U(x,y,1));
26327 cimg_forV(U,k) {
26328 const Tfloat
26329 Ux = 0.5f*(U(_n1x,y,k) - U(_p1x,y,k)),
26330 Uy = 0.5f*(U(x,_n1y,k) - U(x,_p1y,k)),
26331 Uxx = U(_n1x,y,k) + U(_p1x,y,k) - 2*U(x,y,k),
26332 Uyy = U(x,_n1y,k) + U(x,_p1y,k) - 2*U(x,y,k);
26333 nEnergy += (float)(smoothness*(Ux*Ux + Uy*Uy));
26334 Tfloat deltaIgrad = 0;
26335 cimg_forV(I1,i) {
26336 const Tfloat deltaIi = (float)(I2._linear_atXY(X,Y,i) - I1(x,y,i));
26337 nEnergy += (float)(deltaIi*deltaIi/2);
26338 deltaIgrad+=-deltaIi*dI[k]._linear_atXY(X,Y,i);
26339 }
26340 veloc(x,y,k) = deltaIgrad + smoothness*(Uxx + Uyy);
26341 }
26342 }
26343 }
26344 const Tfloat vmax = cimg::max(cimg::abs(veloc.min()), cimg::abs(veloc.max()));
26345 U+=(veloc*=dt/vmax);
26346 if (cimg::abs(nEnergy-Energy)<sprecision) break;
26347 if (nEnergy<Energy) dt*=0.5f;
26348 Energy = nEnergy;
26349 }
26350 U.transfer_to(U0);
26351 }
26352 return U0;
26353 }
26355 //@}
26356 //-----------------------------
26357 //
26358 //! \name Matrix and Vectors
26359 //@{
26360 //-----------------------------
26362 //! Return a vector with specified coefficients.
26363 static CImg<T> vector(const T& a0) {
26364 static CImg<T> r(1,1); r[0] = a0;
26365 return r;
26366 }
26368 //! Return a vector with specified coefficients.
26369 static CImg<T> vector(const T& a0, const T& a1) {
26370 static CImg<T> r(1,2); T *ptr = r.data;
26371 *(ptr++) = a0; *(ptr++) = a1;
26372 return r;
26373 }
26375 //! Return a vector with specified coefficients.
26376 static CImg<T> vector(const T& a0, const T& a1, const T& a2) {
26377 static CImg<T> r(1,3); T *ptr = r.data;
26378 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
26379 return r;
26380 }
26382 //! Return a vector with specified coefficients.
26383 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3) {
26384 static CImg<T> r(1,4); T *ptr = r.data;
26385 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26386 return r;
26387 }
26389 //! Return a vector with specified coefficients.
26390 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
26391 static CImg<T> r(1,5); T *ptr = r.data;
26392 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
26393 return r;
26394 }
26396 //! Return a vector with specified coefficients.
26397 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {
26398 static CImg<T> r(1,6); T *ptr = r.data;
26399 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
26400 return r;
26401 }
26403 //! Return a vector with specified coefficients.
26404 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26405 const T& a4, const T& a5, const T& a6) {
26406 static CImg<T> r(1,7); T *ptr = r.data;
26407 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26408 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6;
26409 return r;
26410 }
26412 //! Return a vector with specified coefficients.
26413 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26414 const T& a4, const T& a5, const T& a6, const T& a7) {
26415 static CImg<T> r(1,8); T *ptr = r.data;
26416 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26417 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26418 return r;
26419 }
26421 //! Return a vector with specified coefficients.
26422 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26423 const T& a4, const T& a5, const T& a6, const T& a7,
26424 const T& a8) {
26425 static CImg<T> r(1,9); T *ptr = r.data;
26426 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26427 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26428 *(ptr++) = a8;
26429 return r;
26430 }
26432 //! Return a vector with specified coefficients.
26433 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26434 const T& a4, const T& a5, const T& a6, const T& a7,
26435 const T& a8, const T& a9) {
26436 static CImg<T> r(1,10); T *ptr = r.data;
26437 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26438 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26439 *(ptr++) = a8; *(ptr++) = a9;
26440 return r;
26441 }
26443 //! Return a vector with specified coefficients.
26444 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26445 const T& a4, const T& a5, const T& a6, const T& a7,
26446 const T& a8, const T& a9, const T& a10) {
26447 static CImg<T> r(1,11); T *ptr = r.data;
26448 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26449 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26450 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10;
26451 return r;
26452 }
26454 //! Return a vector with specified coefficients.
26455 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26456 const T& a4, const T& a5, const T& a6, const T& a7,
26457 const T& a8, const T& a9, const T& a10, const T& a11) {
26458 static CImg<T> r(1,12); T *ptr = r.data;
26459 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26460 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26461 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26462 return r;
26463 }
26465 //! Return a vector with specified coefficients.
26466 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26467 const T& a4, const T& a5, const T& a6, const T& a7,
26468 const T& a8, const T& a9, const T& a10, const T& a11,
26469 const T& a12) {
26470 static CImg<T> r(1,13); T *ptr = r.data;
26471 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26472 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26473 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26474 *(ptr++) = a12;
26475 return r;
26476 }
26478 //! Return a vector with specified coefficients.
26479 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26480 const T& a4, const T& a5, const T& a6, const T& a7,
26481 const T& a8, const T& a9, const T& a10, const T& a11,
26482 const T& a12, const T& a13) {
26483 static CImg<T> r(1,14); T *ptr = r.data;
26484 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26485 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26486 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26487 *(ptr++) = a12; *(ptr++) = a13;
26488 return r;
26489 }
26491 //! Return a vector with specified coefficients.
26492 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26493 const T& a4, const T& a5, const T& a6, const T& a7,
26494 const T& a8, const T& a9, const T& a10, const T& a11,
26495 const T& a12, const T& a13, const T& a14) {
26496 static CImg<T> r(1,15); T *ptr = r.data;
26497 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26498 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26499 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26500 *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
26501 return r;
26502 }
26504 //! Return a vector with specified coefficients.
26505 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
26506 const T& a4, const T& a5, const T& a6, const T& a7,
26507 const T& a8, const T& a9, const T& a10, const T& a11,
26508 const T& a12, const T& a13, const T& a14, const T& a15) {
26509 static CImg<T> r(1,16); T *ptr = r.data;
26510 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26511 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26512 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26513 *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
26514 return r;
26515 }
26517 //! Return a 1x1 square matrix with specified coefficients.
26518 static CImg<T> matrix(const T& a0) {
26519 return vector(a0);
26520 }
26522 //! Return a 2x2 square matrix with specified coefficients.
26523 static CImg<T> matrix(const T& a0, const T& a1,
26524 const T& a2, const T& a3) {
26525 static CImg<T> r(2,2); T *ptr = r.data;
26526 *(ptr++) = a0; *(ptr++) = a1;
26527 *(ptr++) = a2; *(ptr++) = a3;
26528 return r;
26529 }
26531 //! Return a 3x3 square matrix with specified coefficients.
26532 static CImg<T> matrix(const T& a0, const T& a1, const T& a2,
26533 const T& a3, const T& a4, const T& a5,
26534 const T& a6, const T& a7, const T& a8) {
26535 static CImg<T> r(3,3); T *ptr = r.data;
26536 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
26537 *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
26538 *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8;
26539 return r;
26540 }
26542 //! Return a 4x4 square matrix with specified coefficients.
26543 static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3,
26544 const T& a4, const T& a5, const T& a6, const T& a7,
26545 const T& a8, const T& a9, const T& a10, const T& a11,
26546 const T& a12, const T& a13, const T& a14, const T& a15) {
26547 static CImg<T> r(4,4); T *ptr = r.data;
26548 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
26549 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
26550 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
26551 *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
26552 return r;
26553 }
26555 //! Return a 5x5 square matrix with specified coefficients.
26556 static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4,
26557 const T& a5, const T& a6, const T& a7, const T& a8, const T& a9,
26558 const T& a10, const T& a11, const T& a12, const T& a13, const T& a14,
26559 const T& a15, const T& a16, const T& a17, const T& a18, const T& a19,
26560 const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) {
26561 static CImg<T> r(5,5); T *ptr = r.data;
26562 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
26563 *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9;
26564 *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
26565 *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19;
26566 *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24;
26567 return r;
26568 }
26570 //! Return a 1x1 symmetric matrix with specified coefficients.
26571 static CImg<T> tensor(const T& a1) {
26572 return matrix(a1);
26573 }
26575 //! Return a 2x2 symmetric matrix tensor with specified coefficients.
26576 static CImg<T> tensor(const T& a1, const T& a2, const T& a3) {
26577 return matrix(a1,a2,a2,a3);
26578 }
26580 //! Return a 3x3 symmetric matrix with specified coefficients.
26581 static CImg<T> tensor(const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) {
26582 return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6);
26583 }
26585 //! Return a 1x1 diagonal matrix with specified coefficients.
26586 static CImg<T> diagonal(const T& a0) {
26587 return matrix(a0);
26588 }
26590 //! Return a 2x2 diagonal matrix with specified coefficients.
26591 static CImg<T> diagonal(const T& a0, const T& a1) {
26592 return matrix(a0,0,0,a1);
26593 }
26595 //! Return a 3x3 diagonal matrix with specified coefficients.
26596 static CImg<T> diagonal(const T& a0, const T& a1, const T& a2) {
26597 return matrix(a0,0,0,0,a1,0,0,0,a2);
26598 }
26600 //! Return a 4x4 diagonal matrix with specified coefficients.
26601 static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3) {
26602 return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3);
26603 }
26605 //! Return a 5x5 diagonal matrix with specified coefficients.
26606 static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
26607 return matrix(a0,0,0,0,0,0,a1,0,0,0,0,0,a2,0,0,0,0,0,a3,0,0,0,0,0,a4);
26608 }
26610 //! Return a NxN identity matrix.
26611 static CImg<T> identity_matrix(const unsigned int N) {
26612 CImg<T> res(N,N,1,1,0);
26613 cimg_forX(res,x) res(x,x) = 1;
26614 return res;
26615 }
26617 //! Return a N-numbered sequence vector from \p a0 to \p a1.
26618 static CImg<T> sequence(const unsigned int N, const T a0, const T a1) {
26619 if (N) return CImg<T>(1,N).sequence(a0,a1);
26620 return CImg<T>();
26621 }
26623 //! Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w.
26624 static CImg<T> rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) {
26625 float X,Y,Z,W;
26626 if (!quaternion_data) {
26627 const float norm = (float)cimg_std::sqrt(x*x + y*y + z*z),
26628 nx = norm>0?x/norm:0,
26629 ny = norm>0?y/norm:0,
26630 nz = norm>0?z/norm:1,
26631 nw = norm>0?w:0,
26632 sina = (float)cimg_std::sin(nw/2),
26633 cosa = (float)cimg_std::cos(nw/2);
26634 X = nx*sina;
26635 Y = ny*sina;
26636 Z = nz*sina;
26637 W = cosa;
26638 } else {
26639 const float norm = (float)cimg_std::sqrt(x*x + y*y + z*z + w*w);
26640 if (norm>0) { X = x/norm; Y = y/norm; Z = z/norm; W = w/norm; }
26641 else { X = Y = Z = 0; W = 1; }
26642 }
26643 const float xx = X*X, xy = X*Y, xz = X*Z, xw = X*W, yy = Y*Y, yz = Y*Z, yw = Y*W, zz = Z*Z, zw = Z*W;
26644 return CImg<T>::matrix((T)(1-2*(yy+zz)), (T)(2*(xy+zw)), (T)(2*(xz-yw)),
26645 (T)(2*(xy-zw)), (T)(1-2*(xx+zz)), (T)(2*(yz+xw)),
26646 (T)(2*(xz+yw)), (T)(2*(yz-xw)), (T)(1-2*(xx+yy)));
26647 }
26649 //! Return a new image corresponding to the vector located at (\p x,\p y,\p z) of the current vector-valued image.
26650 CImg<T> get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
26651 static CImg<T> dest;
26652 if (dest.height!=dim) dest.assign(1,dim);
26653 const unsigned int whz = width*height*depth;
26654 const T *ptrs = ptr(x,y,z);
26655 T *ptrd = dest.data;
26656 cimg_forV(*this,k) { *(ptrd++) = *ptrs; ptrs+=whz; }
26657 return dest;
26658 }
26660 //! Set the image \p vec as the \a vector \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
26661 template<typename t>
26662 CImg<T>& set_vector_at(const CImg<t>& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) {
26663 if (x<width && y<height && z<depth) {
26664 const unsigned int whz = width*height*depth;
26665 const t *ptrs = vec.data;
26666 T *ptrd = ptr(x,y,z);
26667 for (unsigned int k=cimg::min((unsigned int)vec.size(),dim); k; --k) { *ptrd = (T)*(ptrs++); ptrd+=whz; }
26668 }
26669 return *this;
26670 }
26672 //! Return a new image corresponding to the \a square \a matrix located at (\p x,\p y,\p z) of the current vector-valued image.
26673 CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
26674 const int n = (int)cimg_std::sqrt((double)dim);
26675 CImg<T> dest(n,n);
26676 cimg_forV(*this,k) dest[k]=(*this)(x,y,z,k);
26677 return dest;
26678 }
26680 //! Set the image \p vec as the \a square \a matrix-valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
26681 template<typename t>
26682 CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
26683 return set_vector_at(mat,x,y,z);
26684 }
26686 //! Return a new image corresponding to the \a diffusion \a tensor located at (\p x,\p y,\p z) of the current vector-valued image.
26687 CImg<T> get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
26688 if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2),
26689 (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5));
26690 if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2));
26691 return tensor((*this)(x,y,z,0));
26692 }
26694 //! Set the image \p vec as the \a tensor \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
26695 template<typename t>
26696 CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
26697 if (ten.height==2) {
26698 (*this)(x,y,z,0) = (T)ten[0];
26699 (*this)(x,y,z,1) = (T)ten[1];
26700 (*this)(x,y,z,2) = (T)ten[3];
26701 }
26702 else {
26703 (*this)(x,y,z,0) = (T)ten[0];
26704 (*this)(x,y,z,1) = (T)ten[1];
26705 (*this)(x,y,z,2) = (T)ten[2];
26706 (*this)(x,y,z,3) = (T)ten[4];
26707 (*this)(x,y,z,4) = (T)ten[5];
26708 (*this)(x,y,z,5) = (T)ten[8];
26709 }
26710 return *this;
26711 }
26713 //! Unroll all images values into a one-column vector.
26714 CImg<T>& vector() {
26715 return unroll('y');
26716 }
26718 CImg<T> get_vector() const {
26719 return get_unroll('y');
26720 }
26722 //! Realign pixel values of the instance image as a square matrix
26723 CImg<T>& matrix() {
26724 const unsigned int siz = size();
26725 switch (siz) {
26726 case 1 : break;
26727 case 4 : width = height = 2; break;
26728 case 9 : width = height = 3; break;
26729 case 16 : width = height = 4; break;
26730 case 25 : width = height = 5; break;
26731 case 36 : width = height = 6; break;
26732 case 49 : width = height = 7; break;
26733 case 64 : width = height = 8; break;
26734 case 81 : width = height = 9; break;
26735 case 100 : width = height = 10; break;
26736 default : {
26737 unsigned int i = 11, i2 = i*i;
26738 while (i2<siz) { i2+=2*i+1; ++i; }
26739 if (i2==siz) width = height = i;
26740 else throw CImgInstanceException("CImg<%s>::matrix() : Image size = %u is not a square number",
26741 pixel_type(),siz);
26742 }
26743 }
26744 return *this;
26745 }
26747 CImg<T> get_matrix() const {
26748 return (+*this).matrix();
26749 }
26751 //! Realign pixel values of the instance image as a symmetric tensor.
26752 CImg<T>& tensor() {
26753 return get_tensor().transfer_to(*this);
26754 }
26756 CImg<T> get_tensor() const {
26757 CImg<T> res;
26758 const unsigned int siz = size();
26759 switch (siz) {
26760 case 1 : break;
26761 case 3 :
26762 res.assign(2,2);
26763 res(0,0) = (*this)(0);
26764 res(1,0) = res(0,1) = (*this)(1);
26765 res(1,1) = (*this)(2);
26766 break;
26767 case 6 :
26768 res.assign(3,3);
26769 res(0,0) = (*this)(0);
26770 res(1,0) = res(0,1) = (*this)(1);
26771 res(2,0) = res(0,2) = (*this)(2);
26772 res(1,1) = (*this)(3);
26773 res(2,1) = res(1,2) = (*this)(4);
26774 res(2,2) = (*this)(5);
26775 break;
26776 default :
26777 throw CImgInstanceException("CImg<%s>::tensor() : Wrong vector dimension = %u in instance image.",
26778 pixel_type(), dim);
26779 }
26780 return res;
26781 }
26783 //! Unroll all images values into specified axis.
26784 CImg<T>& unroll(const char axis) {
26785 const unsigned int siz = size();
26786 if (siz) switch (axis) {
26787 case 'x' : width = siz; height=depth=dim=1; break;
26788 case 'y' : height = siz; width=depth=dim=1; break;
26789 case 'z' : depth = siz; width=height=dim=1; break;
26790 case 'v' : dim = siz; width=height=depth=1; break;
26791 default :
26792 throw CImgArgumentException("CImg<%s>::unroll() : Given axis is '%c' which is not 'x','y','z' or 'v'",
26793 pixel_type(),axis);
26794 }
26795 return *this;
26796 }
26798 CImg<T> get_unroll(const char axis) const {
26799 return (+*this).unroll(axis);
26800 }
26802 //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image.
26803 CImg<T>& diagonal() {
26804 return get_diagonal().transfer_to(*this);
26805 }
26807 CImg<T> get_diagonal() const {
26808 if (is_empty()) return *this;
26809 CImg<T> res(size(),size(),1,1,0);
26810 cimg_foroff(*this,off) res(off,off) = (*this)(off);
26811 return res;
26812 }
26814 //! Get an identity matrix having same dimension than instance image.
26815 CImg<T>& identity_matrix() {
26816 return identity_matrix(cimg::max(width,height)).transfer_to(*this);
26817 }
26819 CImg<T> get_identity_matrix() const {
26820 return identity_matrix(cimg::max(width,height));
26821 }
26823 //! Return a N-numbered sequence vector from \p a0 to \p a1.
26824 CImg<T>& sequence(const T a0, const T a1) {
26825 if (is_empty()) return *this;
26826 const unsigned int siz = size() - 1;
26827 T* ptr = data;
26828 if (siz) {
26829 const Tfloat delta = (Tfloat)a1 - a0;
26830 cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);
26831 } else *ptr = a0;
26832 return *this;
26833 }
26835 CImg<T> get_sequence(const T a0, const T a1) const {
26836 return (+*this).sequence(a0,a1);
26837 }
26839 //! Transpose the current matrix.
26840 CImg<T>& transpose() {
26841 if (width==1) { width=height; height=1; return *this; }
26842 if (height==1) { height=width; width=1; return *this; }
26843 if (width==height) {
26844 cimg_forYZV(*this,y,z,v) for (int x=y; x<dimx(); ++x) cimg::swap((*this)(x,y,z,v),(*this)(y,x,z,v));
26845 return *this;
26846 }
26847 return get_transpose().transfer_to(*this);
26848 }
26850 CImg<T> get_transpose() const {
26851 return get_permute_axes("yxzv");
26852 }
26854 //! Invert the current matrix.
26855 CImg<T>& invert(const bool use_LU=true) {
26856 if (!is_empty()) {
26857 if (width!=height || depth!=1 || dim!=1)
26858 throw CImgInstanceException("CImg<%s>::invert() : Instance matrix (%u,%u,%u,%u,%p) is not square.",
26859 pixel_type(),width,height,depth,dim,data);
26860 #ifdef cimg_use_lapack
26861 int INFO = (int)use_LU, N = width, LWORK = 4*N, *IPIV = new int[N];
26862 Tfloat
26863 *lapA = new Tfloat[N*N],
26864 *WORK = new Tfloat[LWORK];
26865 cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
26866 cimg::getrf(N,lapA,IPIV,INFO);
26867 if (INFO)
26868 cimg::warn("CImg<%s>::invert() : LAPACK library function dgetrf_() returned error code %d.",
26869 pixel_type(),INFO);
26870 else {
26871 cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
26872 if (INFO)
26873 cimg::warn("CImg<%s>::invert() : LAPACK library function dgetri_() returned Error code %d",
26874 pixel_type(),INFO);
26875 }
26876 if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N+l]); else fill(0);
26877 delete[] IPIV; delete[] lapA; delete[] WORK;
26878 #else
26879 const double dete = width>3?-1.0:det();
26880 if (dete!=0.0 && width==2) {
26881 const double
26882 a = data[0], c = data[1],
26883 b = data[2], d = data[3];
26884 data[0] = (T)(d/dete); data[1] = (T)(-c/dete);
26885 data[2] = (T)(-b/dete); data[3] = (T)(a/dete);
26886 } else if (dete!=0.0 && width==3) {
26887 const double
26888 a = data[0], d = data[1], g = data[2],
26889 b = data[3], e = data[4], h = data[5],
26890 c = data[6], f = data[7], i = data[8];
26891 data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete);
26892 data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete);
26893 data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete);
26894 } else {
26895 if (use_LU) { // LU-based inverse computation
26896 CImg<Tfloat> A(*this), indx, col(1,width);
26897 bool d;
26898 A._LU(indx,d);
26899 cimg_forX(*this,j) {
26900 col.fill(0);
26901 col(j) = 1;
26902 col._solve(A,indx);
26903 cimg_forX(*this,i) (*this)(j,i) = (T)col(i);
26904 }
26905 } else { // SVD-based inverse computation
26906 CImg<Tfloat> U(width,width), S(1,width), V(width,width);
26907 SVD(U,S,V,false);
26908 U.transpose();
26909 cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k];
26910 S.diagonal();
26911 *this = V*S*U;
26912 }
26913 }
26914 #endif
26915 }
26916 return *this;
26917 }
26919 CImg<Tfloat> get_invert(const bool use_LU=true) const {
26920 return CImg<Tfloat>(*this,false).invert(use_LU);
26921 }
26923 //! Compute the pseudo-inverse (Moore-Penrose) of the matrix.
26924 CImg<T>& pseudoinvert() {
26925 return get_pseudoinvert().transfer_to(*this);
26926 }
26928 CImg<Tfloat> get_pseudoinvert() const {
26929 CImg<Tfloat> U, S, V;
26930 SVD(U,S,V);
26931 cimg_forX(V,x) {
26932 const Tfloat s = S(x), invs = s!=0?1/s:(Tfloat)0;
26933 cimg_forY(V,y) V(x,y)*=invs;
26934 }
26935 return V*U.transpose();
26936 }
26938 //! Compute the cross product between two 3d vectors.
26939 template<typename t>
26940 CImg<T>& cross(const CImg<t>& img) {
26941 if (width!=1 || height<3 || img.width!=1 || img.height<3)
26942 throw CImgInstanceException("CImg<%s>::cross() : Arguments (%u,%u,%u,%u,%p) and (%u,%u,%u,%u,%p) must be both 3d vectors.",
26943 pixel_type(),width,height,depth,dim,data,img.width,img.height,img.depth,img.dim,img.data);
26944 const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
26945 (*this)[0] = (T)(y*img[2]-z*img[1]);
26946 (*this)[1] = (T)(z*img[0]-x*img[2]);
26947 (*this)[2] = (T)(x*img[1]-y*img[0]);
26948 return *this;
26949 }
26951 template<typename t>
26952 CImg<typename cimg::superset<T,t>::type> get_cross(const CImg<t>& img) const {
26953 typedef typename cimg::superset<T,t>::type Tt;
26954 return CImg<Tt>(*this).cross(img);
26955 }
26957 //! Solve a linear system AX=B where B=*this.
26958 template<typename t>
26959 CImg<T>& solve(const CImg<t>& A) {
26960 if (width!=1 || depth!=1 || dim!=1 || height!=A.height || A.depth!=1 || A.dim!=1)
26961 throw CImgArgumentException("CImg<%s>::solve() : Instance matrix size is (%u,%u,%u,%u) while "
26962 "size of given matrix A is (%u,%u,%u,%u).",
26963 pixel_type(),width,height,depth,dim,A.width,A.height,A.depth,A.dim);
26965 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
26966 if (A.width==A.height) {
26967 #ifdef cimg_use_lapack
26968 char TRANS='N';
26969 int INFO, N = height, LWORK = 4*N, one = 1, *IPIV = new int[N];
26970 Ttfloat
26971 *lapA = new Ttfloat[N*N],
26972 *lapB = new Ttfloat[N],
26973 *WORK = new Ttfloat[LWORK];
26974 cimg_forXY(A,k,l) lapA[k*N+l] = (Ttfloat)(A(k,l));
26975 cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));
26976 cimg::getrf(N,lapA,IPIV,INFO);
26977 if (INFO)
26978 cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrf_() returned error code %d.",
26979 pixel_type(),INFO);
26980 if (!INFO) {
26981 cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
26982 if (INFO)
26983 cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrs_() returned Error code %d",
26984 pixel_type(),INFO);
26985 }
26986 if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
26987 delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
26988 #else
26989 CImg<Ttfloat> lu(A);
26990 CImg<Ttfloat> indx;
26991 bool d;
26992 lu._LU(indx,d);
26993 _solve(lu,indx);
26994 #endif
26995 } else assign(A.get_pseudoinvert()*(*this));
26996 return *this;
26997 }
26999 template<typename t>
27000 CImg<typename cimg::superset2<T,t,float>::type> get_solve(const CImg<t>& A) const {
27001 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
27002 return CImg<Ttfloat>(*this,false).solve(A);
27003 }
27005 template<typename t, typename ti>
27006 CImg<T>& _solve(const CImg<t>& A, const CImg<ti>& indx) {
27007 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
27008 const int N = size();
27009 int ii = -1;
27010 Ttfloat sum;
27011 for (int i=0; i<N; ++i) {
27012 const int ip = (int)indx[i];
27013 Ttfloat sum = (*this)(ip);
27014 (*this)(ip) = (*this)(i);
27015 if (ii>=0) for (int j=ii; j<=i-1; ++j) sum-=A(j,i)*(*this)(j);
27016 else if (sum!=0) ii=i;
27017 (*this)(i) = (T)sum;
27018 }
27019 { for (int i=N-1; i>=0; --i) {
27020 sum = (*this)(i);
27021 for (int j=i+1; j<N; ++j) sum-=A(j,i)*(*this)(j);
27022 (*this)(i) = (T)(sum/A(i,i));
27023 }}
27024 return *this;
27025 }
27027 //! Solve a linear system AX=B where B=*this and A is a tridiagonal matrix A = [ b0,c0,0,...; a1,b1,c1,0,... ; ... ; ...,0,aN,bN ].
27028 // (Use the Thomas Algorithm).
27029 template<typename t>
27030 CImg<T>& solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) {
27031 const int siz = (int)size();
27032 if ((int)a.size()!=siz || (int)b.size()!=siz || (int)c.size()!=siz)
27033 throw CImgArgumentException("CImg<%s>::solve_tridiagonal() : arrays of triagonal coefficients have different size.",pixel_type);
27034 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
27035 CImg<Ttfloat> nc(siz);
27036 const T *ptra = a.data, *ptrb = b.data, *ptrc = c.data;
27037 T *ptrnc = nc.data, *ptrd = data;
27038 const Ttfloat valb0 = (Ttfloat)*(ptrb++);
27039 *ptrnc = *(ptrc++)/valb0;
27040 Ttfloat vald = (Ttfloat)(*(ptrd++)/=valb0);
27041 for (int i = 1; i<siz; ++i) {
27042 const Ttfloat
27043 vala = (Tfloat)*(ptra++),
27044 id = 1/(*(ptrb++) - *(ptrnc++)*vala);
27045 *ptrnc = *(ptrc++)*id;
27046 vald = ((*ptrd-=vala*vald)*=id);
27047 ++ptrd;
27048 }
27049 vald = *(--ptrd);
27050 for (int i = siz-2; i>=0; --i) vald = (*(--ptrd)-=*(--ptrnc)*vald);
27051 return *this;
27052 }
27054 template<typename t>
27055 CImg<typename cimg::superset2<T,t,float>::type> get_solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) const {
27056 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
27057 return CImg<Ttfloat>(*this,false).solve_tridiagonal(a,b,c);
27058 }
27060 //! Sort values of a vector and get permutations.
27061 template<typename t>
27062 CImg<T>& sort(CImg<t>& permutations, const bool increasing=true) {
27063 if (is_empty()) permutations.assign();
27064 else {
27065 if (permutations.size()!=size()) permutations.assign(size());
27066 cimg_foroff(permutations,off) permutations[off] = (t)off;
27067 _quicksort(0,size()-1,permutations,increasing);
27068 }
27069 return *this;
27070 }
27072 template<typename t>
27073 CImg<T> get_sort(CImg<t>& permutations, const bool increasing=true) const {
27074 return (+*this).sort(permutations,increasing);
27075 }
27077 // Sort image values.
27078 CImg<T>& sort(const bool increasing=true) {
27079 CImg<T> foo;
27080 return sort(foo,increasing);
27081 }
27083 CImg<T> get_sort(const bool increasing=true) const {
27084 return (+*this).sort(increasing);
27085 }
27087 template<typename t>
27088 CImg<T>& _quicksort(const int min, const int max, CImg<t>& permutations, const bool increasing) {
27089 if (min<max) {
27090 const int mid = (min+max)/2;
27091 if (increasing) {
27092 if ((*this)[min]>(*this)[mid]) {
27093 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
27094 if ((*this)[mid]>(*this)[max]) {
27095 cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
27096 if ((*this)[min]>(*this)[mid]) {
27097 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
27098 } else {
27099 if ((*this)[min]<(*this)[mid]) {
27100 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
27101 if ((*this)[mid]<(*this)[max]) {
27102 cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
27103 if ((*this)[min]<(*this)[mid]) {
27104 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
27105 }
27106 if (max-min>=3) {
27107 const T pivot = (*this)[mid];
27108 int i = min, j = max;
27109 if (increasing) {
27110 do {
27111 while ((*this)[i]<pivot) ++i;
27112 while ((*this)[j]>pivot) --j;
27113 if (i<=j) {
27114 cimg::swap((*this)[i],(*this)[j]);
27115 cimg::swap(permutations[i++],permutations[j--]);
27116 }
27117 } while (i<=j);
27118 } else {
27119 do {
27120 while ((*this)[i]>pivot) ++i;
27121 while ((*this)[j]<pivot) --j;
27122 if (i<=j) {
27123 cimg::swap((*this)[i],(*this)[j]);
27124 cimg::swap(permutations[i++],permutations[j--]);
27125 }
27126 } while (i<=j);
27127 }
27128 if (min<j) _quicksort(min,j,permutations,increasing);
27129 if (i<max) _quicksort(i,max,permutations,increasing);
27130 }
27131 }
27132 return *this;
27133 }
27135 //! Get a permutation of the pixels.
27136 template<typename t>
27137 CImg<T>& permute(const CImg<t>& permutation) {
27138 return get_permute(permutation).transfer_to(*this);
27139 }
27141 template<typename t>
27142 CImg<T> get_permute(const CImg<t>& permutation) const {
27143 if (permutation.size()!=size())
27144 throw CImgArgumentException("CImg<%s>::permute() : Instance image (%u,%u,%u,%u,%p) and permutation (%u,%u,%u,%u,%p)"
27145 "have different sizes.",
27146 pixel_type(),width,height,depth,dim,data,
27147 permutation.width,permutation.height,permutation.depth,permutation.dim,permutation.data);
27148 CImg<T> res(width,height,depth,dim);
27149 const t *p = permutation.ptr(permutation.size());
27150 cimg_for(res,ptr,T) *ptr = (*this)[*(--p)];
27151 return res;
27152 }
27154 //! Compute the SVD of a general matrix.
27155 template<typename t>
27156 const CImg<T>& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V,
27157 const bool sorting=true, const unsigned int max_iter=40, const float lambda=0) const {
27158 if (is_empty()) { U.assign(); S.assign(); V.assign(); }
27159 else {
27160 U = *this;
27161 if (lambda!=0) {
27162 const unsigned int delta = cimg::min(U.width,U.height);
27163 for (unsigned int i=0; i<delta; ++i) U(i,i) = (t)(U(i,i) + lambda);
27164 }
27165 if (S.size()<width) S.assign(1,width);
27166 if (V.width<width || V.height<height) V.assign(width,width);
27167 CImg<t> rv1(width);
27168 t anorm = 0, c, f, g = 0, h, s, scale = 0;
27169 int l = 0, nm = 0;
27171 cimg_forX(U,i) {
27172 l = i+1; rv1[i] = scale*g; g = s = scale = 0;
27173 if (i<dimy()) {
27174 for (int k=i; k<dimy(); ++k) scale+= cimg::abs(U(i,k));
27175 if (scale) {
27176 for (int k=i; k<dimy(); ++k) { U(i,k)/=scale; s+= U(i,k)*U(i,k); }
27177 f = U(i,i); g = (t)((f>=0?-1:1)*cimg_std::sqrt(s)); h=f*g-s; U(i,i) = f-g;
27178 for (int j=l; j<dimx(); ++j) {
27179 s = 0; for (int k=i; k<dimy(); ++k) s+= U(i,k)*U(j,k);
27180 f = s/h;
27181 { for (int k=i; k<dimy(); ++k) U(j,k)+= f*U(i,k); }
27182 }
27183 { for (int k=i; k<dimy(); ++k) U(i,k)*= scale; }
27184 }
27185 }
27186 S[i]=scale*g;
27188 g = s = scale = 0;
27189 if (i<dimy() && i!=dimx()-1) {
27190 for (int k=l; k<dimx(); ++k) scale += cimg::abs(U(k,i));
27191 if (scale) {
27192 for (int k=l; k<dimx(); ++k) { U(k,i)/= scale; s+= U(k,i)*U(k,i); }
27193 f = U(l,i); g = (t)((f>=0?-1:1)*cimg_std::sqrt(s)); h = f*g-s; U(l,i) = f-g;
27194 { for (int k=l; k<dimx(); ++k) rv1[k]=U(k,i)/h; }
27195 for (int j=l; j<dimy(); ++j) {
27196 s = 0; for (int k=l; k<dimx(); ++k) s+= U(k,j)*U(k,i);
27197 { for (int k=l; k<dimx(); ++k) U(k,j)+= s*rv1[k]; }
27198 }
27199 { for (int k=l; k<dimx(); ++k) U(k,i)*= scale; }
27200 }
27201 }
27202 anorm = (t)cimg::max((float)anorm,(float)(cimg::abs(S[i])+cimg::abs(rv1[i])));
27203 }
27205 { for (int i=dimx()-1; i>=0; --i) {
27206 if (i<dimx()-1) {
27207 if (g) {
27208 { for (int j=l; j<dimx(); ++j) V(i,j) =(U(j,i)/U(l,i))/g; }
27209 for (int j=l; j<dimx(); ++j) {
27210 s = 0; for (int k=l; k<dimx(); ++k) s+= U(k,i)*V(j,k);
27211 { for (int k=l; k<dimx(); ++k) V(j,k)+= s*V(i,k); }
27212 }
27213 }
27214 for (int j=l; j<dimx(); ++j) V(j,i) = V(i,j) = (t)0.0;
27215 }
27216 V(i,i) = (t)1.0; g = rv1[i]; l = i;
27217 }
27218 }
27220 { for (int i=cimg::min(dimx(),dimy())-1; i>=0; --i) {
27221 l = i+1; g = S[i];
27222 for (int j=l; j<dimx(); ++j) U(j,i) = 0;
27223 if (g) {
27224 g = 1/g;
27225 for (int j=l; j<dimx(); ++j) {
27226 s = 0; for (int k=l; k<dimy(); ++k) s+= U(i,k)*U(j,k);
27227 f = (s/U(i,i))*g;
27228 { for (int k=i; k<dimy(); ++k) U(j,k)+= f*U(i,k); }
27229 }
27230 { for (int j=i; j<dimy(); ++j) U(i,j)*= g; }
27231 } else for (int j=i; j<dimy(); ++j) U(i,j) = 0;
27232 ++U(i,i);
27233 }
27234 }
27236 for (int k=dimx()-1; k>=0; --k) {
27237 for (unsigned int its=0; its<max_iter; ++its) {
27238 bool flag = true;
27239 for (l=k; l>=1; --l) {
27240 nm = l-1;
27241 if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; }
27242 if ((cimg::abs(S[nm])+anorm)==anorm) break;
27243 }
27244 if (flag) {
27245 c = 0; s = 1;
27246 for (int i=l; i<=k; ++i) {
27247 f = s*rv1[i]; rv1[i] = c*rv1[i];
27248 if ((cimg::abs(f)+anorm)==anorm) break;
27249 g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;
27250 cimg_forY(U,j) { const t y = U(nm,j), z = U(i,j); U(nm,j) = y*c+z*s; U(i,j) = z*c-y*s; }
27251 }
27252 }
27253 const t z = S[k];
27254 if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; }
27255 nm = k-1;
27256 t x = S[l], y = S[nm];
27257 g = rv1[nm]; h = rv1[k];
27258 f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y);
27259 g = (t)cimg::_pythagore(f,1.0);
27260 f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x;
27261 c = s = 1;
27262 for (int j=l; j<=nm; ++j) {
27263 const int i = j+1;
27264 g = rv1[i]; h = s*g; g = c*g;
27265 t y = S[i];
27266 t z = (t)cimg::_pythagore(f,h);
27267 rv1[j] = z; c = f/z; s = h/z;
27268 f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c;
27269 cimg_forX(U,jj) { const t x = V(j,jj), z = V(i,jj); V(j,jj) = x*c+z*s; V(i,jj) = z*c-x*s; }
27270 z = (t)cimg::_pythagore(f,h); S[j] = z;
27271 if (z) { z = 1/z; c = f*z; s = h*z; }
27272 f = c*g+s*y; x = c*y-s*g;
27273 { cimg_forY(U,jj) { const t y = U(j,jj); z = U(i,jj); U(j,jj) = y*c+z*s; U(i,jj) = z*c-y*s; }}
27274 }
27275 rv1[l] = 0; rv1[k]=f; S[k]=x;
27276 }
27277 }
27279 if (sorting) {
27280 CImg<intT> permutations(width);
27281 CImg<t> tmp(width);
27282 S.sort(permutations,false);
27283 cimg_forY(U,k) {
27284 cimg_forX(permutations,x) tmp(x) = U(permutations(x),k);
27285 cimg_std::memcpy(U.ptr(0,k),tmp.data,sizeof(t)*width);
27286 }
27287 { cimg_forY(V,k) {
27288 cimg_forX(permutations,x) tmp(x) = V(permutations(x),k);
27289 cimg_std::memcpy(V.ptr(0,k),tmp.data,sizeof(t)*width);
27290 }}
27291 }
27292 }
27293 return *this;
27294 }
27296 //! Compute the SVD of a general matrix.
27297 template<typename t>
27298 const CImg<T>& SVD(CImgList<t>& USV) const {
27299 if (USV.size<3) USV.assign(3);
27300 return SVD(USV[0],USV[1],USV[2]);
27301 }
27303 //! Compute the SVD of a general matrix.
27304 CImgList<Tfloat> get_SVD(const bool sorting=true) const {
27305 CImgList<Tfloat> res(3);
27306 SVD(res[0],res[1],res[2],sorting);
27307 return res;
27308 }
27310 // INNER ROUTINE : Compute the LU decomposition of a permuted matrix (c.f. numerical recipies)
27311 template<typename t>
27312 CImg<T>& _LU(CImg<t>& indx, bool& d) {
27313 const int N = dimx();
27314 int imax = 0;
27315 CImg<Tfloat> vv(N);
27316 indx.assign(N);
27317 d = true;
27318 cimg_forX(*this,i) {
27319 Tfloat vmax = 0;
27320 cimg_forX(*this,j) {
27321 const Tfloat tmp = cimg::abs((*this)(j,i));
27322 if (tmp>vmax) vmax = tmp;
27323 }
27324 if (vmax==0) { indx.fill(0); return fill(0); }
27325 vv[i] = 1/vmax;
27326 }
27327 cimg_forX(*this,j) {
27328 for (int i=0; i<j; ++i) {
27329 Tfloat sum=(*this)(j,i);
27330 for (int k=0; k<i; ++k) sum-=(*this)(k,i)*(*this)(j,k);
27331 (*this)(j,i) = (T)sum;
27332 }
27333 Tfloat vmax = 0;
27334 { for (int i=j; i<dimx(); ++i) {
27335 Tfloat sum=(*this)(j,i);
27336 for (int k=0; k<j; ++k) sum-=(*this)(k,i)*(*this)(j,k);
27337 (*this)(j,i) = (T)sum;
27338 const Tfloat tmp = vv[i]*cimg::abs(sum);
27339 if (tmp>=vmax) { vmax=tmp; imax=i; }
27340 }}
27341 if (j!=imax) {
27342 cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j));
27343 d =!d;
27344 vv[imax] = vv[j];
27345 }
27346 indx[j] = (t)imax;
27347 if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20;
27348 if (j<N) {
27349 const Tfloat tmp = 1/(Tfloat)(*this)(j,j);
27350 for (int i=j+1; i<N; ++i) (*this)(j,i) = (T)((*this)(j,i)*tmp);
27351 }
27352 }
27353 return *this;
27354 }
27356 //! Compute the eigenvalues and eigenvectors of a matrix.
27357 template<typename t>
27358 const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
27359 if (is_empty()) { val.assign(); vec.assign(); }
27360 else {
27361 if (width!=height || depth>1 || dim>1)
27362 throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
27363 pixel_type(),width,height,depth,dim,data);
27364 if (val.size()<width) val.assign(1,width);
27365 if (vec.size()<width*width) vec.assign(width,width);
27366 switch (width) {
27367 case 1 : { val[0]=(t)(*this)[0]; vec[0]=(t)1; } break;
27368 case 2 : {
27369 const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a+d;
27370 double f = e*e-4*(a*d-b*c);
27371 if (f<0)
27372 cimg::warn("CImg<%s>::eigen() : Complex eigenvalues",
27373 pixel_type());
27374 f = cimg_std::sqrt(f);
27375 const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);
27376 const double theta1 = cimg_std::atan2(l2-a,b), theta2 = cimg_std::atan2(l1-a,b);
27377 val[0]=(t)l2;
27378 val[1]=(t)l1;
27379 vec(0,0) = (t)cimg_std::cos(theta1);
27380 vec(0,1) = (t)cimg_std::sin(theta1);
27381 vec(1,0) = (t)cimg_std::cos(theta2);
27382 vec(1,1) = (t)cimg_std::sin(theta2);
27383 } break;
27384 default :
27385 throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited"
27386 "to 2x2 matrices (given is %ux%u)",
27387 pixel_type(),width,height);
27388 }
27389 }
27390 return *this;
27391 }
27393 //! Compute the eigenvalues and eigenvectors of a matrix.
27394 CImgList<Tfloat> get_eigen() const {
27395 CImgList<Tfloat> res(2);
27396 eigen(res[0],res[1]);
27397 return res;
27398 }
27400 //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
27401 template<typename t>
27402 const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& vec) const {
27403 if (is_empty()) { val.assign(); vec.assign(); }
27404 else {
27405 #ifdef cimg_use_lapack
27406 char JOB = 'V', UPLO = 'U';
27407 int N = width, LWORK = 4*N, INFO;
27408 Tfloat
27409 *lapA = new Tfloat[N*N],
27410 *lapW = new Tfloat[N],
27411 *WORK = new Tfloat[LWORK];
27412 cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
27413 cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO);
27414 if (INFO)
27415 cimg::warn("CImg<%s>::symmetric_eigen() : LAPACK library function dsyev_() returned error code %d.",
27416 pixel_type(),INFO);
27417 val.assign(1,N);
27418 vec.assign(N,N);
27419 if (!INFO) {
27420 cimg_forY(val,i) val(i) = (T)lapW[N-1-i];
27421 cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N-1-k)*N+l]);
27422 } else { val.fill(0); vec.fill(0); }
27423 delete[] lapA; delete[] lapW; delete[] WORK;
27424 #else
27425 if (width!=height || depth>1 || dim>1)
27426 throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
27427 pixel_type(),width,height,depth,dim,data);
27428 val.assign(1,width);
27429 if (vec.data) vec.assign(width,width);
27430 if (width<3) return eigen(val,vec);
27431 CImg<t> V(width,width);
27432 SVD(vec,val,V,false);
27433 bool ambiguous = false;
27434 float eig = 0;
27435 cimg_forY(val,p) { // check for ambiguous cases.
27436 if (val[p]>eig) eig = (float)val[p];
27437 t scal = 0;
27438 cimg_forY(vec,y) scal+=vec(p,y)*V(p,y);
27439 if (cimg::abs(scal)<0.9f) ambiguous = true;
27440 if (scal<0) val[p] = -val[p];
27441 }
27442 if (ambiguous) {
27443 (eig*=2)++;
27444 SVD(vec,val,V,false,40,eig);
27445 val-=eig;
27446 }
27447 CImg<intT> permutations(width); // sort eigenvalues in decreasing order
27448 CImg<t> tmp(width);
27449 val.sort(permutations,false);
27450 cimg_forY(vec,k) {
27451 cimg_forX(permutations,x) tmp(x) = vec(permutations(x),k);
27452 cimg_std::memcpy(vec.ptr(0,k),tmp.data,sizeof(t)*width);
27453 }
27454 #endif
27455 }
27456 return *this;
27457 }
27459 //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
27460 CImgList<Tfloat> get_symmetric_eigen() const {
27461 CImgList<Tfloat> res(2);
27462 symmetric_eigen(res[0],res[1]);
27463 return res;
27464 }
27466 //@}
27467 //-------------------
27468 //
27469 //! \name Display
27470 //@{
27471 //-------------------
27473 //! Display an image into a CImgDisplay window.
27474 const CImg<T>& display(CImgDisplay& disp) const {
27475 disp.display(*this);
27476 return *this;
27477 }
27479 //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n
27480 const CImg<T>& display(CImgDisplay &disp, const bool display_info) const {
27481 return _display(disp,0,display_info);
27482 }
27484 //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n
27485 const CImg<T>& display(const char *const title=0, const bool display_info=true) const {
27486 CImgDisplay disp;
27487 return _display(disp,title,display_info);
27488 }
27490 const CImg<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info) const {
27491 if (is_empty())
27492 throw CImgInstanceException("CImg<%s>::display() : Instance image (%u,%u,%u,%u,%p) is empty.",
27493 pixel_type(),width,height,depth,dim,data);
27494 unsigned int oldw = 0, oldh = 0, XYZ[3], key = 0, mkey = 0;
27495 int x0 = 0, y0 = 0, z0 = 0, x1 = dimx()-1, y1 = dimy()-1, z1 = dimz()-1;
27496 float frametiming = 5;
27498 char ntitle[256] = { 0 };
27499 if (!disp) {
27500 if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
27501 disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
27502 }
27503 cimg_std::strncpy(ntitle,disp.title,255);
27504 if (display_info) print(ntitle);
27506 CImg<T> zoom;
27507 for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
27508 if (reset_view) {
27509 XYZ[0] = (x0 + x1)/2; XYZ[1] = (y0 + y1)/2; XYZ[2] = (z0 + z1)/2;
27510 x0 = 0; y0 = 0; z0 = 0; x1 = width-1; y1 = height-1; z1 = depth-1;
27511 oldw = disp.width; oldh = disp.height;
27512 reset_view = false;
27513 }
27514 if (!x0 && !y0 && !z0 && x1==dimx()-1 && y1==dimy()-1 && z1==dimz()-1) zoom.assign();
27515 else zoom = get_crop(x0,y0,z0,x1,y1,z1);
27517 const unsigned int
27518 dx = 1 + x1 - x0, dy = 1 + y1 - y0, dz = 1 + z1 - z0,
27519 tw = dx + (dz>1?dz:0), th = dy + (dz>1?dz:0);
27520 if (resize_disp) {
27521 const unsigned int
27522 ttw = tw*disp.width/oldw, tth = th*disp.height/oldh,
27523 dM = cimg::max(ttw,tth), diM = cimg::max(disp.width,disp.height),
27524 imgw = cimg::max(16U,ttw*diM/dM), imgh = cimg::max(16U,tth*diM/dM);
27525 disp.normalscreen().resize(cimg_fitscreen(imgw,imgh,1),false);
27526 resize_disp = false;
27527 }
27528 oldw = tw; oldh = th;
27530 bool
27531 go_up = false, go_down = false, go_left = false, go_right = false,
27532 go_inc = false, go_dec = false, go_in = false, go_out = false,
27533 go_in_center = false;
27534 const CImg<T>& visu = zoom?zoom:*this;
27535 const CImg<intT> selection = visu._get_select(disp,0,2,XYZ,0,x0,y0,z0);
27536 if (disp.wheel) {
27537 if (disp.is_keyCTRLLEFT) { if (!mkey || mkey==1) go_out = !(go_in = disp.wheel>0); go_in_center = false; mkey = 1; }
27538 else if (disp.is_keySHIFTLEFT) { if (!mkey || mkey==2) go_right = !(go_left = disp.wheel>0); mkey = 2; }
27539 else if (disp.is_keyALT || depth==1) { if (!mkey || mkey==3) go_down = !(go_up = disp.wheel>0); mkey = 3; }
27540 else mkey = 0;
27541 disp.wheel = 0;
27542 } else mkey = 0;
27543 const int
27544 sx0 = selection(0), sy0 = selection(1), sz0 = selection(2),
27545 sx1 = selection(3), sy1 = selection(4), sz1 = selection(5);
27546 if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) {
27547 x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1; x0+=sx0; y0+=sy0; z0+=sz0;
27548 if (sx0==sx1 && sy0==sy1 && sz0==sz1) reset_view = true;
27549 resize_disp = true;
27550 } else switch (key = disp.key) {
27551 case 0 : case cimg::keyCTRLLEFT : case cimg::keyPAD5 : case cimg::keySHIFTLEFT : case cimg::keyALT : disp.key = key = 0; break;
27552 case cimg::keyP : if (visu.depth>1 && disp.is_keyCTRLLEFT) { // Special mode : play stack of frames
27553 const unsigned int
27554 w1 = visu.width*disp.width/(visu.width+(visu.depth>1?visu.depth:0)),
27555 h1 = visu.height*disp.height/(visu.height+(visu.depth>1?visu.depth:0));
27556 disp.resize(cimg_fitscreen(w1,h1,1),false).key = disp.wheel = key = 0;
27557 for (unsigned int timer = 0; !key && !disp.is_closed && !disp.button; ) {
27558 if (disp.is_resized) disp.resize();
27559 if (!timer) {
27560 visu.get_slice(XYZ[2]).display(disp.set_title("%s | z=%d",ntitle,XYZ[2]));
27561 if (++XYZ[2]>=visu.depth) XYZ[2] = 0;
27562 }
27563 if (++timer>(unsigned int)frametiming) timer = 0;
27564 if (disp.wheel) { frametiming-=disp.wheel/3.0f; disp.wheel = 0; }
27565 switch (key = disp.key) {
27566 case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
27567 case cimg::keyPAGEUP : frametiming-=0.3f; key = 0; break;
27568 case cimg::keyPAGEDOWN : frametiming+=0.3f; key = 0; break;
27569 case cimg::keyD : if (disp.is_keyCTRLLEFT) {
27570 disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
27571 CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false);
27572 disp.key = key = 0;
27573 } break;
27574 case cimg::keyC : if (disp.is_keyCTRLLEFT) {
27575 disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false);
27576 disp.key = key = 0;
27577 } break;
27578 case cimg::keyR : if (disp.is_keyCTRLLEFT) {
27579 disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false);
27580 disp.key = key = 0;
27581 } break;
27582 case cimg::keyF : if (disp.is_keyCTRLLEFT) {
27583 disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen();
27584 disp.key = key = 0;
27585 } break;
27586 }
27587 frametiming = frametiming<1?1:(frametiming>39?39:frametiming);
27588 disp.wait(20);
27589 }
27590 const unsigned int
27591 w2 = (visu.width + (visu.depth>1?visu.depth:0))*disp.width/visu.width,
27592 h2 = (visu.height + (visu.depth>1?visu.depth:0))*disp.height/visu.height;
27593 disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(ntitle);
27594 key = disp.key = disp.button = disp.wheel = 0;
27595 } break;
27596 case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
27597 case cimg::keyPADADD : go_in = true; go_in_center = true; key = 0; break;
27598 case cimg::keyPADSUB : go_out = true; key = 0; break;
27599 case cimg::keyARROWLEFT : case cimg::keyPAD4: go_left = true; key = 0; break;
27600 case cimg::keyARROWRIGHT : case cimg::keyPAD6: go_right = true; key = 0; break;
27601 case cimg::keyARROWUP : case cimg::keyPAD8: go_up = true; key = 0; break;
27602 case cimg::keyARROWDOWN : case cimg::keyPAD2: go_down = true; key = 0; break;
27603 case cimg::keyPAD7 : go_up = go_left = true; key = 0; break;
27604 case cimg::keyPAD9 : go_up = go_right = true; key = 0; break;
27605 case cimg::keyPAD1 : go_down = go_left = true; key = 0; break;
27606 case cimg::keyPAD3 : go_down = go_right = true; key = 0; break;
27607 case cimg::keyPAGEUP : go_inc = true; key = 0; break;
27608 case cimg::keyPAGEDOWN : go_dec = true; key = 0; break;
27609 }
27610 if (go_in) {
27611 const int
27612 mx = go_in_center?disp.dimx()/2:disp.mouse_x,
27613 my = go_in_center?disp.dimy()/2:disp.mouse_y,
27614 mX = mx*(width+(depth>1?depth:0))/disp.width,
27615 mY = my*(height+(depth>1?depth:0))/disp.height;
27616 int X = XYZ[0], Y = XYZ[1], Z = XYZ[2];
27617 if (mX<dimx() && mY<dimy()) { X = x0 + mX*(1+x1-x0)/width; Y = y0 + mY*(1+y1-y0)/height; Z = XYZ[2]; }
27618 if (mX<dimx() && mY>=dimy()) { X = x0 + mX*(1+x1-x0)/width; Z = z0 + (mY-height)*(1+z1-z0)/depth; Y = XYZ[1]; }
27619 if (mX>=dimx() && mY<dimy()) { Y = y0 + mY*(1+y1-y0)/height; Z = z0 + (mX-width)*(1+z1-z0)/depth; X = XYZ[0]; }
27620 if (x1-x0>4) { x0 = X - 7*(X-x0)/8; x1 = X + 7*(x1-X)/8; }
27621 if (y1-y0>4) { y0 = Y - 7*(Y-y0)/8; y1 = Y + 7*(y1-Y)/8; }
27622 if (z1-z0>4) { z0 = Z - 7*(Z-z0)/8; z1 = Z + 7*(z1-Z)/8; }
27623 }
27624 if (go_out) {
27625 const int
27626 deltax = (x1-x0)/8, deltay = (y1-y0)/8, deltaz = (z1-z0)/8,
27627 ndeltax = deltax?deltax:(width>1?1:0),
27628 ndeltay = deltay?deltay:(height>1?1:0),
27629 ndeltaz = deltaz?deltaz:(depth>1?1:0);
27630 x0-=ndeltax; y0-=ndeltay; z0-=ndeltaz;
27631 x1+=ndeltax; y1+=ndeltay; z1+=ndeltaz;
27632 if (x0<0) { x1-=x0; x0 = 0; if (x1>=dimx()) x1 = dimx()-1; }
27633 if (y0<0) { y1-=y0; y0 = 0; if (y1>=dimy()) y1 = dimy()-1; }
27634 if (z0<0) { z1-=z0; z0 = 0; if (z1>=dimz()) z1 = dimz()-1; }
27635 if (x1>=dimx()) { x0-=(x1-dimx()+1); x1 = dimx()-1; if (x0<0) x0 = 0; }
27636 if (y1>=dimy()) { y0-=(y1-dimy()+1); y1 = dimy()-1; if (y0<0) y0 = 0; }
27637 if (z1>=dimz()) { z0-=(z1-dimz()+1); z1 = dimz()-1; if (z0<0) z0 = 0; }
27638 }
27639 if (go_left) {
27640 const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
27641 if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
27642 else { x1-=x0; x0 = 0; }
27643 }
27644 if (go_right) {
27645 const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
27646 if (x1+ndelta<dimx()) { x0+=ndelta; x1+=ndelta; }
27647 else { x0+=(dimx()-1-x1); x1 = dimx()-1; }
27648 }
27649 if (go_up) {
27650 const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
27651 if (y0-ndelta>=0) { y0-=ndelta; y1-=ndelta; }
27652 else { y1-=y0; y0 = 0; }
27653 }
27654 if (go_down) {
27655 const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
27656 if (y1+ndelta<dimy()) { y0+=ndelta; y1+=ndelta; }
27657 else { y0+=(dimy()-1-y1); y1 = dimy()-1; }
27658 }
27659 if (go_inc) {
27660 const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
27661 if (z0-ndelta>=0) { z0-=ndelta; z1-=ndelta; }
27662 else { z1-=z0; z0 = 0; }
27663 }
27664 if (go_dec) {
27665 const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
27666 if (z1+ndelta<dimz()) { z0+=ndelta; z1+=ndelta; }
27667 else { z0+=(depth-1-z1); z1 = depth-1; }
27668 }
27669 }
27670 disp.key = key;
27671 return *this;
27672 }
27674 //! Simple interface to select a shape from an image.
27675 /**
27676 \param selection Array of 6 values containing the selection result
27677 \param coords_type Determine shape type to select (0=point, 1=vector, 2=rectangle, 3=circle)
27678 \param disp Display window used to make the selection
27679 \param XYZ Initial XYZ position (for volumetric images only)
27680 \param color Color of the shape selector.
27681 **/
27682 CImg<T>& select(CImgDisplay &disp,
27683 const int select_type=2, unsigned int *const XYZ=0,
27684 const unsigned char *const color=0) {
27685 return get_select(disp,select_type,XYZ,color).transfer_to(*this);
27686 }
27688 //! Simple interface to select a shape from an image.
27689 CImg<T>& select(const char *const title,
27690 const int select_type=2, unsigned int *const XYZ=0,
27691 const unsigned char *const color=0) {
27692 return get_select(title,select_type,XYZ,color).transfer_to(*this);
27693 }
27695 //! Simple interface to select a shape from an image.
27696 CImg<intT> get_select(CImgDisplay &disp,
27697 const int select_type=2, unsigned int *const XYZ=0,
27698 const unsigned char *const color=0) const {
27699 return _get_select(disp,0,select_type,XYZ,color,0,0,0);
27700 }
27702 //! Simple interface to select a shape from an image.
27703 CImg<intT> get_select(const char *const title,
27704 const int select_type=2, unsigned int *const XYZ=0,
27705 const unsigned char *const color=0) const {
27706 CImgDisplay disp;
27707 return _get_select(disp,title,select_type,XYZ,color,0,0,0);
27708 }
27710 CImg<intT> _get_select(CImgDisplay &disp, const char *const title,
27711 const int coords_type, unsigned int *const XYZ,
27712 const unsigned char *const color,
27713 const int origX, const int origY, const int origZ) const {
27714 if (is_empty())
27715 throw CImgInstanceException("CImg<%s>::select() : Instance image (%u,%u,%u,%u,%p) is empty.",
27716 pixel_type(),width,height,depth,dim,data);
27717 if (!disp) {
27718 char ntitle[64] = { 0 }; if (!title) { cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); }
27719 disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
27720 }
27722 const unsigned int
27723 old_normalization = disp.normalization,
27724 hatch = 0x55555555;
27726 bool old_is_resized = disp.is_resized;
27727 disp.normalization = 0;
27728 disp.show().key = 0;
27730 unsigned char foreground_color[] = { 255,255,105 }, background_color[] = { 0,0,0 };
27731 if (color) cimg_std::memcpy(foreground_color,color,sizeof(unsigned char)*cimg::min(3,dimv()));
27733 int area = 0, clicked_area = 0, phase = 0,
27734 X0 = (int)((XYZ?XYZ[0]:width/2)%width), Y0 = (int)((XYZ?XYZ[1]:height/2)%height), Z0 = (int)((XYZ?XYZ[2]:depth/2)%depth),
27735 X1 =-1, Y1 = -1, Z1 = -1,
27736 X = -1, Y = -1, Z = -1,
27737 oX = X, oY = Y, oZ = Z;
27738 unsigned int old_button = 0, key = 0;
27740 bool shape_selected = false, text_down = false;
27741 CImg<ucharT> visu, visu0;
27742 char text[1024] = { 0 };
27744 while (!key && !disp.is_closed && !shape_selected) {
27746 // Handle mouse motion and selection
27747 oX = X; oY = Y; oZ = Z;
27748 int mx = disp.mouse_x, my = disp.mouse_y;
27749 const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height;
27751 area = 0;
27752 if (mX<dimx() && mY<dimy()) { area = 1; X = mX; Y = mY; Z = phase?Z1:Z0; }
27753 if (mX<dimx() && mY>=dimy()) { area = 2; X = mX; Z = mY-height; Y = phase?Y1:Y0; }
27754 if (mX>=dimx() && mY<dimy()) { area = 3; Y = mY; Z = mX-width; X = phase?X1:X0; }
27756 switch (key = disp.key) {
27757 case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
27758 case cimg::keyPAGEUP : if (disp.is_keyCTRLLEFT) { ++disp.wheel; key = 0; } break;
27759 case cimg::keyPAGEDOWN : if (disp.is_keyCTRLLEFT) { --disp.wheel; key = 0; } break;
27760 case cimg::keyD : if (disp.is_keyCTRLLEFT) {
27761 disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
27762 CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
27763 disp.key = key = 0;
27764 } break;
27765 case cimg::keyC : if (disp.is_keyCTRLLEFT) {
27766 disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
27767 disp.key = key = 0; visu0.assign();
27768 } break;
27769 case cimg::keyR : if (disp.is_keyCTRLLEFT) {
27770 disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false).is_resized = true;
27771 disp.key = key = 0; visu0.assign();
27772 } break;
27773 case cimg::keyF : if (disp.is_keyCTRLLEFT) {
27774 disp.resize(disp.screen_dimx(),disp.screen_dimy(),false).toggle_fullscreen().is_resized = true;
27775 disp.key = key = 0; visu0.assign();
27776 } break;
27777 case cimg::keyS : if (disp.is_keyCTRLLEFT) {
27778 static unsigned int snap_number = 0;
27779 char filename[32] = { 0 };
27780 cimg_std::FILE *file;
27781 do {
27782 cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
27783 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
27784 } while (file);
27785 if (visu0) {
27786 visu.draw_text(2,2,"Saving snapshot...",foreground_color,background_color,0.8f,11).display(disp);
27787 visu0.save(filename);
27788 visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
27789 }
27790 disp.key = key = 0;
27791 } break;
27792 case cimg::keyO : if (disp.is_keyCTRLLEFT) {
27793 static unsigned int snap_number = 0;
27794 char filename[32] = { 0 };
27795 cimg_std::FILE *file;
27796 do {
27797 cimg_std::sprintf(filename,"CImg_%.4u.cimg",snap_number++);
27798 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
27799 } while (file);
27800 visu.draw_text(2,2,"Saving instance...",foreground_color,background_color,0.8f,11).display(disp);
27801 save(filename);
27802 visu.draw_text(2,2,"Instance '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
27803 disp.key = key = 0;
27804 } break;
27805 }
27807 if (!area) mx = my = X = Y = Z = -1;
27808 else {
27809 if (disp.button&1 && phase<2) { X1 = X; Y1 = Y; Z1 = Z; }
27810 if (!(disp.button&1) && phase>=2) {
27811 switch (clicked_area) {
27812 case 1 : Z1 = Z; break;
27813 case 2 : Y1 = Y; break;
27814 case 3 : X1 = X; break;
27815 }
27816 }
27817 if (disp.button&2) { if (phase) { X1 = X; Y1 = Y; Z1 = Z; } else { X0 = X; Y0 = Y; Z0 = Z; } }
27818 if (disp.button&4) { oX = X = X0; oY = Y = Y0; oZ = Z = Z0; phase = 0; visu.assign(); }
27819 if (disp.wheel) {
27820 if (depth>1 && !disp.is_keyCTRLLEFT && !disp.is_keySHIFTLEFT && !disp.is_keyALT) {
27821 switch (area) {
27822 case 1 : if (phase) Z = (Z1+=disp.wheel); else Z = (Z0+=disp.wheel); break;
27823 case 2 : if (phase) Y = (Y1+=disp.wheel); else Y = (Y0+=disp.wheel); break;
27824 case 3 : if (phase) X = (X1+=disp.wheel); else X = (X0+=disp.wheel); break;
27825 }
27826 disp.wheel = 0;
27827 } else key = ~0U;
27828 }
27829 if ((disp.button&1)!=old_button) {
27830 switch (phase++) {
27831 case 0 : X0 = X1 = X; Y0 = Y1 = Y; Z0 = Z1 = Z; clicked_area = area; break;
27832 case 1 : X1 = X; Y1 = Y; Z1 = Z; break;
27833 }
27834 old_button = disp.button&1;
27835 }
27836 if (depth>1 && (X!=oX || Y!=oY || Z!=oZ)) visu0.assign();
27837 }
27839 if (phase) {
27840 if (!coords_type) shape_selected = phase?true:false;
27841 else {
27842 if (depth>1) shape_selected = (phase==3)?true:false;
27843 else shape_selected = (phase==2)?true:false;
27844 }
27845 }
27847 if (X0<0) X0 = 0; if (X0>=dimx()) X0 = dimx()-1; if (Y0<0) Y0 = 0; if (Y0>=dimy()) Y0 = dimy()-1;
27848 if (Z0<0) Z0 = 0; if (Z0>=dimz()) Z0 = dimz()-1;
27849 if (X1<1) X1 = 0; if (X1>=dimx()) X1 = dimx()-1; if (Y1<0) Y1 = 0; if (Y1>=dimy()) Y1 = dimy()-1;
27850 if (Z1<0) Z1 = 0; if (Z1>=dimz()) Z1 = dimz()-1;
27852 // Draw visualization image on the display
27853 if (oX!=X || oY!=Y || oZ!=Z || !visu0) {
27854 if (!visu0) {
27855 CImg<Tuchar> tmp, tmp0;
27856 if (depth!=1) {
27857 tmp0 = (!phase)?get_projections2d(X0,Y0,Z0):get_projections2d(X1,Y1,Z1);
27858 tmp = tmp0.get_channels(0,cimg::min(2U,dim-1));
27859 } else tmp = get_channels(0,cimg::min(2U,dim-1));
27860 switch (old_normalization) {
27861 case 0 : visu0 = tmp; break;
27862 case 3 :
27863 if (cimg::type<T>::is_float()) visu0 = tmp.normalize(0,(T)255);
27864 else {
27865 const float m = (float)cimg::type<T>::min(), M = (float)cimg::type<T>::max();
27866 visu0.assign(tmp.width,tmp.height,1,tmp.dim);
27867 unsigned char *ptrd = visu0.end();
27868 cimg_for(tmp,ptrs,Tuchar) *(--ptrd) = (unsigned char)((*ptrs-m)*255.0f/(M-m));
27869 } break;
27870 default : visu0 = tmp.normalize(0,255);
27871 }
27872 visu0.resize(disp);
27873 }
27874 visu = visu0;
27875 if (!color) {
27876 if (visu.mean()<200) {
27877 foreground_color[0] = foreground_color[1] = foreground_color[2] = 255;
27878 background_color[0] = background_color[1] = background_color[2] = 0;
27879 } else {
27880 foreground_color[0] = foreground_color[1] = foreground_color[2] = 0;
27881 background_color[0] = background_color[1] = background_color[2] = 255;
27882 }
27883 }
27885 const int d = (depth>1)?depth:0;
27886 if (phase) switch (coords_type) {
27887 case 1 : {
27888 const int
27889 x0 = (int)((X0+0.5f)*disp.width/(width+d)),
27890 y0 = (int)((Y0+0.5f)*disp.height/(height+d)),
27891 x1 = (int)((X1+0.5f)*disp.width/(width+d)),
27892 y1 = (int)((Y1+0.5f)*disp.height/(height+d));
27893 visu.draw_arrow(x0,y0,x1,y1,foreground_color,0.6f,30,5,hatch);
27894 if (d) {
27895 const int
27896 zx0 = (int)((width+Z0+0.5f)*disp.width/(width+d)),
27897 zx1 = (int)((width+Z1+0.5f)*disp.width/(width+d)),
27898 zy0 = (int)((height+Z0+0.5f)*disp.height/(height+d)),
27899 zy1 = (int)((height+Z1+0.5f)*disp.height/(height+d));
27900 visu.draw_arrow(zx0,y0,zx1,y1,foreground_color,0.6f,30,5,hatch).
27901 draw_arrow(x0,zy0,x1,zy1,foreground_color,0.6f,30,5,hatch);
27902 }
27903 } break;
27904 case 2 : {
27905 const int
27906 x0 = (X0<X1?X0:X1)*disp.width/(width+d), y0 = (Y0<Y1?Y0:Y1)*disp.height/(height+d),
27907 x1 = ((X0<X1?X1:X0)+1)*disp.width/(width+d)-1, y1 = ((Y0<Y1?Y1:Y0)+1)*disp.height/(height+d)-1;
27908 visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.2f).draw_rectangle(x0,y0,x1,y1,foreground_color,0.6f,hatch);
27909 if (d) {
27910 const int
27911 zx0 = (int)((width+(Z0<Z1?Z0:Z1))*disp.width/(width+d)),
27912 zy0 = (int)((height+(Z0<Z1?Z0:Z1))*disp.height/(height+d)),
27913 zx1 = (int)((width+(Z0<Z1?Z1:Z0)+1)*disp.width/(width+d))-1,
27914 zy1 = (int)((height+(Z0<Z1?Z1:Z0)+1)*disp.height/(height+d))-1;
27915 visu.draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.2f).draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.6f,hatch);
27916 visu.draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.2f).draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.6f,hatch);
27917 }
27918 } break;
27919 case 3 : {
27920 const int
27921 x0 = X0*disp.width/(width+d),
27922 y0 = Y0*disp.height/(height+d),
27923 x1 = X1*disp.width/(width+d)-1,
27924 y1 = Y1*disp.height/(height+d)-1;
27925 visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1,0,foreground_color,0.2f).
27926 draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1,0,foreground_color,0.6f,hatch);
27927 if (d) {
27928 const int
27929 zx0 = (int)((width+Z0)*disp.width/(width+d)),
27930 zy0 = (int)((height+Z0)*disp.height/(height+d)),
27931 zx1 = (int)((width+Z1+1)*disp.width/(width+d))-1,
27932 zy1 = (int)((height+Z1+1)*disp.height/(height+d))-1;
27933 visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1,0,foreground_color,0.2f).
27934 draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1,0,foreground_color,0.6f,hatch).
27935 draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1,0,foreground_color,0.2f).
27936 draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1,0,foreground_color,0.6f,hatch);
27937 }
27938 } break;
27939 } else {
27940 const int
27941 x0 = X*disp.width/(width+d),
27942 y0 = Y*disp.height/(height+d),
27943 x1 = (X+1)*disp.width/(width+d)-1,
27944 y1 = (Y+1)*disp.height/(height+d)-1;
27945 if (x1-x0>=4 && y1-y0>=4) visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.4f,~0U);
27946 }
27948 if (my<12) text_down = true;
27949 if (my>=visu.dimy()-11) text_down = false;
27950 if (!coords_type || !phase) {
27951 if (X>=0 && Y>=0 && Z>=0 && X<dimx() && Y<dimy() && Z<dimz()) {
27952 if (depth>1) cimg_std::sprintf(text,"Point (%d,%d,%d) = [ ",origX+X,origY+Y,origZ+Z);
27953 else cimg_std::sprintf(text,"Point (%d,%d) = [ ",origX+X,origY+Y);
27954 char *ctext = text + cimg::strlen(text), *const ltext = text + 512;
27955 for (unsigned int k=0; k<dim && ctext<ltext; ++k) {
27956 cimg_std::sprintf(ctext,cimg::type<T>::format(),cimg::type<T>::format((*this)(X,Y,Z,k)));
27957 ctext = text + cimg::strlen(text);
27958 *(ctext++) = ' '; *ctext = '\0';
27959 }
27960 cimg_std::sprintf(text + cimg::strlen(text),"]");
27961 }
27962 } else switch (coords_type) {
27963 case 1 : {
27964 const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), norm = cimg_std::sqrt(dX*dX+dY*dY+dZ*dZ);
27965 if (depth>1) cimg_std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), Norm = %g",
27966 origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,norm);
27967 else cimg_std::sprintf(text,"Vect (%d,%d)-(%d,%d), Norm = %g",
27968 origX+X0,origY+Y0,origX+X1,origY+Y1,norm);
27969 } break;
27970 case 2 :
27971 if (depth>1) cimg_std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size = (%d,%d,%d)",
27972 origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origZ+(Z0<Z1?Z0:Z1),
27973 origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),origZ+(Z0<Z1?Z1:Z0),
27974 1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
27975 else cimg_std::sprintf(text,"Box (%d,%d)-(%d,%d), Size = (%d,%d)",
27976 origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),
27977 1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
27978 break;
27979 default :
27980 if (depth>1) cimg_std::sprintf(text,"Ellipse (%d,%d,%d)-(%d,%d,%d), Radii = (%d,%d,%d)",
27981 origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,
27982 1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
27983 else cimg_std::sprintf(text,"Ellipse (%d,%d)-(%d,%d), Radii = (%d,%d)",
27984 origX+X0,origY+Y0,origX+X1,origY+Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
27986 }
27987 if (phase || (mx>=0 && my>=0)) visu.draw_text(0,text_down?visu.dimy()-11:0,text,foreground_color,background_color,0.7f,11);
27988 disp.display(visu).wait(25);
27989 } else if (!shape_selected) disp.wait();
27991 if (disp.is_resized) { disp.resize(false); old_is_resized = true; disp.is_resized = false; visu0.assign(); }
27992 }
27994 // Return result
27995 CImg<intT> res(1,6,1,1,-1);
27996 if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; }
27997 if (shape_selected) {
27998 if (coords_type==2) {
27999 if (X0>X1) cimg::swap(X0,X1);
28000 if (Y0>Y1) cimg::swap(Y0,Y1);
28001 if (Z0>Z1) cimg::swap(Z0,Z1);
28002 }
28003 if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1;
28004 switch (coords_type) {
28005 case 1 :
28006 case 2 : res[3] = X1; res[4] = Y1; res[5] = Z1;
28007 default : res[0] = X0; res[1] = Y0; res[2] = Z0;
28008 }
28009 }
28010 disp.button = 0;
28011 disp.normalization = old_normalization;
28012 disp.is_resized = old_is_resized;
28013 if (key!=~0U) disp.key = key;
28014 return res;
28015 }
28017 //! High-level interface for displaying a 3d object.
28018 template<typename tp, typename tf, typename tc, typename to>
28019 const CImg<T>& display_object3d(CImgDisplay& disp,
28020 const CImg<tp>& points, const CImgList<tf>& primitives,
28021 const CImgList<tc>& colors, const to& opacities,
28022 const bool centering=true,
28023 const int render_static=4, const int render_motion=1,
28024 const bool double_sided=false, const float focale=500,
28025 const float specular_light=0.2f, const float specular_shine=0.1f,
28026 const bool display_axes=true, float *const pose_matrix=0) const {
28027 return _display_object3d(disp,0,points,points.width,primitives,colors,opacities,centering,render_static,
28028 render_motion,double_sided,focale,specular_light,specular_shine,
28029 display_axes,pose_matrix);
28030 }
28032 //! High-level interface for displaying a 3d object.
28033 template<typename tp, typename tf, typename tc, typename to>
28034 const CImg<T>& display_object3d(const char *const title,
28035 const CImg<tp>& points, const CImgList<tf>& primitives,
28036 const CImgList<tc>& colors, const to& opacities,
28037 const bool centering=true,
28038 const int render_static=4, const int render_motion=1,
28039 const bool double_sided=false, const float focale=500,
28040 const float specular_light=0.2f, const float specular_shine=0.1f,
28041 const bool display_axes=true, float *const pose_matrix=0) const {
28042 CImgDisplay disp;
28043 return _display_object3d(disp,title,points,points.width,primitives,colors,opacities,centering,render_static,
28044 render_motion,double_sided,focale,specular_light,specular_shine,
28045 display_axes,pose_matrix);
28046 }
28048 //! High-level interface for displaying a 3d object.
28049 template<typename tp, typename tf, typename tc, typename to>
28050 const CImg<T>& display_object3d(CImgDisplay& disp,
28051 const CImgList<tp>& points, const CImgList<tf>& primitives,
28052 const CImgList<tc>& colors, const to& opacities,
28053 const bool centering=true,
28054 const int render_static=4, const int render_motion=1,
28055 const bool double_sided=false, const float focale=500,
28056 const float specular_light=0.2f, const float specular_shine=0.1f,
28057 const bool display_axes=true, float *const pose_matrix=0) const {
28058 return _display_object3d(disp,0,points,points.size,primitives,colors,opacities,centering,render_static,
28059 render_motion,double_sided,focale,specular_light,specular_shine,
28060 display_axes,pose_matrix);
28061 }
28063 //! High-level interface for displaying a 3d object.
28064 template<typename tp, typename tf, typename tc, typename to>
28065 const CImg<T>& display_object3d(const char *const title,
28066 const CImgList<tp>& points, const CImgList<tf>& primitives,
28067 const CImgList<tc>& colors, const to& opacities,
28068 const bool centering=true,
28069 const int render_static=4, const int render_motion=1,
28070 const bool double_sided=false, const float focale=500,
28071 const float specular_light=0.2f, const float specular_shine=0.1f,
28072 const bool display_axes=true, float *const pose_matrix=0) const {
28073 CImgDisplay disp;
28074 return _display_object3d(disp,title,points,points.size,primitives,colors,opacities,centering,render_static,
28075 render_motion,double_sided,focale,specular_light,specular_shine,
28076 display_axes,pose_matrix);
28077 }
28079 //! High-level interface for displaying a 3d object.
28080 template<typename tp, typename tf, typename tc>
28081 const CImg<T>& display_object3d(CImgDisplay &disp,
28082 const tp& points, const CImgList<tf>& primitives,
28083 const CImgList<tc>& colors,
28084 const bool centering=true,
28085 const int render_static=4, const int render_motion=1,
28086 const bool double_sided=false, const float focale=500,
28087 const float specular_light=0.2f, const float specular_shine=0.1f,
28088 const bool display_axes=true, float *const pose_matrix=0) const {
28089 return display_object3d(disp,points,primitives,colors,CImg<floatT>(),centering,
28090 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28091 display_axes,pose_matrix);
28092 }
28094 //! High-level interface for displaying a 3d object.
28095 template<typename tp, typename tf, typename tc>
28096 const CImg<T>& display_object3d(const char *const title,
28097 const tp& points, const CImgList<tf>& primitives,
28098 const CImgList<tc>& colors,
28099 const bool centering=true,
28100 const int render_static=4, const int render_motion=1,
28101 const bool double_sided=false, const float focale=500,
28102 const float specular_light=0.2f, const float specular_shine=0.1f,
28103 const bool display_axes=true, float *const pose_matrix=0) const {
28104 return display_object3d(title,points,primitives,colors,CImg<floatT>(),centering,
28105 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28106 display_axes,pose_matrix);
28107 }
28109 //! High-level interface for displaying a 3d object.
28110 template<typename tp, typename tf>
28111 const CImg<T>& display_object3d(CImgDisplay &disp,
28112 const tp& points, const CImgList<tf>& primitives,
28113 const bool centering=true,
28114 const int render_static=4, const int render_motion=1,
28115 const bool double_sided=false, const float focale=500,
28116 const float specular_light=0.2f, const float specular_shine=0.1f,
28117 const bool display_axes=true, float *const pose_matrix=0) const {
28118 return display_object3d(disp,points,primitives,CImgList<T>(),centering,
28119 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28120 display_axes,pose_matrix);
28121 }
28123 //! High-level interface for displaying a 3d object.
28124 template<typename tp, typename tf>
28125 const CImg<T>& display_object3d(const char *const title,
28126 const tp& points, const CImgList<tf>& primitives,
28127 const bool centering=true,
28128 const int render_static=4, const int render_motion=1,
28129 const bool double_sided=false, const float focale=500,
28130 const float specular_light=0.2f, const float specular_shine=0.1f,
28131 const bool display_axes=true, float *const pose_matrix=0) const {
28132 return display_object3d(title,points,primitives,CImgList<T>(),centering,
28133 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28134 display_axes,pose_matrix);
28135 }
28137 //! High-level interface for displaying a 3d object.
28138 template<typename tp>
28139 const CImg<T>& display_object3d(CImgDisplay &disp,
28140 const tp& points,
28141 const bool centering=true,
28142 const int render_static=4, const int render_motion=1,
28143 const bool double_sided=false, const float focale=500,
28144 const float specular_light=0.2f, const float specular_shine=0.1f,
28145 const bool display_axes=true, float *const pose_matrix=0) const {
28146 return display_object3d(disp,points,CImgList<uintT>(),centering,
28147 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28148 display_axes,pose_matrix);
28149 }
28151 //! High-level interface for displaying a 3d object.
28152 template<typename tp>
28153 const CImg<T>& display_object3d(const char *const title,
28154 const tp& points,
28155 const bool centering=true,
28156 const int render_static=4, const int render_motion=1,
28157 const bool double_sided=false, const float focale=500,
28158 const float specular_light=0.2f, const float specular_shine=0.1f,
28159 const bool display_axes=true, float *const pose_matrix=0) const {
28160 return display_object3d(title,points,CImgList<uintT>(),centering,
28161 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28162 display_axes,pose_matrix);
28163 }
28165 T _display_object3d_at2(const int i, const int j) const {
28166 return atXY(i,j,0,0,0);
28167 }
28169 template<typename tp, typename tf, typename tc, typename to>
28170 const CImg<T>& _display_object3d(CImgDisplay& disp, const char *const title,
28171 const tp& points, const unsigned int Npoints,
28172 const CImgList<tf>& primitives,
28173 const CImgList<tc>& colors, const to& opacities,
28174 const bool centering,
28175 const int render_static, const int render_motion,
28176 const bool double_sided, const float focale,
28177 const float specular_light, const float specular_shine,
28178 const bool display_axes, float *const pose_matrix) const {
28180 // Check input arguments
28181 if (!points || !Npoints)
28182 throw CImgArgumentException("CImg<%s>::display_object3d() : Given points are empty.",
28183 pixel_type());
28184 if (is_empty()) {
28185 if (disp) return CImg<T>(disp.width,disp.height,1,colors[0].size(),0).
28186 _display_object3d(disp,title,points,Npoints,primitives,colors,opacities,centering,
28187 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28188 display_axes,pose_matrix);
28189 else return CImg<T>(cimg_fitscreen(640,480,1),1,colors[0].size(),0).
28190 _display_object3d(disp,title,points,Npoints,primitives,colors,opacities,centering,
28191 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28192 display_axes,pose_matrix);
28193 }
28194 if (!primitives) {
28195 CImgList<tf> nprimitives(Npoints,1,1,1,1);
28196 cimglist_for(nprimitives,l) nprimitives(l,0) = l;
28197 return _display_object3d(disp,title,points,Npoints,nprimitives,colors,opacities,
28198 centering,render_static,render_motion,double_sided,focale,specular_light,specular_shine,
28199 display_axes,pose_matrix);
28200 }
28201 if (!disp) {
28202 char ntitle[64] = { 0 }; if (!title) { cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); }
28203 disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
28204 }
28206 CImgList<tc> _colors;
28207 if (!colors) _colors.insert(primitives.size,CImg<tc>::vector(200,200,200));
28208 const CImgList<tc> &ncolors = colors?colors:_colors;
28210 // Init 3D objects and compute object statistics
28211 CImg<floatT>
28212 pose, rot_mat, zbuffer,
28213 centered_points = centering?CImg<floatT>(Npoints,3):CImg<floatT>(),
28214 rotated_points(Npoints,3),
28215 bbox_points, rotated_bbox_points,
28216 axes_points, rotated_axes_points,
28217 bbox_opacities, axes_opacities;
28218 CImgList<uintT> bbox_primitives, axes_primitives;
28219 CImgList<T> bbox_colors, bbox_colors2, axes_colors;
28220 float dx = 0, dy = 0, dz = 0, ratio = 1;
28222 T minval = (T)0, maxval = (T)255;
28223 if (disp.normalization && colors) {
28224 minval = colors.minmax(maxval);
28225 if (minval==maxval) { minval = (T)0; maxval = (T)255; }
28226 }
28227 const float meanval = (float)mean();
28228 bool color_model = true;
28229 if (cimg::abs(meanval-minval)>cimg::abs(meanval-maxval)) color_model = false;
28230 const CImg<T>
28231 background_color(1,1,1,dim,color_model?minval:maxval),
28232 foreground_color(1,1,1,dim,color_model?maxval:minval);
28234 float xm = cimg::type<float>::max(), xM = 0, ym = xm, yM = 0, zm = xm, zM = 0;
28235 for (unsigned int i = 0; i<Npoints; ++i) {
28236 const float
28237 x = points._display_object3d_at2(i,0),
28238 y = points._display_object3d_at2(i,1),
28239 z = points._display_object3d_at2(i,2);
28240 if (x<xm) xm = x;
28241 if (x>xM) xM = x;
28242 if (y<ym) ym = y;
28243 if (y>yM) yM = y;
28244 if (z<zm) zm = z;
28245 if (z>zM) zM = z;
28246 }
28247 const float delta = cimg::max(xM-xm,yM-ym,zM-zm);
28249 if (display_axes) {
28250 rotated_axes_points = axes_points.assign(7,3,1,1,
28251 0,20,0,0,22,-6,-6,
28252 0,0,20,0,-6,22,-6,
28253 0,0,0,20,0,0,22);
28254 axes_opacities.assign(3,1,1,1,1);
28255 axes_colors.assign(3,dim,1,1,1,foreground_color[0]);
28256 axes_primitives.assign(3,1,2,1,1, 0,1, 0,2, 0,3);
28257 }
28259 // Begin user interaction loop
28260 CImg<T> visu0(*this), visu;
28261 bool init = true, clicked = false, redraw = true;
28262 unsigned int key = 0;
28263 int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
28264 disp.show().flush();
28266 while (!disp.is_closed && !key) {
28268 // Init object position and scale if necessary
28269 if (init) {
28270 ratio = delta>0?(2.0f*cimg::min(disp.width,disp.height)/(3.0f*delta)):0;
28271 dx = 0.5f*(xM + xm); dy = 0.5f*(yM + ym); dz = 0.5f*(zM + zm);
28272 if (centering) {
28273 cimg_forX(centered_points,l) {
28274 centered_points(l,0) = (float)((points(l,0) - dx)*ratio);
28275 centered_points(l,1) = (float)((points(l,1) - dy)*ratio);
28276 centered_points(l,2) = (float)((points(l,2) - dz)*ratio);
28277 }
28278 }
28280 if (render_static<0 || render_motion<0) {
28281 rotated_bbox_points = bbox_points.assign(8,3,1,1,
28282 xm,xM,xM,xm,xm,xM,xM,xm,
28283 ym,ym,yM,yM,ym,ym,yM,yM,
28284 zm,zm,zm,zm,zM,zM,zM,zM);
28285 bbox_primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 1,2,6,5, 0,4,7,3, 0,1,5,4, 2,3,7,6);
28286 bbox_colors.assign(6,dim,1,1,1,background_color[0]);
28287 bbox_colors2.assign(6,dim,1,1,1,foreground_color[0]);
28288 bbox_opacities.assign(bbox_colors.size,1,1,1,0.3f);
28289 }
28291 if (!pose) {
28292 if (pose_matrix) pose = CImg<floatT>(pose_matrix,4,4,1,1,false);
28293 else pose = CImg<floatT>::identity_matrix(4);
28294 }
28295 init = false;
28296 redraw = true;
28297 }
28299 // Rotate and Draw 3D object
28300 if (redraw) {
28301 const float
28302 r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0),
28303 r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1),
28304 r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2);
28305 if ((clicked && render_motion>=0) || (!clicked && render_static>=0)) {
28306 if (centering) cimg_forX(centered_points,l) {
28307 const float x = centered_points(l,0), y = centered_points(l,1), z = centered_points(l,2);
28308 rotated_points(l,0) = r00*x + r10*y + r20*z + r30;
28309 rotated_points(l,1) = r01*x + r11*y + r21*z + r31;
28310 rotated_points(l,2) = r02*x + r12*y + r22*z + r32;
28311 } else for (unsigned int l = 0; l<Npoints; ++l) {
28312 const float
28313 x = (float)points._display_object3d_at2(l,0),
28314 y = (float)points._display_object3d_at2(l,1),
28315 z = (float)points._display_object3d_at2(l,2);
28316 rotated_points(l,0) = r00*x + r10*y + r20*z + r30;
28317 rotated_points(l,1) = r01*x + r11*y + r21*z + r31;
28318 rotated_points(l,2) = r02*x + r12*y + r22*z + r32;
28319 }
28320 } else {
28321 if (!centering) cimg_forX(bbox_points,l) {
28322 const float x = bbox_points(l,0), y = bbox_points(l,1), z = bbox_points(l,2);
28323 rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30;
28324 rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31;
28325 rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32;
28326 } else cimg_forX(bbox_points,l) {
28327 const float x = (bbox_points(l,0)-dx)*ratio, y = (bbox_points(l,1)-dy)*ratio, z = (bbox_points(l,2)-dz)*ratio;
28328 rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30;
28329 rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31;
28330 rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32;
28331 }
28332 }
28334 // Draw object
28335 visu = visu0;
28336 if ((clicked && render_motion<0) || (!clicked && render_static<0))
28337 visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_points,bbox_primitives,bbox_colors,bbox_opacities,2,false,focale).
28338 draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_points,bbox_primitives,bbox_colors2,1,false,focale);
28339 else visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,
28340 rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
28341 double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
28342 (!clicked && render_static>0)?zbuffer.fill(0).ptr():0);
28344 // Draw axes
28345 if (display_axes) {
28346 const float Xaxes = 25, Yaxes = visu.height - 35.0f;
28347 cimg_forX(axes_points,l) {
28348 const float x = axes_points(l,0), y = axes_points(l,1), z = axes_points(l,2);
28349 rotated_axes_points(l,0) = r00*x + r10*y + r20*z;
28350 rotated_axes_points(l,1) = r01*x + r11*y + r21*z;
28351 rotated_axes_points(l,2) = r02*x + r12*y + r22*z;
28352 }
28353 axes_opacities(0,0) = (rotated_axes_points(1,2)>0)?0.5f:1.0f;
28354 axes_opacities(1,0) = (rotated_axes_points(2,2)>0)?0.5f:1.0f;
28355 axes_opacities(2,0) = (rotated_axes_points(3,2)>0)?0.5f:1.0f;
28356 visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_points,axes_primitives,axes_colors,axes_opacities,1,false,focale).
28357 draw_text((int)(Xaxes+rotated_axes_points(4,0)),
28358 (int)(Yaxes+rotated_axes_points(4,1)),
28359 "X",axes_colors[0].data,0,axes_opacities(0,0),11).
28360 draw_text((int)(Xaxes+rotated_axes_points(5,0)),
28361 (int)(Yaxes+rotated_axes_points(5,1)),
28362 "Y",axes_colors[1].data,0,axes_opacities(1,0),11).
28363 draw_text((int)(Xaxes+rotated_axes_points(6,0)),
28364 (int)(Yaxes+rotated_axes_points(6,1)),
28365 "Z",axes_colors[2].data,0,axes_opacities(2,0),11);
28366 }
28367 visu.display(disp);
28368 if (!clicked || render_motion==render_static) redraw = false;
28369 }
28371 // Handle user interaction
28372 disp.wait();
28373 if ((disp.button || disp.wheel) && disp.mouse_x>=0 && disp.mouse_y>=0) {
28374 redraw = true;
28375 if (!clicked) { x0 = x1 = disp.mouse_x; y0 = y1 = disp.mouse_y; if (!disp.wheel) clicked = true; }
28376 else { x1 = disp.mouse_x; y1 = disp.mouse_y; }
28377 if (disp.button&1) {
28378 const float
28379 R = 0.45f*cimg::min(disp.width,disp.height),
28380 R2 = R*R,
28381 u0 = (float)(x0-disp.dimx()/2),
28382 v0 = (float)(y0-disp.dimy()/2),
28383 u1 = (float)(x1-disp.dimx()/2),
28384 v1 = (float)(y1-disp.dimy()/2),
28385 n0 = (float)cimg_std::sqrt(u0*u0+v0*v0),
28386 n1 = (float)cimg_std::sqrt(u1*u1+v1*v1),
28387 nu0 = n0>R?(u0*R/n0):u0,
28388 nv0 = n0>R?(v0*R/n0):v0,
28389 nw0 = (float)cimg_std::sqrt(cimg::max(0,R2-nu0*nu0-nv0*nv0)),
28390 nu1 = n1>R?(u1*R/n1):u1,
28391 nv1 = n1>R?(v1*R/n1):v1,
28392 nw1 = (float)cimg_std::sqrt(cimg::max(0,R2-nu1*nu1-nv1*nv1)),
28393 u = nv0*nw1-nw0*nv1,
28394 v = nw0*nu1-nu0*nw1,
28395 w = nv0*nu1-nu0*nv1,
28396 n = (float)cimg_std::sqrt(u*u+v*v+w*w),
28397 alpha = (float)cimg_std::asin(n/R2);
28398 rot_mat = CImg<floatT>::rotation_matrix(u,v,w,alpha);
28399 rot_mat *= pose.get_crop(0,0,2,2);
28400 pose.draw_image(rot_mat);
28401 x0=x1; y0=y1;
28402 }
28403 if (disp.button&2) { pose(3,2)+=(y1-y0); x0 = x1; y0 = y1; }
28404 if (disp.wheel) { pose(3,2)-=focale*disp.wheel/10; disp.wheel = 0; }
28405 if (disp.button&4) { pose(3,0)+=(x1-x0); pose(3,1)+=(y1-y0); x0 = x1; y0 = y1; }
28406 if ((disp.button&1) && (disp.button&2)) { init = true; disp.button = 0; x0 = x1; y0 = y1; pose = CImg<floatT>::identity_matrix(4); }
28407 } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; }
28409 switch (key = disp.key) {
28410 case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
28411 case cimg::keyD: if (disp.is_keyCTRLLEFT) {
28412 disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
28413 CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
28414 disp.key = key = 0;
28415 } break;
28416 case cimg::keyC : if (disp.is_keyCTRLLEFT) {
28417 disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
28418 disp.key = key = 0;
28419 } break;
28420 case cimg::keyR : if (disp.is_keyCTRLLEFT) {
28421 disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false).is_resized = true;
28422 disp.key = key = 0;
28423 } break;
28424 case cimg::keyF : if (disp.is_keyCTRLLEFT) {
28425 disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
28426 disp.key = key = 0;
28427 } break;
28428 case cimg::keyZ : if (disp.is_keyCTRLLEFT) { // Enable/Disable Z-buffer
28429 if (zbuffer) zbuffer.assign();
28430 else zbuffer.assign(disp.width,disp.height);
28431 disp.key = key = 0; redraw = true;
28432 } break;
28433 case cimg::keyS : if (disp.is_keyCTRLLEFT) { // Save snapshot
28434 static unsigned int snap_number = 0;
28435 char filename[32] = { 0 };
28436 cimg_std::FILE *file;
28437 do {
28438 cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
28439 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
28440 } while (file);
28441 (+visu).draw_text(2,2,"Saving BMP snapshot...",foreground_color,background_color,1,11).display(disp);
28442 visu.save(filename);
28443 visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
28444 disp.key = key = 0;
28445 } break;
28446 case cimg::keyO : if (disp.is_keyCTRLLEFT) { // Save object as an .OFF file
28447 static unsigned int snap_number = 0;
28448 char filename[32] = { 0 };
28449 cimg_std::FILE *file;
28450 do {
28451 cimg_std::sprintf(filename,"CImg_%.4u.off",snap_number++);
28452 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
28453 } while (file);
28454 visu.draw_text(2,2,"Saving object...",foreground_color,background_color,1,11).display(disp);
28455 points.save_off(filename,primitives,ncolors);
28456 visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
28457 disp.key = key = 0;
28458 } break;
28459 #ifdef cimg_use_board
28460 case cimg::keyP : if (disp.is_keyCTRLLEFT) { // Save object as a .EPS file
28461 static unsigned int snap_number = 0;
28462 char filename[32] = { 0 };
28463 cimg_std::FILE *file;
28464 do {
28465 cimg_std::sprintf(filename,"CImg_%.4u.eps",snap_number++);
28466 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
28467 } while (file);
28468 visu.draw_text(2,2,"Saving EPS snapshot...",foreground_color,background_color,1,11).display(disp);
28469 BoardLib::Board board;
28470 (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
28471 rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
28472 double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
28473 zbuffer.fill(0).ptr());
28474 board.saveEPS(filename);
28475 visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
28476 disp.key = key = 0;
28477 } break;
28478 case cimg::keyV : if (disp.is_keyCTRLLEFT) { // Save object as a .SVG file
28479 static unsigned int snap_number = 0;
28480 char filename[32] = { 0 };
28481 cimg_std::FILE *file;
28482 do {
28483 cimg_std::sprintf(filename,"CImg_%.4u.svg",snap_number++);
28484 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
28485 } while (file);
28486 visu.draw_text(2,2,"Saving SVG snapshot...",foreground_color,background_color,1,11).display(disp);
28487 BoardLib::Board board;
28488 (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
28489 rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
28490 double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
28491 zbuffer.fill(0).ptr());
28492 board.saveSVG(filename);
28493 visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
28494 disp.key = key = 0;
28495 } break;
28496 #endif
28497 }
28498 if (disp.is_resized) { disp.resize(false); visu0 = get_resize(disp,1); if (zbuffer) zbuffer.assign(disp.width,disp.height); redraw = true; }
28499 }
28500 if (pose_matrix) cimg_std::memcpy(pose_matrix,pose.data,16*sizeof(float));
28501 disp.button = 0;
28502 disp.key = key;
28503 return *this;
28504 }
28506 //! High-level interface for displaying a graph.
28507 const CImg<T>& display_graph(CImgDisplay &disp,
28508 const unsigned int plot_type=1, const unsigned int vertex_type=1,
28509 const char *const labelx=0, const double xmin=0, const double xmax=0,
28510 const char *const labely=0, const double ymin=0, const double ymax=0) const {
28511 if (is_empty())
28512 throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
28513 pixel_type(),width,height,depth,dim,data);
28514 const unsigned int siz = width*height*depth, onormalization = disp.normalization;
28515 if (!disp) { char ntitle[64] = { 0 }; cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
28516 disp.show().flush().normalization = 0;
28517 double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax;
28518 if (nxmin==nxmax) { nxmin = 0; nxmax = siz - 1.0; }
28519 int x0 = 0, x1 = size()/dimv()-1, key = 0;
28521 for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
28522 if (reset_view) { x0 = 0; x1 = size()/dimv()-1; y0 = ymin; y1 = ymax; reset_view = false; }
28523 CImg<T> zoom(x1-x0+1,1,1,dimv());
28524 cimg_forV(*this,k) zoom.get_shared_channel(k) = CImg<T>(ptr(x0,0,0,k),x1-x0+1,1,1,1,true);
28526 if (y0==y1) y0 = zoom.minmax(y1);
28527 if (y0==y1) { --y0; ++y1; }
28528 const CImg<intT> selection = zoom.get_select_graph(disp,plot_type,vertex_type,
28529 labelx,nxmin + x0*(nxmax-nxmin)/siz,nxmin + x1*(nxmax-nxmin)/siz,
28530 labely,y0,y1);
28532 const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
28533 if (selection[0]>=0 && selection[2]>=0) {
28534 x1 = x0 + selection[2];
28535 x0 += selection[0];
28536 if (x0==x1) reset_view = true;
28537 if (selection[1]>=0 && selection[3]>=0) {
28538 y0 = y1 - selection[3]*(y1-y0)/(disp.dimy()-32);
28539 y1 -= selection[1]*(y1-y0)/(disp.dimy()-32);
28540 }
28541 } else {
28542 bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false;
28543 switch (key = disp.key) {
28544 case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
28545 case cimg::keyPADADD : go_in = true; key = 0; break;
28546 case cimg::keyPADSUB : go_out = true; key = 0; break;
28547 case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; key = 0; break;
28548 case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; key = 0; break;
28549 case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; key = 0; break;
28550 case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; key = 0; break;
28551 case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; break;
28552 case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; break;
28553 case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; break;
28554 case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; break;
28555 }
28556 if (disp.wheel) go_out = !(go_in = disp.wheel>0);
28558 if (go_in) {
28559 const int
28560 xsiz = x1 - x0,
28561 mx = (mouse_x-16)*xsiz/(disp.dimx()-32),
28562 cx = x0 + (mx<0?0:(mx>=xsiz?xsiz:mx));
28563 if (x1-x0>4) {
28564 x0 = cx - 7*(cx-x0)/8; x1 = cx + 7*(x1-cx)/8;
28565 if (disp.is_keyCTRLLEFT) {
28566 const double
28567 ysiz = y1 - y0,
28568 my = (mouse_y-16)*ysiz/(disp.dimy()-32),
28569 cy = y1 - (my<0?0:(my>=ysiz?ysiz:my));
28570 y0 = cy - 7*(cy-y0)/8; y1 = cy + 7*(y1-cy)/8;
28571 } else y0 = y1 = 0;
28572 }
28573 }
28574 if (go_out) {
28575 const int deltax = (x1-x0)/8, ndeltax = deltax?deltax:(siz>1?1:0);
28576 x0-=ndeltax; x1+=ndeltax;
28577 if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz-1; }
28578 if (x1>=(int)siz) { x0-=(x1-siz+1); x1 = (int)siz-1; if (x0<0) x0 = 0; }
28579 if (disp.is_keyCTRLLEFT) {
28580 const double deltay = (y1-y0)/8, ndeltay = deltay?deltay:0.01;
28581 y0-=ndeltay; y1+=ndeltay;
28582 }
28583 }
28584 if (go_left) {
28585 const int delta = (x1-x0)/5, ndelta = delta?delta:1;
28586 if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
28587 else { x1-=x0; x0 = 0; }
28588 go_left = false;
28589 }
28590 if (go_right) {
28591 const int delta = (x1-x0)/5, ndelta = delta?delta:1;
28592 if (x1+ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; }
28593 else { x0+=(siz-1-x1); x1 = siz-1; }
28594 go_right = false;
28595 }
28596 if (go_up) {
28597 const double delta = (y1-y0)/10, ndelta = delta?delta:1;
28598 y0+=ndelta; y1+=ndelta;
28599 go_up = false;
28600 }
28601 if (go_down) {
28602 const double delta = (y1-y0)/10, ndelta = delta?delta:1;
28603 y0-=ndelta; y1-=ndelta;
28604 go_down = false;
28605 }
28606 }
28607 }
28608 disp.normalization = onormalization;
28609 return *this;
28610 }
28612 //! High-level interface for displaying a graph.
28613 const CImg<T>& display_graph(const char *const title=0,
28614 const unsigned int plot_type=1, const unsigned int vertex_type=1,
28615 const char *const labelx=0, const double xmin=0, const double xmax=0,
28616 const char *const labely=0, const double ymin=0, const double ymax=0) const {
28617 if (is_empty())
28618 throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
28619 pixel_type(),width,height,depth,dim,data);
28620 char ntitle[64] = { 0 }; if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
28621 CImgDisplay disp(cimg_fitscreen(640,480,1),title?title:ntitle,0);
28622 return display_graph(disp,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax);
28623 }
28625 //! Select sub-graph in a graph.
28626 CImg<intT> get_select_graph(CImgDisplay &disp,
28627 const unsigned int plot_type=1, const unsigned int vertex_type=1,
28628 const char *const labelx=0, const double xmin=0, const double xmax=0,
28629 const char *const labely=0, const double ymin=0, const double ymax=0) const {
28630 if (is_empty())
28631 throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
28632 pixel_type(),width,height,depth,dim,data);
28633 const unsigned int siz = width*height*depth, onormalization = disp.normalization;
28634 if (!disp) { char ntitle[64] = { 0 }; cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
28635 disp.show().key = disp.normalization = disp.button = disp.wheel = 0; // Must keep 'key' field unchanged.
28636 double nymin = ymin, nymax = ymax, nxmin = xmin, nxmax = xmax;
28637 if (nymin==nymax) nymin = (Tfloat)minmax(nymax);
28638 if (nymin==nymax) { --nymin; ++nymax; }
28639 if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; }
28641 const unsigned char black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 220,220,220 };
28642 const unsigned char gray2[] = { 110,110,110 }, ngray[] = { 35,35,35 };
28643 static unsigned int odimv = 0;
28644 static CImg<ucharT> palette;
28645 if (odimv!=dim) {
28646 odimv = dim;
28647 palette = CImg<ucharT>(3,dim,1,1,120).noise(70,1);
28648 if (dim==1) { palette[0] = palette[1] = 120; palette[2] = 200; }
28649 else {
28650 palette(0,0) = 220; palette(1,0) = 10; palette(2,0) = 10;
28651 if (dim>1) { palette(0,1) = 10; palette(1,1) = 220; palette(2,1) = 10; }
28652 if (dim>2) { palette(0,2) = 10; palette(1,2) = 10; palette(2,2) = 220; }
28653 }
28654 }
28656 CImg<ucharT> visu0, visu, graph, text, axes;
28657 const unsigned int whz = width*height*depth;
28658 int x0 = -1, x1 = -1, y0 = -1, y1 = -1, omouse_x = -2, omouse_y = -2;
28659 char message[1024] = { 0 };
28660 unsigned int okey = 0, obutton = 0;
28661 CImg_3x3(I,unsigned char);
28663 for (bool selected = false; !selected && !disp.is_closed && !okey && !disp.wheel; ) {
28664 const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
28665 const unsigned int key = disp.key, button = disp.button;
28667 // Generate graph representation.
28668 if (!visu0) {
28669 visu0.assign(disp.dimx(),disp.dimy(),1,3,220);
28670 const int gdimx = disp.dimx() - 32, gdimy = disp.dimy() - 32;
28671 if (gdimx>0 && gdimy>0) {
28672 graph.assign(gdimx,gdimy,1,3,255);
28673 graph.draw_grid(-10,-10,0,0,false,true,black,0.2f,0x33333333,0x33333333);
28674 cimg_forV(*this,k) graph.draw_graph(get_shared_channel(k),&palette(0,k),(plot_type!=3 || dim==1)?1:0.6f,
28675 plot_type,vertex_type,nymax,nymin);
28677 axes.assign(gdimx,gdimy,1,1,0);
28678 const float
28679 dx = (float)cimg::abs(nxmax-nxmin), dy = (float)cimg::abs(nymax-nymin),
28680 px = (float)cimg_std::pow(10.0,(int)cimg_std::log10(dx)-2.0),
28681 py = (float)cimg_std::pow(10.0,(int)cimg_std::log10(dy)-2.0);
28682 const CImg<Tdouble>
28683 seqx = CImg<Tdouble>::sequence(1 + gdimx/60,nxmin,nxmax).round(px),
28684 seqy = CImg<Tdouble>::sequence(1 + gdimy/60,nymax,nymin).round(py);
28685 axes.draw_axis(seqx,seqy,white);
28686 if (nymin>0) axes.draw_axis(seqx,gdimy-1,gray);
28687 if (nymax<0) axes.draw_axis(seqx,0,gray);
28688 if (nxmin>0) axes.draw_axis(0,seqy,gray);
28689 if (nxmax<0) axes.draw_axis(gdimx-1,seqy,gray);
28691 cimg_for3x3(axes,x,y,0,0,I)
28692 if (Icc) {
28693 if (Icc==255) cimg_forV(graph,k) graph(x,y,k) = 0;
28694 else cimg_forV(graph,k) graph(x,y,k) = (unsigned char)(2*graph(x,y,k)/3);
28695 }
28696 else if (Ipc || Inc || Icp || Icn || Ipp || Inn || Ipn || Inp) cimg_forV(graph,k) graph(x,y,k) = (graph(x,y,k)+255)/2;
28698 visu0.draw_image(16,16,graph);
28699 visu0.draw_line(15,15,16+gdimx,15,gray2).draw_line(16+gdimx,15,16+gdimx,16+gdimy,gray2).
28700 draw_line(16+gdimx,16+gdimy,15,16+gdimy,white).draw_line(15,16+gdimy,15,15,white);
28701 } else graph.assign();
28702 text.assign().draw_text(0,0,labelx?labelx:"X-axis",white,ngray,1);
28703 visu0.draw_image((visu0.dimx()-text.dimx())/2,visu0.dimy()-14,~text);
28704 text.assign().draw_text(0,0,labely?labely:"Y-axis",white,ngray,1).rotate(-90);
28705 visu0.draw_image(2,(visu0.dimy()-text.dimy())/2,~text);
28706 visu.assign();
28707 }
28709 // Generate and display current view.
28710 if (!visu) {
28711 visu.assign(visu0);
28712 if (graph && x0>=0 && x1>=0) {
28713 const int
28714 nx0 = x0<=x1?x0:x1,
28715 nx1 = x0<=x1?x1:x0,
28716 ny0 = y0<=y1?y0:y1,
28717 ny1 = y0<=y1?y1:y0,
28718 sx0 = 16 + nx0*(visu.dimx()-32)/whz,
28719 sx1 = 15 + (nx1+1)*(visu.dimx()-32)/whz,
28720 sy0 = 16 + ny0,
28721 sy1 = 16 + ny1;
28723 if (y0>=0 && y1>=0)
28724 visu.draw_rectangle(sx0,sy0,sx1,sy1,gray,0.5f).draw_rectangle(sx0,sy0,sx1,sy1,black,0.5f,0xCCCCCCCCU);
28725 else visu.draw_rectangle(sx0,0,sx1,visu.dimy()-17,gray,0.5f).
28726 draw_line(sx0,16,sx0,visu.dimy()-17,black,0.5f,0xCCCCCCCCU).
28727 draw_line(sx1,16,sx1,visu.dimy()-17,black,0.5f,0xCCCCCCCCU);
28728 }
28729 if (mouse_x>=16 && mouse_y>=16 && mouse_x<visu.dimx()-16 && mouse_y<visu.dimy()-16) {
28730 if (graph) visu.draw_line(mouse_x,16,mouse_x,visu.dimy()-17,black,0.5f,0x55555555U);
28731 const unsigned x = (mouse_x-16)*whz/(disp.dimx()-32);
28732 const double cx = nxmin + x*(nxmax-nxmin)/whz;
28733 if (dim>=7)
28734 cimg_std::sprintf(message,"Value[%g] = ( %g %g %g ... %g %g %g )",cx,
28735 (double)(*this)(x,0,0,0),(double)(*this)(x,0,0,1),(double)(*this)(x,0,0,2),
28736 (double)(*this)(x,0,0,dim-4),(double)(*this)(x,0,0,dim-3),(double)(*this)(x,0,0,dim-1));
28737 else {
28738 cimg_std::sprintf(message,"Value[%g] = ( ",cx);
28739 cimg_forV(*this,k) cimg_std::sprintf(message+cimg::strlen(message),"%g ",(double)(*this)(x,0,0,k));
28740 cimg_std::sprintf(message+cimg::strlen(message),")");
28741 }
28742 if (x0>=0 && x1>=0) {
28743 const int
28744 nx0 = x0<=x1?x0:x1,
28745 nx1 = x0<=x1?x1:x0,
28746 ny0 = y0<=y1?y0:y1,
28747 ny1 = y0<=y1?y1:y0;
28748 const double
28749 cx0 = nxmin + nx0*(nxmax-nxmin)/(visu.dimx()-32),
28750 cx1 = nxmin + nx1*(nxmax-nxmin)/(visu.dimx()-32),
28751 cy0 = nymax - ny0*(nymax-nymin)/(visu.dimy()-32),
28752 cy1 = nymax - ny1*(nymax-nymin)/(visu.dimy()-32);
28753 if (y0>=0 && y1>=0)
28754 cimg_std::sprintf(message+cimg::strlen(message)," - Range ( %g, %g ) - ( %g, %g )",cx0,cy0,cx1,cy1);
28755 else
28756 cimg_std::sprintf(message+cimg::strlen(message)," - Range [ %g - %g ]",cx0,cx1);
28757 }
28758 text.assign().draw_text(0,0,message,white,ngray,1);
28759 visu.draw_image((visu.dimx()-text.dimx())/2,2,~text);
28760 }
28761 visu.display(disp);
28762 }
28764 // Test keys.
28765 switch (okey = key) {
28766 case cimg::keyCTRLLEFT : okey = 0; break;
28767 case cimg::keyD : if (disp.is_keyCTRLLEFT) {
28768 disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
28769 CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
28770 disp.key = okey = 0;
28771 } break;
28772 case cimg::keyC : if (disp.is_keyCTRLLEFT) {
28773 disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
28774 disp.key = okey = 0;
28775 } break;
28776 case cimg::keyR : if (disp.is_keyCTRLLEFT) {
28777 disp.normalscreen().resize(cimg_fitscreen(640,480,1),false).is_resized = true;
28778 disp.key = okey = 0;
28779 } break;
28780 case cimg::keyF : if (disp.is_keyCTRLLEFT) {
28781 disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
28782 disp.key = okey = 0;
28783 } break;
28784 case cimg::keyS : if (disp.is_keyCTRLLEFT) {
28785 static unsigned int snap_number = 0;
28786 if (visu || visu0) {
28787 CImg<ucharT> &screen = visu?visu:visu0;
28788 char filename[32] = { 0 };
28789 cimg_std::FILE *file;
28790 do {
28791 cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
28792 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
28793 } while (file);
28794 (+screen).draw_text(2,2,"Saving BMP snapshot...",black,gray,1,11).display(disp);
28795 screen.save(filename);
28796 screen.draw_text(2,2,"Snapshot '%s' saved.",black,gray,1,11,filename).display(disp);
28797 }
28798 disp.key = okey = 0;
28799 } break;
28800 }
28802 // Handle mouse motion and mouse buttons
28803 if (obutton!=button || omouse_x!=mouse_x || omouse_y!=mouse_y) {
28804 visu.assign();
28805 if (disp.mouse_x>=0 && disp.mouse_y>=0) {
28806 const int
28807 mx = (mouse_x-16)*(int)whz/(disp.dimx()-32),
28808 cx = mx<0?0:(mx>=(int)whz?whz-1:mx),
28809 my = mouse_y-16,
28810 cy = my<=0?0:(my>=(disp.dimy()-32)?(disp.dimy()-32):my);
28811 if (button&1) { if (!obutton) { x0 = cx; y0 = -1; } else { x1 = cx; y1 = -1; }}
28812 else if (button&2) { if (!obutton) { x0 = cx; y0 = cy; } else { x1 = cx; y1 = cy; }}
28813 else if (obutton) { x1 = cx; y1 = y1>=0?cy:-1; selected = true; }
28814 } else if (!button && obutton) selected = true;
28815 obutton = button; omouse_x = mouse_x; omouse_y = mouse_y;
28816 }
28817 if (disp.is_resized) { disp.resize(false); visu0.assign(); }
28818 if (visu && visu0) disp.wait();
28819 }
28820 disp.normalization = onormalization;
28821 if (x1<x0) cimg::swap(x0,x1);
28822 if (y1<y0) cimg::swap(y0,y1);
28823 disp.key = okey;
28824 return CImg<intT>(4,1,1,1,x0,y0,x1,y1);
28825 }
28827 //@}
28828 //---------------------------
28829 //
28830 //! \name Image File Loading
28831 //@{
28832 //---------------------------
28834 //! Load an image from a file.
28835 /**
28836 \param filename is the name of the image file to load.
28837 \note The extension of \c filename defines the file format. If no filename
28838 extension is provided, CImg<T>::get_load() will try to load a .cimg file.
28839 **/
28840 CImg<T>& load(const char *const filename) {
28841 if (!filename)
28842 throw CImgArgumentException("CImg<%s>::load() : Cannot load (null) filename.",
28843 pixel_type());
28844 const char *ext = cimg::split_filename(filename);
28845 const unsigned int odebug = cimg::exception_mode();
28846 cimg::exception_mode() = 0;
28847 assign();
28848 try {
28849 #ifdef cimg_load_plugin
28850 cimg_load_plugin(filename);
28851 #endif
28852 #ifdef cimg_load_plugin1
28853 cimg_load_plugin1(filename);
28854 #endif
28855 #ifdef cimg_load_plugin2
28856 cimg_load_plugin2(filename);
28857 #endif
28858 #ifdef cimg_load_plugin3
28859 cimg_load_plugin3(filename);
28860 #endif
28861 #ifdef cimg_load_plugin4
28862 cimg_load_plugin4(filename);
28863 #endif
28864 #ifdef cimg_load_plugin5
28865 cimg_load_plugin5(filename);
28866 #endif
28867 #ifdef cimg_load_plugin6
28868 cimg_load_plugin6(filename);
28869 #endif
28870 #ifdef cimg_load_plugin7
28871 cimg_load_plugin7(filename);
28872 #endif
28873 #ifdef cimg_load_plugin8
28874 cimg_load_plugin8(filename);
28875 #endif
28876 // ASCII formats
28877 if (!cimg::strcasecmp(ext,"asc")) load_ascii(filename);
28878 if (!cimg::strcasecmp(ext,"dlm") ||
28879 !cimg::strcasecmp(ext,"txt")) load_dlm(filename);
28881 // 2D binary formats
28882 if (!cimg::strcasecmp(ext,"bmp")) load_bmp(filename);
28883 if (!cimg::strcasecmp(ext,"jpg") ||
28884 !cimg::strcasecmp(ext,"jpeg") ||
28885 !cimg::strcasecmp(ext,"jpe") ||
28886 !cimg::strcasecmp(ext,"jfif") ||
28887 !cimg::strcasecmp(ext,"jif")) load_jpeg(filename);
28888 if (!cimg::strcasecmp(ext,"png")) load_png(filename);
28889 if (!cimg::strcasecmp(ext,"ppm") ||
28890 !cimg::strcasecmp(ext,"pgm") ||
28891 !cimg::strcasecmp(ext,"pnm")) load_pnm(filename);
28892 if (!cimg::strcasecmp(ext,"tif") ||
28893 !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
28894 if (!cimg::strcasecmp(ext,"cr2") ||
28895 !cimg::strcasecmp(ext,"crw") ||
28896 !cimg::strcasecmp(ext,"dcr") ||
28897 !cimg::strcasecmp(ext,"mrw") ||
28898 !cimg::strcasecmp(ext,"nef") ||
28899 !cimg::strcasecmp(ext,"orf") ||
28900 !cimg::strcasecmp(ext,"pix") ||
28901 !cimg::strcasecmp(ext,"ptx") ||
28902 !cimg::strcasecmp(ext,"raf") ||
28903 !cimg::strcasecmp(ext,"srf")) load_dcraw_external(filename);
28905 // 3D binary formats
28906 if (!cimg::strcasecmp(ext,"dcm") ||
28907 !cimg::strcasecmp(ext,"dicom")) load_medcon_external(filename);
28908 if (!cimg::strcasecmp(ext,"hdr") ||
28909 !cimg::strcasecmp(ext,"nii")) load_analyze(filename);
28910 if (!cimg::strcasecmp(ext,"par") ||
28911 !cimg::strcasecmp(ext,"rec")) load_parrec(filename);
28912 if (!cimg::strcasecmp(ext,"inr")) load_inr(filename);
28913 if (!cimg::strcasecmp(ext,"pan")) load_pandore(filename);
28914 if (!cimg::strcasecmp(ext,"cimg") ||
28915 !cimg::strcasecmp(ext,"cimgz") ||
28916 *ext=='\0') return load_cimg(filename);
28918 // Archive files
28919 if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
28921 // Image sequences
28922 if (!cimg::strcasecmp(ext,"avi") ||
28923 !cimg::strcasecmp(ext,"mov") ||
28924 !cimg::strcasecmp(ext,"asf") ||
28925 !cimg::strcasecmp(ext,"divx") ||
28926 !cimg::strcasecmp(ext,"flv") ||
28927 !cimg::strcasecmp(ext,"mpg") ||
28928 !cimg::strcasecmp(ext,"m1v") ||
28929 !cimg::strcasecmp(ext,"m2v") ||
28930 !cimg::strcasecmp(ext,"m4v") ||
28931 !cimg::strcasecmp(ext,"mjp") ||
28932 !cimg::strcasecmp(ext,"mkv") ||
28933 !cimg::strcasecmp(ext,"mpe") ||
28934 !cimg::strcasecmp(ext,"movie") ||
28935 !cimg::strcasecmp(ext,"ogm") ||
28936 !cimg::strcasecmp(ext,"qt") ||
28937 !cimg::strcasecmp(ext,"rm") ||
28938 !cimg::strcasecmp(ext,"vob") ||
28939 !cimg::strcasecmp(ext,"wmv") ||
28940 !cimg::strcasecmp(ext,"xvid") ||
28941 !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
28942 if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
28943 } catch (CImgException& e) {
28944 if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
28945 cimg::exception_mode() = odebug;
28946 throw CImgIOException("CImg<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
28947 } else try {
28948 const char *const ftype = cimg::file_type(0,filename);
28949 assign();
28950 if (!cimg::strcmp(ftype,"pnm")) load_pnm(filename);
28951 if (!cimg::strcmp(ftype,"bmp")) load_bmp(filename);
28952 if (!cimg::strcmp(ftype,"jpeg")) load_jpeg(filename);
28953 if (!cimg::strcmp(ftype,"pan")) load_pandore(filename);
28954 if (!cimg::strcmp(ftype,"png")) load_png(filename);
28955 if (!cimg::strcmp(ftype,"tiff")) load_tiff(filename);
28956 if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
28957 } catch (CImgException&) {
28958 try {
28959 load_other(filename);
28960 } catch (CImgException&) {
28961 assign();
28962 }
28963 }
28964 }
28965 cimg::exception_mode() = odebug;
28966 if (is_empty())
28967 throw CImgIOException("CImg<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
28968 return *this;
28969 }
28971 static CImg<T> get_load(const char *const filename) {
28972 return CImg<T>().load(filename);
28973 }
28975 //! Load an image from an ASCII file.
28976 CImg<T>& load_ascii(const char *const filename) {
28977 return _load_ascii(0,filename);
28978 }
28980 static CImg<T> get_load_ascii(const char *const filename) {
28981 return CImg<T>().load_ascii(filename);
28982 }
28984 //! Load an image from an ASCII file.
28985 CImg<T>& load_ascii(cimg_std::FILE *const file) {
28986 return _load_ascii(file,0);
28987 }
28989 static CImg<T> get_load_ascii(cimg_std::FILE *const file) {
28990 return CImg<T>().load_ascii(file);
28991 }
28993 CImg<T>& _load_ascii(cimg_std::FILE *const file, const char *const filename) {
28994 if (!filename && !file)
28995 throw CImgArgumentException("CImg<%s>::load_ascii() : Cannot load (null) filename.",
28996 pixel_type());
28997 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
28998 char line[256] = { 0 };
28999 int err = cimg_std::fscanf(nfile,"%*[^0-9]%255[^\n]",line);
29000 unsigned int off, dx = 0, dy = 1, dz = 1, dv = 1;
29001 cimg_std::sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dv);
29002 err = cimg_std::fscanf(nfile,"%*[^0-9.+-]");
29003 if (!dx || !dy || !dz || !dv) {
29004 if (!file) cimg::fclose(nfile);
29005 throw CImgIOException("CImg<%s>::load_ascii() : File '%s', invalid .ASC header, specified image dimensions are (%u,%u,%u,%u).",
29006 pixel_type(),filename?filename:"(FILE*)",dx,dy,dz,dv);
29007 }
29008 assign(dx,dy,dz,dv);
29009 const unsigned long siz = size();
29010 double val;
29011 T *ptr = data;
29012 for (err = 1, off = 0; off<siz && err==1; ++off) {
29013 err = cimg_std::fscanf(nfile,"%lf%*[^0-9.+-]",&val);
29014 *(ptr++) = (T)val;
29015 }
29016 if (err!=1)
29017 cimg::warn("CImg<%s>::load_ascii() : File '%s', only %u/%lu values read.",
29018 pixel_type(),filename?filename:"(FILE*)",off-1,siz);
29019 if (!file) cimg::fclose(nfile);
29020 return *this;
29021 }
29023 //! Load an image from a DLM file.
29024 CImg<T>& load_dlm(const char *const filename) {
29025 return _load_dlm(0,filename);
29026 }
29028 static CImg<T> get_load_dlm(const char *const filename) {
29029 return CImg<T>().load_dlm(filename);
29030 }
29032 //! Load an image from a DLM file.
29033 CImg<T>& load_dlm(cimg_std::FILE *const file) {
29034 return _load_dlm(file,0);
29035 }
29037 static CImg<T> get_load_dlm(cimg_std::FILE *const file) {
29038 return CImg<T>().load_dlm(file);
29039 }
29041 CImg<T>& _load_dlm(cimg_std::FILE *const file, const char *const filename) {
29042 if (!filename && !file)
29043 throw CImgArgumentException("CImg<%s>::load_dlm() : Cannot load (null) filename.",
29044 pixel_type());
29045 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
29046 assign(256,256);
29047 char c, delimiter[256] = { 0 }, tmp[256];
29048 unsigned int cdx = 0, dx = 0, dy = 0;
29049 int oerr = 0, err;
29050 double val;
29051 while ((err = cimg_std::fscanf(nfile,"%lf%255[^0-9.+-]",&val,delimiter))!=EOF) {
29052 oerr = err;
29053 if (err>0) (*this)(cdx++,dy) = (T)val;
29054 if (cdx>=width) resize(width+256,1,1,1,0);
29055 c = 0; if (!cimg_std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') {
29056 dx = cimg::max(cdx,dx);
29057 ++dy;
29058 if (dy>=height) resize(width,height+256,1,1,0);
29059 cdx = 0;
29060 }
29061 }
29062 if (cdx && oerr==1) { dx=cdx; ++dy; }
29063 if (!dx || !dy) {
29064 if (!file) cimg::fclose(nfile);
29065 throw CImgIOException("CImg<%s>::load_dlm() : File '%s', invalid DLM file, specified image dimensions are (%u,%u).",
29066 pixel_type(),filename?filename:"(FILE*)",dx,dy);
29067 }
29068 resize(dx,dy,1,1,0);
29069 if (!file) cimg::fclose(nfile);
29070 return *this;
29071 }
29073 //! Load an image from a BMP file.
29074 CImg<T>& load_bmp(const char *const filename) {
29075 return _load_bmp(0,filename);
29076 }
29078 static CImg<T> get_load_bmp(const char *const filename) {
29079 return CImg<T>().load_bmp(filename);
29080 }
29082 //! Load an image from a BMP file.
29083 CImg<T>& load_bmp(cimg_std::FILE *const file) {
29084 return _load_bmp(file,0);
29085 }
29087 static CImg<T> get_load_bmp(cimg_std::FILE *const file) {
29088 return CImg<T>().load_bmp(file);
29089 }
29091 CImg<T>& _load_bmp(cimg_std::FILE *const file, const char *const filename) {
29092 if (!filename && !file)
29093 throw CImgArgumentException("CImg<%s>::load_bmp() : Cannot load (null) filename.",
29094 pixel_type());
29095 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29096 unsigned char header[64];
29097 cimg::fread(header,54,nfile);
29098 if (header[0]!='B' || header[1]!='M') {
29099 if (!file) cimg::fclose(nfile);
29100 throw CImgIOException("CImg<%s>::load_bmp() : Invalid valid BMP file (filename '%s').",
29101 pixel_type(),filename?filename:"(FILE*)");
29102 }
29103 assign();
29105 // Read header and pixel buffer
29106 int
29107 file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24),
29108 offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24),
29109 dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24),
29110 dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24),
29111 compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24),
29112 nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24),
29113 bpp = header[0x1C] + (header[0x1D]<<8),
29114 *palette = 0;
29115 const int
29116 dx_bytes = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)),
29117 align = (4-dx_bytes%4)%4,
29118 buf_size = cimg::min(cimg::abs(dy)*(dx_bytes+align),file_size-offset);
29120 if (bpp<16) { if (!nb_colors) nb_colors=1<<bpp; } else nb_colors = 0;
29121 if (nb_colors) { palette = new int[nb_colors]; cimg::fread(palette,nb_colors,nfile); }
29122 const int xoffset = offset-54-4*nb_colors;
29123 if (xoffset>0) cimg_std::fseek(nfile,xoffset,SEEK_CUR);
29124 unsigned char *buffer = new unsigned char[buf_size], *ptrs = buffer;
29125 cimg::fread(buffer,buf_size,nfile);
29126 if (!file) cimg::fclose(nfile);
29128 // Decompress buffer (if necessary)
29129 if (compression) {
29130 delete[] buffer;
29131 if (file) {
29132 throw CImgIOException("CImg<%s>::load_bmp() : Not able to read a compressed BMP file using a *FILE input",
29133 pixel_type());
29134 } else return load_other(filename);
29135 }
29137 // Read pixel data
29138 assign(dx,cimg::abs(dy),1,3);
29139 switch (bpp) {
29140 case 1 : { // Monochrome
29141 for (int y=height-1; y>=0; --y) {
29142 unsigned char mask = 0x80, val = 0;
29143 cimg_forX(*this,x) {
29144 if (mask==0x80) val = *(ptrs++);
29145 const unsigned char *col = (unsigned char*)(palette+(val&mask?1:0));
29146 (*this)(x,y,2) = (T)*(col++);
29147 (*this)(x,y,1) = (T)*(col++);
29148 (*this)(x,y,0) = (T)*(col++);
29149 mask = cimg::ror(mask);
29150 } ptrs+=align; }
29151 } break;
29152 case 4 : { // 16 colors
29153 for (int y=height-1; y>=0; --y) {
29154 unsigned char mask = 0xF0, val = 0;
29155 cimg_forX(*this,x) {
29156 if (mask==0xF0) val = *(ptrs++);
29157 const unsigned char color = (unsigned char)((mask<16)?(val&mask):((val&mask)>>4));
29158 unsigned char *col = (unsigned char*)(palette+color);
29159 (*this)(x,y,2) = (T)*(col++);
29160 (*this)(x,y,1) = (T)*(col++);
29161 (*this)(x,y,0) = (T)*(col++);
29162 mask = cimg::ror(mask,4);
29163 } ptrs+=align; }
29164 } break;
29165 case 8 : { // 256 colors
29166 for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
29167 const unsigned char *col = (unsigned char*)(palette+*(ptrs++));
29168 (*this)(x,y,2) = (T)*(col++);
29169 (*this)(x,y,1) = (T)*(col++);
29170 (*this)(x,y,0) = (T)*(col++);
29171 } ptrs+=align; }
29172 } break;
29173 case 16 : { // 16 bits colors
29174 for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
29175 const unsigned char c1 = *(ptrs++), c2 = *(ptrs++);
29176 const unsigned short col = (unsigned short)(c1|(c2<<8));
29177 (*this)(x,y,2) = (T)(col&0x1F);
29178 (*this)(x,y,1) = (T)((col>>5)&0x1F);
29179 (*this)(x,y,0) = (T)((col>>10)&0x1F);
29180 } ptrs+=align; }
29181 } break;
29182 case 24 : { // 24 bits colors
29183 for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
29184 (*this)(x,y,2) = (T)*(ptrs++);
29185 (*this)(x,y,1) = (T)*(ptrs++);
29186 (*this)(x,y,0) = (T)*(ptrs++);
29187 } ptrs+=align; }
29188 } break;
29189 case 32 : { // 32 bits colors
29190 for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
29191 (*this)(x,y,2) = (T)*(ptrs++);
29192 (*this)(x,y,1) = (T)*(ptrs++);
29193 (*this)(x,y,0) = (T)*(ptrs++);
29194 ++ptrs;
29195 } ptrs+=align; }
29196 } break;
29197 }
29198 if (palette) delete[] palette;
29199 delete[] buffer;
29200 if (dy<0) mirror('y');
29201 return *this;
29202 }
29204 //! Load an image from a JPEG file.
29205 CImg<T>& load_jpeg(const char *const filename) {
29206 return _load_jpeg(0,filename);
29207 }
29209 static CImg<T> get_load_jpeg(const char *const filename) {
29210 return CImg<T>().load_jpeg(filename);
29211 }
29213 //! Load an image from a JPEG file.
29214 CImg<T>& load_jpeg(cimg_std::FILE *const file) {
29215 return _load_jpeg(file,0);
29216 }
29218 static CImg<T> get_load_jpeg(cimg_std::FILE *const file) {
29219 return CImg<T>().load_jpeg(file);
29220 }
29222 CImg<T>& _load_jpeg(cimg_std::FILE *const file, const char *const filename) {
29223 if (!filename && !file)
29224 throw CImgArgumentException("CImg<%s>::load_jpeg() : Cannot load (null) filename.",
29225 pixel_type());
29226 #ifndef cimg_use_jpeg
29227 if (file)
29228 throw CImgIOException("CImg<%s>::load_jpeg() : File '(FILE*)' cannot be read without using libjpeg.",
29229 pixel_type());
29230 else return load_other(filename);
29231 #else
29232 struct jpeg_decompress_struct cinfo;
29233 struct jpeg_error_mgr jerr;
29234 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29236 cinfo.err = jpeg_std_error(&jerr);
29237 jpeg_create_decompress(&cinfo);
29238 jpeg_stdio_src(&cinfo,nfile);
29239 jpeg_read_header(&cinfo,TRUE);
29240 jpeg_start_decompress(&cinfo);
29242 if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) {
29243 cimg::warn("CImg<%s>::load_jpeg() : Don't know how to read image '%s' with libpeg, trying ImageMagick's convert",
29244 pixel_type(),filename?filename:"(FILE*)");
29245 if (!file) return load_other(filename);
29246 else {
29247 if (!file) cimg::fclose(nfile);
29248 throw CImgIOException("CImg<%s>::load_jpeg() : Cannot read JPEG image '%s' using a *FILE input.",
29249 pixel_type(),filename?filename:"(FILE*)");
29250 }
29251 }
29253 const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
29254 unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components], *buf2 = buf;
29255 JSAMPROW row_pointer[1];
29256 while (cinfo.output_scanline < cinfo.output_height) {
29257 row_pointer[0] = &buf[cinfo.output_scanline*row_stride];
29258 jpeg_read_scanlines(&cinfo,row_pointer,1);
29259 }
29260 jpeg_finish_decompress(&cinfo);
29261 jpeg_destroy_decompress(&cinfo);
29262 if (!file) cimg::fclose(nfile);
29264 assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components);
29265 switch (dim) {
29266 case 1 : {
29267 T *ptr_g = data;
29268 cimg_forXY(*this,x,y) *(ptr_g++) = (T)*(buf2++);
29269 } break;
29270 case 3 : {
29271 T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
29272 cimg_forXY(*this,x,y) {
29273 *(ptr_r++) = (T)*(buf2++);
29274 *(ptr_g++) = (T)*(buf2++);
29275 *(ptr_b++) = (T)*(buf2++);
29276 }
29277 } break;
29278 case 4 : {
29279 T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1),
29280 *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3);
29281 cimg_forXY(*this,x,y) {
29282 *(ptr_r++) = (T)*(buf2++);
29283 *(ptr_g++) = (T)*(buf2++);
29284 *(ptr_b++) = (T)*(buf2++);
29285 *(ptr_a++) = (T)*(buf2++);
29286 }
29287 } break;
29288 }
29289 delete[] buf;
29290 return *this;
29291 #endif
29292 }
29294 //! Load an image from a file, using Magick++ library.
29295 // Added April/may 2006 by Christoph Hormann <chris_hormann@gmx.de>
29296 // This is experimental code, not much tested, use with care.
29297 CImg<T>& load_magick(const char *const filename) {
29298 if (!filename)
29299 throw CImgArgumentException("CImg<%s>::load_magick() : Cannot load (null) filename.",
29300 pixel_type());
29301 #ifdef cimg_use_magick
29302 Magick::Image image(filename);
29303 const unsigned int W = image.size().width(), H = image.size().height();
29304 switch (image.type()) {
29305 case Magick::PaletteMatteType :
29306 case Magick::TrueColorMatteType :
29307 case Magick::ColorSeparationType : {
29308 assign(W,H,1,4);
29309 T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2), *adata = ptr(0,0,0,3);
29310 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29311 for (unsigned int off = W*H; off; --off) {
29312 *(rdata++) = (T)(pixels->red);
29313 *(gdata++) = (T)(pixels->green);
29314 *(bdata++) = (T)(pixels->blue);
29315 *(adata++) = (T)(pixels->opacity);
29316 ++pixels;
29317 }
29318 } break;
29319 case Magick::PaletteType :
29320 case Magick::TrueColorType : {
29321 assign(W,H,1,3);
29322 T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
29323 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29324 for (unsigned int off = W*H; off; --off) {
29325 *(rdata++) = (T)(pixels->red);
29326 *(gdata++) = (T)(pixels->green);
29327 *(bdata++) = (T)(pixels->blue);
29328 ++pixels;
29329 }
29330 } break;
29331 case Magick::GrayscaleMatteType : {
29332 assign(W,H,1,2);
29333 T *data = ptr(0,0,0,0), *adata = ptr(0,0,0,1);
29334 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29335 for (unsigned int off = W*H; off; --off) {
29336 *(data++) = (T)(pixels->red);
29337 *(adata++) = (T)(pixels->opacity);
29338 ++pixels;
29339 }
29340 } break;
29341 default : {
29342 assign(W,H,1,1);
29343 T *data = ptr(0,0,0,0);
29344 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
29345 for (unsigned int off = W*H; off; --off) {
29346 *(data++) = (T)(pixels->red);
29347 ++pixels;
29348 }
29349 }
29350 }
29351 #else
29352 throw CImgIOException("CImg<%s>::load_magick() : File '%s', Magick++ library has not been linked.",
29353 pixel_type(),filename);
29354 #endif
29355 return *this;
29356 }
29358 static CImg<T> get_load_magick(const char *const filename) {
29359 return CImg<T>().load_magick(filename);
29360 }
29362 //! Load an image from a PNG file.
29363 CImg<T>& load_png(const char *const filename) {
29364 return _load_png(0,filename);
29365 }
29367 static CImg<T> get_load_png(const char *const filename) {
29368 return CImg<T>().load_png(filename);
29369 }
29371 //! Load an image from a PNG file.
29372 CImg<T>& load_png(cimg_std::FILE *const file) {
29373 return _load_png(file,0);
29374 }
29376 static CImg<T> get_load_png(cimg_std::FILE *const file) {
29377 return CImg<T>().load_png(file);
29378 }
29380 // (Note : Most of this function has been written by Eric Fausett)
29381 CImg<T>& _load_png(cimg_std::FILE *const file, const char *const filename) {
29382 if (!filename && !file)
29383 throw CImgArgumentException("CImg<%s>::load_png() : Cannot load (null) filename.",
29384 pixel_type());
29385 #ifndef cimg_use_png
29386 if (file)
29387 throw CImgIOException("CImg<%s>::load_png() : File '(FILE*)' cannot be read without using libpng.",
29388 pixel_type());
29389 else return load_other(filename);
29390 #else
29391 // Open file and check for PNG validity
29392 const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
29393 cimg_std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb");
29395 unsigned char pngCheck[8];
29396 cimg::fread(pngCheck,8,(cimg_std::FILE*)nfile);
29397 if (png_sig_cmp(pngCheck,0,8)) {
29398 if (!file) cimg::fclose(nfile);
29399 throw CImgIOException("CImg<%s>::load_png() : File '%s' is not a valid PNG file.",
29400 pixel_type(),nfilename?nfilename:"(FILE*)");
29401 }
29403 // Setup PNG structures for read
29404 png_voidp user_error_ptr = 0;
29405 png_error_ptr user_error_fn = 0, user_warning_fn = 0;
29406 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn);
29407 if (!png_ptr) {
29408 if (!file) cimg::fclose(nfile);
29409 throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'png_ptr' data structure.",
29410 pixel_type(),nfilename?nfilename:"(FILE*)");
29411 }
29412 png_infop info_ptr = png_create_info_struct(png_ptr);
29413 if (!info_ptr) {
29414 if (!file) cimg::fclose(nfile);
29415 png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0);
29416 throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'info_ptr' data structure.",
29417 pixel_type(),nfilename?nfilename:"(FILE*)");
29418 }
29419 png_infop end_info = png_create_info_struct(png_ptr);
29420 if (!end_info) {
29421 if (!file) cimg::fclose(nfile);
29422 png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0);
29423 throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'end_info' data structure.",
29424 pixel_type(),nfilename?nfilename:"(FILE*)");
29425 }
29427 // Error handling callback for png file reading
29428 if (setjmp(png_jmpbuf(png_ptr))) {
29429 if (!file) cimg::fclose((cimg_std::FILE*)nfile);
29430 png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
29431 throw CImgIOException("CImg<%s>::load_png() : File '%s', unknown fatal error.",
29432 pixel_type(),nfilename?nfilename:"(FILE*)");
29433 }
29434 png_init_io(png_ptr, nfile);
29435 png_set_sig_bytes(png_ptr, 8);
29437 // Get PNG Header Info up to data block
29438 png_read_info(png_ptr,info_ptr);
29439 png_uint_32 W, H;
29440 int bit_depth, color_type, interlace_type;
29441 png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,int_p_NULL,int_p_NULL);
29442 int new_bit_depth = bit_depth;
29443 int new_color_type = color_type;
29445 // Transforms to unify image data
29446 if (new_color_type == PNG_COLOR_TYPE_PALETTE){
29447 png_set_palette_to_rgb(png_ptr);
29448 new_color_type -= PNG_COLOR_MASK_PALETTE;
29449 new_bit_depth = 8;
29450 }
29451 if (new_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){
29452 png_set_gray_1_2_4_to_8(png_ptr);
29453 new_bit_depth = 8;
29454 }
29455 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
29456 png_set_tRNS_to_alpha(png_ptr);
29457 if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){
29458 png_set_gray_to_rgb(png_ptr);
29459 new_color_type |= PNG_COLOR_MASK_COLOR;
29460 }
29461 if (new_color_type == PNG_COLOR_TYPE_RGB)
29462 png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);
29463 png_read_update_info(png_ptr,info_ptr);
29464 if (!(new_bit_depth==8 || new_bit_depth==16)) {
29465 if (!file) cimg::fclose(nfile);
29466 png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
29467 throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong bit coding (bit_depth=%u)",
29468 pixel_type(),nfilename?nfilename:"(FILE*)",new_bit_depth);
29469 }
29470 const int byte_depth = new_bit_depth>>3;
29472 // Allocate Memory for Image Read
29473 png_bytep *imgData = new png_bytep[H];
29474 for (unsigned int row = 0; row<H; ++row) imgData[row] = new png_byte[byte_depth*4*W];
29475 png_read_image(png_ptr,imgData);
29476 png_read_end(png_ptr,end_info);
29478 // Read pixel data
29479 if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA)) {
29480 if (!file) cimg::fclose(nfile);
29481 png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);
29482 throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong color coding (new_color_type=%u)",
29483 pixel_type(),nfilename?nfilename:"(FILE*)",new_color_type);
29484 }
29485 const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB);
29486 assign(W,H,1,no_alpha_channel?3:4);
29487 T *ptr1 = ptr(0,0,0,0), *ptr2 = ptr(0,0,0,1), *ptr3 = ptr(0,0,0,2), *ptr4 = ptr(0,0,0,3);
29488 switch (new_bit_depth) {
29489 case 8 : {
29490 cimg_forY(*this,y){
29491 const unsigned char *ptrs = (unsigned char*)imgData[y];
29492 cimg_forX(*this,x){
29493 *(ptr1++) = (T)*(ptrs++);
29494 *(ptr2++) = (T)*(ptrs++);
29495 *(ptr3++) = (T)*(ptrs++);
29496 if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
29497 }
29498 }
29499 } break;
29500 case 16 : {
29501 cimg_forY(*this,y){
29502 const unsigned short *ptrs = (unsigned short*)(imgData[y]);
29503 if (!cimg::endianness()) cimg::invert_endianness(ptrs,4*width);
29504 cimg_forX(*this,x){
29505 *(ptr1++) = (T)*(ptrs++);
29506 *(ptr2++) = (T)*(ptrs++);
29507 *(ptr3++) = (T)*(ptrs++);
29508 if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
29509 }
29510 }
29511 } break;
29512 }
29513 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
29515 // Deallocate Image Read Memory
29516 cimg_forY(*this,n) delete[] imgData[n];
29517 delete[] imgData;
29518 if (!file) cimg::fclose(nfile);
29519 return *this;
29520 #endif
29521 }
29523 //! Load an image from a PNM file.
29524 CImg<T>& load_pnm(const char *const filename) {
29525 return _load_pnm(0,filename);
29526 }
29528 static CImg<T> get_load_pnm(const char *const filename) {
29529 return CImg<T>().load_pnm(filename);
29530 }
29532 //! Load an image from a PNM file.
29533 CImg<T>& load_pnm(cimg_std::FILE *const file) {
29534 return _load_pnm(file,0);
29535 }
29537 static CImg<T> get_load_pnm(cimg_std::FILE *const file) {
29538 return CImg<T>().load_pnm(file);
29539 }
29541 CImg<T>& _load_pnm(cimg_std::FILE *const file, const char *const filename) {
29542 if (!filename && !file)
29543 throw CImgArgumentException("CImg<%s>::load_pnm() : Cannot load (null) filename.",
29544 pixel_type());
29545 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29546 unsigned int ppm_type, W, H, colormax = 255;
29547 char item[1024] = { 0 };
29548 int err, rval, gval, bval;
29549 const int cimg_iobuffer = 12*1024*1024;
29550 while ((err=cimg_std::fscanf(nfile,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
29551 if (cimg_std::sscanf(item," P%u",&ppm_type)!=1) {
29552 if (!file) cimg::fclose(nfile);
29553 throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PNM header 'P?' not found.",
29554 pixel_type(),filename?filename:"(FILE*)");
29555 }
29556 while ((err=cimg_std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
29557 if ((err=cimg_std::sscanf(item," %u %u %u",&W,&H,&colormax))<2) {
29558 if (!file) cimg::fclose(nfile);
29559 throw CImgIOException("CImg<%s>::load_pnm() : File '%s', WIDTH and HEIGHT fields are not defined in PNM header.",
29560 pixel_type(),filename?filename:"(FILE*)");
29561 }
29562 if (err==2) {
29563 while ((err=cimg_std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
29564 if (cimg_std::sscanf(item,"%u",&colormax)!=1)
29565 cimg::warn("CImg<%s>::load_pnm() : File '%s', COLORMAX field is not defined in PNM header.",
29566 pixel_type(),filename?filename:"(FILE*)");
29567 }
29568 cimg_std::fgetc(nfile);
29569 assign();
29571 switch (ppm_type) {
29572 case 2 : { // Grey Ascii
29573 assign(W,H,1,1);
29574 T* rdata = data;
29575 cimg_foroff(*this,off) { if (cimg_std::fscanf(nfile,"%d",&rval)>0) *(rdata++) = (T)rval; else break; }
29576 } break;
29577 case 3 : { // Color Ascii
29578 assign(W,H,1,3);
29579 T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
29580 cimg_forXY(*this,x,y) {
29581 if (cimg_std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval)==3) { *(rdata++) = (T)rval; *(gdata++) = (T)gval; *(bdata++) = (T)bval; }
29582 else break;
29583 }
29584 } break;
29585 case 5 : { // Grey Binary
29586 if (colormax<256) { // 8 bits
29587 CImg<ucharT> raw;
29588 assign(W,H,1,1);
29589 T *ptrd = ptr(0,0,0,0);
29590 for (int toread = (int)size(); toread>0; ) {
29591 raw.assign(cimg::min(toread,cimg_iobuffer));
29592 cimg::fread(raw.data,raw.width,nfile);
29593 toread-=raw.width;
29594 const unsigned char *ptrs = raw.data;
29595 for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
29596 }
29597 } else { // 16 bits
29598 CImg<ushortT> raw;
29599 assign(W,H,1,1);
29600 T *ptrd = ptr(0,0,0,0);
29601 for (int toread = (int)size(); toread>0; ) {
29602 raw.assign(cimg::min(toread,cimg_iobuffer/2));
29603 cimg::fread(raw.data,raw.width,nfile);
29604 if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
29605 toread-=raw.width;
29606 const unsigned short *ptrs = raw.data;
29607 for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
29608 }
29609 }
29610 } break;
29611 case 6 : { // Color Binary
29612 if (colormax<256) { // 8 bits
29613 CImg<ucharT> raw;
29614 assign(W,H,1,3);
29615 T
29616 *ptr_r = ptr(0,0,0,0),
29617 *ptr_g = ptr(0,0,0,1),
29618 *ptr_b = ptr(0,0,0,2);
29619 for (int toread = (int)size(); toread>0; ) {
29620 raw.assign(cimg::min(toread,cimg_iobuffer));
29621 cimg::fread(raw.data,raw.width,nfile);
29622 toread-=raw.width;
29623 const unsigned char *ptrs = raw.data;
29624 for (unsigned int off = raw.width/3; off; --off) {
29625 *(ptr_r++) = (T)*(ptrs++);
29626 *(ptr_g++) = (T)*(ptrs++);
29627 *(ptr_b++) = (T)*(ptrs++);
29628 }
29629 }
29630 } else { // 16 bits
29631 CImg<ushortT> raw;
29632 assign(W,H,1,3);
29633 T
29634 *ptr_r = ptr(0,0,0,0),
29635 *ptr_g = ptr(0,0,0,1),
29636 *ptr_b = ptr(0,0,0,2);
29637 for (int toread = (int)size(); toread>0; ) {
29638 raw.assign(cimg::min(toread,cimg_iobuffer/2));
29639 cimg::fread(raw.data,raw.width,nfile);
29640 if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
29641 toread-=raw.width;
29642 const unsigned short *ptrs = raw.data;
29643 for (unsigned int off = raw.width/3; off; --off) {
29644 *(ptr_r++) = (T)*(ptrs++);
29645 *(ptr_g++) = (T)*(ptrs++);
29646 *(ptr_b++) = (T)*(ptrs++);
29647 }
29648 }
29649 }
29650 } break;
29651 default :
29652 if (!file) cimg::fclose(nfile);
29653 throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PPM type 'P%d' not supported.",
29654 pixel_type(),filename?filename:"(FILE*)",ppm_type);
29655 }
29656 if (!file) cimg::fclose(nfile);
29657 return *this;
29658 }
29660 //! Load an image from a RGB file.
29661 CImg<T>& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
29662 return _load_rgb(0,filename,dimw,dimh);
29663 }
29665 static CImg<T> get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
29666 return CImg<T>().load_rgb(filename,dimw,dimh);
29667 }
29669 //! Load an image from a RGB file.
29670 CImg<T>& load_rgb(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
29671 return _load_rgb(file,0,dimw,dimh);
29672 }
29674 static CImg<T> get_load_rgb(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
29675 return CImg<T>().load_rgb(file,dimw,dimh);
29676 }
29678 CImg<T>& _load_rgb(cimg_std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
29679 if (!filename && !file)
29680 throw CImgArgumentException("CImg<%s>::load_rgb() : Cannot load (null) filename.",
29681 pixel_type());
29682 if (!dimw || !dimh) return assign();
29683 const int cimg_iobuffer = 12*1024*1024;
29684 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29685 CImg<ucharT> raw;
29686 assign(dimw,dimh,1,3);
29687 T
29688 *ptr_r = ptr(0,0,0,0),
29689 *ptr_g = ptr(0,0,0,1),
29690 *ptr_b = ptr(0,0,0,2);
29691 for (int toread = (int)size(); toread>0; ) {
29692 raw.assign(cimg::min(toread,cimg_iobuffer));
29693 cimg::fread(raw.data,raw.width,nfile);
29694 toread-=raw.width;
29695 const unsigned char *ptrs = raw.data;
29696 for (unsigned int off = raw.width/3; off; --off) {
29697 *(ptr_r++) = (T)*(ptrs++);
29698 *(ptr_g++) = (T)*(ptrs++);
29699 *(ptr_b++) = (T)*(ptrs++);
29700 }
29701 }
29702 if (!file) cimg::fclose(nfile);
29703 return *this;
29704 }
29706 //! Load an image from a RGBA file.
29707 CImg<T>& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
29708 return _load_rgba(0,filename,dimw,dimh);
29709 }
29711 static CImg<T> get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
29712 return CImg<T>().load_rgba(filename,dimw,dimh);
29713 }
29715 //! Load an image from a RGBA file.
29716 CImg<T>& load_rgba(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
29717 return _load_rgba(file,0,dimw,dimh);
29718 }
29720 static CImg<T> get_load_rgba(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
29721 return CImg<T>().load_rgba(file,dimw,dimh);
29722 }
29724 CImg<T>& _load_rgba(cimg_std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
29725 if (!filename && !file)
29726 throw CImgArgumentException("CImg<%s>::load_rgba() : Cannot load (null) filename.",
29727 pixel_type());
29728 if (!dimw || !dimh) return assign();
29729 const int cimg_iobuffer = 12*1024*1024;
29730 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
29731 CImg<ucharT> raw;
29732 assign(dimw,dimh,1,4);
29733 T
29734 *ptr_r = ptr(0,0,0,0),
29735 *ptr_g = ptr(0,0,0,1),
29736 *ptr_b = ptr(0,0,0,2),
29737 *ptr_a = ptr(0,0,0,3);
29738 for (int toread = (int)size(); toread>0; ) {
29739 raw.assign(cimg::min(toread,cimg_iobuffer));
29740 cimg::fread(raw.data,raw.width,nfile);
29741 toread-=raw.width;
29742 const unsigned char *ptrs = raw.data;
29743 for (unsigned int off = raw.width/4; off; --off) {
29744 *(ptr_r++) = (T)*(ptrs++);
29745 *(ptr_g++) = (T)*(ptrs++);
29746 *(ptr_b++) = (T)*(ptrs++);
29747 *(ptr_a++) = (T)*(ptrs++);
29748 }
29749 }
29750 if (!file) cimg::fclose(nfile);
29751 return *this;
29752 }
29754 //! Load an image from a TIFF file.
29755 CImg<T>& load_tiff(const char *const filename,
29756 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
29757 const unsigned int step_frame=1) {
29758 if (!filename)
29759 throw CImgArgumentException("CImg<%s>::load_tiff() : Cannot load (null) filename.",
29760 pixel_type());
29761 const unsigned int
29762 nfirst_frame = first_frame<last_frame?first_frame:last_frame,
29763 nstep_frame = step_frame?step_frame:1;
29764 unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
29766 #ifndef cimg_use_tiff
29767 if (nfirst_frame || nlast_frame!=~0U || nstep_frame>1)
29768 throw CImgArgumentException("CImg<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
29769 "('cimg_use_tiff' must be defined).",
29770 pixel_type(),filename);
29771 return load_other(filename);
29772 #else
29773 TIFF *tif = TIFFOpen(filename,"r");
29774 if (tif) {
29775 unsigned int nb_images = 0;
29776 do ++nb_images; while (TIFFReadDirectory(tif));
29777 if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
29778 cimg::warn("CImg<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
29779 pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
29780 if (nfirst_frame>=nb_images) return assign();
29781 if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
29782 TIFFSetDirectory(tif,0);
29783 CImg<T> frame;
29784 for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) {
29785 frame._load_tiff(tif,l);
29786 if (l==nfirst_frame) assign(frame.width,frame.height,1+(nlast_frame-nfirst_frame)/nstep_frame,frame.dim);
29787 if (frame.width>width || frame.height>height || frame.dim>dim)
29788 resize(cimg::max(frame.width,width),cimg::max(frame.height,height),-100,cimg::max(frame.dim,dim),0);
29789 draw_image(0,0,(l-nfirst_frame)/nstep_frame,frame);
29790 }
29791 TIFFClose(tif);
29792 } else throw CImgException("CImg<%s>::load_tiff() : File '%s' cannot be opened.",
29793 pixel_type(),filename);
29794 return *this;
29795 #endif
29796 }
29798 static CImg<T> get_load_tiff(const char *const filename,
29799 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
29800 const unsigned int step_frame=1) {
29801 return CImg<T>().load_tiff(filename,first_frame,last_frame,step_frame);
29802 }
29804 // (Original contribution by Jerome Boulanger).
29805 #ifdef cimg_use_tiff
29806 CImg<T>& _load_tiff(TIFF *tif, const unsigned int directory) {
29807 if (!TIFFSetDirectory(tif,directory)) return assign();
29808 uint16 samplesperpixel, bitspersample;
29809 uint32 nx,ny;
29810 const char *const filename = TIFFFileName(tif);
29811 TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx);
29812 TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny);
29813 TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel);
29814 if (samplesperpixel!=1 && samplesperpixel!=3 && samplesperpixel!=4) {
29815 cimg::warn("CImg<%s>::load_tiff() : File '%s', unknow value for tag : TIFFTAG_SAMPLESPERPIXEL, will force it to 1.",
29816 pixel_type(),filename);
29817 samplesperpixel = 1;
29818 }
29819 TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample);
29820 assign(nx,ny,1,samplesperpixel);
29821 if (bitspersample!=8 || !(samplesperpixel==3 || samplesperpixel==4)) {
29822 uint16 photo, config;
29823 TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config);
29824 TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo);
29825 if (TIFFIsTiled(tif)) {
29826 uint32 tw, th;
29827 TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw);
29828 TIFFGetField(tif,TIFFTAG_TILELENGTH,&th);
29829 if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
29830 case 8 : {
29831 unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
29832 if (buf) {
29833 for (unsigned int row = 0; row<ny; row+=th)
29834 for (unsigned int col = 0; col<nx; col+=tw) {
29835 if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
29836 _TIFFfree(buf); TIFFClose(tif);
29837 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
29838 pixel_type(),filename);
29839 } else {
29840 unsigned char *ptr = buf;
29841 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29842 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29843 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29844 (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
29845 }
29846 }
29847 _TIFFfree(buf);
29848 }
29849 } break;
29850 case 16 : {
29851 unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
29852 if (buf) {
29853 for (unsigned int row = 0; row<ny; row+=th)
29854 for (unsigned int col = 0; col<nx; col+=tw) {
29855 if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
29856 _TIFFfree(buf); TIFFClose(tif);
29857 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
29858 pixel_type(),filename);
29859 } else {
29860 unsigned short *ptr = buf;
29861 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29862 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29863 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29864 (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
29865 }
29866 }
29867 _TIFFfree(buf);
29868 }
29869 } break;
29870 case 32 : {
29871 float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
29872 if (buf) {
29873 for (unsigned int row = 0; row<ny; row+=th)
29874 for (unsigned int col = 0; col<nx; col+=tw) {
29875 if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
29876 _TIFFfree(buf); TIFFClose(tif);
29877 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
29878 pixel_type(),filename);
29879 } else {
29880 float *ptr = buf;
29881 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29882 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29883 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29884 (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
29885 }
29886 }
29887 _TIFFfree(buf);
29888 }
29889 } break;
29890 } else switch (bitspersample) {
29891 case 8 : {
29892 unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
29893 if (buf) {
29894 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29895 for (unsigned int row = 0; row<ny; row+=th)
29896 for (unsigned int col = 0; col<nx; col+=tw) {
29897 if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
29898 _TIFFfree(buf); TIFFClose(tif);
29899 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
29900 pixel_type(),filename);
29901 } else {
29902 unsigned char *ptr = buf;
29903 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29904 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29905 (*this)(cc,rr,vv) = (T)(float)*(ptr++);
29906 }
29907 }
29908 _TIFFfree(buf);
29909 }
29910 } break;
29911 case 16 : {
29912 unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
29913 if (buf) {
29914 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29915 for (unsigned int row = 0; row<ny; row+=th)
29916 for (unsigned int col = 0; col<nx; col+=tw) {
29917 if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
29918 _TIFFfree(buf); TIFFClose(tif);
29919 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
29920 pixel_type(),filename);
29921 } else {
29922 unsigned short *ptr = buf;
29923 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29924 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29925 (*this)(cc,rr,vv) = (T)(float)*(ptr++);
29926 }
29927 }
29928 _TIFFfree(buf);
29929 }
29930 } break;
29931 case 32 : {
29932 float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
29933 if (buf) {
29934 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
29935 for (unsigned int row = 0; row<ny; row+=th)
29936 for (unsigned int col = 0; col<nx; col+=tw) {
29937 if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
29938 _TIFFfree(buf); TIFFClose(tif);
29939 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
29940 pixel_type(),filename);
29941 } else {
29942 float *ptr = buf;
29943 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
29944 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
29945 (*this)(cc,rr,vv) = (T)(float)*(ptr++);
29946 }
29947 }
29948 _TIFFfree(buf);
29949 }
29950 } break;
29951 }
29952 } else {
29953 if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
29954 case 8 : {
29955 unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
29956 if (buf) {
29957 uint32 row, rowsperstrip = (uint32)-1;
29958 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
29959 for (row = 0; row<ny; row+= rowsperstrip) {
29960 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
29961 tstrip_t strip = TIFFComputeStrip(tif, row, 0);
29962 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
29963 _TIFFfree(buf); TIFFClose(tif);
29964 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
29965 pixel_type(),filename);
29966 }
29967 unsigned char *ptr = buf;
29968 for (unsigned int rr = 0; rr<nrow; ++rr)
29969 for (unsigned int cc = 0; cc<nx; ++cc)
29970 for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
29971 }
29972 _TIFFfree(buf);
29973 }
29974 } break;
29975 case 16 : {
29976 unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
29977 if (buf) {
29978 uint32 row, rowsperstrip = (uint32)-1;
29979 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
29980 for (row = 0; row<ny; row+= rowsperstrip) {
29981 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
29982 tstrip_t strip = TIFFComputeStrip(tif, row, 0);
29983 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
29984 _TIFFfree(buf); TIFFClose(tif);
29985 throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
29986 pixel_type(),filename);
29987 }
29988 unsigned short *ptr = buf;
29989 for (unsigned int rr = 0; rr<nrow; ++rr)
29990 for (unsigned int cc = 0; cc<nx; ++cc)
29991 for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
29992 }
29993 _TIFFfree(buf);
29994 }
29995 } break;
29996 case 32 : {
29997 float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
29998 if (buf) {
29999 uint32 row, rowsperstrip = (uint32)-1;
30000 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30001 for (row = 0; row<ny; row+= rowsperstrip) {
30002 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30003 tstrip_t strip = TIFFComputeStrip(tif, row, 0);
30004 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30005 _TIFFfree(buf); TIFFClose(tif);
30006 throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
30007 pixel_type(),filename);
30008 }
30009 float *ptr = buf;
30010 for (unsigned int rr = 0; rr<nrow; ++rr)
30011 for (unsigned int cc = 0; cc<nx; ++cc)
30012 for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30013 }
30014 _TIFFfree(buf);
30015 }
30016 } break;
30017 } else switch (bitspersample){
30018 case 8 : {
30019 unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
30020 if (buf) {
30021 uint32 row, rowsperstrip = (uint32)-1;
30022 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30023 for (unsigned int vv=0; vv<samplesperpixel; ++vv)
30024 for (row = 0; row<ny; row+= rowsperstrip) {
30025 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30026 tstrip_t strip = TIFFComputeStrip(tif, row, vv);
30027 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30028 _TIFFfree(buf); TIFFClose(tif);
30029 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
30030 pixel_type(),filename);
30031 }
30032 unsigned char *ptr = buf;
30033 for (unsigned int rr = 0;rr<nrow; ++rr)
30034 for (unsigned int cc = 0; cc<nx; ++cc)
30035 (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30036 }
30037 _TIFFfree(buf);
30038 }
30039 } break;
30040 case 16 : {
30041 unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
30042 if (buf) {
30043 uint32 row, rowsperstrip = (uint32)-1;
30044 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30045 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30046 for (row = 0; row<ny; row+= rowsperstrip) {
30047 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30048 tstrip_t strip = TIFFComputeStrip(tif, row, vv);
30049 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30050 _TIFFfree(buf); TIFFClose(tif);
30051 throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
30052 pixel_type(),filename);
30053 }
30054 unsigned short *ptr = buf;
30055 for (unsigned int rr = 0; rr<nrow; ++rr)
30056 for (unsigned int cc = 0; cc<nx; ++cc)
30057 (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30058 }
30059 _TIFFfree(buf);
30060 }
30061 } break;
30062 case 32 : {
30063 float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
30064 if (buf) {
30065 uint32 row, rowsperstrip = (uint32)-1;
30066 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
30067 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
30068 for (row = 0; row<ny; row+= rowsperstrip) {
30069 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
30070 tstrip_t strip = TIFFComputeStrip(tif, row, vv);
30071 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
30072 _TIFFfree(buf); TIFFClose(tif);
30073 throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
30074 pixel_type(),filename);
30075 }
30076 float *ptr = buf;
30077 for (unsigned int rr = 0; rr<nrow; ++rr) for (unsigned int cc = 0; cc<nx; ++cc)
30078 (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
30079 }
30080 _TIFFfree(buf);
30081 }
30082 } break;
30083 }
30084 }
30085 } else {
30086 uint32* raster = (uint32*)_TIFFmalloc(nx * ny * sizeof (uint32));
30087 if (!raster) {
30088 _TIFFfree(raster); TIFFClose(tif);
30089 throw CImgException("CImg<%s>::load_tiff() : File '%s', not enough memory for buffer allocation.",
30090 pixel_type(),filename);
30091 }
30092 TIFFReadRGBAImage(tif,nx,ny,raster,0);
30093 switch (samplesperpixel) {
30094 case 1 : {
30095 cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny-1-y)+x]+ 128) / 257);
30096 } break;
30097 case 3 : {
30098 cimg_forXY(*this,x,y) {
30099 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
30100 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
30101 (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
30102 }
30103 } break;
30104 case 4 : {
30105 cimg_forXY(*this,x,y) {
30106 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
30107 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
30108 (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
30109 (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny-1-y)+x]);
30110 }
30111 } break;
30112 }
30113 _TIFFfree(raster);
30114 }
30115 return *this;
30116 }
30117 #endif
30119 //! Load an image from an ANALYZE7.5/NIFTI file.
30120 CImg<T>& load_analyze(const char *const filename, float *const voxsize=0) {
30121 return _load_analyze(0,filename,voxsize);
30122 }
30124 static CImg<T> get_load_analyze(const char *const filename, float *const voxsize=0) {
30125 return CImg<T>().load_analyze(filename,voxsize);
30126 }
30128 //! Load an image from an ANALYZE7.5/NIFTI file.
30129 CImg<T>& load_analyze(cimg_std::FILE *const file, float *const voxsize=0) {
30130 return _load_analyze(file,0,voxsize);
30131 }
30133 static CImg<T> get_load_analyze(cimg_std::FILE *const file, float *const voxsize=0) {
30134 return CImg<T>().load_analyze(file,voxsize);
30135 }
30137 CImg<T>& _load_analyze(cimg_std::FILE *const file, const char *const filename, float *const voxsize=0) {
30138 if (!filename && !file)
30139 throw CImgArgumentException("CImg<%s>::load_analyze() : Cannot load (null) filename.",
30140 pixel_type());
30141 cimg_std::FILE *nfile_header = 0, *nfile = 0;
30142 if (!file) {
30143 char body[1024];
30144 const char *ext = cimg::split_filename(filename,body);
30145 if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file.
30146 nfile_header = cimg::fopen(filename,"rb");
30147 cimg_std::sprintf(body+cimg::strlen(body),".img");
30148 nfile = cimg::fopen(body,"rb");
30149 } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file.
30150 nfile = cimg::fopen(filename,"rb");
30151 cimg_std::sprintf(body+cimg::strlen(body),".hdr");
30152 nfile_header = cimg::fopen(body,"rb");
30153 } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file.
30154 } else nfile_header = nfile = file; // File is a Niftii file.
30155 if (!nfile || !nfile_header)
30156 throw CImgIOException("CImg<%s>::load_analyze() : File '%s', not recognized as an Analyze7.5 or NIFTI file.",
30157 pixel_type(),filename?filename:"(FILE*)");
30159 // Read header.
30160 bool endian = false;
30161 unsigned int header_size;
30162 cimg::fread(&header_size,1,nfile_header);
30163 if (!header_size)
30164 throw CImgIOException("CImg<%s>::load_analyze() : File '%s', zero-sized header found.",
30165 pixel_type(),filename?filename:"(FILE*)");
30166 if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); }
30167 unsigned char *header = new unsigned char[header_size];
30168 cimg::fread(header+4,header_size-4,nfile_header);
30169 if (!file && nfile_header!=nfile) cimg::fclose(nfile_header);
30170 if (endian) {
30171 cimg::invert_endianness((short*)(header+40),5);
30172 cimg::invert_endianness((short*)(header+70),1);
30173 cimg::invert_endianness((short*)(header+72),1);
30174 cimg::invert_endianness((float*)(header+76),4);
30175 cimg::invert_endianness((float*)(header+112),1);
30176 }
30177 unsigned short *dim = (unsigned short*)(header+40), dimx = 1, dimy = 1, dimz = 1, dimv = 1;
30178 if (!dim[0])
30179 cimg::warn("CImg<%s>::load_analyze() : File '%s', tells that image has zero dimensions.",
30180 pixel_type(),filename?filename:"(FILE*)");
30181 if (dim[0]>4)
30182 cimg::warn("CImg<%s>::load_analyze() : File '%s', number of image dimension is %u, reading only the 4 first dimensions",
30183 pixel_type(),filename?filename:"(FILE*)",dim[0]);
30184 if (dim[0]>=1) dimx = dim[1];
30185 if (dim[0]>=2) dimy = dim[2];
30186 if (dim[0]>=3) dimz = dim[3];
30187 if (dim[0]>=4) dimv = dim[4];
30188 float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
30189 const unsigned short datatype = *(short*)(header+70);
30190 if (voxsize) {
30191 const float *vsize = (float*)(header+76);
30192 voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3];
30193 }
30194 delete[] header;
30196 // Read pixel data.
30197 assign(dimx,dimy,dimz,dimv);
30198 switch (datatype) {
30199 case 2 : {
30200 unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
30201 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30202 cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30203 delete[] buffer;
30204 } break;
30205 case 4 : {
30206 short *buffer = new short[dimx*dimy*dimz*dimv];
30207 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30208 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30209 cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30210 delete[] buffer;
30211 } break;
30212 case 8 : {
30213 int *buffer = new int[dimx*dimy*dimz*dimv];
30214 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30215 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30216 cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30217 delete[] buffer;
30218 } break;
30219 case 16 : {
30220 float *buffer = new float[dimx*dimy*dimz*dimv];
30221 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30222 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30223 cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30224 delete[] buffer;
30225 } break;
30226 case 64 : {
30227 double *buffer = new double[dimx*dimy*dimz*dimv];
30228 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
30229 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
30230 cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
30231 delete[] buffer;
30232 } break;
30233 default :
30234 if (!file) cimg::fclose(nfile);
30235 throw CImgIOException("CImg<%s>::load_analyze() : File '%s', cannot read images with 'datatype = %d'",
30236 pixel_type(),filename?filename:"(FILE*)",datatype);
30237 }
30238 if (!file) cimg::fclose(nfile);
30239 return *this;
30240 }
30242 //! Load an image (list) from a .cimg file.
30243 CImg<T>& load_cimg(const char *const filename, const char axis='z', const char align='p') {
30244 CImgList<T> list;
30245 list.load_cimg(filename);
30246 if (list.size==1) return list[0].transfer_to(*this);
30247 return assign(list.get_append(axis,align));
30248 }
30250 static CImg<T> get_load_cimg(const char *const filename, const char axis='z', const char align='p') {
30251 return CImg<T>().load_cimg(filename,axis,align);
30252 }
30254 //! Load an image (list) from a .cimg file.
30255 CImg<T>& load_cimg(cimg_std::FILE *const file, const char axis='z', const char align='p') {
30256 CImgList<T> list;
30257 list.load_cimg(file);
30258 if (list.size==1) return list[0].transfer_to(*this);
30259 return assign(list.get_append(axis,align));
30260 }
30262 static CImg<T> get_load_cimg(cimg_std::FILE *const file, const char axis='z', const char align='p') {
30263 return CImg<T>().load_cimg(file,axis,align);
30264 }
30266 //! Load a sub-image (list) from a .cimg file.
30267 CImg<T>& load_cimg(const char *const filename,
30268 const unsigned int n0, const unsigned int n1,
30269 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30270 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30271 const char axis='z', const char align='p') {
30272 CImgList<T> list;
30273 list.load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
30274 if (list.size==1) return list[0].transfer_to(*this);
30275 return assign(list.get_append(axis,align));
30276 }
30278 static CImg<T> get_load_cimg(const char *const filename,
30279 const unsigned int n0, const unsigned int n1,
30280 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30281 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30282 const char axis='z', const char align='p') {
30283 return CImg<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
30284 }
30286 //! Load a sub-image (list) from a non-compressed .cimg file.
30287 CImg<T>& load_cimg(cimg_std::FILE *const file,
30288 const unsigned int n0, const unsigned int n1,
30289 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30290 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30291 const char axis='z', const char align='p') {
30292 CImgList<T> list;
30293 list.load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
30294 if (list.size==1) return list[0].transfer_to(*this);
30295 return assign(list.get_append(axis,align));
30296 }
30298 static CImg<T> get_load_cimg(cimg_std::FILE *const file,
30299 const unsigned int n0, const unsigned int n1,
30300 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
30301 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
30302 const char axis='z', const char align='p') {
30303 return CImg<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
30304 }
30306 //! Load an image from an INRIMAGE-4 file.
30307 CImg<T>& load_inr(const char *const filename, float *const voxsize=0) {
30308 return _load_inr(0,filename,voxsize);
30309 }
30311 static CImg<T> get_load_inr(const char *const filename, float *const voxsize=0) {
30312 return CImg<T>().load_inr(filename,voxsize);
30313 }
30315 //! Load an image from an INRIMAGE-4 file.
30316 CImg<T>& load_inr(cimg_std::FILE *const file, float *const voxsize=0) {
30317 return _load_inr(file,0,voxsize);
30318 }
30320 static CImg<T> get_load_inr(cimg_std::FILE *const file, float *voxsize=0) {
30321 return CImg<T>().load_inr(file,voxsize);
30322 }
30324 // Load an image from an INRIMAGE-4 file (internal).
30325 static void _load_inr_header(cimg_std::FILE *file, int out[8], float *const voxsize) {
30326 char item[1024], tmp1[64], tmp2[64];
30327 out[0] = cimg_std::fscanf(file,"%63s",item);
30328 out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1;
30329 if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0)
30330 throw CImgIOException("CImg<%s>::load_inr() : File does not appear to be a valid INR file.\n"
30331 "(INRIMAGE-4 identifier not found)",
30332 pixel_type());
30333 while (cimg_std::fscanf(file," %63[^\n]%*c",item)!=EOF && cimg::strncmp(item,"##}",3)) {
30334 cimg_std::sscanf(item," XDIM%*[^0-9]%d",out);
30335 cimg_std::sscanf(item," YDIM%*[^0-9]%d",out+1);
30336 cimg_std::sscanf(item," ZDIM%*[^0-9]%d",out+2);
30337 cimg_std::sscanf(item," VDIM%*[^0-9]%d",out+3);
30338 cimg_std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6);
30339 if (voxsize) {
30340 cimg_std::sscanf(item," VX%*[^0-9.+-]%f",voxsize);
30341 cimg_std::sscanf(item," VY%*[^0-9.+-]%f",voxsize+1);
30342 cimg_std::sscanf(item," VZ%*[^0-9.+-]%f",voxsize+2);
30343 }
30344 if (cimg_std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1;
30345 switch (cimg_std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
30346 case 0 : break;
30347 case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; cimg_std::strcpy(tmp1,tmp2);
30348 case 1 :
30349 if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4] = 0;
30350 if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1;
30351 if (!cimg::strncasecmp(tmp1,"packed",6)) out[4] = 2;
30352 if (out[4]>=0) break;
30353 default :
30354 throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2);
30355 }
30356 }
30357 if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
30358 throw CImgIOException("CImg<%s>::load_inr() : Bad dimensions in .inr file = ( %d , %d , %d , %d )",
30359 pixel_type(),out[0],out[1],out[2],out[3]);
30360 if(out[4]<0 || out[5]<0)
30361 throw CImgIOException("CImg<%s>::load_inr() : TYPE is not fully defined",
30362 pixel_type());
30363 if(out[6]<0)
30364 throw CImgIOException("CImg<%s>::load_inr() : PIXSIZE is not fully defined",
30365 pixel_type());
30366 if(out[7]<0)
30367 throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type is not defined",
30368 pixel_type());
30369 }
30371 CImg<T>& _load_inr(cimg_std::FILE *const file, const char *const filename, float *const voxsize) {
30372 #define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \
30373 if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \
30374 Ts *xval, *val = new Ts[fopt[0]*fopt[3]]; \
30375 cimg_forYZ(*this,y,z) { \
30376 cimg::fread(val,fopt[0]*fopt[3],nfile); \
30377 if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \
30378 xval = val; cimg_forX(*this,x) cimg_forV(*this,k) (*this)(x,y,z,k) = (T)*(xval++); \
30379 } \
30380 delete[] val; \
30381 loaded = true; \
30382 }
30384 if (!filename && !file)
30385 throw CImgArgumentException("CImg<%s>::load_inr() : Cannot load (null) filename.",
30386 pixel_type());
30387 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
30388 int fopt[8], endian=cimg::endianness()?1:0;
30389 bool loaded = false;
30390 if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1;
30391 _load_inr_header(nfile,fopt,voxsize);
30392 assign(fopt[0],fopt[1],fopt[2],fopt[3]);
30393 _cimg_load_inr_case(0,0,8, unsigned char);
30394 _cimg_load_inr_case(0,1,8, char);
30395 _cimg_load_inr_case(0,0,16,unsigned short);
30396 _cimg_load_inr_case(0,1,16,short);
30397 _cimg_load_inr_case(0,0,32,unsigned int);
30398 _cimg_load_inr_case(0,1,32,int);
30399 _cimg_load_inr_case(1,0,32,float);
30400 _cimg_load_inr_case(1,1,32,float);
30401 _cimg_load_inr_case(1,0,64,double);
30402 _cimg_load_inr_case(1,1,64,double);
30403 if (!loaded) {
30404 if (!file) cimg::fclose(nfile);
30405 throw CImgIOException("CImg<%s>::load_inr() : File '%s', cannot read images of the type specified in the file",
30406 pixel_type(),filename?filename:"(FILE*)");
30407 }
30408 if (!file) cimg::fclose(nfile);
30409 return *this;
30410 }
30412 //! Load an image from a PANDORE file.
30413 CImg<T>& load_pandore(const char *const filename) {
30414 return _load_pandore(0,filename);
30415 }
30417 static CImg<T> get_load_pandore(const char *const filename) {
30418 return CImg<T>().load_pandore(filename);
30419 }
30421 //! Load an image from a PANDORE file.
30422 CImg<T>& load_pandore(cimg_std::FILE *const file) {
30423 return _load_pandore(file,0);
30424 }
30426 static CImg<T> get_load_pandore(cimg_std::FILE *const file) {
30427 return CImg<T>().load_pandore(file);
30428 }
30430 CImg<T>& _load_pandore(cimg_std::FILE *const file, const char *const filename) {
30431 #define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \
30432 cimg::fread(dims,nbdim,nfile); \
30433 if (endian) cimg::invert_endianness(dims,nbdim); \
30434 assign(nwidth,nheight,ndepth,ndim); \
30435 const unsigned int siz = size(); \
30436 stype *buffer = new stype[siz]; \
30437 cimg::fread(buffer,siz,nfile); \
30438 if (endian) cimg::invert_endianness(buffer,siz); \
30439 T *ptrd = data; \
30440 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \
30441 buffer-=siz; \
30442 delete[] buffer
30444 #define _cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1,stype2,stype3,ltype) { \
30445 if (sizeof(stype1)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1); } \
30446 else if (sizeof(stype2)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype2); } \
30447 else if (sizeof(stype3)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype3); } \
30448 else throw CImgIOException("CImg<%s>::load_pandore() : File '%s' cannot be read, datatype not supported on this architecture.", \
30449 pixel_type(),filename?filename:"(FILE*)"); }
30451 if (!filename && !file)
30452 throw CImgArgumentException("CImg<%s>::load_pandore() : Cannot load (null) filename.",
30453 pixel_type());
30454 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
30455 typedef unsigned char uchar;
30456 typedef unsigned short ushort;
30457 typedef unsigned int uint;
30458 typedef unsigned long ulong;
30459 char header[32];
30460 cimg::fread(header,12,nfile);
30461 if (cimg::strncasecmp("PANDORE",header,7)) {
30462 if (!file) cimg::fclose(nfile);
30463 throw CImgIOException("CImg<%s>::load_pandore() : File '%s' is not a valid PANDORE file, "
30464 "(PANDORE identifier not found).",
30465 pixel_type(),filename?filename:"(FILE*)");
30466 }
30467 unsigned int imageid, dims[8];
30468 cimg::fread(&imageid,1,nfile);
30469 const bool endian = (imageid>255);
30470 if (endian) cimg::invert_endianness(imageid);
30471 cimg::fread(header,20,nfile);
30473 switch (imageid) {
30474 case 2: _cimg_load_pandore_case(2,dims[1],1,1,1,uchar,uchar,uchar,1); break;
30475 case 3: _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break;
30476 case 4: _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break;
30477 case 5: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,uchar,uchar,uchar,1); break;
30478 case 6: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break;
30479 case 7: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break;
30480 case 8: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,uchar,uchar,uchar,1); break;
30481 case 9: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break;
30482 case 10: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break;
30483 case 11 : { // Region 1D
30484 cimg::fread(dims,3,nfile);
30485 if (endian) cimg::invert_endianness(dims,3);
30486 assign(dims[1],1,1,1);
30487 const unsigned siz = size();
30488 if (dims[2]<256) {
30489 unsigned char *buffer = new unsigned char[siz];
30490 cimg::fread(buffer,siz,nfile);
30491 T *ptrd = data;
30492 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30493 buffer-=siz;
30494 delete[] buffer;
30495 } else {
30496 if (dims[2]<65536) {
30497 unsigned short *buffer = new unsigned short[siz];
30498 cimg::fread(buffer,siz,nfile);
30499 if (endian) cimg::invert_endianness(buffer,siz);
30500 T *ptrd = data;
30501 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30502 buffer-=siz;
30503 delete[] buffer;
30504 } else {
30505 unsigned int *buffer = new unsigned int[siz];
30506 cimg::fread(buffer,siz,nfile);
30507 if (endian) cimg::invert_endianness(buffer,siz);
30508 T *ptrd = data;
30509 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30510 buffer-=siz;
30511 delete[] buffer;
30512 }
30513 }
30514 }
30515 break;
30516 case 12 : { // Region 2D
30517 cimg::fread(dims,4,nfile);
30518 if (endian) cimg::invert_endianness(dims,4);
30519 assign(dims[2],dims[1],1,1);
30520 const unsigned int siz = size();
30521 if (dims[3]<256) {
30522 unsigned char *buffer = new unsigned char[siz];
30523 cimg::fread(buffer,siz,nfile);
30524 T *ptrd = data;
30525 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30526 buffer-=siz;
30527 delete[] buffer;
30528 } else {
30529 if (dims[3]<65536) {
30530 unsigned short *buffer = new unsigned short[siz];
30531 cimg::fread(buffer,siz,nfile);
30532 if (endian) cimg::invert_endianness(buffer,siz);
30533 T *ptrd = data;
30534 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30535 buffer-=siz;
30536 delete[] buffer;
30537 } else {
30538 unsigned long *buffer = new unsigned long[siz];
30539 cimg::fread(buffer,siz,nfile);
30540 if (endian) cimg::invert_endianness(buffer,siz);
30541 T *ptrd = data;
30542 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30543 buffer-=siz;
30544 delete[] buffer;
30545 }
30546 }
30547 }
30548 break;
30549 case 13 : { // Region 3D
30550 cimg::fread(dims,5,nfile);
30551 if (endian) cimg::invert_endianness(dims,5);
30552 assign(dims[3],dims[2],dims[1],1);
30553 const unsigned int siz = size();
30554 if (dims[4]<256) {
30555 unsigned char *buffer = new unsigned char[siz];
30556 cimg::fread(buffer,siz,nfile);
30557 T *ptrd = data;
30558 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30559 buffer-=siz;
30560 delete[] buffer;
30561 } else {
30562 if (dims[4]<65536) {
30563 unsigned short *buffer = new unsigned short[siz];
30564 cimg::fread(buffer,siz,nfile);
30565 if (endian) cimg::invert_endianness(buffer,siz);
30566 T *ptrd = data;
30567 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30568 buffer-=siz;
30569 delete[] buffer;
30570 } else {
30571 unsigned int *buffer = new unsigned int[siz];
30572 cimg::fread(buffer,siz,nfile);
30573 if (endian) cimg::invert_endianness(buffer,siz);
30574 T *ptrd = data;
30575 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
30576 buffer-=siz;
30577 delete[] buffer;
30578 }
30579 }
30580 }
30581 break;
30582 case 16: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,uchar,uchar,uchar,1); break;
30583 case 17: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break;
30584 case 18: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break;
30585 case 19: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,uchar,uchar,uchar,1); break;
30586 case 20: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break;
30587 case 21: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break;
30588 case 22: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],uchar,uchar,uchar,1); break;
30589 case 23: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4);
30590 case 24: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],ulong,uint,ushort,4); break;
30591 case 25: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break;
30592 case 26: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],uchar,uchar,uchar,1); break;
30593 case 27: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break;
30594 case 28: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],ulong,uint,ushort,4); break;
30595 case 29: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break;
30596 case 30: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],uchar,uchar,uchar,1); break;
30597 case 31: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break;
30598 case 32: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],ulong,uint,ushort,4); break;
30599 case 33: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break;
30600 case 34 : { // Points 1D
30601 int ptbuf[4];
30602 cimg::fread(ptbuf,1,nfile);
30603 if (endian) cimg::invert_endianness(ptbuf,1);
30604 assign(1); (*this)(0) = (T)ptbuf[0];
30605 } break;
30606 case 35 : { // Points 2D
30607 int ptbuf[4];
30608 cimg::fread(ptbuf,2,nfile);
30609 if (endian) cimg::invert_endianness(ptbuf,2);
30610 assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0];
30611 } break;
30612 case 36 : { // Points 3D
30613 int ptbuf[4];
30614 cimg::fread(ptbuf,3,nfile);
30615 if (endian) cimg::invert_endianness(ptbuf,3);
30616 assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0];
30617 } break;
30618 default :
30619 if (!file) cimg::fclose(nfile);
30620 throw CImgIOException("CImg<%s>::load_pandore() : File '%s', cannot read images with ID_type = %u",
30621 pixel_type(),filename?filename:"(FILE*)",imageid);
30622 }
30623 if (!file) cimg::fclose(nfile);
30624 return *this;
30625 }
30627 //! Load an image from a PAR-REC (Philips) file.
30628 CImg<T>& load_parrec(const char *const filename, const char axis='v', const char align='p') {
30629 CImgList<T> list;
30630 list.load_parrec(filename);
30631 if (list.size==1) return list[0].transfer_to(*this);
30632 return assign(list.get_append(axis,align));
30633 }
30635 static CImg<T> get_load_parrec(const char *const filename, const char axis='v', const char align='p') {
30636 return CImg<T>().load_parrec(filename,axis,align);
30637 }
30639 //! Load an image from a .RAW file.
30640 CImg<T>& load_raw(const char *const filename,
30641 const unsigned int sizex, const unsigned int sizey=1,
30642 const unsigned int sizez=1, const unsigned int sizev=1,
30643 const bool multiplexed=false, const bool invert_endianness=false) {
30644 return _load_raw(0,filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30645 }
30647 static CImg<T> get_load_raw(const char *const filename,
30648 const unsigned int sizex, const unsigned int sizey=1,
30649 const unsigned int sizez=1, const unsigned int sizev=1,
30650 const bool multiplexed=false, const bool invert_endianness=false) {
30651 return CImg<T>().load_raw(filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30652 }
30654 //! Load an image from a .RAW file.
30655 CImg<T>& load_raw(cimg_std::FILE *const file,
30656 const unsigned int sizex, const unsigned int sizey=1,
30657 const unsigned int sizez=1, const unsigned int sizev=1,
30658 const bool multiplexed=false, const bool invert_endianness=false) {
30659 return _load_raw(file,0,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30660 }
30662 static CImg<T> get_load_raw(cimg_std::FILE *const file,
30663 const unsigned int sizex, const unsigned int sizey=1,
30664 const unsigned int sizez=1, const unsigned int sizev=1,
30665 const bool multiplexed=false, const bool invert_endianness=false) {
30666 return CImg<T>().load_raw(file,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
30667 }
30669 CImg<T>& _load_raw(cimg_std::FILE *const file, const char *const filename,
30670 const unsigned int sizex, const unsigned int sizey,
30671 const unsigned int sizez, const unsigned int sizev,
30672 const bool multiplexed, const bool invert_endianness) {
30673 if (!filename && !file)
30674 throw CImgArgumentException("CImg<%s>::load_raw() : Cannot load (null) filename.",
30675 pixel_type());
30676 assign(sizex,sizey,sizez,sizev,0);
30677 const unsigned int siz = size();
30678 if (siz) {
30679 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
30680 if (!multiplexed) {
30681 cimg::fread(data,siz,nfile);
30682 if (invert_endianness) cimg::invert_endianness(data,siz);
30683 }
30684 else {
30685 CImg<T> buf(1,1,1,sizev);
30686 cimg_forXYZ(*this,x,y,z) {
30687 cimg::fread(buf.data,sizev,nfile);
30688 if (invert_endianness) cimg::invert_endianness(buf.data,sizev);
30689 set_vector_at(buf,x,y,z); }
30690 }
30691 if (!file) cimg::fclose(nfile);
30692 }
30693 return *this;
30694 }
30696 //! Load a video sequence using FFMPEG av's libraries.
30697 CImg<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30698 const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
30699 const char axis='z', const char align='p') {
30700 return get_load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume,axis,align).transfer_to(*this);
30701 }
30703 static CImg<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30704 const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
30705 const char axis='z', const char align='p') {
30706 return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume).get_append(axis,align);
30707 }
30709 //! Load an image sequence from a YUV file.
30710 CImg<T>& load_yuv(const char *const filename,
30711 const unsigned int sizex, const unsigned int sizey=1,
30712 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30713 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
30714 return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
30715 }
30717 static CImg<T> get_load_yuv(const char *const filename,
30718 const unsigned int sizex, const unsigned int sizey=1,
30719 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30720 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
30721 return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
30722 }
30724 //! Load an image sequence from a YUV file.
30725 CImg<T>& load_yuv(cimg_std::FILE *const file,
30726 const unsigned int sizex, const unsigned int sizey=1,
30727 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30728 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
30729 return get_load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
30730 }
30732 static CImg<T> get_load_yuv(cimg_std::FILE *const file,
30733 const unsigned int sizex, const unsigned int sizey=1,
30734 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
30735 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
30736 return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
30737 }
30739 //! Load a 3D object from a .OFF file.
30740 template<typename tf, typename tc>
30741 CImg<T>& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
30742 return _load_off(0,filename,primitives,colors,invert_faces);
30743 }
30745 template<typename tf, typename tc>
30746 static CImg<T> get_load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors,
30747 const bool invert_faces=false) {
30748 return CImg<T>().load_off(filename,primitives,colors,invert_faces);
30749 }
30751 //! Load a 3D object from a .OFF file.
30752 template<typename tf, typename tc>
30753 CImg<T>& load_off(cimg_std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
30754 return _load_off(file,0,primitives,colors,invert_faces);
30755 }
30757 template<typename tf, typename tc>
30758 static CImg<T> get_load_off(cimg_std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors,
30759 const bool invert_faces=false) {
30760 return CImg<T>().load_off(file,primitives,colors,invert_faces);
30761 }
30763 template<typename tf, typename tc>
30764 CImg<T>& _load_off(cimg_std::FILE *const file, const char *const filename,
30765 CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces) {
30766 if (!filename && !file)
30767 throw CImgArgumentException("CImg<%s>::load_off() : Cannot load (null) filename.",
30768 pixel_type());
30769 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
30770 unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0;
30771 char line[256] = { 0 };
30772 int err;
30774 // Skip comments, and read magic string OFF
30775 do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
30776 if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) {
30777 if (!file) cimg::fclose(nfile);
30778 throw CImgIOException("CImg<%s>::load_off() : File '%s', keyword 'OFF' not found.",
30779 pixel_type(),filename?filename:"(FILE*)");
30780 }
30781 do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
30782 if ((err = cimg_std::sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) {
30783 if (!file) cimg::fclose(nfile);
30784 throw CImgIOException("CImg<%s>::load_off() : File '%s', invalid vertices/primitives numbers.",
30785 pixel_type(),filename?filename:"(FILE*)");
30786 }
30788 // Read points data
30789 assign(nb_points,3);
30790 float X = 0, Y = 0, Z = 0;
30791 cimg_forX(*this,l) {
30792 do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
30793 if ((err = cimg_std::sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) {
30794 if (!file) cimg::fclose(nfile);
30795 throw CImgIOException("CImg<%s>::load_off() : File '%s', cannot read point %u/%u.\n",
30796 pixel_type(),filename?filename:"(FILE*)",l+1,nb_points);
30797 }
30798 (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z;
30799 }
30801 // Read primitive data
30802 primitives.assign();
30803 colors.assign();
30804 bool stopflag = false;
30805 while (!stopflag) {
30806 float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f;
30807 unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
30808 line[0]='\0';
30809 if ((err = cimg_std::fscanf(nfile,"%u",&prim))!=1) stopflag=true;
30810 else {
30811 ++nb_read;
30812 switch (prim) {
30813 case 1 : {
30814 if ((err = cimg_std::fscanf(nfile,"%u%255[^\n] ",&i0,line))<2) {
30815 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30816 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30817 err = cimg_std::fscanf(nfile,"%*[^\n] ");
30818 } else {
30819 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30820 primitives.insert(CImg<tf>::vector(i0));
30821 colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
30822 }
30823 } break;
30824 case 2 : {
30825 if ((err = cimg_std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line))<2) {
30826 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30827 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30828 err = cimg_std::fscanf(nfile,"%*[^\n] ");
30829 } else {
30830 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30831 primitives.insert(CImg<tf>::vector(i0,i1));
30832 colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
30833 }
30834 } break;
30835 case 3 : {
30836 if ((err = cimg_std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line))<3) {
30837 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30838 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30839 err = cimg_std::fscanf(nfile,"%*[^\n] ");
30840 } else {
30841 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30842 if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2));
30843 else primitives.insert(CImg<tf>::vector(i0,i2,i1));
30844 colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
30845 }
30846 } break;
30847 case 4 : {
30848 if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line))<4) {
30849 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30850 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30851 err = cimg_std::fscanf(nfile,"%*[^\n] ");
30852 } else {
30853 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30854 if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
30855 else primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
30856 colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
30857 }
30858 } break;
30859 case 5 : {
30860 if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line))<5) {
30861 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30862 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30863 err = cimg_std::fscanf(nfile,"%*[^\n] ");
30864 } else {
30865 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30866 if (invert_faces) {
30867 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
30868 primitives.insert(CImg<tf>::vector(i0,i3,i4));
30869 }
30870 else {
30871 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
30872 primitives.insert(CImg<tf>::vector(i0,i4,i3));
30873 }
30874 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
30875 ++nb_primitives;
30876 }
30877 } break;
30878 case 6 : {
30879 if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line))<6) {
30880 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30881 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30882 err = cimg_std::fscanf(nfile,"%*[^\n] ");
30883 } else {
30884 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30885 if (invert_faces) {
30886 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
30887 primitives.insert(CImg<tf>::vector(i0,i3,i4,i5));
30888 }
30889 else {
30890 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
30891 primitives.insert(CImg<tf>::vector(i0,i5,i4,i3));
30892 }
30893 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
30894 ++nb_primitives;
30895 }
30896 } break;
30897 case 7 : {
30898 if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line))<7) {
30899 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30900 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30901 err = cimg_std::fscanf(nfile,"%*[^\n] ");
30902 } else {
30903 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30904 if (invert_faces) {
30905 primitives.insert(CImg<tf>::vector(i0,i1,i3,i4));
30906 primitives.insert(CImg<tf>::vector(i0,i4,i5,i6));
30907 primitives.insert(CImg<tf>::vector(i1,i2,i3));
30908 }
30909 else {
30910 primitives.insert(CImg<tf>::vector(i0,i4,i3,i1));
30911 primitives.insert(CImg<tf>::vector(i0,i6,i5,i4));
30912 primitives.insert(CImg<tf>::vector(i3,i2,i1));
30913 }
30914 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
30915 ++(++nb_primitives);
30916 }
30917 } break;
30918 case 8 : {
30919 if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line))<7) {
30920 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
30921 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
30922 err = cimg_std::fscanf(nfile,"%*[^\n] ");
30923 } else {
30924 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
30925 if (invert_faces) {
30926 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
30927 primitives.insert(CImg<tf>::vector(i0,i3,i4,i5));
30928 primitives.insert(CImg<tf>::vector(i0,i5,i6,i7));
30929 }
30930 else {
30931 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
30932 primitives.insert(CImg<tf>::vector(i0,i5,i4,i3));
30933 primitives.insert(CImg<tf>::vector(i0,i7,i6,i5));
30934 }
30935 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
30936 ++(++nb_primitives);
30937 }
30938 } break;
30939 default :
30940 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u (%u vertices).",
30941 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives,prim);
30942 err = cimg_std::fscanf(nfile,"%*[^\n] ");
30943 }
30944 }
30945 }
30946 if (!file) cimg::fclose(nfile);
30947 if (primitives.size!=nb_primitives)
30948 cimg::warn("CImg<%s>::load_off() : File '%s', read only %u primitives instead of %u as claimed in the header.",
30949 pixel_type(),filename?filename:"(FILE*)",primitives.size,nb_primitives);
30950 return *this;
30951 }
30953 //! Load a video sequence using FFMPEG's external tool 'ffmpeg'.
30954 CImg<T>& load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
30955 return get_load_ffmpeg_external(filename,axis,align).transfer_to(*this);
30956 }
30958 static CImg<T> get_load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
30959 return CImgList<T>().load_ffmpeg_external(filename).get_append(axis,align);
30960 }
30962 //! Load an image using GraphicsMagick's external tool 'gm'.
30963 CImg<T>& load_graphicsmagick_external(const char *const filename) {
30964 if (!filename)
30965 throw CImgArgumentException("CImg<%s>::load_graphicsmagick_external() : Cannot load (null) filename.",
30966 pixel_type());
30967 char command[1024], filetmp[512];
30968 cimg_std::FILE *file = 0;
30969 #if cimg_OS==1
30970 cimg_std::sprintf(command,"%s convert \"%s\" ppm:-",cimg::graphicsmagick_path(),filename);
30971 file = popen(command,"r");
30972 if (file) { load_pnm(file); pclose(file); return *this; }
30973 #endif
30974 do {
30975 cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
30976 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
30977 } while (file);
30978 cimg_std::sprintf(command,"%s convert \"%s\" %s",cimg::graphicsmagick_path(),filename,filetmp);
30979 cimg::system(command,cimg::graphicsmagick_path());
30980 if (!(file = cimg_std::fopen(filetmp,"rb"))) {
30981 cimg::fclose(cimg::fopen(filename,"r"));
30982 throw CImgIOException("CImg<%s>::load_graphicsmagick_external() : Failed to open image '%s'.\n\n"
30983 "Path of 'GraphicsMagick's gm' : \"%s\"\n"
30984 "Path of temporary filename : \"%s\"",
30985 pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
30986 } else cimg::fclose(file);
30987 load_pnm(filetmp);
30988 cimg_std::remove(filetmp);
30989 return *this;
30990 }
30992 static CImg<T> get_load_graphicsmagick_external(const char *const filename) {
30993 return CImg<T>().load_graphicsmagick_external(filename);
30994 }
30996 //! Load a gzipped image file, using external tool 'gunzip'.
30997 CImg<T>& load_gzip_external(const char *const filename) {
30998 if (!filename)
30999 throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
31000 pixel_type());
31001 char command[1024], filetmp[512], body[512];
31002 const char
31003 *ext = cimg::split_filename(filename,body),
31004 *ext2 = cimg::split_filename(body,0);
31005 cimg_std::FILE *file = 0;
31006 do {
31007 if (!cimg::strcasecmp(ext,"gz")) {
31008 if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
31009 cimg::filenamerand(),ext2);
31010 else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
31011 cimg::filenamerand());
31012 } else {
31013 if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
31014 cimg::filenamerand(),ext);
31015 else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
31016 cimg::filenamerand());
31017 }
31018 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
31019 } while (file);
31020 cimg_std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
31021 cimg::system(command);
31022 if (!(file = cimg_std::fopen(filetmp,"rb"))) {
31023 cimg::fclose(cimg::fopen(filename,"r"));
31024 throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
31025 pixel_type(),filename);
31026 } else cimg::fclose(file);
31027 load(filetmp);
31028 cimg_std::remove(filetmp);
31029 return *this;
31030 }
31032 static CImg<T> get_load_gzip_external(const char *const filename) {
31033 return CImg<T>().load_gzip_external(filename);
31034 }
31036 //! Load an image using ImageMagick's external tool 'convert'.
31037 CImg<T>& load_imagemagick_external(const char *const filename) {
31038 if (!filename)
31039 throw CImgArgumentException("CImg<%s>::load_imagemagick_external() : Cannot load (null) filename.",
31040 pixel_type());
31041 char command[1024], filetmp[512];
31042 cimg_std::FILE *file = 0;
31043 #if cimg_OS==1
31044 cimg_std::sprintf(command,"%s \"%s\" ppm:-",cimg::imagemagick_path(),filename);
31045 file = popen(command,"r");
31046 if (file) { load_pnm(file); pclose(file); return *this; }
31047 #endif
31048 do {
31049 cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
31050 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
31051 } while (file);
31052 cimg_std::sprintf(command,"%s \"%s\" %s",cimg::imagemagick_path(),filename,filetmp);
31053 cimg::system(command,cimg::imagemagick_path());
31054 if (!(file = cimg_std::fopen(filetmp,"rb"))) {
31055 cimg::fclose(cimg::fopen(filename,"r"));
31056 throw CImgIOException("CImg<%s>::load_imagemagick_external() : Failed to open image '%s'.\n\n"
31057 "Path of 'ImageMagick's convert' : \"%s\"\n"
31058 "Path of temporary filename : \"%s\"",
31059 pixel_type(),filename,cimg::imagemagick_path(),filetmp);
31060 } else cimg::fclose(file);
31061 load_pnm(filetmp);
31062 cimg_std::remove(filetmp);
31063 return *this;
31064 }
31066 static CImg<T> get_load_imagemagick_external(const char *const filename) {
31067 return CImg<T>().load_imagemagick_external(filename);
31068 }
31070 //! Load a DICOM image file, using XMedcon's external tool 'medcon'.
31071 CImg<T>& load_medcon_external(const char *const filename) {
31072 if (!filename)
31073 throw CImgArgumentException("CImg<%s>::load_medcon_external() : Cannot load (null) filename.",
31074 pixel_type());
31075 char command[1024], filetmp[512], body[512];
31076 cimg::fclose(cimg::fopen(filename,"r"));
31077 cimg_std::FILE *file = 0;
31078 do {
31079 cimg_std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
31080 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
31081 } while (file);
31082 cimg_std::sprintf(command,"%s -w -c anlz -o %s -f %s",cimg::medcon_path(),filetmp,filename);
31083 cimg::system(command);
31084 cimg::split_filename(filetmp,body);
31085 cimg_std::sprintf(command,"m000-%s.hdr",body);
31086 file = cimg_std::fopen(command,"rb");
31087 if (!file) {
31088 throw CImgIOException("CImg<%s>::load_medcon_external() : Failed to open image '%s'.\n\n"
31089 "Path of 'medcon' : \"%s\"\n"
31090 "Path of temporary filename : \"%s\"",
31091 pixel_type(),filename,cimg::medcon_path(),filetmp);
31092 } else cimg::fclose(file);
31093 load_analyze(command);
31094 cimg_std::remove(command);
31095 cimg_std::sprintf(command,"m000-%s.img",body);
31096 cimg_std::remove(command);
31097 return *this;
31098 }
31100 static CImg<T> get_load_medcon_external(const char *const filename) {
31101 return CImg<T>().load_medcon_external(filename);
31102 }
31104 //! Load a RAW Color Camera image file, using external tool 'dcraw'.
31105 CImg<T>& load_dcraw_external(const char *const filename) {
31106 if (!filename)
31107 throw CImgArgumentException("CImg<%s>::load_dcraw_external() : Cannot load (null) filename.",
31108 pixel_type());
31109 char command[1024], filetmp[512];
31110 cimg_std::FILE *file = 0;
31111 #if cimg_OS==1
31112 cimg_std::sprintf(command,"%s -4 -c \"%s\"",cimg::dcraw_path(),filename);
31113 file = popen(command,"r");
31114 if (file) { load_pnm(file); pclose(file); return *this; }
31115 #endif
31116 do {
31117 cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
31118 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
31119 } while (file);
31120 cimg_std::sprintf(command,"%s -4 -c \"%s\" > %s",cimg::dcraw_path(),filename,filetmp);
31121 cimg::system(command,cimg::dcraw_path());
31122 if (!(file = cimg_std::fopen(filetmp,"rb"))) {
31123 cimg::fclose(cimg::fopen(filename,"r"));
31124 throw CImgIOException("CImg<%s>::load_dcraw_external() : Failed to open image '%s'.\n\n"
31125 "Path of 'dcraw' : \"%s\"\n"
31126 "Path of temporary filename : \"%s\"",
31127 pixel_type(),filename,cimg::dcraw_path(),filetmp);
31128 } else cimg::fclose(file);
31129 load_pnm(filetmp);
31130 cimg_std::remove(filetmp);
31131 return *this;
31132 }
31134 static CImg<T> get_load_dcraw_external(const char *const filename) {
31135 return CImg<T>().load_dcraw_external(filename);
31136 }
31138 //! Load an image using ImageMagick's or GraphicsMagick's executables.
31139 CImg<T>& load_other(const char *const filename) {
31140 if (!filename)
31141 throw CImgArgumentException("CImg<%s>::load_other() : Cannot load (null) filename.",
31142 pixel_type());
31143 const unsigned int odebug = cimg::exception_mode();
31144 cimg::exception_mode() = 0;
31145 try { load_magick(filename); }
31146 catch (CImgException&) {
31147 try { load_imagemagick_external(filename); }
31148 catch (CImgException&) {
31149 try { load_graphicsmagick_external(filename); }
31150 catch (CImgException&) {
31151 assign();
31152 }
31153 }
31154 }
31155 cimg::exception_mode() = odebug;
31156 if (is_empty())
31157 throw CImgIOException("CImg<%s>::load_other() : File '%s' cannot be opened.",
31158 pixel_type(),filename);
31159 return *this;
31160 }
31162 static CImg<T> get_load_other(const char *const filename) {
31163 return CImg<T>().load_other(filename);
31164 }
31166 //@}
31167 //---------------------------
31168 //
31169 //! \name Image File Saving
31170 //@{
31171 //---------------------------
31173 //! Save the image as a file.
31174 /**
31175 The used file format is defined by the file extension in the filename \p filename.
31176 Parameter \p number can be used to add a 6-digit number to the filename before saving.
31177 **/
31178 const CImg<T>& save(const char *const filename, const int number=-1) const {
31179 if (is_empty())
31180 throw CImgInstanceException("CImg<%s>::save() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31181 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
31182 if (!filename)
31183 throw CImgArgumentException("CImg<%s>::save() : Instance image (%u,%u,%u,%u,%p) cannot be saved as a (null) filename.",
31184 pixel_type(),width,height,depth,dim,data);
31185 const char *ext = cimg::split_filename(filename);
31186 char nfilename[1024];
31187 const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
31188 #ifdef cimg_save_plugin
31189 cimg_save_plugin(fn);
31190 #endif
31191 #ifdef cimg_save_plugin1
31192 cimg_save_plugin1(fn);
31193 #endif
31194 #ifdef cimg_save_plugin2
31195 cimg_save_plugin2(fn);
31196 #endif
31197 #ifdef cimg_save_plugin3
31198 cimg_save_plugin3(fn);
31199 #endif
31200 #ifdef cimg_save_plugin4
31201 cimg_save_plugin4(fn);
31202 #endif
31203 #ifdef cimg_save_plugin5
31204 cimg_save_plugin5(fn);
31205 #endif
31206 #ifdef cimg_save_plugin6
31207 cimg_save_plugin6(fn);
31208 #endif
31209 #ifdef cimg_save_plugin7
31210 cimg_save_plugin7(fn);
31211 #endif
31212 #ifdef cimg_save_plugin8
31213 cimg_save_plugin8(fn);
31214 #endif
31215 // ASCII formats
31216 if (!cimg::strcasecmp(ext,"asc")) return save_ascii(fn);
31217 if (!cimg::strcasecmp(ext,"dlm") ||
31218 !cimg::strcasecmp(ext,"txt")) return save_dlm(fn);
31219 if (!cimg::strcasecmp(ext,"cpp") ||
31220 !cimg::strcasecmp(ext,"hpp") ||
31221 !cimg::strcasecmp(ext,"h") ||
31222 !cimg::strcasecmp(ext,"c")) return save_cpp(fn);
31224 // 2D binary formats
31225 if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(fn);
31226 if (!cimg::strcasecmp(ext,"jpg") ||
31227 !cimg::strcasecmp(ext,"jpeg") ||
31228 !cimg::strcasecmp(ext,"jpe") ||
31229 !cimg::strcasecmp(ext,"jfif") ||
31230 !cimg::strcasecmp(ext,"jif")) return save_jpeg(fn);
31231 if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(fn);
31232 if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(fn);
31233 if (!cimg::strcasecmp(ext,"png")) return save_png(fn);
31234 if (!cimg::strcasecmp(ext,"pgm") ||
31235 !cimg::strcasecmp(ext,"ppm") ||
31236 !cimg::strcasecmp(ext,"pnm")) return save_pnm(fn);
31237 if (!cimg::strcasecmp(ext,"tif") ||
31238 !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
31240 // 3D binary formats
31241 if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
31242 if (!cimg::strcasecmp(ext,"cimg") || ext[0]=='\0') return save_cimg(fn,false);
31243 if (!cimg::strcasecmp(ext,"dcm")) return save_medcon_external(fn);
31244 if (!cimg::strcasecmp(ext,"hdr") ||
31245 !cimg::strcasecmp(ext,"nii")) return save_analyze(fn);
31246 if (!cimg::strcasecmp(ext,"inr")) return save_inr(fn);
31247 if (!cimg::strcasecmp(ext,"pan")) return save_pandore(fn);
31248 if (!cimg::strcasecmp(ext,"raw")) return save_raw(fn);
31250 // Archive files
31251 if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
31253 // Image sequences
31254 if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
31255 if (!cimg::strcasecmp(ext,"avi") ||
31256 !cimg::strcasecmp(ext,"mov") ||
31257 !cimg::strcasecmp(ext,"asf") ||
31258 !cimg::strcasecmp(ext,"divx") ||
31259 !cimg::strcasecmp(ext,"flv") ||
31260 !cimg::strcasecmp(ext,"mpg") ||
31261 !cimg::strcasecmp(ext,"m1v") ||
31262 !cimg::strcasecmp(ext,"m2v") ||
31263 !cimg::strcasecmp(ext,"m4v") ||
31264 !cimg::strcasecmp(ext,"mjp") ||
31265 !cimg::strcasecmp(ext,"mkv") ||
31266 !cimg::strcasecmp(ext,"mpe") ||
31267 !cimg::strcasecmp(ext,"movie") ||
31268 !cimg::strcasecmp(ext,"ogm") ||
31269 !cimg::strcasecmp(ext,"qt") ||
31270 !cimg::strcasecmp(ext,"rm") ||
31271 !cimg::strcasecmp(ext,"vob") ||
31272 !cimg::strcasecmp(ext,"wmv") ||
31273 !cimg::strcasecmp(ext,"xvid") ||
31274 !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
31275 return save_other(fn);
31276 }
31278 // Save the image as an ASCII file (ASCII Raw + simple header) (internal).
31279 const CImg<T>& _save_ascii(cimg_std::FILE *const file, const char *const filename) const {
31280 if (is_empty())
31281 throw CImgInstanceException("CImg<%s>::save_ascii() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31282 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31283 if (!file && !filename)
31284 throw CImgArgumentException("CImg<%s>::save_ascii() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31285 pixel_type(),width,height,depth,dim,data);
31286 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
31287 cimg_std::fprintf(nfile,"%u %u %u %u\n",width,height,depth,dim);
31288 const T* ptrs = data;
31289 cimg_forYZV(*this,y,z,v) {
31290 cimg_forX(*this,x) cimg_std::fprintf(nfile,"%g ",(double)*(ptrs++));
31291 cimg_std::fputc('\n',nfile);
31292 }
31293 if (!file) cimg::fclose(nfile);
31294 return *this;
31295 }
31297 //! Save the image as an ASCII file (ASCII Raw + simple header).
31298 const CImg<T>& save_ascii(const char *const filename) const {
31299 return _save_ascii(0,filename);
31300 }
31302 //! Save the image as an ASCII file (ASCII Raw + simple header).
31303 const CImg<T>& save_ascii(cimg_std::FILE *const file) const {
31304 return _save_ascii(file,0);
31305 }
31307 // Save the image as a C or CPP source file (internal).
31308 const CImg<T>& _save_cpp(cimg_std::FILE *const file, const char *const filename) const {
31309 if (!file && !filename)
31310 throw CImgArgumentException("CImg<%s>::save_cpp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31311 pixel_type(),width,height,depth,dim,data);
31312 if (is_empty())
31313 throw CImgInstanceException("CImg<%s>::save_cpp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31314 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31315 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
31316 char varname[1024] = { 0 };
31317 if (filename) cimg_std::sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname);
31318 if (varname[0]=='\0') cimg_std::sprintf(varname,"unnamed");
31319 cimg_std::fprintf(nfile,
31320 "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n"
31321 "%s data_%s[] = { \n ",
31322 varname,width,height,depth,dim,pixel_type(),pixel_type(),varname);
31323 for (unsigned long off = 0, siz = size()-1; off<=siz; ++off) {
31324 cimg_std::fprintf(nfile,cimg::type<T>::format(),cimg::type<T>::format((*this)[off]));
31325 if (off==siz) cimg_std::fprintf(nfile," };\n");
31326 else if (!((off+1)%16)) cimg_std::fprintf(nfile,",\n ");
31327 else cimg_std::fprintf(nfile,", ");
31328 }
31329 if (!file) cimg::fclose(nfile);
31330 return *this;
31331 }
31333 //! Save the image as a CPP source file.
31334 const CImg<T>& save_cpp(const char *const filename) const {
31335 return _save_cpp(0,filename);
31336 }
31338 //! Save the image as a CPP source file.
31339 const CImg<T>& save_cpp(cimg_std::FILE *const file) const {
31340 return _save_cpp(file,0);
31341 }
31343 // Save the image as a DLM file (internal).
31344 const CImg<T>& _save_dlm(cimg_std::FILE *const file, const char *const filename) const {
31345 if (is_empty())
31346 throw CImgInstanceException("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31347 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31348 if (!file && !filename)
31349 throw CImgArgumentException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31350 pixel_type(),width,height,depth,dim,data);
31351 if (depth>1)
31352 cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Pixel values along Z will be unrolled.",
31353 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31354 if (dim>1)
31355 cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. "
31356 "Pixel values along V will be unrolled.",
31357 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31359 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
31360 const T* ptrs = data;
31361 cimg_forYZV(*this,y,z,v) {
31362 cimg_forX(*this,x) cimg_std::fprintf(nfile,"%g%s",(double)*(ptrs++),(x==dimx()-1)?"":",");
31363 cimg_std::fputc('\n',nfile);
31364 }
31365 if (!file) cimg::fclose(nfile);
31366 return *this;
31367 }
31369 //! Save the image as a DLM file.
31370 const CImg<T>& save_dlm(const char *const filename) const {
31371 return _save_dlm(0,filename);
31372 }
31374 //! Save the image as a DLM file.
31375 const CImg<T>& save_dlm(cimg_std::FILE *const file) const {
31376 return _save_dlm(file,0);
31377 }
31379 // Save the image as a BMP file (internal).
31380 const CImg<T>& _save_bmp(cimg_std::FILE *const file, const char *const filename) const {
31381 if (is_empty())
31382 throw CImgInstanceException("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31383 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31384 if (!file && !filename)
31385 throw CImgArgumentException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31386 pixel_type(),width,height,depth,dim,data);
31387 if (depth>1)
31388 cimg::warn("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
31389 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31390 if (dim>3)
31391 cimg::warn("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved.",
31392 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31394 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
31395 unsigned char header[54] = { 0 }, align_buf[4] = { 0 };
31396 const unsigned int
31397 align = (4 - (3*width)%4)%4,
31398 buf_size = (3*width+align)*dimy(),
31399 file_size = 54 + buf_size;
31400 header[0] = 'B'; header[1] = 'M';
31401 header[0x02] = file_size&0xFF;
31402 header[0x03] = (file_size>>8)&0xFF;
31403 header[0x04] = (file_size>>16)&0xFF;
31404 header[0x05] = (file_size>>24)&0xFF;
31405 header[0x0A] = 0x36;
31406 header[0x0E] = 0x28;
31407 header[0x12] = width&0xFF;
31408 header[0x13] = (width>>8)&0xFF;
31409 header[0x14] = (width>>16)&0xFF;
31410 header[0x15] = (width>>24)&0xFF;
31411 header[0x16] = height&0xFF;
31412 header[0x17] = (height>>8)&0xFF;
31413 header[0x18] = (height>>16)&0xFF;
31414 header[0x19] = (height>>24)&0xFF;
31415 header[0x1A] = 1;
31416 header[0x1B] = 0;
31417 header[0x1C] = 24;
31418 header[0x1D] = 0;
31419 header[0x22] = buf_size&0xFF;
31420 header[0x23] = (buf_size>>8)&0xFF;
31421 header[0x24] = (buf_size>>16)&0xFF;
31422 header[0x25] = (buf_size>>24)&0xFF;
31423 header[0x27] = 0x1;
31424 header[0x2B] = 0x1;
31425 cimg::fwrite(header,54,nfile);
31427 const T
31428 *pR = ptr(0,height-1,0,0),
31429 *pG = (dim>=2)?ptr(0,height-1,0,1):0,
31430 *pB = (dim>=3)?ptr(0,height-1,0,2):0;
31432 switch (dim) {
31433 case 1 : {
31434 cimg_forY(*this,y) { cimg_forX(*this,x) {
31435 const unsigned char val = (unsigned char)*(pR++);
31436 cimg_std::fputc(val,nfile); cimg_std::fputc(val,nfile); cimg_std::fputc(val,nfile);
31437 }
31438 cimg::fwrite(align_buf,align,nfile);
31439 pR-=2*width;
31440 }} break;
31441 case 2 : {
31442 cimg_forY(*this,y) { cimg_forX(*this,x) {
31443 cimg_std::fputc(0,nfile);
31444 cimg_std::fputc((unsigned char)(*(pG++)),nfile);
31445 cimg_std::fputc((unsigned char)(*(pR++)),nfile);
31446 }
31447 cimg::fwrite(align_buf,align,nfile);
31448 pR-=2*width; pG-=2*width;
31449 }} break;
31450 default : {
31451 cimg_forY(*this,y) { cimg_forX(*this,x) {
31452 cimg_std::fputc((unsigned char)(*(pB++)),nfile);
31453 cimg_std::fputc((unsigned char)(*(pG++)),nfile);
31454 cimg_std::fputc((unsigned char)(*(pR++)),nfile);
31455 }
31456 cimg::fwrite(align_buf,align,nfile);
31457 pR-=2*width; pG-=2*width; pB-=2*width;
31458 }
31459 }
31460 }
31461 if (!file) cimg::fclose(nfile);
31462 return *this;
31463 }
31465 //! Save the image as a BMP file.
31466 const CImg<T>& save_bmp(const char *const filename) const {
31467 return _save_bmp(0,filename);
31468 }
31470 //! Save the image as a BMP file.
31471 const CImg<T>& save_bmp(cimg_std::FILE *const file) const {
31472 return _save_bmp(file,0);
31473 }
31475 // Save a file in JPEG format (internal).
31476 const CImg<T>& _save_jpeg(cimg_std::FILE *const file, const char *const filename, const unsigned int quality) const {
31477 if (is_empty())
31478 throw CImgInstanceException("CImg<%s>::save_jpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31479 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31480 if (!file && !filename)
31481 throw CImgArgumentException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
31482 pixel_type(),width,height,depth,dim,data);
31483 if (depth>1)
31484 cimg::warn("CImg<%s>::save_jpeg() : File '%s, instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
31485 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31486 #ifndef cimg_use_jpeg
31487 if (!file) return save_other(filename,quality);
31488 else throw CImgIOException("CImg<%s>::save_jpeg() : Cannot save a JPEG image in a *FILE output. Use libjpeg instead.",
31489 pixel_type());
31490 #else
31491 // Fill pixel buffer
31492 unsigned char *buf;
31493 unsigned int dimbuf = 0;
31494 J_COLOR_SPACE colortype = JCS_RGB;
31495 switch (dim) {
31496 case 1 : { // Greyscale images
31497 unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=1)];
31498 colortype = JCS_GRAYSCALE;
31499 const T *ptr_g = data;
31500 cimg_forXY(*this,x,y) *(buf2++) = (unsigned char)*(ptr_g++);
31501 } break;
31502 case 2 : { // RG images
31503 unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
31504 const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1);
31505 colortype = JCS_RGB;
31506 cimg_forXY(*this,x,y) {
31507 *(buf2++) = (unsigned char)*(ptr_r++);
31508 *(buf2++) = (unsigned char)*(ptr_g++);
31509 *(buf2++) = 0;
31510 }
31511 } break;
31512 case 3 : { // RGB images
31513 unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
31514 const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
31515 colortype = JCS_RGB;
31516 cimg_forXY(*this,x,y) {
31517 *(buf2++) = (unsigned char)*(ptr_r++);
31518 *(buf2++) = (unsigned char)*(ptr_g++);
31519 *(buf2++) = (unsigned char)*(ptr_b++);
31520 }
31521 } break;
31522 default : { // CMYK images
31523 unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=4)];
31524 const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3);
31525 colortype = JCS_CMYK;
31526 cimg_forXY(*this,x,y) {
31527 *(buf2++) = (unsigned char)*(ptr_r++);
31528 *(buf2++) = (unsigned char)*(ptr_g++);
31529 *(buf2++) = (unsigned char)*(ptr_b++);
31530 *(buf2++) = (unsigned char)*(ptr_a++);
31531 }
31532 }
31533 }
31535 // Call libjpeg functions
31536 struct jpeg_compress_struct cinfo;
31537 struct jpeg_error_mgr jerr;
31538 cinfo.err = jpeg_std_error(&jerr);
31539 jpeg_create_compress(&cinfo);
31540 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
31541 jpeg_stdio_dest(&cinfo,nfile);
31542 cinfo.image_width = width;
31543 cinfo.image_height = height;
31544 cinfo.input_components = dimbuf;
31545 cinfo.in_color_space = colortype;
31546 jpeg_set_defaults(&cinfo);
31547 jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
31548 jpeg_start_compress(&cinfo,TRUE);
31550 const unsigned int row_stride = width*dimbuf;
31551 JSAMPROW row_pointer[1];
31552 while (cinfo.next_scanline < cinfo.image_height) {
31553 row_pointer[0] = &buf[cinfo.next_scanline*row_stride];
31554 jpeg_write_scanlines(&cinfo,row_pointer,1);
31555 }
31556 jpeg_finish_compress(&cinfo);
31558 delete[] buf;
31559 if (!file) cimg::fclose(nfile);
31560 jpeg_destroy_compress(&cinfo);
31561 return *this;
31562 #endif
31563 }
31565 //! Save a file in JPEG format.
31566 const CImg<T>& save_jpeg(const char *const filename, const unsigned int quality=100) const {
31567 return _save_jpeg(0,filename,quality);
31568 }
31570 //! Save a file in JPEG format.
31571 const CImg<T>& save_jpeg(cimg_std::FILE *const file, const unsigned int quality=100) const {
31572 return _save_jpeg(file,0,quality);
31573 }
31575 //! Save the image using built-in ImageMagick++ library.
31576 const CImg<T>& save_magick(const char *const filename) const {
31577 if (is_empty())
31578 throw CImgInstanceException("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31579 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
31580 if (!filename)
31581 throw CImgArgumentException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31582 pixel_type(),width,height,depth,dim,data);
31583 #ifdef cimg_use_magick
31584 Magick::Image image(Magick::Geometry(width,height),"black");
31585 image.type(Magick::TrueColorType);
31586 const T
31587 *rdata = ptr(0,0,0,0),
31588 *gdata = dim>1?ptr(0,0,0,1):0,
31589 *bdata = dim>2?ptr(0,0,0,2):0;
31590 Magick::PixelPacket *pixels = image.getPixels(0,0,width,height);
31591 switch (dim) {
31592 case 1 : // Scalar images
31593 for (unsigned int off = width*height; off; --off) {
31594 pixels->red = pixels->green = pixels->blue = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
31595 ++pixels;
31596 }
31597 break;
31598 case 2 : // RG images
31599 for (unsigned int off = width*height; off; --off) {
31600 pixels->red = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
31601 pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
31602 pixels->blue = 0;
31603 ++pixels;
31604 }
31605 break;
31606 default : // RGB images
31607 for (unsigned int off = width*height; off; --off) {
31608 pixels->red = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
31609 pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
31610 pixels->blue = Magick::Color::scaleDoubleToQuantum(*(bdata++)/255.0);
31611 ++pixels;
31612 }
31613 }
31614 image.syncPixels();
31615 image.write(filename);
31616 #else
31617 throw CImgIOException("CImg<%s>::save_magick() : File '%s', Magick++ library has not been linked.",
31618 pixel_type(),filename);
31619 #endif
31620 return *this;
31621 }
31623 // Save an image to a PNG file (internal).
31624 // Most of this function has been written by Eric Fausett
31625 const CImg<T>& _save_png(cimg_std::FILE *const file, const char *const filename) const {
31626 if (is_empty())
31627 throw CImgInstanceException("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31628 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31629 if (!filename)
31630 throw CImgArgumentException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
31631 pixel_type(),width,height,depth,dim,data);
31632 if (depth>1)
31633 cimg::warn("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
31634 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31635 #ifndef cimg_use_png
31636 if (!file) return save_other(filename);
31637 else throw CImgIOException("CImg<%s>::save_png() : Cannot save a PNG image in a *FILE output. You must use 'libpng' to do this instead.",
31638 pixel_type());
31639 #else
31640 const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
31641 cimg_std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb");
31643 // Setup PNG structures for write
31644 png_voidp user_error_ptr = 0;
31645 png_error_ptr user_error_fn = 0, user_warning_fn = 0;
31646 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn, user_warning_fn);
31647 if(!png_ptr){
31648 if (!file) cimg::fclose(nfile);
31649 throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'png_ptr' data structure.",
31650 pixel_type(),nfilename?nfilename:"(FILE*)");
31651 }
31652 png_infop info_ptr = png_create_info_struct(png_ptr);
31653 if (!info_ptr) {
31654 png_destroy_write_struct(&png_ptr,(png_infopp)0);
31655 if (!file) cimg::fclose(nfile);
31656 throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'info_ptr' data structure.",
31657 pixel_type(),nfilename?nfilename:"(FILE*)");
31658 }
31659 if (setjmp(png_jmpbuf(png_ptr))) {
31660 png_destroy_write_struct(&png_ptr, &info_ptr);
31661 if (!file) cimg::fclose(nfile);
31662 throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
31663 pixel_type(),nfilename?nfilename:"(FILE*)");
31664 }
31665 png_init_io(png_ptr, nfile);
31666 png_uint_32 width = dimx(), height = dimy();
31667 float vmin, vmax = (float)maxmin(vmin);
31668 const int bit_depth = (vmin<0 || vmax>=256)?16:8;
31669 int color_type;
31670 switch (dimv()) {
31671 case 1 : color_type = PNG_COLOR_TYPE_GRAY; break;
31672 case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
31673 case 3 : color_type = PNG_COLOR_TYPE_RGB; break;
31674 default : color_type = PNG_COLOR_TYPE_RGB_ALPHA;
31675 }
31676 const int interlace_type = PNG_INTERLACE_NONE;
31677 const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
31678 const int filter_method = PNG_FILTER_TYPE_DEFAULT;
31679 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type,compression_type, filter_method);
31680 png_write_info(png_ptr, info_ptr);
31681 const int byte_depth = bit_depth>>3;
31682 const int numChan = dimv()>4?4:dimv();
31683 const int pixel_bit_depth_flag = numChan * (bit_depth-1);
31685 // Allocate Memory for Image Save and Fill pixel data
31686 png_bytep *imgData = new png_byte*[height];
31687 for (unsigned int row = 0; row<height; ++row) imgData[row] = new png_byte[byte_depth*numChan*width];
31688 const T *pC0 = ptr(0,0,0,0);
31689 switch (pixel_bit_depth_flag) {
31690 case 7 : { // Gray 8-bit
31691 cimg_forY(*this,y) {
31692 unsigned char *ptrd = imgData[y];
31693 cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++);
31694 }
31695 } break;
31696 case 14 : { // Gray w/ Alpha 8-bit
31697 const T *pC1 = ptr(0,0,0,1);
31698 cimg_forY(*this,y) {
31699 unsigned char *ptrd = imgData[y];
31700 cimg_forX(*this,x) {
31701 *(ptrd++) = (unsigned char)*(pC0++);
31702 *(ptrd++) = (unsigned char)*(pC1++);
31703 }
31704 }
31705 } break;
31706 case 21 : { // RGB 8-bit
31707 const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
31708 cimg_forY(*this,y) {
31709 unsigned char *ptrd = imgData[y];
31710 cimg_forX(*this,x) {
31711 *(ptrd++) = (unsigned char)*(pC0++);
31712 *(ptrd++) = (unsigned char)*(pC1++);
31713 *(ptrd++) = (unsigned char)*(pC2++);
31714 }
31715 }
31716 } break;
31717 case 28 : { // RGB x/ Alpha 8-bit
31718 const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
31719 cimg_forY(*this,y){
31720 unsigned char *ptrd = imgData[y];
31721 cimg_forX(*this,x){
31722 *(ptrd++) = (unsigned char)*(pC0++);
31723 *(ptrd++) = (unsigned char)*(pC1++);
31724 *(ptrd++) = (unsigned char)*(pC2++);
31725 *(ptrd++) = (unsigned char)*(pC3++);
31726 }
31727 }
31728 } break;
31729 case 15 : { // Gray 16-bit
31730 cimg_forY(*this,y){
31731 unsigned short *ptrd = (unsigned short*)(imgData[y]);
31732 cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++);
31733 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],width);
31734 }
31735 } break;
31736 case 30 : { // Gray w/ Alpha 16-bit
31737 const T *pC1 = ptr(0,0,0,1);
31738 cimg_forY(*this,y){
31739 unsigned short *ptrd = (unsigned short*)(imgData[y]);
31740 cimg_forX(*this,x) {
31741 *(ptrd++) = (unsigned short)*(pC0++);
31742 *(ptrd++) = (unsigned short)*(pC1++);
31743 }
31744 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*width);
31745 }
31746 } break;
31747 case 45 : { // RGB 16-bit
31748 const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
31749 cimg_forY(*this,y) {
31750 unsigned short *ptrd = (unsigned short*)(imgData[y]);
31751 cimg_forX(*this,x) {
31752 *(ptrd++) = (unsigned short)*(pC0++);
31753 *(ptrd++) = (unsigned short)*(pC1++);
31754 *(ptrd++) = (unsigned short)*(pC2++);
31755 }
31756 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*width);
31757 }
31758 } break;
31759 case 60 : { // RGB w/ Alpha 16-bit
31760 const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
31761 cimg_forY(*this,y) {
31762 unsigned short *ptrd = (unsigned short*)(imgData[y]);
31763 cimg_forX(*this,x) {
31764 *(ptrd++) = (unsigned short)*(pC0++);
31765 *(ptrd++) = (unsigned short)*(pC1++);
31766 *(ptrd++) = (unsigned short)*(pC2++);
31767 *(ptrd++) = (unsigned short)*(pC3++);
31768 }
31769 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*width);
31770 }
31771 } break;
31772 default :
31773 if (!file) cimg::fclose(nfile);
31774 throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
31775 pixel_type(),nfilename?nfilename:"(FILE*)");
31776 }
31777 png_write_image(png_ptr, imgData);
31778 png_write_end(png_ptr, info_ptr);
31779 png_destroy_write_struct(&png_ptr, &info_ptr);
31781 // Deallocate Image Write Memory
31782 cimg_forY(*this,n) delete[] imgData[n];
31783 delete[] imgData;
31784 if (!file) cimg::fclose(nfile);
31785 return *this;
31786 #endif
31787 }
31789 //! Save a file in PNG format
31790 const CImg<T>& save_png(const char *const filename) const {
31791 return _save_png(0,filename);
31792 }
31794 //! Save a file in PNG format
31795 const CImg<T>& save_png(cimg_std::FILE *const file) const {
31796 return _save_png(file,0);
31797 }
31799 // Save the image as a PNM file (internal function).
31800 const CImg<T>& _save_pnm(cimg_std::FILE *const file, const char *const filename) const {
31801 if (!file && !filename)
31802 throw CImgArgumentException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31803 pixel_type(),width,height,depth,dim,data);
31804 if (is_empty())
31805 throw CImgInstanceException("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31806 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31807 double stmin, stmax = (double)maxmin(stmin);
31808 if (depth>1)
31809 cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
31810 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31811 if (dim>3)
31812 cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved.",
31813 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31814 if (stmin<0 || stmax>65535)
31815 cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) has pixel values in [%g,%g]. Probable type overflow.",
31816 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data,stmin,stmax);
31817 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
31818 const T
31819 *ptrR = ptr(0,0,0,0),
31820 *ptrG = (dim>=2)?ptr(0,0,0,1):0,
31821 *ptrB = (dim>=3)?ptr(0,0,0,2):0;
31822 const unsigned int buf_size = width*height*(dim==1?1:3);
31824 cimg_std::fprintf(nfile,"P%c\n# CREATOR: CImg Library (original size = %ux%ux%ux%u)\n%u %u\n%u\n",
31825 (dim==1?'5':'6'),width,height,depth,dim,width,height,stmax<256?255:(stmax<4096?4095:65535));
31827 switch (dim) {
31828 case 1 : { // Scalar image
31829 if (stmax<256) { // Binary PGM 8 bits
31830 unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
31831 cimg_forXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++);
31832 cimg::fwrite(ptrd,buf_size,nfile);
31833 delete[] ptrd;
31834 } else { // Binary PGM 16 bits
31835 unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
31836 cimg_forXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++);
31837 if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
31838 cimg::fwrite(ptrd,buf_size,nfile);
31839 delete[] ptrd;
31840 }
31841 } break;
31842 case 2 : { // RG image
31843 if (stmax<256) { // Binary PPM 8 bits
31844 unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
31845 cimg_forXY(*this,x,y) {
31846 *(xptrd++) = (unsigned char)*(ptrR++);
31847 *(xptrd++) = (unsigned char)*(ptrG++);
31848 *(xptrd++) = 0;
31849 }
31850 cimg::fwrite(ptrd,buf_size,nfile);
31851 delete[] ptrd;
31852 } else { // Binary PPM 16 bits
31853 unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
31854 cimg_forXY(*this,x,y) {
31855 *(xptrd++) = (unsigned short)*(ptrR++);
31856 *(xptrd++) = (unsigned short)*(ptrG++);
31857 *(xptrd++) = 0;
31858 }
31859 if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
31860 cimg::fwrite(ptrd,buf_size,nfile);
31861 delete[] ptrd;
31862 }
31863 } break;
31864 default : { // RGB image
31865 if (stmax<256) { // Binary PPM 8 bits
31866 unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
31867 cimg_forXY(*this,x,y) {
31868 *(xptrd++) = (unsigned char)*(ptrR++);
31869 *(xptrd++) = (unsigned char)*(ptrG++);
31870 *(xptrd++) = (unsigned char)*(ptrB++);
31871 }
31872 cimg::fwrite(ptrd,buf_size,nfile);
31873 delete[] ptrd;
31874 } else { // Binary PPM 16 bits
31875 unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
31876 cimg_forXY(*this,x,y) {
31877 *(xptrd++) = (unsigned short)*(ptrR++);
31878 *(xptrd++) = (unsigned short)*(ptrG++);
31879 *(xptrd++) = (unsigned short)*(ptrB++);
31880 }
31881 if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
31882 cimg::fwrite(ptrd,buf_size,nfile);
31883 delete[] ptrd;
31884 }
31885 }
31886 }
31887 if (!file) cimg::fclose(nfile);
31888 return *this;
31889 }
31891 //! Save the image as a PNM file.
31892 const CImg<T>& save_pnm(const char *const filename) const {
31893 return _save_pnm(0,filename);
31894 }
31896 //! Save the image as a PNM file.
31897 const CImg<T>& save_pnm(cimg_std::FILE *const file) const {
31898 return _save_pnm(file,0);
31899 }
31901 // Save the image as a RGB file (internal).
31902 const CImg<T>& _save_rgb(cimg_std::FILE *const file, const char *const filename) const {
31903 if (is_empty())
31904 throw CImgInstanceException("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31905 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31906 if (!file && !filename)
31907 throw CImgArgumentException("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31908 pixel_type(),width,height,depth,dim,data);
31909 if (dim!=3)
31910 cimg::warn("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) has not exactly 3 channels.",
31911 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31912 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
31913 const unsigned int wh = width*height;
31914 unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer;
31915 const T
31916 *ptr1 = ptr(0,0,0,0),
31917 *ptr2 = dim>1?ptr(0,0,0,1):0,
31918 *ptr3 = dim>2?ptr(0,0,0,2):0;
31919 switch (dim) {
31920 case 1 : { // Scalar image
31921 for (unsigned int k=0; k<wh; ++k) {
31922 const unsigned char val = (unsigned char)*(ptr1++);
31923 *(nbuffer++) = val;
31924 *(nbuffer++) = val;
31925 *(nbuffer++) = val;
31926 }} break;
31927 case 2 : { // RG image
31928 for (unsigned int k=0; k<wh; ++k) {
31929 *(nbuffer++) = (unsigned char)(*(ptr1++));
31930 *(nbuffer++) = (unsigned char)(*(ptr2++));
31931 *(nbuffer++) = 0;
31932 }} break;
31933 default : { // RGB image
31934 for (unsigned int k=0; k<wh; ++k) {
31935 *(nbuffer++) = (unsigned char)(*(ptr1++));
31936 *(nbuffer++) = (unsigned char)(*(ptr2++));
31937 *(nbuffer++) = (unsigned char)(*(ptr3++));
31938 }
31939 }
31940 }
31941 cimg::fwrite(buffer,3*wh,nfile);
31942 if (!file) cimg::fclose(nfile);
31943 delete[] buffer;
31944 return *this;
31945 }
31947 //! Save the image as a RGB file.
31948 const CImg<T>& save_rgb(const char *const filename) const {
31949 return _save_rgb(0,filename);
31950 }
31952 //! Save the image as a RGB file.
31953 const CImg<T>& save_rgb(cimg_std::FILE *const file) const {
31954 return _save_rgb(file,0);
31955 }
31957 // Save the image as a RGBA file (internal).
31958 const CImg<T>& _save_rgba(cimg_std::FILE *const file, const char *const filename) const {
31959 if (is_empty())
31960 throw CImgInstanceException("CImg<%s>::save_rgba() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
31961 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31962 if (!file && !filename)
31963 throw CImgArgumentException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
31964 pixel_type(),width,height,depth,dim,data);
31965 if (dim!=4)
31966 cimg::warn("CImg<%s>::save_rgba() : File '%s, instance image (%u,%u,%u,%u,%p) has not exactly 4 channels.",
31967 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
31968 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
31969 const unsigned int wh = width*height;
31970 unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer;
31971 const T
31972 *ptr1 = ptr(0,0,0,0),
31973 *ptr2 = dim>1?ptr(0,0,0,1):0,
31974 *ptr3 = dim>2?ptr(0,0,0,2):0,
31975 *ptr4 = dim>3?ptr(0,0,0,3):0;
31976 switch (dim) {
31977 case 1 : { // Scalar images
31978 for (unsigned int k=0; k<wh; ++k) {
31979 const unsigned char val = (unsigned char)*(ptr1++);
31980 *(nbuffer++) = val;
31981 *(nbuffer++) = val;
31982 *(nbuffer++) = val;
31983 *(nbuffer++) = 255;
31984 }} break;
31985 case 2 : { // RG images
31986 for (unsigned int k=0; k<wh; ++k) {
31987 *(nbuffer++) = (unsigned char)(*(ptr1++));
31988 *(nbuffer++) = (unsigned char)(*(ptr2++));
31989 *(nbuffer++) = 0;
31990 *(nbuffer++) = 255;
31991 }} break;
31992 case 3 : { // RGB images
31993 for (unsigned int k=0; k<wh; ++k) {
31994 *(nbuffer++) = (unsigned char)(*(ptr1++));
31995 *(nbuffer++) = (unsigned char)(*(ptr2++));
31996 *(nbuffer++) = (unsigned char)(*(ptr3++));
31997 *(nbuffer++) = 255;
31998 }} break;
31999 default : { // RGBA images
32000 for (unsigned int k=0; k<wh; ++k) {
32001 *(nbuffer++) = (unsigned char)(*(ptr1++));
32002 *(nbuffer++) = (unsigned char)(*(ptr2++));
32003 *(nbuffer++) = (unsigned char)(*(ptr3++));
32004 *(nbuffer++) = (unsigned char)(*(ptr4++));
32005 }
32006 }
32007 }
32008 cimg::fwrite(buffer,4*wh,nfile);
32009 if (!file) cimg::fclose(nfile);
32010 delete[] buffer;
32011 return *this;
32012 }
32014 //! Save the image as a RGBA file.
32015 const CImg<T>& save_rgba(const char *const filename) const {
32016 return _save_rgba(0,filename);
32017 }
32019 //! Save the image as a RGBA file.
32020 const CImg<T>& save_rgba(cimg_std::FILE *const file) const {
32021 return _save_rgba(file,0);
32022 }
32024 // Save a plane into a tiff file
32025 #ifdef cimg_use_tiff
32026 const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory) const {
32027 if (is_empty() || !tif) return *this;
32028 const char *const filename = TIFFFileName(tif);
32029 uint32 rowsperstrip = (uint32)-1;
32030 uint16 spp = dim, bpp = sizeof(T)*8, photometric, compression = COMPRESSION_NONE;
32031 if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB;
32032 else photometric = PHOTOMETRIC_MINISBLACK;
32033 TIFFSetDirectory(tif,directory);
32034 TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,width);
32035 TIFFSetField(tif,TIFFTAG_IMAGELENGTH,height);
32036 TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
32037 TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp);
32038 if (cimg::type<T>::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3);
32039 else if (cimg::type<T>::min()==0) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,1);
32040 else TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,2);
32041 TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp);
32042 TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
32043 TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric);
32044 TIFFSetField(tif,TIFFTAG_COMPRESSION,compression);
32045 rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip);
32046 TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip);
32047 TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB);
32048 TIFFSetField(tif,TIFFTAG_SOFTWARE,"CImg");
32049 T *buf = (T*)_TIFFmalloc(TIFFStripSize(tif));
32050 if (buf){
32051 for (unsigned int row = 0; row<height; row+=rowsperstrip) {
32052 uint32 nrow = (row+rowsperstrip>height?height-row:rowsperstrip);
32053 tstrip_t strip = TIFFComputeStrip(tif,row,0);
32054 tsize_t i = 0;
32055 for (unsigned int rr = 0; rr<nrow; ++rr)
32056 for (unsigned int cc = 0; cc<width; ++cc)
32057 for (unsigned int vv = 0; vv<spp; ++vv)
32058 buf[i++] = (*this)(cc,row+rr,vv);
32059 if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(T))<0)
32060 throw CImgException("CImg<%s>::save_tiff() : File '%s', an error has occured while writing a strip.",
32061 pixel_type(),filename?filename:"(FILE*)");
32062 }
32063 _TIFFfree(buf);
32064 }
32065 TIFFWriteDirectory(tif);
32066 return (*this);
32067 }
32068 #endif
32070 //! Save a file in TIFF format.
32071 const CImg<T>& save_tiff(const char *const filename) const {
32072 if (is_empty())
32073 throw CImgInstanceException("CImg<%s>::save_tiff() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32074 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32075 if (!filename)
32076 throw CImgArgumentException("CImg<%s>::save_tiff() : Specified filename is (null) for instance image (%u,%u,%u,%u,%p).",
32077 pixel_type(),width,height,depth,dim,data);
32078 #ifdef cimg_use_tiff
32079 TIFF *tif = TIFFOpen(filename,"w");
32080 if (tif) {
32081 cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z);
32082 TIFFClose(tif);
32083 } else throw CImgException("CImg<%s>::save_tiff() : File '%s', error while opening file stream for writing.",
32084 pixel_type(),filename);
32085 #else
32086 return save_other(filename);
32087 #endif
32088 return *this;
32089 }
32091 //! Save the image as an ANALYZE7.5 or NIFTI file.
32092 const CImg<T>& save_analyze(const char *const filename, const float *const voxsize=0) const {
32093 if (is_empty())
32094 throw CImgInstanceException("CImg<%s>::save_analyze() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32095 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32096 if (!filename)
32097 throw CImgArgumentException("CImg<%s>::save_analyze() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32098 pixel_type(),width,height,depth,dim,data);
32099 cimg_std::FILE *file;
32100 char header[348], hname[1024], iname[1024];
32101 const char *ext = cimg::split_filename(filename);
32102 short datatype=-1;
32103 cimg_std::memset(header,0,348);
32104 if (!ext[0]) { cimg_std::sprintf(hname,"%s.hdr",filename); cimg_std::sprintf(iname,"%s.img",filename); }
32105 if (!cimg::strncasecmp(ext,"hdr",3)) {
32106 cimg_std::strcpy(hname,filename); cimg_std::strcpy(iname,filename); cimg_std::sprintf(iname+cimg::strlen(iname)-3,"img");
32107 }
32108 if (!cimg::strncasecmp(ext,"img",3)) {
32109 cimg_std::strcpy(hname,filename); cimg_std::strcpy(iname,filename); cimg_std::sprintf(hname+cimg::strlen(iname)-3,"hdr");
32110 }
32111 if (!cimg::strncasecmp(ext,"nii",3)) {
32112 cimg_std::strcpy(hname,filename); iname[0] = 0;
32113 }
32114 ((int*)(header))[0] = 348;
32115 cimg_std::sprintf(header+4,"CImg");
32116 cimg_std::sprintf(header+14," ");
32117 ((short*)(header+36))[0] = 4096;
32118 ((char*)(header+38))[0] = 114;
32119 ((short*)(header+40))[0] = 4;
32120 ((short*)(header+40))[1] = width;
32121 ((short*)(header+40))[2] = height;
32122 ((short*)(header+40))[3] = depth;
32123 ((short*)(header+40))[4] = dim;
32124 if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2;
32125 if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2;
32126 if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2;
32127 if (!cimg::strcasecmp(pixel_type(),"unsigned short")) datatype = 4;
32128 if (!cimg::strcasecmp(pixel_type(),"short")) datatype = 4;
32129 if (!cimg::strcasecmp(pixel_type(),"unsigned int")) datatype = 8;
32130 if (!cimg::strcasecmp(pixel_type(),"int")) datatype = 8;
32131 if (!cimg::strcasecmp(pixel_type(),"unsigned long")) datatype = 8;
32132 if (!cimg::strcasecmp(pixel_type(),"long")) datatype = 8;
32133 if (!cimg::strcasecmp(pixel_type(),"float")) datatype = 16;
32134 if (!cimg::strcasecmp(pixel_type(),"double")) datatype = 64;
32135 if (datatype<0)
32136 throw CImgIOException("CImg<%s>::save_analyze() : Cannot save image '%s' since pixel type (%s)"
32137 "is not handled in Analyze7.5 specifications.\n",
32138 pixel_type(),filename,pixel_type());
32139 ((short*)(header+70))[0] = datatype;
32140 ((short*)(header+72))[0] = sizeof(T);
32141 ((float*)(header+112))[0] = 1;
32142 ((float*)(header+76))[0] = 0;
32143 if (voxsize) {
32144 ((float*)(header+76))[1] = voxsize[0];
32145 ((float*)(header+76))[2] = voxsize[1];
32146 ((float*)(header+76))[3] = voxsize[2];
32147 } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1;
32148 file = cimg::fopen(hname,"wb");
32149 cimg::fwrite(header,348,file);
32150 if (iname[0]) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); }
32151 cimg::fwrite(data,size(),file);
32152 cimg::fclose(file);
32153 return *this;
32154 }
32156 //! Save the image as a .cimg file.
32157 const CImg<T>& save_cimg(const char *const filename, const bool compress=false) const {
32158 CImgList<T>(*this,true).save_cimg(filename,compress);
32159 return *this;
32160 }
32162 // Save the image as a .cimg file.
32163 const CImg<T>& save_cimg(cimg_std::FILE *const file, const bool compress=false) const {
32164 CImgList<T>(*this,true).save_cimg(file,compress);
32165 return *this;
32166 }
32168 //! Insert the image into an existing .cimg file, at specified coordinates.
32169 const CImg<T>& save_cimg(const char *const filename,
32170 const unsigned int n0,
32171 const unsigned int x0, const unsigned int y0,
32172 const unsigned int z0, const unsigned int v0) const {
32173 CImgList<T>(*this,true).save_cimg(filename,n0,x0,y0,z0,v0);
32174 return *this;
32175 }
32177 //! Insert the image into an existing .cimg file, at specified coordinates.
32178 const CImg<T>& save_cimg(cimg_std::FILE *const file,
32179 const unsigned int n0,
32180 const unsigned int x0, const unsigned int y0,
32181 const unsigned int z0, const unsigned int v0) const {
32182 CImgList<T>(*this,true).save_cimg(file,n0,x0,y0,z0,v0);
32183 return *this;
32184 }
32186 //! Save an empty .cimg file with specified dimensions.
32187 static void save_empty_cimg(const char *const filename,
32188 const unsigned int dx, const unsigned int dy=1,
32189 const unsigned int dz=1, const unsigned int dv=1) {
32190 return CImgList<T>::save_empty_cimg(filename,1,dx,dy,dz,dv);
32191 }
32193 //! Save an empty .cimg file with specified dimensions.
32194 static void save_empty_cimg(cimg_std::FILE *const file,
32195 const unsigned int dx, const unsigned int dy=1,
32196 const unsigned int dz=1, const unsigned int dv=1) {
32197 return CImgList<T>::save_empty_cimg(file,1,dx,dy,dz,dv);
32198 }
32200 // Save the image as an INRIMAGE-4 file (internal).
32201 const CImg<T>& _save_inr(cimg_std::FILE *const file, const char *const filename, const float *const voxsize) const {
32202 if (is_empty())
32203 throw CImgInstanceException("CImg<%s>::save_inr() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32204 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32205 if (!filename)
32206 throw CImgArgumentException("CImg<%s>::save_inr() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32207 pixel_type(),width,height,depth,dim,data);
32208 int inrpixsize=-1;
32209 const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0";
32210 if (!cimg::strcasecmp(pixel_type(),"unsigned char")) { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
32211 if (!cimg::strcasecmp(pixel_type(),"char")) { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
32212 if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; }
32213 if (!cimg::strcasecmp(pixel_type(),"short")) { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; }
32214 if (!cimg::strcasecmp(pixel_type(),"unsigned int")) { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; }
32215 if (!cimg::strcasecmp(pixel_type(),"int")) { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; }
32216 if (!cimg::strcasecmp(pixel_type(),"float")) { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; }
32217 if (!cimg::strcasecmp(pixel_type(),"double")) { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; }
32218 if (inrpixsize<=0)
32219 throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of '%s'",
32220 pixel_type(),pixel_type());
32221 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
32222 char header[257];
32223 int err = cimg_std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim);
32224 if (voxsize) err += cimg_std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]);
32225 err += cimg_std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm");
32226 cimg_std::memset(header+err,'\n',252-err);
32227 cimg_std::memcpy(header+252,"##}\n",4);
32228 cimg::fwrite(header,256,nfile);
32229 cimg_forXYZ(*this,x,y,z) cimg_forV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),1,nfile);
32230 if (!file) cimg::fclose(nfile);
32231 return *this;
32232 }
32234 //! Save the image as an INRIMAGE-4 file.
32235 const CImg<T>& save_inr(const char *const filename, const float *const voxsize=0) const {
32236 return _save_inr(0,filename,voxsize);
32237 }
32239 //! Save the image as an INRIMAGE-4 file.
32240 const CImg<T>& save_inr(cimg_std::FILE *const file, const float *const voxsize=0) const {
32241 return _save_inr(file,0,voxsize);
32242 }
32244 // Save the image as a PANDORE-5 file (internal).
32245 unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const {
32246 unsigned int nbdims = 0;
32247 if (id==2 || id==3 || id==4) { dims[0] = 1; dims[1] = width; nbdims = 2; }
32248 if (id==5 || id==6 || id==7) { dims[0] = 1; dims[1] = height; dims[2] = width; nbdims=3; }
32249 if (id==8 || id==9 || id==10) { dims[0] = dim; dims[1] = depth; dims[2] = height; dims[3] = width; nbdims = 4; }
32250 if (id==16 || id==17 || id==18) { dims[0] = 3; dims[1] = height; dims[2] = width; dims[3] = colorspace; nbdims = 4; }
32251 if (id==19 || id==20 || id==21) { dims[0] = 3; dims[1] = depth; dims[2] = height; dims[3] = width; dims[4] = colorspace; nbdims = 5; }
32252 if (id==22 || id==23 || id==25) { dims[0] = dim; dims[1] = width; nbdims = 2; }
32253 if (id==26 || id==27 || id==29) { dims[0] = dim; dims[1] = height; dims[2] = width; nbdims=3; }
32254 if (id==30 || id==31 || id==33) { dims[0] = dim; dims[1] = depth; dims[2] = height; dims[3] = width; nbdims = 4; }
32255 return nbdims;
32256 }
32258 const CImg<T>& _save_pandore(cimg_std::FILE *const file, const char *const filename, const unsigned int colorspace) const {
32259 typedef unsigned char uchar;
32260 typedef unsigned short ushort;
32261 typedef unsigned int uint;
32262 typedef unsigned long ulong;
32264 #define __cimg_save_pandore_case(dtype) \
32265 dtype *buffer = new dtype[size()]; \
32266 const T *ptrs = data; \
32267 cimg_foroff(*this,off) *(buffer++) = (dtype)(*(ptrs++)); \
32268 buffer-=size(); \
32269 cimg::fwrite(buffer,size(),nfile); \
32270 delete[] buffer
32272 #define _cimg_save_pandore_case(sy,sz,sv,stype,id) \
32273 if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !cimg::strcmp(stype,pixel_type())) { \
32274 unsigned int *iheader = (unsigned int*)(header+12); \
32275 nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \
32276 cimg::fwrite(header,36,nfile); \
32277 if (sizeof(ulong)==4) { ulong ndims[5]; for (int d = 0; d<5; ++d) ndims[d] = (ulong)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
32278 else if (sizeof(uint)==4) { uint ndims[5]; for (int d = 0; d<5; ++d) ndims[d] = (uint)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
32279 else if (sizeof(ushort)==4) { ushort ndims[5]; for (int d = 0; d<5; ++d) ndims[d] = (ushort)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
32280 else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
32281 "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
32282 depth,dim,data); \
32283 if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
32284 __cimg_save_pandore_case(uchar); \
32285 } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
32286 if (sizeof(ulong)==4) { __cimg_save_pandore_case(ulong); } \
32287 else if (sizeof(uint)==4) { __cimg_save_pandore_case(uint); } \
32288 else if (sizeof(ushort)==4) { __cimg_save_pandore_case(ushort); } \
32289 else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
32290 "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
32291 depth,dim,data); \
32292 } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
32293 if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \
32294 else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \
32295 else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
32296 "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
32297 depth,dim,data); \
32298 } \
32299 saved = true; \
32300 }
32302 if (is_empty())
32303 throw CImgInstanceException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32304 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32305 if (!file && !filename)
32306 throw CImgArgumentException("CImg<%s>::save_pandore() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32307 pixel_type(),width,height,depth,dim,data);
32308 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
32309 unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
32310 0,0,0,0,'C','I','m','g',0,0,0,0,0,'N','o',' ','d','a','t','e',0,0,0,0 };
32311 unsigned int nbdims, dims[5];
32312 bool saved = false;
32313 _cimg_save_pandore_case(1,1,1,"unsigned char",2);
32314 _cimg_save_pandore_case(1,1,1,"char",3);
32315 _cimg_save_pandore_case(1,1,1,"short",3);
32316 _cimg_save_pandore_case(1,1,1,"unsigned short",3);
32317 _cimg_save_pandore_case(1,1,1,"unsigned int",3);
32318 _cimg_save_pandore_case(1,1,1,"int",3);
32319 _cimg_save_pandore_case(1,1,1,"unsigned long",4);
32320 _cimg_save_pandore_case(1,1,1,"long",3);
32321 _cimg_save_pandore_case(1,1,1,"float",4);
32322 _cimg_save_pandore_case(1,1,1,"double",4);
32324 _cimg_save_pandore_case(0,1,1,"unsigned char",5);
32325 _cimg_save_pandore_case(0,1,1,"char",6);
32326 _cimg_save_pandore_case(0,1,1,"short",6);
32327 _cimg_save_pandore_case(0,1,1,"unsigned short",6);
32328 _cimg_save_pandore_case(0,1,1,"unsigned int",6);
32329 _cimg_save_pandore_case(0,1,1,"int",6);
32330 _cimg_save_pandore_case(0,1,1,"unsigned long",7);
32331 _cimg_save_pandore_case(0,1,1,"long",6);
32332 _cimg_save_pandore_case(0,1,1,"float",7);
32333 _cimg_save_pandore_case(0,1,1,"double",7);
32335 _cimg_save_pandore_case(0,0,1,"unsigned char",8);
32336 _cimg_save_pandore_case(0,0,1,"char",9);
32337 _cimg_save_pandore_case(0,0,1,"short",9);
32338 _cimg_save_pandore_case(0,0,1,"unsigned short",9);
32339 _cimg_save_pandore_case(0,0,1,"unsigned int",9);
32340 _cimg_save_pandore_case(0,0,1,"int",9);
32341 _cimg_save_pandore_case(0,0,1,"unsigned long",10);
32342 _cimg_save_pandore_case(0,0,1,"long",9);
32343 _cimg_save_pandore_case(0,0,1,"float",10);
32344 _cimg_save_pandore_case(0,0,1,"double",10);
32346 _cimg_save_pandore_case(0,1,3,"unsigned char",16);
32347 _cimg_save_pandore_case(0,1,3,"char",17);
32348 _cimg_save_pandore_case(0,1,3,"short",17);
32349 _cimg_save_pandore_case(0,1,3,"unsigned short",17);
32350 _cimg_save_pandore_case(0,1,3,"unsigned int",17);
32351 _cimg_save_pandore_case(0,1,3,"int",17);
32352 _cimg_save_pandore_case(0,1,3,"unsigned long",18);
32353 _cimg_save_pandore_case(0,1,3,"long",17);
32354 _cimg_save_pandore_case(0,1,3,"float",18);
32355 _cimg_save_pandore_case(0,1,3,"double",18);
32357 _cimg_save_pandore_case(0,0,3,"unsigned char",19);
32358 _cimg_save_pandore_case(0,0,3,"char",20);
32359 _cimg_save_pandore_case(0,0,3,"short",20);
32360 _cimg_save_pandore_case(0,0,3,"unsigned short",20);
32361 _cimg_save_pandore_case(0,0,3,"unsigned int",20);
32362 _cimg_save_pandore_case(0,0,3,"int",20);
32363 _cimg_save_pandore_case(0,0,3,"unsigned long",21);
32364 _cimg_save_pandore_case(0,0,3,"long",20);
32365 _cimg_save_pandore_case(0,0,3,"float",21);
32366 _cimg_save_pandore_case(0,0,3,"double",21);
32368 _cimg_save_pandore_case(1,1,0,"unsigned char",22);
32369 _cimg_save_pandore_case(1,1,0,"char",23);
32370 _cimg_save_pandore_case(1,1,0,"short",23);
32371 _cimg_save_pandore_case(1,1,0,"unsigned short",23);
32372 _cimg_save_pandore_case(1,1,0,"unsigned int",23);
32373 _cimg_save_pandore_case(1,1,0,"int",23);
32374 _cimg_save_pandore_case(1,1,0,"unsigned long",25);
32375 _cimg_save_pandore_case(1,1,0,"long",23);
32376 _cimg_save_pandore_case(1,1,0,"float",25);
32377 _cimg_save_pandore_case(1,1,0,"double",25);
32379 _cimg_save_pandore_case(0,1,0,"unsigned char",26);
32380 _cimg_save_pandore_case(0,1,0,"char",27);
32381 _cimg_save_pandore_case(0,1,0,"short",27);
32382 _cimg_save_pandore_case(0,1,0,"unsigned short",27);
32383 _cimg_save_pandore_case(0,1,0,"unsigned int",27);
32384 _cimg_save_pandore_case(0,1,0,"int",27);
32385 _cimg_save_pandore_case(0,1,0,"unsigned long",29);
32386 _cimg_save_pandore_case(0,1,0,"long",27);
32387 _cimg_save_pandore_case(0,1,0,"float",29);
32388 _cimg_save_pandore_case(0,1,0,"double",29);
32390 _cimg_save_pandore_case(0,0,0,"unsigned char",30);
32391 _cimg_save_pandore_case(0,0,0,"char",31);
32392 _cimg_save_pandore_case(0,0,0,"short",31);
32393 _cimg_save_pandore_case(0,0,0,"unsigned short",31);
32394 _cimg_save_pandore_case(0,0,0,"unsigned int",31);
32395 _cimg_save_pandore_case(0,0,0,"int",31);
32396 _cimg_save_pandore_case(0,0,0,"unsigned long",33);
32397 _cimg_save_pandore_case(0,0,0,"long",31);
32398 _cimg_save_pandore_case(0,0,0,"float",33);
32399 _cimg_save_pandore_case(0,0,0,"double",33);
32401 if (!file) cimg::fclose(nfile);
32402 return *this;
32403 }
32405 //! Save the image as a PANDORE-5 file.
32406 const CImg<T>& save_pandore(const char *const filename, const unsigned int colorspace=0) const {
32407 return _save_pandore(0,filename,colorspace);
32408 }
32410 //! Save the image as a PANDORE-5 file.
32411 const CImg<T>& save_pandore(cimg_std::FILE *const file, const unsigned int colorspace=0) const {
32412 return _save_pandore(file,0,colorspace);
32413 }
32415 // Save the image as a RAW file (internal).
32416 const CImg<T>& _save_raw(cimg_std::FILE *const file, const char *const filename, const bool multiplexed) const {
32417 if (is_empty())
32418 throw CImgInstanceException("CImg<%s>::save_raw() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32419 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32420 if (!file && !filename)
32421 throw CImgArgumentException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
32422 pixel_type(),width,height,depth,dim,data);
32423 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
32424 if (!multiplexed) cimg::fwrite(data,size(),nfile);
32425 else {
32426 CImg<T> buf(dim);
32427 cimg_forXYZ(*this,x,y,z) {
32428 cimg_forV(*this,k) buf[k] = (*this)(x,y,z,k);
32429 cimg::fwrite(buf.data,dim,nfile);
32430 }
32431 }
32432 if (!file) cimg::fclose(nfile);
32433 return *this;
32434 }
32436 //! Save the image as a RAW file.
32437 const CImg<T>& save_raw(const char *const filename, const bool multiplexed=false) const {
32438 return _save_raw(0,filename,multiplexed);
32439 }
32441 //! Save the image as a RAW file.
32442 const CImg<T>& save_raw(cimg_std::FILE *const file, const bool multiplexed=false) const {
32443 return _save_raw(file,0,multiplexed);
32444 }
32446 //! Save the image as a video sequence file, using FFMPEG library.
32447 const CImg<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
32448 const unsigned int fps=25) const {
32449 if (is_empty())
32450 throw CImgInstanceException("CImg<%s>::save_ffmpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32451 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32452 if (!filename)
32453 throw CImgArgumentException("CImg<%s>::save_ffmpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32454 pixel_type(),width,height,depth,dim,data);
32455 if (!fps)
32456 throw CImgArgumentException("CImg<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
32457 pixel_type(),filename);
32458 #ifndef cimg_use_ffmpeg
32459 return save_ffmpeg_external(filename,first_frame,last_frame);
32460 #else
32461 get_split('z').save_ffmpeg(filename,first_frame,last_frame,fps);
32462 #endif
32463 return *this;
32464 }
32466 //! Save the image as a YUV video sequence file.
32467 const CImg<T>& save_yuv(const char *const filename, const bool rgb2yuv=true) const {
32468 get_split('z').save_yuv(filename,rgb2yuv);
32469 return *this;
32470 }
32472 //! Save the image as a YUV video sequence file.
32473 const CImg<T>& save_yuv(cimg_std::FILE *const file, const bool rgb2yuv=true) const {
32474 get_split('z').save_yuv(file,rgb2yuv);
32475 return *this;
32476 }
32478 // Save OFF files (internal).
32479 template<typename tf, typename tc>
32480 const CImg<T>& _save_off(cimg_std::FILE *const file, const char *const filename,
32481 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces) const {
32482 if (is_empty())
32483 throw CImgInstanceException("CImg<%s>::save_off() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32484 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
32485 if (!file && !filename)
32486 throw CImgArgumentException("CImg<%s>::save_off() : Specified filename is (null).",
32487 pixel_type());
32488 if (height<3) return get_resize(-100,3,1,1,0)._save_off(file,filename,primitives,colors,invert_faces);
32489 CImgList<tc> _colors;
32490 if (!colors) _colors.insert(primitives.size,CImg<tc>::vector(200,200,200));
32491 const CImgList<tc>& ncolors = colors?colors:_colors;
32493 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
32494 cimg_std::fprintf(nfile,"OFF\n%u %u %u\n",width,primitives.size,3*primitives.size);
32495 cimg_forX(*this,i) cimg_std::fprintf(nfile,"%f %f %f\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2)));
32496 cimglist_for(primitives,l) {
32497 const unsigned int prim = primitives[l].size();
32498 const bool textured = (prim>4);
32499 const CImg<tc>& color = ncolors[l];
32500 const unsigned int s = textured?color.dimv():color.size();
32501 const float
32502 r = textured?(s>0?(float)(color.get_shared_channel(0).mean()/255.0f):1.0f):(s>0?(float)(color(0)/255.0f):1.0f),
32503 g = textured?(s>1?(float)(color.get_shared_channel(1).mean()/255.0f):r) :(s>1?(float)(color(1)/255.0f):r),
32504 b = textured?(s>2?(float)(color.get_shared_channel(2).mean()/255.0f):r) :(s>2?(float)(color(2)/255.0f):r);
32506 switch (prim) {
32507 case 1 :
32508 cimg_std::fprintf(nfile,"1 %u %f %f %f\n",(unsigned int)primitives(l,0),r,g,b);
32509 break;
32510 case 2 : case 6 :
32511 cimg_std::fprintf(nfile,"2 %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b);
32512 break;
32513 case 3 : case 9 :
32514 if (invert_faces)
32515 cimg_std::fprintf(nfile,"3 %u %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),(unsigned int)primitives(l,2),r,g,b);
32516 else
32517 cimg_std::fprintf(nfile,"3 %u %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b);
32518 break;
32519 case 4 : case 12 :
32520 if (invert_faces)
32521 cimg_std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
32522 (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),(unsigned int)primitives(l,2),(unsigned int)primitives(l,3),r,g,b);
32523 else
32524 cimg_std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
32525 (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),(unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b);
32526 break;
32527 }
32528 }
32529 if (!file) cimg::fclose(nfile);
32530 return *this;
32531 }
32533 //! Save OFF files.
32534 template<typename tf, typename tc>
32535 const CImg<T>& save_off(const char *const filename,
32536 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
32537 return _save_off(0,filename,primitives,colors,invert_faces);
32538 }
32540 //! Save OFF files.
32541 template<typename tf, typename tc>
32542 const CImg<T>& save_off(cimg_std::FILE *const file,
32543 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
32544 return _save_off(file,0,primitives,colors,invert_faces);
32545 }
32547 //! Save the image as a video sequence file, using the external tool 'ffmpeg'.
32548 const CImg<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
32549 const char *const codec="mpeg2video") const {
32550 if (is_empty())
32551 throw CImgInstanceException("CImg<%s>::save_ffmpeg_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32552 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32553 if (!filename)
32554 throw CImgArgumentException("CImg<%s>::save_ffmpeg_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32555 pixel_type(),width,height,depth,dim,data);
32556 get_split('z').save_ffmpeg_external(filename,first_frame,last_frame,codec);
32557 return *this;
32558 }
32560 //! Save the image using GraphicsMagick's gm.
32561 /** Function that saves the image for other file formats that are not natively handled by CImg,
32562 using the tool 'gm' from the GraphicsMagick package.\n
32563 This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
32564 the GraphicsMagick package in order to get
32565 this function working properly (see http://www.graphicsmagick.org ).
32566 **/
32567 const CImg<T>& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const {
32568 if (is_empty())
32569 throw CImgInstanceException("CImg<%s>::save_graphicsmagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32570 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32571 if (!filename)
32572 throw CImgArgumentException("CImg<%s>::save_graphicsmagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32573 pixel_type(),width,height,depth,dim,data);
32574 char command[1024],filetmp[512];
32575 cimg_std::FILE *file;
32576 do {
32577 if (dim==1) cimg_std::sprintf(filetmp,"%s%s%s.pgm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
32578 else cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
32579 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
32580 } while (file);
32581 save_pnm(filetmp);
32582 cimg_std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::graphicsmagick_path(),quality,filetmp,filename);
32583 cimg::system(command);
32584 file = cimg_std::fopen(filename,"rb");
32585 if (!file)
32586 throw CImgIOException("CImg<%s>::save_graphicsmagick_external() : Failed to save image '%s'.\n\n"
32587 "Path of 'gm' : \"%s\"\n"
32588 "Path of temporary filename : \"%s\"\n",
32589 pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
32590 if (file) cimg::fclose(file);
32591 cimg_std::remove(filetmp);
32592 return *this;
32593 }
32595 //! Save an image as a gzipped file, using external tool 'gzip'.
32596 const CImg<T>& save_gzip_external(const char *const filename) const {
32597 if (!filename)
32598 throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
32599 pixel_type());
32600 char command[1024], filetmp[512], body[512];
32601 const char
32602 *ext = cimg::split_filename(filename,body),
32603 *ext2 = cimg::split_filename(body,0);
32604 cimg_std::FILE *file;
32605 do {
32606 if (!cimg::strcasecmp(ext,"gz")) {
32607 if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
32608 cimg::filenamerand(),ext2);
32609 else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
32610 cimg::filenamerand());
32611 } else {
32612 if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
32613 cimg::filenamerand(),ext);
32614 else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
32615 cimg::filenamerand());
32616 }
32617 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
32618 } while (file);
32619 save(filetmp);
32620 cimg_std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
32621 cimg::system(command);
32622 file = cimg_std::fopen(filename,"rb");
32623 if (!file)
32624 throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
32625 pixel_type(),filename);
32626 else cimg::fclose(file);
32627 cimg_std::remove(filetmp);
32628 return *this;
32629 }
32631 //! Save the image using ImageMagick's convert.
32632 /** Function that saves the image for other file formats that are not natively handled by CImg,
32633 using the tool 'convert' from the ImageMagick package.\n
32634 This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
32635 the ImageMagick package in order to get
32636 this function working properly (see http://www.imagemagick.org ).
32637 **/
32638 const CImg<T>& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const {
32639 if (is_empty())
32640 throw CImgInstanceException("CImg<%s>::save_imagemagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32641 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32642 if (!filename)
32643 throw CImgArgumentException("CImg<%s>::save_imagemagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32644 pixel_type(),width,height,depth,dim,data);
32645 char command[1024], filetmp[512];
32646 cimg_std::FILE *file;
32647 do {
32648 cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand(),dim==1?"pgm":"ppm");
32649 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
32650 } while (file);
32651 save_pnm(filetmp);
32652 cimg_std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::imagemagick_path(),quality,filetmp,filename);
32653 cimg::system(command);
32654 file = cimg_std::fopen(filename,"rb");
32655 if (!file)
32656 throw CImgIOException("CImg<%s>::save_imagemagick_external() : Failed to save image '%s'.\n\n"
32657 "Path of 'convert' : \"%s\"\n"
32658 "Path of temporary filename : \"%s\"\n",
32659 pixel_type(),filename,cimg::imagemagick_path(),filetmp);
32660 if (file) cimg::fclose(file);
32661 cimg_std::remove(filetmp);
32662 return *this;
32663 }
32665 //! Save an image as a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net )
32666 const CImg<T>& save_medcon_external(const char *const filename) const {
32667 if (is_empty())
32668 throw CImgInstanceException("CImg<%s>::save_medcon_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32669 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32670 if (!filename)
32671 throw CImgArgumentException("CImg<%s>::save_medcon_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32672 pixel_type(),width,height,depth,dim,data);
32674 char command[1024], filetmp[512], body[512];
32675 cimg_std::FILE *file;
32676 do {
32677 cimg_std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
32678 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
32679 } while (file);
32680 save_analyze(filetmp);
32681 cimg_std::sprintf(command,"%s -w -c dicom -o %s -f %s",cimg::medcon_path(),filename,filetmp);
32682 cimg::system(command);
32683 cimg_std::remove(filetmp);
32684 cimg::split_filename(filetmp,body);
32685 cimg_std::sprintf(filetmp,"%s.img",body);
32686 cimg_std::remove(filetmp);
32687 cimg_std::sprintf(command,"m000-%s",filename);
32688 file = cimg_std::fopen(command,"rb");
32689 if (!file) {
32690 cimg::fclose(cimg::fopen(filename,"r"));
32691 throw CImgIOException("CImg<%s>::save_medcon_external() : Failed to save image '%s'.\n\n"
32692 "Path of 'medcon' : \"%s\"\n"
32693 "Path of temporary filename : \"%s\"",
32694 pixel_type(),filename,cimg::medcon_path(),filetmp);
32695 } else cimg::fclose(file);
32696 cimg_std::rename(command,filename);
32697 return *this;
32698 }
32700 // Try to save the image if other extension is provided.
32701 const CImg<T>& save_other(const char *const filename, const unsigned int quality=100) const {
32702 if (is_empty())
32703 throw CImgInstanceException("CImg<%s>::save_other() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
32704 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
32705 if (!filename)
32706 throw CImgIOException("CImg<%s>::save_other() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
32707 pixel_type());
32708 const unsigned int odebug = cimg::exception_mode();
32709 bool is_saved = true;
32710 cimg::exception_mode() = 0;
32711 try { save_magick(filename); }
32712 catch (CImgException&) {
32713 try { save_imagemagick_external(filename,quality); }
32714 catch (CImgException&) {
32715 try { save_graphicsmagick_external(filename,quality); }
32716 catch (CImgException&) {
32717 is_saved = false;
32718 }
32719 }
32720 }
32721 cimg::exception_mode() = odebug;
32722 if (!is_saved)
32723 throw CImgIOException("CImg<%s>::save_other() : File '%s' cannot be saved.\n"
32724 "Check you have either the ImageMagick or GraphicsMagick package installed.",
32725 pixel_type(),filename);
32726 return *this;
32727 }
32729 // Get a 40x38 color logo of a 'danger' item (internal).
32730 static CImg<T> logo40x38() {
32731 static bool first_time = true;
32732 static CImg<T> res(40,38,1,3);
32733 if (first_time) {
32734 const unsigned char *ptrs = cimg::logo40x38;
32735 T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2);
32736 for (unsigned int off = 0; off<res.width*res.height;) {
32737 const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++);
32738 for (unsigned int l=0; l<n; ++off, ++l) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; }
32739 }
32740 first_time = false;
32741 }
32742 return res;
32743 }
32745 };
32747 /*
32748 #-----------------------------------------
32749 #
32750 #
32751 #
32752 # Definition of the CImgList<> structure
32753 #
32754 #
32755 #
32756 #------------------------------------------
32757 */
32759 //! Class representing list of images CImg<T>.
32760 template<typename T>
32761 struct CImgList {
32763 //! Size of the list (number of elements inside).
32764 unsigned int size;
32766 //! Allocation size of the list.
32767 unsigned int allocsize;
32769 //! Pointer to the first list element.
32770 CImg<T> *data;
32772 //! Define a CImgList<T>::iterator.
32773 typedef CImg<T>* iterator;
32775 //! Define a CImgList<T>::const_iterator.
32776 typedef const CImg<T>* const_iterator;
32778 //! Get value type.
32779 typedef T value_type;
32781 // Define common T-dependant types.
32782 typedef typename cimg::superset<T,bool>::type Tbool;
32783 typedef typename cimg::superset<T,unsigned char>::type Tuchar;
32784 typedef typename cimg::superset<T,char>::type Tchar;
32785 typedef typename cimg::superset<T,unsigned short>::type Tushort;
32786 typedef typename cimg::superset<T,short>::type Tshort;
32787 typedef typename cimg::superset<T,unsigned int>::type Tuint;
32788 typedef typename cimg::superset<T,int>::type Tint;
32789 typedef typename cimg::superset<T,unsigned long>::type Tulong;
32790 typedef typename cimg::superset<T,long>::type Tlong;
32791 typedef typename cimg::superset<T,float>::type Tfloat;
32792 typedef typename cimg::superset<T,double>::type Tdouble;
32793 typedef typename cimg::last<T,bool>::type boolT;
32794 typedef typename cimg::last<T,unsigned char>::type ucharT;
32795 typedef typename cimg::last<T,char>::type charT;
32796 typedef typename cimg::last<T,unsigned short>::type ushortT;
32797 typedef typename cimg::last<T,short>::type shortT;
32798 typedef typename cimg::last<T,unsigned int>::type uintT;
32799 typedef typename cimg::last<T,int>::type intT;
32800 typedef typename cimg::last<T,unsigned long>::type ulongT;
32801 typedef typename cimg::last<T,long>::type longT;
32802 typedef typename cimg::last<T,float>::type floatT;
32803 typedef typename cimg::last<T,double>::type doubleT;
32805 //@}
32806 //---------------------------
32807 //
32808 //! \name Plugins
32809 //@{
32810 //---------------------------
32811 #ifdef cimglist_plugin
32812 #include cimglist_plugin
32813 #endif
32814 #ifdef cimglist_plugin1
32815 #include cimglist_plugin1
32816 #endif
32817 #ifdef cimglist_plugin2
32818 #include cimglist_plugin2
32819 #endif
32820 #ifdef cimglist_plugin3
32821 #include cimglist_plugin3
32822 #endif
32823 #ifdef cimglist_plugin4
32824 #include cimglist_plugin4
32825 #endif
32826 #ifdef cimglist_plugin5
32827 #include cimglist_plugin5
32828 #endif
32829 #ifdef cimglist_plugin6
32830 #include cimglist_plugin6
32831 #endif
32832 #ifdef cimglist_plugin7
32833 #include cimglist_plugin7
32834 #endif
32835 #ifdef cimglist_plugin8
32836 #include cimglist_plugin8
32837 #endif
32838 //@}
32840 //------------------------------------------
32841 //
32842 //! \name Constructors - Destructor - Copy
32843 //@{
32844 //------------------------------------------
32846 //! Destructor.
32847 ~CImgList() {
32848 if (data) delete[] data;
32849 }
32851 //! Default constructor.
32852 CImgList():
32853 size(0),allocsize(0),data(0) {}
32855 //! Construct an image list containing n empty images.
32856 explicit CImgList(const unsigned int n):
32857 size(n) {
32858 data = new CImg<T>[allocsize = cimg::max(16UL,cimg::nearest_pow2(n))];
32859 }
32861 //! Default copy constructor.
32862 template<typename t>
32863 CImgList(const CImgList<t>& list):
32864 size(0),allocsize(0),data(0) {
32865 assign(list.size);
32866 cimglist_for(*this,l) data[l].assign(list[l],false);
32867 }
32869 CImgList(const CImgList<T>& list):
32870 size(0),allocsize(0),data(0) {
32871 assign(list.size);
32872 cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
32873 }
32875 //! Advanced copy constructor.
32876 template<typename t>
32877 CImgList(const CImgList<t>& list, const bool shared):
32878 size(0),allocsize(0),data(0) {
32879 assign(list.size);
32880 if (shared)
32881 throw CImgArgumentException("CImgList<%s>::CImgList() : Cannot construct a list instance with shared images from "
32882 "a CImgList<%s> (different pixel types).",
32883 pixel_type(),CImgList<t>::pixel_type());
32884 cimglist_for(*this,l) data[l].assign(list[l],false);
32885 }
32887 CImgList(const CImgList<T>& list, const bool shared):
32888 size(0),allocsize(0),data(0) {
32889 assign(list.size);
32890 cimglist_for(*this,l) data[l].assign(list[l],shared);
32891 }
32893 //! Construct an image list containing n images with specified size.
32894 CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1,
32895 const unsigned int depth=1, const unsigned int dim=1):
32896 size(0),allocsize(0),data(0) {
32897 assign(n);
32898 cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
32899 }
32901 //! Construct an image list containing n images with specified size, filled with specified value.
32902 CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
32903 const unsigned int depth, const unsigned int dim, const T val):
32904 size(0),allocsize(0),data(0) {
32905 assign(n);
32906 cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
32907 }
32909 //! Construct an image list containing n images with specified size and specified pixel values (int version).
32910 CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
32911 const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...):
32912 size(0),allocsize(0),data(0) {
32913 #define _CImgList_stdarg(t) { \
32914 assign(n,width,height,depth,dim); \
32915 const unsigned int siz = width*height*depth*dim, nsiz = siz*n; \
32916 T *ptrd = data->data; \
32917 va_list ap; \
32918 va_start(ap,val1); \
32919 for (unsigned int l=0, s=0, i=0; i<nsiz; ++i) { \
32920 *(ptrd++) = (T)(i==0?val0:(i==1?val1:va_arg(ap,t))); \
32921 if ((++s)==siz) { ptrd = data[++l].data; s=0; } \
32922 } \
32923 va_end(ap); \
32924 }
32925 _CImgList_stdarg(int);
32926 }
32928 //! Construct an image list containing n images with specified size and specified pixel values (double version).
32929 CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
32930 const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...):
32931 size(0),allocsize(0),data(0) {
32932 _CImgList_stdarg(double);
32933 }
32935 //! Construct a list containing n copies of the image img.
32936 template<typename t>
32937 CImgList(const unsigned int n, const CImg<t>& img):
32938 size(0),allocsize(0),data(0) {
32939 assign(n);
32940 cimglist_for(*this,l) data[l].assign(img,img.is_shared);
32941 }
32943 //! Construct a list containing n copies of the image img, forcing the shared state.
32944 template<typename t>
32945 CImgList(const unsigned int n, const CImg<t>& img, const bool shared):
32946 size(0),allocsize(0),data(0) {
32947 assign(n);
32948 cimglist_for(*this,l) data[l].assign(img,shared);
32949 }
32951 //! Construct an image list from one image.
32952 template<typename t>
32953 explicit CImgList(const CImg<t>& img):
32954 size(0),allocsize(0),data(0) {
32955 assign(1);
32956 data[0].assign(img,img.is_shared);
32957 }
32959 //! Construct an image list from one image, forcing the shared state.
32960 template<typename t>
32961 explicit CImgList(const CImg<t>& img, const bool shared):
32962 size(0),allocsize(0),data(0) {
32963 assign(1);
32964 data[0].assign(img,shared);
32965 }
32967 //! Construct an image list from two images.
32968 template<typename t1, typename t2>
32969 CImgList(const CImg<t1>& img1, const CImg<t2>& img2):
32970 size(0),allocsize(0),data(0) {
32971 assign(2);
32972 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared);
32973 }
32975 //! Construct an image list from two images, forcing the shared state.
32976 template<typename t1, typename t2>
32977 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared):
32978 size(0),allocsize(0),data(0) {
32979 assign(2);
32980 data[0].assign(img1,shared); data[1].assign(img2,shared);
32981 }
32983 //! Construct an image list from three images.
32984 template<typename t1, typename t2, typename t3>
32985 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3):
32986 size(0),allocsize(0),data(0) {
32987 assign(3);
32988 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared);
32989 }
32991 //! Construct an image list from three images, forcing the shared state.
32992 template<typename t1, typename t2, typename t3>
32993 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared):
32994 size(0),allocsize(0),data(0) {
32995 assign(3);
32996 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
32997 }
32999 //! Construct an image list from four images.
33000 template<typename t1, typename t2, typename t3, typename t4>
33001 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4):
33002 size(0),allocsize(0),data(0) {
33003 assign(4);
33004 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
33005 }
33007 //! Construct an image list from four images, forcing the shared state.
33008 template<typename t1, typename t2, typename t3, typename t4>
33009 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const bool shared):
33010 size(0),allocsize(0),data(0) {
33011 assign(4);
33012 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33013 }
33015 //! Construct an image list from five images.
33016 template<typename t1, typename t2, typename t3, typename t4, typename t5>
33017 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33018 const CImg<t5>& img5):
33019 size(0),allocsize(0),data(0) {
33020 assign(5);
33021 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
33022 data[4].assign(img5,img5.is_shared);
33023 }
33025 //! Construct an image list from five images, forcing the shared state.
33026 template<typename t1, typename t2, typename t3, typename t4, typename t5>
33027 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33028 const CImg<t5>& img5, const bool shared):
33029 size(0),allocsize(0),data(0) {
33030 assign(5);
33031 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33032 data[4].assign(img5,shared);
33033 }
33035 //! Construct an image list from six images.
33036 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
33037 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33038 const CImg<t5>& img5, const CImg<t6>& img6):
33039 size(0),allocsize(0),data(0) {
33040 assign(6);
33041 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
33042 data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared);
33043 }
33045 //! Construct an image list from six images, forcing the shared state.
33046 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
33047 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33048 const CImg<t5>& img5, const CImg<t6>& img6, const bool shared):
33049 size(0),allocsize(0),data(0) {
33050 assign(6);
33051 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33052 data[4].assign(img5,shared); data[5].assign(img6,shared);
33053 }
33055 //! Construct an image list from seven images.
33056 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
33057 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33058 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7):
33059 size(0),allocsize(0),data(0) {
33060 assign(7);
33061 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
33062 data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared); data[6].assign(img7,img7.is_shared);
33063 }
33065 //! Construct an image list from seven images, forcing the shared state.
33066 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
33067 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33068 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared):
33069 size(0),allocsize(0),data(0) {
33070 assign(7);
33071 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33072 data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
33073 }
33075 //! Construct an image list from eight images.
33076 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
33077 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33078 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8):
33079 size(0),allocsize(0),data(0) {
33080 assign(8);
33081 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
33082 data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared); data[6].assign(img7,img7.is_shared); data[7].assign(img8,img8.is_shared);
33083 }
33085 //! Construct an image list from eight images, forcing the shared state.
33086 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
33087 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33088 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared):
33089 size(0),allocsize(0),data(0) {
33090 assign(8);
33091 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33092 data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
33093 }
33095 //! Construct an image list from a filename.
33096 CImgList(const char *const filename):
33097 size(0),allocsize(0),data(0) {
33098 assign(filename);
33099 }
33101 //! In-place version of the default constructor and default destructor.
33102 CImgList<T>& assign() {
33103 if (data) delete[] data;
33104 size = allocsize = 0;
33105 data = 0;
33106 return *this;
33107 }
33109 //! Equivalent to assign() (STL-compliant name).
33110 CImgList<T>& clear() {
33111 return assign();
33112 }
33114 //! In-place version of the corresponding constructor.
33115 CImgList<T>& assign(const unsigned int n) {
33116 if (n) {
33117 if (allocsize<n || allocsize>(n<<2)) {
33118 if (data) delete[] data;
33119 data = new CImg<T>[allocsize=cimg::max(16UL,cimg::nearest_pow2(n))];
33120 }
33121 size = n;
33122 } else assign();
33123 return *this;
33124 }
33126 //! In-place version of the corresponding constructor.
33127 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height=1,
33128 const unsigned int depth=1, const unsigned int dim=1) {
33129 assign(n);
33130 cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
33131 return *this;
33132 }
33134 //! In-place version of the corresponding constructor.
33135 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
33136 const unsigned int depth, const unsigned int dim, const T val) {
33137 assign(n);
33138 cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
33139 return *this;
33140 }
33142 //! In-place version of the corresponding constructor.
33143 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
33144 const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...) {
33145 _CImgList_stdarg(int);
33146 return *this;
33147 }
33149 //! In-place version of the corresponding constructor.
33150 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
33151 const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...) {
33152 _CImgList_stdarg(double);
33153 return *this;
33154 }
33156 //! In-place version of the copy constructor.
33157 template<typename t>
33158 CImgList<T>& assign(const CImgList<t>& list) {
33159 assign(list.size);
33160 cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
33161 return *this;
33162 }
33164 //! In-place version of the copy constructor.
33165 template<typename t>
33166 CImgList<T>& assign(const CImgList<t>& list, const bool shared) {
33167 assign(list.size);
33168 cimglist_for(*this,l) data[l].assign(list[l],shared);
33169 return *this;
33170 }
33172 //! In-place version of the corresponding constructor.
33173 template<typename t>
33174 CImgList<T>& assign(const unsigned int n, const CImg<t>& img, const bool shared=false) {
33175 assign(n);
33176 cimglist_for(*this,l) data[l].assign(img,shared);
33177 return *this;
33178 }
33180 //! In-place version of the corresponding constructor.
33181 template<typename t>
33182 CImgList<T>& assign(const CImg<t>& img, const bool shared=false) {
33183 assign(1);
33184 data[0].assign(img,shared);
33185 return *this;
33186 }
33188 //! In-place version of the corresponding constructor.
33189 template<typename t1, typename t2>
33190 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false) {
33191 assign(2);
33192 data[0].assign(img1,shared); data[1].assign(img2,shared);
33193 return *this;
33194 }
33196 //! In-place version of the corresponding constructor.
33197 template<typename t1, typename t2, typename t3>
33198 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false) {
33199 assign(3);
33200 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
33201 return *this;
33202 }
33204 //! In-place version of the corresponding constructor.
33205 template<typename t1, typename t2, typename t3, typename t4>
33206 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33207 const bool shared=false) {
33208 assign(4);
33209 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33210 return *this;
33211 }
33213 //! In-place version of the corresponding constructor.
33214 template<typename t1, typename t2, typename t3, typename t4, typename t5>
33215 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33216 const CImg<t5>& img5, const bool shared=false) {
33217 assign(5);
33218 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33219 data[4].assign(img5,shared);
33220 return *this;
33221 }
33223 //! In-place version of the corresponding constructor.
33224 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
33225 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33226 const CImg<t5>& img5, const CImg<t6>& img6, const bool shared=false) {
33227 assign(6);
33228 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33229 data[4].assign(img5,shared); data[5].assign(img6,shared);
33230 return *this;
33231 }
33233 //! In-place version of the corresponding constructor.
33234 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
33235 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33236 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false) {
33237 assign(7);
33238 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33239 data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
33240 return *this;
33241 }
33243 //! In-place version of the corresponding constructor.
33244 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
33245 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
33246 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false) {
33247 assign(8);
33248 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
33249 data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
33250 return *this;
33251 }
33253 //! In-place version of the corresponding constructor.
33254 CImgList<T>& assign(const char *const filename) {
33255 return load(filename);
33256 }
33258 //! Transfer the content of the instance image list into another one.
33259 template<typename t>
33260 CImgList<T>& transfer_to(CImgList<t>& list) {
33261 list.assign(*this);
33262 assign();
33263 return list;
33264 }
33266 CImgList<T>& transfer_to(CImgList<T>& list) {
33267 list.assign();
33268 return swap(list);
33269 }
33271 //! Swap all fields of two CImgList instances (use with care !)
33272 CImgList<T>& swap(CImgList<T>& list) {
33273 cimg::swap(size,list.size);
33274 cimg::swap(allocsize,list.allocsize);
33275 cimg::swap(data,list.data);
33276 return list;
33277 }
33279 //! Return a string describing the type of the image pixels in the list (template parameter \p T).
33280 static const char* pixel_type() {
33281 return cimg::type<T>::string();
33282 }
33284 //! Return \p true if list is empty.
33285 bool is_empty() const {
33286 return (!data || !size);
33287 }
33289 //! Return \p true if list is not empty.
33290 operator bool() const {
33291 return !is_empty();
33292 }
33294 //! Return \p true if list if of specified size.
33295 bool is_sameN(const unsigned int n) const {
33296 return (size==n);
33297 }
33299 //! Return \p true if list if of specified size.
33300 template<typename t>
33301 bool is_sameN(const CImgList<t>& list) const {
33302 return (size==list.size);
33303 }
33305 // Define useful dimension check functions.
33306 // (not documented because they are macro-generated).
33307 #define _cimglist_def_is_same1(axis) \
33308 bool is_same##axis(const unsigned int val) const { \
33309 bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis(val); return res; \
33310 } \
33311 bool is_sameN##axis(const unsigned int n, const unsigned int val) const { \
33312 return is_sameN(n) && is_same##axis(val); \
33313 } \
33315 #define _cimglist_def_is_same2(axis1,axis2) \
33316 bool is_same##axis1##axis2(const unsigned int val1, const unsigned int val2) const { \
33317 bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis1##axis2(val1,val2); return res; \
33318 } \
33319 bool is_sameN##axis1##axis2(const unsigned int n, const unsigned int val1, const unsigned int val2) const { \
33320 return is_sameN(n) && is_same##axis1##axis2(val1,val2); \
33321 } \
33323 #define _cimglist_def_is_same3(axis1,axis2,axis3) \
33324 bool is_same##axis1##axis2##axis3(const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
33325 bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis1##axis2##axis3(val1,val2,val3); return res; \
33326 } \
33327 bool is_sameN##axis1##axis2##axis3(const unsigned int n, const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
33328 return is_sameN(n) && is_same##axis1##axis2##axis3(val1,val2,val3); \
33329 } \
33331 #define _cimglist_def_is_same(axis) \
33332 template<typename t> bool is_same##axis(const CImg<t>& img) const { \
33333 bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis(img); return res; \
33334 } \
33335 template<typename t> bool is_same##axis(const CImgList<t>& list) const { \
33336 const unsigned int lmin = cimg::min(size,list.size); \
33337 bool res = true; for (unsigned int l = 0; l<lmin && res; ++l) res = data[l].is_same##axis(list[l]); return res; \
33338 } \
33339 template<typename t> bool is_sameN##axis(const unsigned int n, const CImg<t>& img) const { \
33340 return (is_sameN(n) && is_same##axis(img)); \
33341 } \
33342 template<typename t> bool is_sameN##axis(const CImgList<t>& list) const { \
33343 return (is_sameN(list) && is_same##axis(list)); \
33344 }
33346 _cimglist_def_is_same(XY)
33347 _cimglist_def_is_same(XZ)
33348 _cimglist_def_is_same(XV)
33349 _cimglist_def_is_same(YZ)
33350 _cimglist_def_is_same(YV)
33351 _cimglist_def_is_same(XYZ)
33352 _cimglist_def_is_same(XYV)
33353 _cimglist_def_is_same(YZV)
33354 _cimglist_def_is_same(XYZV)
33355 _cimglist_def_is_same1(X)
33356 _cimglist_def_is_same1(Y)
33357 _cimglist_def_is_same1(Z)
33358 _cimglist_def_is_same1(V)
33359 _cimglist_def_is_same2(X,Y)
33360 _cimglist_def_is_same2(X,Z)
33361 _cimglist_def_is_same2(X,V)
33362 _cimglist_def_is_same2(Y,Z)
33363 _cimglist_def_is_same2(Y,V)
33364 _cimglist_def_is_same2(Z,V)
33365 _cimglist_def_is_same3(X,Y,Z)
33366 _cimglist_def_is_same3(X,Y,V)
33367 _cimglist_def_is_same3(X,Z,V)
33368 _cimglist_def_is_same3(Y,Z,V)
33370 bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
33371 bool res = true;
33372 for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_sameXYZV(dx,dy,dz,dv);
33373 return res;
33374 }
33376 bool is_sameNXYZV(const unsigned int n, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
33377 return is_sameN(n) && is_sameXYZV(dx,dy,dz,dv);
33378 }
33380 //! Return \c true if the list contains the pixel (n,x,y,z,v).
33381 bool containsNXYZV(const int n, const int x=0, const int y=0, const int z=0, const int v=0) const {
33382 if (is_empty()) return false;
33383 return n>=0 && n<(int)size && x>=0 && x<data[n].dimx() && y>=0 && y<data[n].dimy() && z>=0 && z<data[n].dimz() && v>=0 && v<data[n].dimv();
33384 }
33386 //! Return \c true if the list contains the image (n).
33387 bool containsN(const int n) const {
33388 if (is_empty()) return false;
33389 return n>=0 && n<(int)size;
33390 }
33392 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z,v).
33393 template<typename t>
33394 bool contains(const T& pixel, t& n, t& x, t&y, t& z, t& v) const {
33395 if (is_empty()) return false;
33396 cimglist_for(*this,l) if (data[l].contains(pixel,x,y,z,v)) { n = (t)l; return true; }
33397 return false;
33398 }
33400 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z).
33401 template<typename t>
33402 bool contains(const T& pixel, t& n, t& x, t&y, t& z) const {
33403 t v;
33404 return contains(pixel,n,x,y,z,v);
33405 }
33407 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y).
33408 template<typename t>
33409 bool contains(const T& pixel, t& n, t& x, t&y) const {
33410 t z,v;
33411 return contains(pixel,n,x,y,z,v);
33412 }
33414 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x).
33415 template<typename t>
33416 bool contains(const T& pixel, t& n, t& x) const {
33417 t y,z,v;
33418 return contains(pixel,n,x,y,z,v);
33419 }
33421 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n).
33422 template<typename t>
33423 bool contains(const T& pixel, t& n) const {
33424 t x,y,z,v;
33425 return contains(pixel,n,x,y,z,v);
33426 }
33428 //! Return \c true if one of the image list contains the specified referenced value.
33429 bool contains(const T& pixel) const {
33430 unsigned int n,x,y,z,v;
33431 return contains(pixel,n,x,y,z,v);
33432 }
33434 //! Return \c true if the list contains the image 'img'. If true, returns the position (n) of the image in the list.
33435 template<typename t>
33436 bool contains(const CImg<T>& img, t& n) const {
33437 if (is_empty()) return false;
33438 const CImg<T> *const ptr = &img;
33439 cimglist_for(*this,i) if (data+i==ptr) { n = (t)i; return true; }
33440 return false;
33441 }
33443 //! Return \c true if the list contains the image img.
33444 bool contains(const CImg<T>& img) const {
33445 unsigned int n;
33446 return contains(img,n);
33447 }
33449 //@}
33450 //------------------------------
33451 //
33452 //! \name Arithmetics Operators
33453 //@{
33454 //------------------------------
33456 //! Assignment operator
33457 template<typename t>
33458 CImgList<T>& operator=(const CImgList<t>& list) {
33459 return assign(list);
33460 }
33462 CImgList<T>& operator=(const CImgList<T>& list) {
33463 return assign(list);
33464 }
33466 //! Assignment operator.
33467 template<typename t>
33468 CImgList<T>& operator=(const CImg<t>& img) {
33469 cimglist_for(*this,l) data[l] = img;
33470 return *this;
33471 }
33473 //! Assignment operator.
33474 CImgList<T>& operator=(const T val) {
33475 cimglist_for(*this,l) data[l].fill(val);
33476 return *this;
33477 }
33479 //! Operator+.
33480 CImgList<T> operator+() const {
33481 return CImgList<T>(*this);
33482 }
33484 //! Operator+=.
33485 #ifdef cimg_use_visualcpp6
33486 CImgList<T>& operator+=(const T val)
33487 #else
33488 template<typename t>
33489 CImgList<T>& operator+=(const t val)
33490 #endif
33491 {
33492 cimglist_for(*this,l) (*this)[l]+=val;
33493 return *this;
33494 }
33496 //! Operator+=.
33497 template<typename t>
33498 CImgList<T>& operator+=(const CImgList<t>& list) {
33499 const unsigned int sizemax = cimg::min(size,list.size);
33500 for (unsigned int l=0; l<sizemax; ++l) (*this)[l]+=list[l];
33501 return *this;
33502 }
33504 //! Operator++ (prefix).
33505 CImgList<T>& operator++() {
33506 cimglist_for(*this,l) ++(*this)[l];
33507 return *this;
33508 }
33510 //! Operator++ (postfix).
33511 CImgList<T> operator++(int) {
33512 CImgList<T> copy(*this);
33513 ++*this;
33514 return copy;
33515 }
33517 //! Operator-.
33518 CImgList<T> operator-() const {
33519 CImgList<T> res(size);
33520 cimglist_for(res,l) res[l].assign(-data[l]);
33521 return res;
33522 }
33524 //! Operator-=.
33525 #ifdef cimg_use_visualcpp6
33526 CImgList<T>& operator-=(const T val)
33527 #else
33528 template<typename t>
33529 CImgList<T>& operator-=(const t val)
33530 #endif
33531 {
33532 cimglist_for(*this,l) (*this)[l]-=val;
33533 return *this;
33534 }
33536 //! Operator-=.
33537 template<typename t>
33538 CImgList<T>& operator-=(const CImgList<t>& list) {
33539 const unsigned int sizemax = min(size,list.size);
33540 for (unsigned int l=0; l<sizemax; ++l) (*this)[l]-=list[l];
33541 return *this;
33542 }
33544 //! Operator-- (prefix).
33545 CImgList<T>& operator--() {
33546 cimglist_for(*this,l) --(*this)[l];
33547 return *this;
33548 }
33550 //! Operator-- (postfix).
33551 CImgList<T> operator--(int) {
33552 CImgList<T> copy(*this);
33553 --*this;
33554 return copy;
33555 }
33557 //! Operator*=.
33558 #ifdef cimg_use_visualcpp6
33559 CImgList<T>& operator*=(const double val)
33560 #else
33561 template<typename t>
33562 CImgList<T>& operator*=(const t val)
33563 #endif
33564 {
33565 cimglist_for(*this,l) (*this)[l]*=val;
33566 return *this;
33567 }
33569 //! Operator*=.
33570 template<typename t>
33571 CImgList<T>& operator*=(const CImgList<t>& list) {
33572 const unsigned int N = cimg::min(size,list.size);
33573 for (unsigned int l=0; l<N; ++l) (*this)[l]*=list[l];
33574 return this;
33575 }
33577 //! Operator/=.
33578 #ifdef cimg_use_visualcpp6
33579 CImgList<T>& operator/=(const double val)
33580 #else
33581 template<typename t>
33582 CImgList<T>& operator/=(const t val)
33583 #endif
33584 {
33585 cimglist_for(*this,l) (*this)[l]/=val;
33586 return *this;
33587 }
33589 //! Operator/=.
33590 template<typename t>
33591 CImgList<T>& operator/=(const CImgList<t>& list) {
33592 const unsigned int N = cimg::min(size,list.size);
33593 for (unsigned int l=0; l<N; ++l) (*this)[l]/=list[l];
33594 return this;
33595 }
33597 //! Return a reference to the maximum pixel value of the instance list.
33598 const T& max() const {
33599 if (is_empty())
33600 throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
33601 pixel_type());
33602 const T *ptrmax = data->data;
33603 T max_value = *ptrmax;
33604 cimglist_for(*this,l) {
33605 const CImg<T>& img = data[l];
33606 cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
33607 }
33608 return *ptrmax;
33609 }
33611 //! Return a reference to the maximum pixel value of the instance list.
33612 T& max() {
33613 if (is_empty())
33614 throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
33615 pixel_type());
33616 T *ptrmax = data->data;
33617 T max_value = *ptrmax;
33618 cimglist_for(*this,l) {
33619 const CImg<T>& img = data[l];
33620 cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
33621 }
33622 return *ptrmax;
33623 }
33625 //! Return a reference to the minimum pixel value of the instance list.
33626 const T& min() const {
33627 if (is_empty())
33628 throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
33629 pixel_type());
33630 const T *ptrmin = data->data;
33631 T min_value = *ptrmin;
33632 cimglist_for(*this,l) {
33633 const CImg<T>& img = data[l];
33634 cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
33635 }
33636 return *ptrmin;
33637 }
33639 //! Return a reference to the minimum pixel value of the instance list.
33640 T& min() {
33641 if (is_empty())
33642 throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
33643 pixel_type());
33644 T *ptrmin = data->data;
33645 T min_value = *ptrmin;
33646 cimglist_for(*this,l) {
33647 const CImg<T>& img = data[l];
33648 cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
33649 }
33650 return *ptrmin;
33651 }
33653 //! Return a reference to the minimum pixel value of the instance list.
33654 template<typename t>
33655 const T& minmax(t& max_val) const {
33656 if (is_empty())
33657 throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
33658 pixel_type());
33659 const T *ptrmin = data->data;
33660 T min_value = *ptrmin, max_value = min_value;
33661 cimglist_for(*this,l) {
33662 const CImg<T>& img = data[l];
33663 cimg_for(img,ptr,T) {
33664 const T val = *ptr;
33665 if (val<min_value) { min_value = val; ptrmin = ptr; }
33666 if (val>max_value) max_value = val;
33667 }
33668 }
33669 max_val = (t)max_value;
33670 return *ptrmin;
33671 }
33673 //! Return a reference to the minimum pixel value of the instance list.
33674 template<typename t>
33675 T& minmax(t& max_val) {
33676 if (is_empty())
33677 throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
33678 pixel_type());
33679 T *ptrmin = data->data;
33680 T min_value = *ptrmin, max_value = min_value;
33681 cimglist_for(*this,l) {
33682 const CImg<T>& img = data[l];
33683 cimg_for(img,ptr,T) {
33684 const T val = *ptr;
33685 if (val<min_value) { min_value = val; ptrmin = ptr; }
33686 if (val>max_value) max_value = val;
33687 }
33688 }
33689 max_val = (t)max_value;
33690 return *ptrmin;
33691 }
33693 //! Return a reference to the minimum pixel value of the instance list.
33694 template<typename t>
33695 const T& maxmin(t& min_val) const {
33696 if (is_empty())
33697 throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
33698 pixel_type());
33699 const T *ptrmax = data->data;
33700 T min_value = *ptrmax, max_value = min_value;
33701 cimglist_for(*this,l) {
33702 const CImg<T>& img = data[l];
33703 cimg_for(img,ptr,T) {
33704 const T val = *ptr;
33705 if (val>max_value) { max_value = val; ptrmax = ptr; }
33706 if (val<min_value) min_value = val;
33707 }
33708 }
33709 min_val = (t)min_value;
33710 return *ptrmax;
33711 }
33713 //! Return a reference to the minimum pixel value of the instance list.
33714 template<typename t>
33715 T& maxmin(t& min_val) {
33716 if (is_empty())
33717 throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
33718 pixel_type());
33719 T *ptrmax = data->data;
33720 T min_value = *ptrmax, max_value = min_value;
33721 cimglist_for(*this,l) {
33722 const CImg<T>& img = data[l];
33723 cimg_for(img,ptr,T) {
33724 const T val = *ptr;
33725 if (val>max_value) { max_value = val; ptrmax = ptr; }
33726 if (val<min_value) min_value = val;
33727 }
33728 }
33729 min_val = (t)min_value;
33730 return *ptrmax;
33731 }
33733 //! Return the mean pixel value of the instance list.
33734 double mean() const {
33735 if (is_empty())
33736 throw CImgInstanceException("CImgList<%s>::mean() : Instance image list is empty.",
33737 pixel_type());
33738 double val = 0;
33739 unsigned int siz = 0;
33740 cimglist_for(*this,l) {
33741 const CImg<T>& img = data[l];
33742 cimg_for(img,ptr,T) val+=(double)*ptr;
33743 siz+=img.size();
33744 }
33745 return val/siz;
33746 }
33748 //! Return the variance of the instance list.
33749 double variance() {
33750 if (is_empty())
33751 throw CImgInstanceException("CImgList<%s>::variance() : Instance image list is empty.",
33752 pixel_type());
33753 double res = 0;
33754 unsigned int siz = 0;
33755 double S = 0, S2 = 0;
33756 cimglist_for(*this,l) {
33757 const CImg<T>& img = data[l];
33758 cimg_for(img,ptr,T) { const double val = (double)*ptr; S+=val; S2+=val*val; }
33759 siz+=img.size();
33760 }
33761 res = (S2 - S*S/siz)/siz;
33762 return res;
33763 }
33765 //! Compute a list of statistics vectors (min,max,mean,variance,xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax).
33766 CImgList<T>& stats(const unsigned int variance_method=1) {
33767 if (is_empty()) return *this;
33768 cimglist_for(*this,l) data[l].stats(variance_method);
33769 return *this;
33770 }
33772 CImgList<Tfloat> get_stats(const unsigned int variance_method=1) const {
33773 CImgList<Tfloat> res(size);
33774 cimglist_for(*this,l) res[l] = data[l].get_stats(variance_method);
33775 return res;
33776 }
33778 //@}
33779 //-------------------------
33780 //
33781 //! \name List Manipulation
33782 //@{
33783 //-------------------------
33785 //! Return a reference to the i-th element of the image list.
33786 CImg<T>& operator[](const unsigned int pos) {
33787 #if cimg_debug>=3
33788 if (pos>=size) {
33789 cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
33790 pixel_type(),pos,size);
33791 return *data;
33792 }
33793 #endif
33794 return data[pos];
33795 }
33797 const CImg<T>& operator[](const unsigned int pos) const {
33798 #if cimg_debug>=3
33799 if (pos>=size) {
33800 cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
33801 pixel_type(),pos,size);
33802 return *data;
33803 }
33804 #endif
33805 return data[pos];
33806 }
33808 //! Equivalent to CImgList<T>::operator[]
33809 CImg<T>& operator()(const unsigned int pos) {
33810 return (*this)[pos];
33811 }
33813 const CImg<T>& operator()(const unsigned int pos) const {
33814 return (*this)[pos];
33815 }
33817 //! Return a reference to (x,y,z,v) pixel of the pos-th image of the list
33818 T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
33819 const unsigned int z=0, const unsigned int v=0) {
33820 return (*this)[pos](x,y,z,v);
33821 }
33822 const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
33823 const unsigned int z=0, const unsigned int v=0) const {
33824 return (*this)[pos](x,y,z,v);
33825 }
33827 // This function is only here for template tricks.
33828 T _display_object3d_at2(const int i, const int j) const {
33829 return atNXY(i,0,j,0,0,0);
33830 }
33832 //! Read an image in specified position.
33833 CImg<T>& at(const int pos) {
33834 if (is_empty())
33835 throw CImgInstanceException("CImgList<%s>::at() : Instance list is empty.",
33836 pixel_type());
33837 return data[pos<0?0:pos>=(int)size?(int)size-1:pos];
33838 }
33840 //! Read a pixel value with Dirichlet boundary conditions.
33841 T& atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
33842 return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXYZV(x,y,z,v,out_val);
33843 }
33845 T atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
33846 return (pos<0 || pos>=(int)size)?out_val:data[pos].atXYZV(x,y,z,v,out_val);
33847 }
33849 //! Read a pixel value with Neumann boundary conditions.
33850 T& atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
33851 if (is_empty())
33852 throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
33853 pixel_type());
33854 return _atNXYZV(pos,x,y,z,v);
33855 }
33857 T atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
33858 if (is_empty())
33859 throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
33860 pixel_type());
33861 return _atNXYZV(pos,x,y,z,v);
33862 }
33864 T& _atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
33865 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZV(x,y,z,v);
33866 }
33868 T _atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
33869 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZV(x,y,z,v);
33870 }
33872 //! Read a pixel value with Dirichlet boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z).
33873 T& atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
33874 return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXYZ(x,y,z,v,out_val);
33875 }
33877 T atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
33878 return (pos<0 || pos>=(int)size)?out_val:data[pos].atXYZ(x,y,z,v,out_val);
33879 }
33881 //! Read a pixel value with Neumann boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z).
33882 T& atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
33883 if (is_empty())
33884 throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
33885 pixel_type());
33886 return _atNXYZ(pos,x,y,z,v);
33887 }
33889 T atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
33890 if (is_empty())
33891 throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
33892 pixel_type());
33893 return _atNXYZ(pos,x,y,z,v);
33894 }
33896 T& _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
33897 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZ(x,y,z,v);
33898 }
33900 T _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
33901 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZ(x,y,z,v);
33902 }
33904 //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c pos, \c x,\c y).
33905 T& atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
33906 return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXY(x,y,z,v,out_val);
33907 }
33909 T atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
33910 return (pos<0 || pos>=(int)size)?out_val:data[pos].atXY(x,y,z,v,out_val);
33911 }
33913 //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c pos, \c x,\c y).
33914 T& atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
33915 if (is_empty())
33916 throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
33917 pixel_type());
33918 return _atNXY(pos,x,y,z,v);
33919 }
33921 T atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
33922 if (is_empty())
33923 throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
33924 pixel_type());
33925 return _atNXY(pos,x,y,z,v);
33926 }
33928 T& _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
33929 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXY(x,y,z,v);
33930 }
33932 T _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
33933 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXY(x,y,z,v);
33934 }
33936 //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c pos,\c x).
33937 T& atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
33938 return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atX(x,y,z,v,out_val);
33939 }
33941 T atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
33942 return (pos<0 || pos>=(int)size)?out_val:data[pos].atX(x,y,z,v,out_val);
33943 }
33945 //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c pos, \c x).
33946 T& atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
33947 if (is_empty())
33948 throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
33949 pixel_type());
33950 return _atNX(pos,x,y,z,v);
33951 }
33953 T atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
33954 if (is_empty())
33955 throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
33956 pixel_type());
33957 return _atNX(pos,x,y,z,v);
33958 }
33960 T& _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
33961 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atX(x,y,z,v);
33962 }
33964 T _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
33965 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atX(x,y,z,v);
33966 }
33968 //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c pos).
33969 T& atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
33970 return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):(*this)(pos,x,y,z,v);
33971 }
33973 T atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
33974 return (pos<0 || pos>=(int)size)?out_val:(*this)(pos,x,y,z,v);
33975 }
33977 //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c pos).
33978 T& atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
33979 if (is_empty())
33980 throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
33981 pixel_type());
33982 return _atN(pos,x,y,z,v);
33983 }
33985 T atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
33986 if (is_empty())
33987 throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
33988 pixel_type());
33989 return _atN(pos,x,y,z,v);
33990 }
33992 T& _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
33993 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)](x,y,z,v);
33994 }
33996 T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
33997 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)](x,y,z,v);
33998 }
34000 //! Returns a reference to the last element.
34001 CImg<T>& back() {
34002 return (*this)(size-1);
34003 }
34005 const CImg<T>& back() const {
34006 return (*this)(size-1);
34007 }
34009 //! Returns a reference to the first element.
34010 CImg<T>& front() {
34011 return *data;
34012 }
34014 const CImg<T>& front() const {
34015 return *data;
34016 }
34018 //! Returns an iterator to the beginning of the vector.
34019 iterator begin() {
34020 return data;
34021 }
34023 const_iterator begin() const {
34024 return data;
34025 }
34027 //! Return a reference to the first image.
34028 const CImg<T>& first() const {
34029 return *data;
34030 }
34032 CImg<T>& first() {
34033 return *data;
34034 }
34036 //! Returns an iterator just past the last element.
34037 iterator end() {
34038 return data + size;
34039 }
34041 const_iterator end() const {
34042 return data + size;
34043 }
34045 //! Return a reference to the last image.
34046 const CImg<T>& last() const {
34047 return data[size - 1];
34048 }
34050 CImg<T>& last() {
34051 return data[size - 1];
34052 }
34054 //! Insert a copy of the image \p img into the current image list, at position \p pos.
34055 template<typename t>
34056 CImgList<T>& insert(const CImg<t>& img, const unsigned int pos, const bool shared) {
34057 const unsigned int npos = pos==~0U?size:pos;
34058 if (npos>size)
34059 throw CImgArgumentException("CImgList<%s>::insert() : Cannot insert at position %u into a list with %u elements",
34060 pixel_type(),npos,size);
34061 if (shared)
34062 throw CImgArgumentException("CImgList<%s>::insert(): Cannot insert a shared image CImg<%s> into a CImgList<%s>",
34063 pixel_type(),img.pixel_type(),pixel_type());
34064 CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
34065 if (!size || !data) {
34066 data = new_data;
34067 *data = img;
34068 } else {
34069 if (new_data) {
34070 if (npos) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
34071 if (npos!=size-1) cimg_std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
34072 cimg_std::memset(data,0,sizeof(CImg<T>)*(size-1));
34073 delete[] data;
34074 data = new_data;
34075 }
34076 else if (npos!=size-1) cimg_std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
34077 data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
34078 data[npos] = img;
34079 }
34080 return *this;
34081 }
34083 CImgList<T>& insert(const CImg<T>& img, const unsigned int pos, const bool shared) {
34084 const unsigned int npos = pos==~0U?size:pos;
34085 if (npos>size)
34086 throw CImgArgumentException("CImgList<%s>::insert() : Can't insert at position %u into a list with %u elements",
34087 pixel_type(),npos,size);
34088 if (&img>=data && &img<data+size) return insert(+img,pos,shared);
34089 CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
34090 if (!size || !data) {
34091 data = new_data;
34092 if (shared && img) {
34093 data->width = img.width; data->height = img.height; data->depth = img.depth; data->dim = img.dim;
34094 data->is_shared = true; data->data = img.data;
34095 } else *data = img;
34096 }
34097 else {
34098 if (new_data) {
34099 if (npos) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
34100 if (npos!=size-1) cimg_std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
34101 if (shared && img) {
34102 new_data[npos].width = img.width; new_data[npos].height = img.height; new_data[npos].depth = img.depth;
34103 new_data[npos].dim = img.dim; new_data[npos].is_shared = true; new_data[npos].data = img.data;
34104 } else {
34105 new_data[npos].width = new_data[npos].height = new_data[npos].depth = new_data[npos].dim = 0; new_data[npos].data = 0;
34106 new_data[npos] = img;
34107 }
34108 cimg_std::memset(data,0,sizeof(CImg<T>)*(size-1));
34109 delete[] data;
34110 data = new_data;
34111 } else {
34112 if (npos!=size-1) cimg_std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
34113 if (shared && img) {
34114 data[npos].width = img.width; data[npos].height = img.height; data[npos].depth = img.depth; data[npos].dim = img.dim;
34115 data[npos].is_shared = true; data[npos].data = img.data;
34116 } else {
34117 data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
34118 data[npos] = img;
34119 }
34120 }
34121 }
34122 return *this;
34123 }
34125 // The two functions below are necessary due to Visual C++ 6.0 function overloading bugs, when
34126 // default parameters are used in function signatures.
34127 template<typename t>
34128 CImgList<T>& insert(const CImg<t>& img, const unsigned int pos) {
34129 return insert(img,pos,false);
34130 }
34132 //! Insert a copy of the image \p img into the current image list, at position \p pos.
34133 template<typename t>
34134 CImgList<T>& insert(const CImg<t>& img) {
34135 return insert(img,~0U,false);
34136 }
34138 template<typename t>
34139 CImgList<T> get_insert(const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
34140 return (+*this).insert(img,pos,shared);
34141 }
34143 //! Insert n empty images img into the current image list, at position \p pos.
34144 CImgList<T>& insert(const unsigned int n, const unsigned int pos=~0U) {
34145 CImg<T> foo;
34146 if (!n) return *this;
34147 const unsigned int npos = pos==~0U?size:pos;
34148 for (unsigned int i=0; i<n; ++i) insert(foo,npos+i);
34149 return *this;
34150 }
34152 CImgList<T> get_insert(const unsigned int n, const unsigned int pos=~0U) const {
34153 return (+*this).insert(n,pos);
34154 }
34156 //! Insert n copies of the image \p img into the current image list, at position \p pos.
34157 template<typename t>
34158 CImgList<T>& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) {
34159 if (!n) return *this;
34160 const unsigned int npos = pos==~0U?size:pos;
34161 insert(img,npos,shared);
34162 for (unsigned int i=1; i<n; ++i) insert(data[npos],npos+i,shared);
34163 return *this;
34164 }
34166 template<typename t>
34167 CImgList<T> get_insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
34168 return (+*this).insert(n,img,pos,shared);
34169 }
34171 //! Insert a copy of the image list \p list into the current image list, starting from position \p pos.
34172 template<typename t>
34173 CImgList<T>& insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
34174 const unsigned int npos = pos==~0U?size:pos;
34175 if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos+l,shared);
34176 else insert(CImgList<T>(list),npos,shared);
34177 return *this;
34178 }
34180 template<typename t>
34181 CImgList<T> get_insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
34182 return (+*this).insert(list,pos,shared);
34183 }
34185 //! Insert n copies of the list \p list at position \p pos of the current list.
34186 template<typename t>
34187 CImgList<T>& insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
34188 if (!n) return *this;
34189 const unsigned int npos = pos==~0U?size:pos;
34190 for (unsigned int i=0; i<n; ++i) insert(list,npos,shared);
34191 return *this;
34192 }
34194 template<typename t>
34195 CImgList<T> get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
34196 return (+*this).insert(n,list,pos,shared);
34197 }
34199 //! Insert a copy of the image \p img at the end of the current image list.
34200 template<typename t>
34201 CImgList<T>& operator<<(const CImg<t>& img) {
34202 return insert(img);
34203 }
34205 //! Insert a copy of the image list \p list at the end of the current image list.
34206 template<typename t>
34207 CImgList<T>& operator<<(const CImgList<t>& list) {
34208 return insert(list);
34209 }
34211 //! Return a copy of the current image list, where the image \p img has been inserted at the end.
34212 template<typename t>
34213 CImgList<T>& operator>>(CImg<t>& img) const {
34214 typedef typename cimg::superset<T,t>::type Tt;
34215 return CImgList<Tt>(*this).insert(img);
34216 }
34218 //! Insert a copy of the current image list at the beginning of the image list \p list.
34219 template<typename t>
34220 CImgList<T>& operator>>(CImgList<t>& list) const {
34221 return list.insert(*this,0);
34222 }
34224 //! Remove the images at positions \p pos1 to \p pos2 from the image list.
34225 CImgList<T>& remove(const unsigned int pos1, const unsigned int pos2) {
34226 const unsigned int
34227 npos1 = pos1<pos2?pos1:pos2,
34228 tpos2 = pos1<pos2?pos2:pos1,
34229 npos2 = tpos2<size?tpos2:size-1;
34230 if (npos1>=size)
34231 cimg::warn("CImgList<%s>::remove() : Cannot remove images from a list (%p,%u), at positions %u->%u.",
34232 pixel_type(),data,size,npos1,tpos2);
34233 else {
34234 if (tpos2>=size)
34235 cimg::warn("CImgList<%s>::remove() : Cannot remove all images from a list (%p,%u), at positions %u->%u.",
34236 pixel_type(),data,size,npos1,tpos2);
34237 for (unsigned int k = npos1; k<=npos2; ++k) data[k].assign();
34238 const unsigned int nb = 1 + npos2 - npos1;
34239 if (!(size-=nb)) return assign();
34240 if (size>(allocsize>>2) || allocsize<=8) { // Removing items without reallocation.
34241 if (npos1!=size) cimg_std::memmove(data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
34242 cimg_std::memset(data+size,0,sizeof(CImg<T>)*nb);
34243 } else { // Removing items with reallocation.
34244 allocsize>>=2;
34245 while (allocsize>8 && size<(allocsize>>1)) allocsize>>=1;
34246 CImg<T> *new_data = new CImg<T>[allocsize];
34247 if (npos1) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos1);
34248 if (npos1!=size) cimg_std::memcpy(new_data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
34249 if (size!=allocsize) cimg_std::memset(new_data+size,0,sizeof(allocsize-size));
34250 cimg_std::memset(data,0,sizeof(CImg<T>)*(size+nb));
34251 delete[] data;
34252 data = new_data;
34253 }
34254 }
34255 return *this;
34256 }
34258 CImgList<T> get_remove(const unsigned int pos1, const unsigned int pos2) const {
34259 return (+*this).remove(pos1,pos2);
34260 }
34262 //! Remove the image at position \p pos from the image list.
34263 CImgList<T>& remove(const unsigned int pos) {
34264 return remove(pos,pos);
34265 }
34267 CImgList<T> get_remove(const unsigned int pos) const {
34268 return (+*this).remove(pos);
34269 }
34271 //! Remove the last image from the image list.
34272 CImgList<T>& remove() {
34273 if (size) return remove(size-1);
34274 else cimg::warn("CImgList<%s>::remove() : List is empty",
34275 pixel_type());
34276 return *this;
34277 }
34279 CImgList<T> get_remove() const {
34280 return (+*this).remove();
34281 }
34283 //! Reverse list order.
34284 CImgList<T>& reverse() {
34285 for (unsigned int l=0; l<size/2; ++l) (*this)[l].swap((*this)[size-1-l]);
34286 return *this;
34287 }
34289 CImgList<T> get_reverse() const {
34290 return (+*this).reverse();
34291 }
34293 //! Get a sub-list.
34294 CImgList<T>& crop(const unsigned int i0, const unsigned int i1, const bool shared=false) {
34295 return get_crop(i0,i1,shared).transfer_to(*this);
34296 }
34298 CImgList<T> get_crop(const unsigned int i0, const unsigned int i1, const bool shared=false) const {
34299 if (i0>i1 || i1>=size)
34300 throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
34301 pixel_type(),i0,i1,size,data);
34302 CImgList<T> res(i1-i0+1);
34303 cimglist_for(res,l) res[l].assign((*this)[i0+l],shared);
34304 return res;
34305 }
34307 //! Get sub-images of a sublist.
34308 CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
34309 const int x0, const int y0, const int z0, const int v0,
34310 const int x1, const int y1, const int z1, const int v1) {
34311 return get_crop(i0,i1,x0,y0,z0,v0,x1,y1,z1,v1).transfer_to(*this);
34312 }
34314 CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
34315 const int x0, const int y0, const int z0, const int v0,
34316 const int x1, const int y1, const int z1, const int v1) const {
34317 if (i0>i1 || i1>=size)
34318 throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
34319 pixel_type(),i0,i1,size,data);
34320 CImgList<T> res(i1-i0+1);
34321 cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,v0,x1,y1,z1,v1);
34322 return res;
34323 }
34325 //! Get sub-images of a sublist.
34326 CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
34327 const int x0, const int y0, const int z0,
34328 const int x1, const int y1, const int z1) {
34329 return get_crop(i0,i1,x0,y0,z0,x1,y1,z1).transfer_to(*this);
34330 }
34332 CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
34333 const int x0, const int y0, const int z0,
34334 const int x1, const int y1, const int z1) const {
34335 if (i0>i1 || i1>=size)
34336 throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
34337 pixel_type(),i0,i1,size,data);
34338 CImgList<T> res(i1-i0+1);
34339 cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,x1,y1,z1);
34340 return res;
34341 }
34343 //! Get sub-images of a sublist.
34344 CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
34345 const int x0, const int y0,
34346 const int x1, const int y1) {
34347 return get_crop(i0,i1,x0,y0,x1,y1).transfer_to(*this);
34348 }
34350 CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
34351 const int x0, const int y0,
34352 const int x1, const int y1) const {
34353 if (i0>i1 || i1>=size)
34354 throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
34355 pixel_type(),i0,i1,size,data);
34356 CImgList<T> res(i1-i0+1);
34357 cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,x1,y1);
34358 return res;
34359 }
34361 //! Get sub-images of a sublist.
34362 CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
34363 const int x0, const int x1) {
34364 return get_crop(i0,i1,x0,x1).transfer_to(*this);
34365 }
34367 CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
34368 const int x0, const int x1) const {
34369 if (i0>i1 || i1>=size)
34370 throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
34371 pixel_type(),i0,i1,size,data);
34372 CImgList<T> res(i1-i0+1);
34373 cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,x1);
34374 return res;
34375 }
34377 //! Display an image list into a CImgDisplay.
34378 const CImgList<T>& operator>>(CImgDisplay& disp) const {
34379 return display(disp);
34380 }
34382 //! Insert image \p img at the end of the list.
34383 template<typename t>
34384 CImgList<T>& push_back(const CImg<t>& img) {
34385 return insert(img);
34386 }
34388 //! Insert image \p img at the front of the list.
34389 template<typename t>
34390 CImgList<T>& push_front(const CImg<t>& img) {
34391 return insert(img,0);
34392 }
34394 //! Insert list \p list at the end of the current list.
34395 template<typename t>
34396 CImgList<T>& push_back(const CImgList<t>& list) {
34397 return insert(list);
34398 }
34400 //! Insert list \p list at the front of the current list.
34401 template<typename t>
34402 CImgList<T>& push_front(const CImgList<t>& list) {
34403 return insert(list,0);
34404 }
34406 //! Remove last element of the list.
34407 CImgList<T>& pop_back() {
34408 return remove(size-1);
34409 }
34411 //! Remove first element of the list.
34412 CImgList<T>& pop_front() {
34413 return remove(0);
34414 }
34416 //! Remove the element pointed by iterator \p iter.
34417 CImgList<T>& erase(const iterator iter) {
34418 return remove(iter-data);
34419 }
34421 //@}
34422 //----------------------------
34423 //
34424 //! \name Fourier Transforms
34425 //@{
34426 //----------------------------
34428 //! Compute the Fast Fourier Transform (along the specified axis).
34429 CImgList<T>& FFT(const char axis, const bool invert=false) {
34430 if (is_empty())
34431 throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",
34432 pixel_type(),size,data);
34433 if (!data[0])
34434 throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) is empty",
34435 pixel_type(),data[0].width,data[0].height,data[0].depth,data[0].dim,data[0].data);
34436 if (size>2)
34437 cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
34438 pixel_type(),size,data);
34439 if (size==1) insert(CImg<T>(data[0].width,data[0].height,data[0].depth,data[0].dim,0));
34440 CImg<T> &Ir = data[0], &Ii = data[1];
34441 if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim)
34442 throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) and imaginary part (%u,%u,%u,%u,%p)"
34443 "have different dimensions",
34444 pixel_type(),Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data);
34446 #ifdef cimg_use_fftw3
34447 fftw_complex *data_in;
34448 fftw_plan data_plan;
34450 switch (cimg::uncase(axis)) {
34451 case 'x' : {
34452 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Ir.width);
34453 data_plan = fftw_plan_dft_1d(Ir.width,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
34454 cimg_forYZV(Ir,y,z,k) {
34455 T *ptrr = Ir.ptr(0,y,z,k), *ptri = Ii.ptr(0,y,z,k);
34456 double *ptrd = (double*)data_in;
34457 cimg_forX(Ir,x) { *(ptrd++) = (double)*(ptrr++); *(ptrd++) = (double)*(ptri++); }
34458 fftw_execute(data_plan);
34459 const unsigned int fact = Ir.width;
34460 if (invert) { cimg_forX(Ir,x) { *(--ptri) = (T)(*(--ptrd)/fact); *(--ptrr) = (T)(*(--ptrd)/fact); }}
34461 else { cimg_forX(Ir,x) { *(--ptri) = (T)*(--ptrd); *(--ptrr) = (T)*(--ptrd); }}
34462 }
34463 } break;
34465 case 'y' : {
34466 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.height);
34467 data_plan = fftw_plan_dft_1d(Ir.height,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
34468 const unsigned int off = Ir.width;
34469 cimg_forXZV(Ir,x,z,k) {
34470 T *ptrr = Ir.ptr(x,0,z,k), *ptri = Ii.ptr(x,0,z,k);
34471 double *ptrd = (double*)data_in;
34472 cimg_forY(Ir,y) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
34473 fftw_execute(data_plan);
34474 const unsigned int fact = Ir.height;
34475 if (invert) { cimg_forY(Ir,y) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
34476 else { cimg_forY(Ir,y) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
34477 }
34478 } break;
34480 case 'z' : {
34481 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.depth);
34482 data_plan = fftw_plan_dft_1d(Ir.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
34483 const unsigned int off = Ir.width*Ir.height;
34484 cimg_forXYV(Ir,x,y,k) {
34485 T *ptrr = Ir.ptr(x,y,0,k), *ptri = Ii.ptr(x,y,0,k);
34486 double *ptrd = (double*)data_in;
34487 cimg_forZ(Ir,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
34488 fftw_execute(data_plan);
34489 const unsigned int fact = Ir.depth;
34490 if (invert) { cimg_forZ(Ir,z) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
34491 else { cimg_forZ(Ir,z) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
34492 }
34493 } break;
34495 case 'v' : {
34496 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.dim);
34497 data_plan = fftw_plan_dft_1d(Ir.dim,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
34498 const unsigned int off = Ir.width*Ir.height*Ir.depth;
34499 cimg_forXYZ(Ir,x,y,z) {
34500 T *ptrr = Ir.ptr(x,y,z,0), *ptri = Ii.ptr(x,y,z,0);
34501 double *ptrd = (double*)data_in;
34502 cimg_forV(Ir,k) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
34503 fftw_execute(data_plan);
34504 const unsigned int fact = Ir.dim;
34505 if (invert) { cimg_forV(Ir,k) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
34506 else { cimg_forV(Ir,k) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
34507 }
34508 } break;
34509 }
34511 fftw_destroy_plan(data_plan);
34512 fftw_free(data_in);
34513 #else
34514 switch (cimg::uncase(axis)) {
34515 case 'x' : { // Fourier along X
34516 const unsigned int N = Ir.width, N2 = (N>>1);
34517 if (((N-1)&N) && N!=1)
34518 throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image along 'x' is %d != 2^N",
34519 pixel_type(),N);
34520 for (unsigned int i=0, j=0; i<N2; ++i) {
34521 if (j>i) cimg_forYZV(Ir,y,z,v) { cimg::swap(Ir(i,y,z,v),Ir(j,y,z,v)); cimg::swap(Ii(i,y,z,v),Ii(j,y,z,v));
34522 if (j<N2) {
34523 const unsigned int ri = N-1-i, rj = N-1-j;
34524 cimg::swap(Ir(ri,y,z,v),Ir(rj,y,z,v)); cimg::swap(Ii(ri,y,z,v),Ii(rj,y,z,v));
34525 }}
34526 for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
34527 }
34528 for (unsigned int delta=2; delta<=N; delta<<=1) {
34529 const unsigned int delta2 = (delta>>1);
34530 for (unsigned int i=0; i<N; i+=delta) {
34531 float wr = 1, wi = 0;
34532 const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
34533 ca = (float)cimg_std::cos(angle),
34534 sa = (float)cimg_std::sin(angle);
34535 for (unsigned int k=0; k<delta2; ++k) {
34536 const unsigned int j = i + k, nj = j + delta2;
34537 cimg_forYZV(Ir,y,z,k) {
34538 T &ir = Ir(j,y,z,k), &ii = Ii(j,y,z,k), &nir = Ir(nj,y,z,k), &nii = Ii(nj,y,z,k);
34539 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
34540 nir = (T)(ir - tmpr);
34541 nii = (T)(ii - tmpi);
34542 ir += (T)tmpr;
34543 ii += (T)tmpi;
34544 }
34545 const float nwr = wr*ca-wi*sa;
34546 wi = wi*ca + wr*sa;
34547 wr = nwr;
34548 }
34549 }
34550 }
34551 if (invert) (*this)/=N;
34552 } break;
34554 case 'y' : { // Fourier along Y
34555 const unsigned int N = Ir.height, N2 = (N>>1);
34556 if (((N-1)&N) && N!=1)
34557 throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'y' is %d != 2^N",
34558 pixel_type(),N);
34559 for (unsigned int i=0, j=0; i<N2; ++i) {
34560 if (j>i) cimg_forXZV(Ir,x,z,v) { cimg::swap(Ir(x,i,z,v),Ir(x,j,z,v)); cimg::swap(Ii(x,i,z,v),Ii(x,j,z,v));
34561 if (j<N2) {
34562 const unsigned int ri = N-1-i, rj = N-1-j;
34563 cimg::swap(Ir(x,ri,z,v),Ir(x,rj,z,v)); cimg::swap(Ii(x,ri,z,v),Ii(x,rj,z,v));
34564 }}
34565 for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
34566 }
34567 for (unsigned int delta=2; delta<=N; delta<<=1) {
34568 const unsigned int delta2 = (delta>>1);
34569 for (unsigned int i=0; i<N; i+=delta) {
34570 float wr = 1, wi = 0;
34571 const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
34572 ca = (float)cimg_std::cos(angle), sa = (float)cimg_std::sin(angle);
34573 for (unsigned int k=0; k<delta2; ++k) {
34574 const unsigned int j = i + k, nj = j + delta2;
34575 cimg_forXZV(Ir,x,z,k) {
34576 T &ir = Ir(x,j,z,k), &ii = Ii(x,j,z,k), &nir = Ir(x,nj,z,k), &nii = Ii(x,nj,z,k);
34577 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
34578 nir = (T)(ir - tmpr);
34579 nii = (T)(ii - tmpi);
34580 ir += (T)tmpr;
34581 ii += (T)tmpi;
34582 }
34583 const float nwr = wr*ca-wi*sa;
34584 wi = wi*ca + wr*sa;
34585 wr = nwr;
34586 }
34587 }
34588 }
34589 if (invert) (*this)/=N;
34590 } break;
34592 case 'z' : { // Fourier along Z
34593 const unsigned int N = Ir.depth, N2 = (N>>1);
34594 if (((N-1)&N) && N!=1)
34595 throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'z' is %d != 2^N",
34596 pixel_type(),N);
34597 for (unsigned int i=0, j=0; i<N2; ++i) {
34598 if (j>i) cimg_forXYV(Ir,x,y,v) { cimg::swap(Ir(x,y,i,v),Ir(x,y,j,v)); cimg::swap(Ii(x,y,i,v),Ii(x,y,j,v));
34599 if (j<N2) {
34600 const unsigned int ri = N-1-i, rj = N-1-j;
34601 cimg::swap(Ir(x,y,ri,v),Ir(x,y,rj,v)); cimg::swap(Ii(x,y,ri,v),Ii(x,y,rj,v));
34602 }}
34603 for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
34604 }
34605 for (unsigned int delta=2; delta<=N; delta<<=1) {
34606 const unsigned int delta2 = (delta>>1);
34607 for (unsigned int i=0; i<N; i+=delta) {
34608 float wr = 1, wi = 0;
34609 const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
34610 ca = (float)cimg_std::cos(angle), sa = (float)cimg_std::sin(angle);
34611 for (unsigned int k=0; k<delta2; ++k) {
34612 const unsigned int j = i + k, nj = j + delta2;
34613 cimg_forXYV(Ir,x,y,k) {
34614 T &ir = Ir(x,y,j,k), &ii = Ii(x,y,j,k), &nir = Ir(x,y,nj,k), &nii = Ii(x,y,nj,k);
34615 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
34616 nir = (T)(ir - tmpr);
34617 nii = (T)(ii - tmpi);
34618 ir += (T)tmpr;
34619 ii += (T)tmpi;
34620 }
34621 const float nwr = wr*ca-wi*sa;
34622 wi = wi*ca + wr*sa;
34623 wr = nwr;
34624 }
34625 }
34626 }
34627 if (invert) (*this)/=N;
34628 } break;
34630 default :
34631 throw CImgArgumentException("CImgList<%s>::FFT() : Invalid axis '%c', must be 'x','y' or 'z'.");
34632 }
34633 #endif
34634 return *this;
34635 }
34637 CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
34638 return CImgList<Tfloat>(*this).FFT(axis,invert);
34639 }
34641 //! Compute the Fast Fourier Transform of a complex image.
34642 CImgList<T>& FFT(const bool invert=false) {
34643 if (is_empty())
34644 throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",
34645 pixel_type(),size,data);
34646 if (size>2)
34647 cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
34648 pixel_type(),size,data);
34649 if (size==1) insert(CImg<T>(data->width,data->height,data->depth,data->dim,0));
34650 CImg<T> &Ir = data[0], &Ii = data[1];
34651 if (Ii.width!=Ir.width || Ii.height!=Ir.height || Ii.depth!=Ir.depth || Ii.dim!=Ir.dim)
34652 throw CImgInstanceException("CImgList<%s>::FFT() : Real (%u,%u,%u,%u,%p) and Imaginary (%u,%u,%u,%u,%p) parts "
34653 "of the instance image have different dimensions",
34654 pixel_type(),Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,
34655 Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data);
34656 #ifdef cimg_use_fftw3
34657 fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.width*Ir.height*Ir.depth);
34658 fftw_plan data_plan;
34659 const unsigned int w = Ir.width, wh = w*Ir.height, whd = wh*Ir.depth;
34660 data_plan = fftw_plan_dft_3d(Ir.width,Ir.height,Ir.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
34661 cimg_forV(Ir,k) {
34662 T *ptrr = Ir.ptr(0,0,0,k), *ptri = Ii.ptr(0,0,0,k);
34663 double *ptrd = (double*)data_in;
34664 for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
34665 for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
34666 for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
34667 *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri;
34668 }
34669 fftw_execute(data_plan);
34670 ptrd = (double*)data_in;
34671 ptrr = Ir.ptr(0,0,0,k);
34672 ptri = Ii.ptr(0,0,0,k);
34673 if (!invert) for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
34674 for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
34675 for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
34676 *ptrr = (T)*(ptrd++); *ptri = (T)*(ptrd++);
34677 }
34678 else for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
34679 for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
34680 for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
34681 *ptrr = (T)(*(ptrd++)/whd); *ptri = (T)(*(ptrd++)/whd);
34682 }
34683 }
34684 fftw_destroy_plan(data_plan);
34685 fftw_free(data_in);
34686 #else
34687 if (Ir.depth>1) FFT('z',invert);
34688 if (Ir.height>1) FFT('y',invert);
34689 if (Ir.width>1) FFT('x',invert);
34690 #endif
34691 return *this;
34692 }
34694 CImgList<Tfloat> get_FFT(const bool invert=false) const {
34695 return CImgList<Tfloat>(*this).FFT(invert);
34696 }
34698 // Return a list where each image has been split along the specified axis.
34699 CImgList<T>& split(const char axis) {
34700 return get_split(axis).transfer_to(*this);
34701 }
34703 CImgList<T> get_split(const char axis) const {
34704 CImgList<T> res;
34705 cimglist_for(*this,l) {
34706 CImgList<T> tmp = data[l].get_split(axis);
34707 const unsigned int pos = res.size;
34708 res.insert(tmp.size);
34709 cimglist_for(tmp,i) tmp[i].transfer_to(data[pos+i]);
34710 }
34711 return res;
34712 }
34714 //! Return a single image which is the concatenation of all images of the current CImgList instance.
34715 /**
34716 \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
34717 \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
34718 \return A CImg<T> image corresponding to the concatenation is returned.
34719 **/
34720 CImg<T> get_append(const char axis, const char align='p') const {
34721 if (is_empty()) return CImg<T>();
34722 if (size==1) return +((*this)[0]);
34723 unsigned int dx = 0, dy = 0, dz = 0, dv = 0, pos = 0;
34724 CImg<T> res;
34725 switch (cimg::uncase(axis)) {
34726 case 'x' : {
34727 switch (cimg::uncase(align)) {
34728 case 'x' : { dy = dz = dv = 1; cimglist_for(*this,l) dx+=(*this)[l].size(); } break;
34729 case 'y' : { dx = size; dz = dv = 1; cimglist_for(*this,l) dy = cimg::max(dy,(unsigned int)(*this)[l].size()); } break;
34730 case 'z' : { dx = size; dy = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
34731 case 'v' : { dx = size; dy = dz = 1; cimglist_for(*this,l) dv = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
34732 default :
34733 cimglist_for(*this,l) {
34734 const CImg<T>& img = (*this)[l];
34735 dx += img.width;
34736 dy = cimg::max(dy,img.height);
34737 dz = cimg::max(dz,img.depth);
34738 dv = cimg::max(dv,img.dim);
34739 }
34740 }
34741 res.assign(dx,dy,dz,dv,0);
34742 switch (cimg::uncase(align)) {
34743 case 'x' : {
34744 cimglist_for(*this,l) {
34745 res.draw_image(pos,CImg<T>((*this)[l],true).unroll('x'));
34746 pos+=(*this)[l].size();
34747 }
34748 } break;
34749 case 'y' : {
34750 cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('y'));
34751 } break;
34752 case 'z' : {
34753 cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('z'));
34754 } break;
34755 case 'v' : {
34756 cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('v'));
34757 } break;
34758 case 'p' : {
34759 cimglist_for(*this,l) { res.draw_image(pos,(*this)[l]); pos+=(*this)[l].width; }
34760 } break;
34761 case 'n' : {
34762 cimglist_for(*this,l) {
34763 res.draw_image(pos,dy-(*this)[l].height,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
34764 pos+=(*this)[l].width;
34765 }
34766 } break;
34767 default : {
34768 cimglist_for(*this,l) {
34769 res.draw_image(pos,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
34770 pos+=(*this)[l].width;
34771 }
34772 } break;
34773 }
34774 } break;
34776 case 'y' : {
34777 switch (cimg::uncase(align)) {
34778 case 'x' : { dy = size; dz = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
34779 case 'y' : { dx = dz = dv = 1; cimglist_for(*this,l) dy+=(*this)[l].size(); } break;
34780 case 'z' : { dy = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
34781 case 'v' : { dy = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
34782 default :
34783 cimglist_for(*this,l) {
34784 const CImg<T>& img = (*this)[l];
34785 dx = cimg::max(dx,img.width);
34786 dy += img.height;
34787 dz = cimg::max(dz,img.depth);
34788 dv = cimg::max(dv,img.dim);
34789 }
34790 }
34791 res.assign(dx,dy,dz,dv,0);
34792 switch (cimg::uncase(align)) {
34793 case 'x' : {
34794 cimglist_for(*this,l) res.draw_image(0,++pos,CImg<T>((*this)[l],true).unroll('x'));
34795 } break;
34796 case 'y' : {
34797 cimglist_for(*this,l) {
34798 res.draw_image(0,pos,CImg<T>((*this)[l],true).unroll('y'));
34799 pos+=(*this)[l].size();
34800 }
34801 } break;
34802 case 'z' : {
34803 cimglist_for(*this,l) res.draw_image(0,pos++,CImg<T>((*this)[l],true).unroll('z'));
34804 } break;
34805 case 'v' : {
34806 cimglist_for(*this,l) res.draw_image(0,pos++,CImg<T>((*this)[l],true).unroll('v'));
34807 } break;
34808 case 'p' : {
34809 cimglist_for(*this,l) { res.draw_image(0,pos,(*this)[l]); pos+=(*this)[l].height; }
34810 } break;
34811 case 'n' : {
34812 cimglist_for(*this,l) {
34813 res.draw_image(dx-(*this)[l].width,pos,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
34814 pos+=(*this)[l].height;
34815 }
34816 } break;
34817 default : {
34818 cimglist_for(*this,l) {
34819 res.draw_image((dx-(*this)[l].width)/2,pos,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
34820 pos+=(*this)[l].height;
34821 }
34822 } break;
34823 }
34824 } break;
34826 case 'z' : {
34827 switch (cimg::uncase(align)) {
34828 case 'x' : { dz = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
34829 case 'y' : { dz = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
34830 case 'z' : { dx = dy = dv = 1; cimglist_for(*this,l) dz+=(*this)[l].size(); } break;
34831 case 'v' : { dz = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
34832 default :
34833 cimglist_for(*this,l) {
34834 const CImg<T>& img = (*this)[l];
34835 dx = cimg::max(dx,img.width);
34836 dy = cimg::max(dy,img.height);
34837 dz += img.depth;
34838 dv = cimg::max(dv,img.dim);
34839 }
34840 }
34841 res.assign(dx,dy,dz,dv,0);
34842 switch (cimg::uncase(align)) {
34843 case 'x' : {
34844 cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('x'));
34845 } break;
34846 case 'y' : {
34847 cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('y'));
34848 } break;
34849 case 'z' : {
34850 cimglist_for(*this,l) {
34851 res.draw_image(0,0,pos,CImg<T>((*this)[l],true).unroll('z'));
34852 pos+=(*this)[l].size();
34853 }
34854 } break;
34855 case 'v' : {
34856 cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('v'));
34857 } break;
34858 case 'p' : {
34859 cimglist_for(*this,l) { res.draw_image(0,0,pos,(*this)[l]); pos+=(*this)[l].depth; }
34860 } break;
34861 case 'n' : {
34862 cimglist_for(*this,l) {
34863 res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,pos,dv-(*this)[l].dim,(*this)[l]);
34864 pos+=(*this)[l].depth;
34865 }
34866 } break;
34867 case 'c' : {
34868 cimglist_for(*this,l) {
34869 res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,pos,(dv-(*this)[l].dim)/2,(*this)[l]);
34870 pos+=(*this)[l].depth;
34871 }
34872 } break;
34873 }
34874 } break;
34876 case 'v' : {
34877 switch (cimg::uncase(align)) {
34878 case 'x' : { dv = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
34879 case 'y' : { dv = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
34880 case 'z' : { dv = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
34881 case 'v' : { dx = dy = dz = 1; cimglist_for(*this,l) dv+=(*this)[l].size(); } break;
34882 default :
34883 cimglist_for(*this,l) {
34884 const CImg<T>& img = (*this)[l];
34885 dx = cimg::max(dx,img.width);
34886 dy = cimg::max(dy,img.height);
34887 dz = cimg::max(dz,img.depth);
34888 dv += img.dim;
34889 }
34890 }
34891 res.assign(dx,dy,dz,dv,0);
34892 switch (cimg::uncase(align)) {
34893 case 'x' : {
34894 cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('x'));
34895 } break;
34896 case 'y' : {
34897 cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('y'));
34898 } break;
34899 case 'z' : {
34900 cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('v'));
34901 } break;
34902 case 'v' : {
34903 cimglist_for(*this,l) {
34904 res.draw_image(0,0,0,pos,CImg<T>((*this)[l],true).unroll('z'));
34905 pos+=(*this)[l].size();
34906 }
34907 } break;
34908 case 'p' : {
34909 cimglist_for(*this,l) { res.draw_image(0,0,0,pos,(*this)[l]); pos+=(*this)[l].dim; }
34910 } break;
34911 case 'n' : {
34912 cimglist_for(*this,l) {
34913 res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,dz-(*this)[l].depth,pos,(*this)[l]);
34914 pos+=(*this)[l].dim;
34915 }
34916 } break;
34917 case 'c' : {
34918 cimglist_for(*this,l) {
34919 res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,pos,(*this)[l]);
34920 pos+=(*this)[l].dim;
34921 }
34922 } break;
34923 }
34924 } break;
34925 default :
34926 throw CImgArgumentException("CImgList<%s>::get_append() : unknow axis '%c', must be 'x','y','z' or 'v'",
34927 pixel_type(),axis);
34928 }
34929 return res;
34930 }
34932 //! Create an auto-cropped font (along the X axis) from a input font \p font.
34933 CImgList<T>& crop_font() {
34934 return get_crop_font().transfer_to(*this);
34935 }
34937 CImgList<T> get_crop_font() const {
34938 CImgList<T> res;
34939 cimglist_for(*this,l) {
34940 const CImg<T>& letter = (*this)[l];
34941 int xmin = letter.width, xmax = 0;
34942 cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
34943 if (xmin>xmax) res.insert(CImg<T>(letter.width,letter.height,1,letter.dim,0));
34944 else res.insert(letter.get_crop(xmin,0,xmax,letter.height-1));
34945 }
34946 res[' '].resize(res['f'].width);
34947 res[' '+256].resize(res['f'].width);
34948 return res;
34949 }
34951 //! Invert primitives orientation of a 3D object.
34952 CImgList<T>& invert_object3d() {
34953 cimglist_for(*this,l) {
34954 CImg<T>& p = data[l];
34955 const unsigned int siz = p.size();
34956 if (siz==2 || siz==3 || siz==6 || siz==9) cimg::swap(p[0],p[1]);
34957 else if (siz==4 || siz==12) cimg::swap(p[0],p[3],p[1],p[2]);
34958 }
34959 return *this;
34960 }
34962 CImgList<T> get_invert_object3d() const {
34963 return (+*this).invert_object3d();
34964 }
34966 //! Return a CImg pre-defined font with desired size.
34967 /**
34968 \param font_height = height of the desired font (can be 11,13,24,38 or 57)
34969 \param fixed_size = tell if the font has a fixed or variable width.
34970 **/
34971 static CImgList<T> font(const unsigned int font_width, const bool variable_size=true) {
34972 if (font_width<=11) {
34973 static CImgList<T> font7x11, nfont7x11;
34974 if (!variable_size && !font7x11) font7x11 = _font(cimg::font7x11,7,11,1,0,false);
34975 if (variable_size && !nfont7x11) nfont7x11 = _font(cimg::font7x11,7,11,1,0,true);
34976 return variable_size?nfont7x11:font7x11;
34977 }
34978 if (font_width<=13) {
34979 static CImgList<T> font10x13, nfont10x13;
34980 if (!variable_size && !font10x13) font10x13 = _font(cimg::font10x13,10,13,1,0,false);
34981 if (variable_size && !nfont10x13) nfont10x13 = _font(cimg::font10x13,10,13,1,0,true);
34982 return variable_size?nfont10x13:font10x13;
34983 }
34984 if (font_width<=17) {
34985 static CImgList<T> font8x17, nfont8x17;
34986 if (!variable_size && !font8x17) font8x17 = _font(cimg::font8x17,8,17,1,0,false);
34987 if (variable_size && !nfont8x17) nfont8x17 = _font(cimg::font8x17,8,17,1,0,true);
34988 return variable_size?nfont8x17:font8x17;
34989 }
34990 if (font_width<=19) {
34991 static CImgList<T> font10x19, nfont10x19;
34992 if (!variable_size && !font10x19) font10x19 = _font(cimg::font10x19,10,19,2,0,false);
34993 if (variable_size && !nfont10x19) nfont10x19 = _font(cimg::font10x19,10,19,2,0,true);
34994 return variable_size?nfont10x19:font10x19;
34995 }
34996 if (font_width<=24) {
34997 static CImgList<T> font12x24, nfont12x24;
34998 if (!variable_size && !font12x24) font12x24 = _font(cimg::font12x24,12,24,2,0,false);
34999 if (variable_size && !nfont12x24) nfont12x24 = _font(cimg::font12x24,12,24,2,0,true);
35000 return variable_size?nfont12x24:font12x24;
35001 }
35002 if (font_width<=32) {
35003 static CImgList<T> font16x32, nfont16x32;
35004 if (!variable_size && !font16x32) font16x32 = _font(cimg::font16x32,16,32,2,0,false);
35005 if (variable_size && !nfont16x32) nfont16x32 = _font(cimg::font16x32,16,32,2,0,true);
35006 return variable_size?nfont16x32:font16x32;
35007 }
35008 if (font_width<=38) {
35009 static CImgList<T> font19x38, nfont19x38;
35010 if (!variable_size && !font19x38) font19x38 = _font(cimg::font19x38,19,38,3,0,false);
35011 if (variable_size && !nfont19x38) nfont19x38 = _font(cimg::font19x38,19,38,3,0,true);
35012 return variable_size?nfont19x38:font19x38;
35013 }
35014 static CImgList<T> font29x57, nfont29x57;
35015 if (!variable_size && !font29x57) font29x57 = _font(cimg::font29x57,29,57,5,0,false);
35016 if (variable_size && !nfont29x57) nfont29x57 = _font(cimg::font29x57,29,57,5,0,true);
35017 return variable_size?nfont29x57:font29x57;
35018 }
35020 static CImgList<T> _font(const unsigned int *const font, const unsigned int w, const unsigned int h,
35021 const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true) {
35022 CImgList<T> res = CImgList<T>(256,w,h,1,3).insert(CImgList<T>(256,w,h,1,1));
35023 const unsigned int *ptr = font;
35024 unsigned int m = 0, val = 0;
35025 for (unsigned int y=0; y<h; ++y)
35026 for (unsigned int x=0; x<256*w; ++x) {
35027 m>>=1; if (!m) { m = 0x80000000; val = *(ptr++); }
35028 CImg<T>& img = res[x/w], &mask = res[x/w+256];
35029 unsigned int xm = x%w;
35030 img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0);
35031 }
35032 if (variable_size) res.crop_font();
35033 if (paddingx || paddingy) cimglist_for(res,l) res[l].resize(res[l].dimx()+paddingx, res[l].dimy()+paddingy,1,-100,0);
35034 return res;
35035 }
35037 //! Display the current CImgList instance in an existing CImgDisplay window (by reference).
35038 /**
35039 This function displays the list images of the current CImgList instance into an existing CImgDisplay window.
35040 Images of the list are concatenated in a single temporarly image for visualization purposes.
35041 The function returns immediately.
35042 \param disp : reference to an existing CImgDisplay instance, where the current image list will be displayed.
35043 \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
35044 \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
35045 \return A reference to the current CImgList instance is returned.
35046 **/
35047 const CImgList<T>& display(CImgDisplay& disp, const char axis='x', const char align='p') const {
35048 get_append(axis,align).display(disp);
35049 return *this;
35050 }
35052 //! Display the current CImgList instance in a new display window.
35053 /**
35054 This function opens a new window with a specific title and displays the list images of the current CImgList instance into it.
35055 Images of the list are concatenated in a single temporarly image for visualization purposes.
35056 The function returns when a key is pressed or the display window is closed by the user.
35057 \param title : specify the title of the opening display window.
35058 \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
35059 \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
35060 \return A reference to the current CImgList instance is returned.
35061 **/
35062 const CImgList<T>& display(CImgDisplay &disp,
35063 const bool display_info, const char axis='x', const char align='p') const {
35064 if (is_empty())
35065 throw CImgInstanceException("CImgList<%s>::display() : Instance list (%u,%u) is empty.",
35066 pixel_type(),size,data);
35067 const CImg<T> visu = get_append(axis,align);
35068 if (display_info) print(disp.title);
35069 visu.display(disp,false);
35070 return *this;
35071 }
35073 //! Display the current CImgList instance in a new display window.
35074 const CImgList<T>& display(const char *const title=0,
35075 const bool display_info=true, const char axis='x', const char align='p') const {
35076 const CImg<T> visu = get_append(axis,align);
35077 char ntitle[64] = { 0 };
35078 if (!title) cimg_std::sprintf(ntitle,"CImgList<%s>",pixel_type());
35079 if (display_info) print(title?title:ntitle);
35080 visu.display(title?title:ntitle,false);
35081 return *this;
35082 }
35084 //@}
35085 //----------------------------------
35086 //
35087 //! \name Input-Output
35088 //@{
35089 //----------------------------------
35091 //! Return a C-string containing the values of all images in the instance list.
35092 CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
35093 if (is_empty()) return CImg<ucharT>(1,1,1,1,0);
35094 CImgList<charT> items;
35095 for (unsigned int l = 0; l<size-1; ++l) {
35096 CImg<charT> item = data[l].value_string(separator,0);
35097 item[item.size()-1] = separator;
35098 items.insert(item);
35099 }
35100 items.insert(data[size-1].value_string(separator,0));
35101 CImg<charT> res = items.get_append('x');
35102 if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
35103 return res;
35104 }
35106 //! Print informations about the list on the standard output.
35107 const CImgList<T>& print(const char* title=0, const bool display_stats=true) const {
35108 unsigned long msiz = 0;
35109 cimglist_for(*this,l) msiz += data[l].size();
35110 msiz*=sizeof(T);
35111 const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2);
35112 char ntitle[64] = { 0 };
35113 if (!title) cimg_std::sprintf(ntitle,"CImgList<%s>",pixel_type());
35114 cimg_std::fprintf(cimg_stdout,"%s: this = %p, size = %u [%lu %s], data = (CImg<%s>*)%p.\n",
35115 title?title:ntitle,(void*)this,size,
35116 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
35117 mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
35118 pixel_type(),(void*)data);
35119 char tmp[16] = { 0 };
35120 cimglist_for(*this,ll) {
35121 cimg_std::sprintf(tmp,"[%d]",ll);
35122 cimg_std::fprintf(cimg_stdout," ");
35123 data[ll].print(tmp,display_stats);
35124 if (ll==3 && size>8) { ll = size-5; cimg_std::fprintf(cimg_stdout," ...\n"); }
35125 }
35126 return *this;
35127 }
35129 //! Load an image list from a file.
35130 CImgList<T>& load(const char *const filename) {
35131 const char *ext = cimg::split_filename(filename);
35132 const unsigned int odebug = cimg::exception_mode();
35133 cimg::exception_mode() = 0;
35134 assign();
35135 try {
35136 #ifdef cimglist_load_plugin
35137 cimglist_load_plugin(filename);
35138 #endif
35139 #ifdef cimglist_load_plugin1
35140 cimglist_load_plugin1(filename);
35141 #endif
35142 #ifdef cimglist_load_plugin2
35143 cimglist_load_plugin2(filename);
35144 #endif
35145 #ifdef cimglist_load_plugin3
35146 cimglist_load_plugin3(filename);
35147 #endif
35148 #ifdef cimglist_load_plugin4
35149 cimglist_load_plugin4(filename);
35150 #endif
35151 #ifdef cimglist_load_plugin5
35152 cimglist_load_plugin5(filename);
35153 #endif
35154 #ifdef cimglist_load_plugin6
35155 cimglist_load_plugin6(filename);
35156 #endif
35157 #ifdef cimglist_load_plugin7
35158 cimglist_load_plugin7(filename);
35159 #endif
35160 #ifdef cimglist_load_plugin8
35161 cimglist_load_plugin8(filename);
35162 #endif
35163 if (!cimg::strcasecmp(ext,"tif") ||
35164 !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
35165 if (!cimg::strcasecmp(ext,"cimg") ||
35166 !cimg::strcasecmp(ext,"cimgz") ||
35167 !ext[0]) load_cimg(filename);
35168 if (!cimg::strcasecmp(ext,"rec") ||
35169 !cimg::strcasecmp(ext,"par")) load_parrec(filename);
35170 if (!cimg::strcasecmp(ext,"avi") ||
35171 !cimg::strcasecmp(ext,"mov") ||
35172 !cimg::strcasecmp(ext,"asf") ||
35173 !cimg::strcasecmp(ext,"divx") ||
35174 !cimg::strcasecmp(ext,"flv") ||
35175 !cimg::strcasecmp(ext,"mpg") ||
35176 !cimg::strcasecmp(ext,"m1v") ||
35177 !cimg::strcasecmp(ext,"m2v") ||
35178 !cimg::strcasecmp(ext,"m4v") ||
35179 !cimg::strcasecmp(ext,"mjp") ||
35180 !cimg::strcasecmp(ext,"mkv") ||
35181 !cimg::strcasecmp(ext,"mpe") ||
35182 !cimg::strcasecmp(ext,"movie") ||
35183 !cimg::strcasecmp(ext,"ogm") ||
35184 !cimg::strcasecmp(ext,"qt") ||
35185 !cimg::strcasecmp(ext,"rm") ||
35186 !cimg::strcasecmp(ext,"vob") ||
35187 !cimg::strcasecmp(ext,"wmv") ||
35188 !cimg::strcasecmp(ext,"xvid") ||
35189 !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
35190 if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
35191 if (is_empty()) throw CImgIOException("CImgList<%s>::load()",pixel_type());
35192 } catch (CImgIOException& e) {
35193 if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
35194 cimg::exception_mode() = odebug;
35195 throw CImgIOException("CImgList<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
35196 } else try {
35197 assign(1);
35198 data->load(filename);
35199 } catch (CImgException&) {
35200 assign();
35201 }
35202 }
35203 cimg::exception_mode() = odebug;
35204 if (is_empty())
35205 throw CImgIOException("CImgList<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
35206 return *this;
35207 }
35209 static CImgList<T> get_load(const char *const filename) {
35210 return CImgList<T>().load(filename);
35211 }
35213 //! Load an image list from a .cimg file.
35214 CImgList<T>& load_cimg(const char *const filename) {
35215 return _load_cimg(0,filename);
35216 }
35218 static CImgList<T> get_load_cimg(const char *const filename) {
35219 return CImgList<T>().load_cimg(filename);
35220 }
35222 //! Load an image list from a .cimg file.
35223 CImgList<T>& load_cimg(cimg_std::FILE *const file) {
35224 return _load_cimg(file,0);
35225 }
35227 static CImgList<T> get_load_cimg(cimg_std::FILE *const file) {
35228 return CImgList<T>().load_cimg(file);
35229 }
35231 CImgList<T>& _load_cimg(cimg_std::FILE *const file, const char *const filename) {
35232 #ifdef cimg_use_zlib
35233 #define _cimgz_load_cimg_case(Tss) { \
35234 Bytef *const cbuf = new Bytef[csiz]; \
35235 cimg::fread(cbuf,csiz,nfile); \
35236 raw.assign(W,H,D,V); \
35237 unsigned long destlen = raw.size()*sizeof(T); \
35238 uncompress((Bytef*)raw.data,&destlen,cbuf,csiz); \
35239 delete[] cbuf; \
35240 const Tss *ptrs = raw.data; \
35241 for (unsigned int off = raw.size(); off; --off) *(ptrd++) = (T)*(ptrs++); \
35242 }
35243 #else
35244 #define _cimgz_load_cimg_case(Tss) \
35245 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s' contains compressed data, zlib must be used",\
35246 pixel_type(),filename?filename:"(FILE*)");
35247 #endif
35249 #define _cimg_load_cimg_case(Ts,Tss) \
35250 if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
35251 for (unsigned int l = 0; l<N; ++l) { \
35252 j = 0; while ((i=cimg_std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = '\0'; \
35253 W = H = D = V = 0; csiz = 0; \
35254 if ((err = cimg_std::sscanf(tmp,"%u %u %u %u #%u",&W,&H,&D,&V,&csiz))<4) \
35255 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
35256 pixel_type(),filename?filename:("(FILE*)"),W,H,D,V); \
35257 if (W*H*D*V>0) { \
35258 CImg<Tss> raw; \
35259 CImg<T> &img = data[l]; \
35260 img.assign(W,H,D,V); \
35261 T *ptrd = img.data; \
35262 if (err==5) _cimgz_load_cimg_case(Tss) \
35263 else for (int toread = (int)img.size(); toread>0; ) { \
35264 raw.assign(cimg::min(toread,cimg_iobuffer)); \
35265 cimg::fread(raw.data,raw.width,nfile); \
35266 if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
35267 toread-=raw.width; \
35268 const Tss *ptrs = raw.data; \
35269 for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
35270 } \
35271 } \
35272 } \
35273 loaded = true; \
35274 }
35276 if (!filename && !file)
35277 throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
35278 pixel_type());
35279 typedef unsigned char uchar;
35280 typedef unsigned short ushort;
35281 typedef unsigned int uint;
35282 typedef unsigned long ulong;
35283 const int cimg_iobuffer = 12*1024*1024;
35284 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
35285 bool loaded = false, endian = cimg::endianness();
35286 char tmp[256], str_pixeltype[256], str_endian[256];
35287 unsigned int j, err, N = 0, W, H, D, V, csiz;
35288 int i;
35289 j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
35290 err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
35291 if (err<2) {
35292 if (!file) cimg::fclose(nfile);
35293 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
35294 pixel_type(),filename?filename:"(FILE*)");
35295 }
35296 if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
35297 else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
35298 assign(N);
35299 _cimg_load_cimg_case("bool",bool);
35300 _cimg_load_cimg_case("unsigned_char",uchar);
35301 _cimg_load_cimg_case("uchar",uchar);
35302 _cimg_load_cimg_case("char",char);
35303 _cimg_load_cimg_case("unsigned_short",ushort);
35304 _cimg_load_cimg_case("ushort",ushort);
35305 _cimg_load_cimg_case("short",short);
35306 _cimg_load_cimg_case("unsigned_int",uint);
35307 _cimg_load_cimg_case("uint",uint);
35308 _cimg_load_cimg_case("int",int);
35309 _cimg_load_cimg_case("unsigned_long",ulong);
35310 _cimg_load_cimg_case("ulong",ulong);
35311 _cimg_load_cimg_case("long",long);
35312 _cimg_load_cimg_case("float",float);
35313 _cimg_load_cimg_case("double",double);
35314 if (!loaded) {
35315 if (!file) cimg::fclose(nfile);
35316 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
35317 pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
35318 }
35319 if (!file) cimg::fclose(nfile);
35320 return *this;
35321 }
35323 //! Load a sub-image list from a non compressed .cimg file.
35324 CImgList<T>& load_cimg(const char *const filename,
35325 const unsigned int n0, const unsigned int n1,
35326 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35327 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35328 return _load_cimg(0,filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35329 }
35331 static CImgList<T> get_load_cimg(const char *const filename,
35332 const unsigned int n0, const unsigned int n1,
35333 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35334 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35335 return CImgList<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35336 }
35338 //! Load a sub-image list from a non compressed .cimg file.
35339 CImgList<T>& load_cimg(cimg_std::FILE *const file,
35340 const unsigned int n0, const unsigned int n1,
35341 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35342 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35343 return _load_cimg(file,0,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35344 }
35346 static CImgList<T> get_load_cimg(cimg_std::FILE *const file,
35347 const unsigned int n0, const unsigned int n1,
35348 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35349 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35350 return CImgList<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35351 }
35353 CImgList<T>& _load_cimg(cimg_std::FILE *const file, const char *const filename,
35354 const unsigned int n0, const unsigned int n1,
35355 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
35356 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
35357 #define _cimg_load_cimg_case2(Ts,Tss) \
35358 if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
35359 for (unsigned int l = 0; l<=nn1; ++l) { \
35360 j = 0; while ((i=cimg_std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = '\0'; \
35361 W = H = D = V = 0; \
35362 if (cimg_std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
35363 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
35364 pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
35365 if (W*H*D*V>0) { \
35366 if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) cimg_std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
35367 else { \
35368 const unsigned int \
35369 nx1 = x1>=W?W-1:x1, \
35370 ny1 = y1>=H?H-1:y1, \
35371 nz1 = z1>=D?D-1:z1, \
35372 nv1 = v1>=V?V-1:v1; \
35373 CImg<Tss> raw(1+nx1-x0); \
35374 CImg<T> &img = data[l-n0]; \
35375 img.assign(1+nx1-x0,1+ny1-y0,1+nz1-z0,1+nv1-v0); \
35376 T *ptrd = img.data; \
35377 const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
35378 if (skipvb) cimg_std::fseek(nfile,skipvb,SEEK_CUR); \
35379 for (unsigned int v=1+nv1-v0; v; --v) { \
35380 const unsigned int skipzb = z0*W*H*sizeof(Tss); \
35381 if (skipzb) cimg_std::fseek(nfile,skipzb,SEEK_CUR); \
35382 for (unsigned int z=1+nz1-z0; z; --z) { \
35383 const unsigned int skipyb = y0*W*sizeof(Tss); \
35384 if (skipyb) cimg_std::fseek(nfile,skipyb,SEEK_CUR); \
35385 for (unsigned int y=1+ny1-y0; y; --y) { \
35386 const unsigned int skipxb = x0*sizeof(Tss); \
35387 if (skipxb) cimg_std::fseek(nfile,skipxb,SEEK_CUR); \
35388 cimg::fread(raw.data,raw.width,nfile); \
35389 if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
35390 const Tss *ptrs = raw.data; \
35391 for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
35392 const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
35393 if (skipxe) cimg_std::fseek(nfile,skipxe,SEEK_CUR); \
35394 } \
35395 const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \
35396 if (skipye) cimg_std::fseek(nfile,skipye,SEEK_CUR); \
35397 } \
35398 const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \
35399 if (skipze) cimg_std::fseek(nfile,skipze,SEEK_CUR); \
35400 } \
35401 const unsigned int skipve = (V-1-nv1)*W*H*D*sizeof(Tss); \
35402 if (skipve) cimg_std::fseek(nfile,skipve,SEEK_CUR); \
35403 } \
35404 } \
35405 } \
35406 loaded = true; \
35407 }
35409 if (!filename && !file)
35410 throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
35411 pixel_type());
35412 typedef unsigned char uchar;
35413 typedef unsigned short ushort;
35414 typedef unsigned int uint;
35415 typedef unsigned long ulong;
35416 if (n1<n0 || x1<x0 || y1<y0 || z1<z0 || v1<v0)
35417 throw CImgArgumentException("CImgList<%s>::load_cimg() : File '%s', Bad sub-region coordinates [%u->%u] "
35418 "(%u,%u,%u,%u)->(%u,%u,%u,%u).",
35419 pixel_type(),filename?filename:"(FILE*)",
35420 n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
35421 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
35422 bool loaded = false, endian = cimg::endianness();
35423 char tmp[256], str_pixeltype[256], str_endian[256];
35424 unsigned int j, err, N, W, H, D, V;
35425 int i;
35426 j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
35427 err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
35428 if (err<2) {
35429 if (!file) cimg::fclose(nfile);
35430 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
35431 pixel_type(),filename?filename:"(FILE*)");
35432 }
35433 if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
35434 else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
35435 const unsigned int nn1 = n1>=N?N-1:n1;
35436 assign(1+nn1-n0);
35437 _cimg_load_cimg_case2("bool",bool);
35438 _cimg_load_cimg_case2("unsigned_char",uchar);
35439 _cimg_load_cimg_case2("uchar",uchar);
35440 _cimg_load_cimg_case2("char",char);
35441 _cimg_load_cimg_case2("unsigned_short",ushort);
35442 _cimg_load_cimg_case2("ushort",ushort);
35443 _cimg_load_cimg_case2("short",short);
35444 _cimg_load_cimg_case2("unsigned_int",uint);
35445 _cimg_load_cimg_case2("uint",uint);
35446 _cimg_load_cimg_case2("int",int);
35447 _cimg_load_cimg_case2("unsigned_long",ulong);
35448 _cimg_load_cimg_case2("ulong",ulong);
35449 _cimg_load_cimg_case2("long",long);
35450 _cimg_load_cimg_case2("float",float);
35451 _cimg_load_cimg_case2("double",double);
35452 if (!loaded) {
35453 if (!file) cimg::fclose(nfile);
35454 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
35455 pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
35456 }
35457 if (!file) cimg::fclose(nfile);
35458 return *this;
35459 }
35461 //! Load an image list from a PAR/REC (Philips) file.
35462 CImgList<T>& load_parrec(const char *const filename) {
35463 if (!filename)
35464 throw CImgArgumentException("CImgList<%s>::load_parrec() : Cannot load (null) filename.",
35465 pixel_type());
35466 char body[1024], filenamepar[1024], filenamerec[1024];
35467 const char *ext = cimg::split_filename(filename,body);
35468 if (!cimg::strcmp(ext,"par")) { cimg_std::strcpy(filenamepar,filename); cimg_std::sprintf(filenamerec,"%s.rec",body); }
35469 if (!cimg::strcmp(ext,"PAR")) { cimg_std::strcpy(filenamepar,filename); cimg_std::sprintf(filenamerec,"%s.REC",body); }
35470 if (!cimg::strcmp(ext,"rec")) { cimg_std::strcpy(filenamerec,filename); cimg_std::sprintf(filenamepar,"%s.par",body); }
35471 if (!cimg::strcmp(ext,"REC")) { cimg_std::strcpy(filenamerec,filename); cimg_std::sprintf(filenamepar,"%s.PAR",body); }
35472 cimg_std::FILE *file = cimg::fopen(filenamepar,"r");
35474 // Parse header file
35475 CImgList<floatT> st_slices;
35476 CImgList<uintT> st_global;
35477 int err;
35478 char line[256] = { 0 };
35479 do { err=cimg_std::fscanf(file,"%255[^\n]%*c",line); } while (err!=EOF && (line[0]=='#' || line[0]=='.'));
35480 do {
35481 unsigned int sn,sizex,sizey,pixsize;
35482 float rs,ri,ss;
35483 err = cimg_std::fscanf(file,"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\n]",&sn,&pixsize,&sizex,&sizey,&ri,&rs,&ss);
35484 if (err==7) {
35485 st_slices.insert(CImg<floatT>::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,
35486 ri,rs,ss,0));
35487 unsigned int i; for (i=0; i<st_global.size && sn<=st_global[i][2]; ++i) {}
35488 if (i==st_global.size) st_global.insert(CImg<uintT>::vector(sizex,sizey,sn));
35489 else {
35490 CImg<uintT> &vec = st_global[i];
35491 if (sizex>vec[0]) vec[0] = sizex;
35492 if (sizey>vec[1]) vec[1] = sizey;
35493 vec[2] = sn;
35494 }
35495 st_slices[st_slices.size-1][7] = (float)i;
35496 }
35497 } while (err==7);
35499 // Read data
35500 cimg_std::FILE *file2 = cimg::fopen(filenamerec,"rb");
35501 { cimglist_for(st_global,l) {
35502 const CImg<uintT>& vec = st_global[l];
35503 insert(CImg<T>(vec[0],vec[1],vec[2]));
35504 }}
35506 cimglist_for(st_slices,l) {
35507 const CImg<floatT>& vec = st_slices[l];
35508 const unsigned int
35509 sn = (unsigned int)vec[0]-1,
35510 pixsize = (unsigned int)vec[1],
35511 sizex = (unsigned int)vec[2],
35512 sizey = (unsigned int)vec[3],
35513 imn = (unsigned int)vec[7];
35514 const float ri = vec[4], rs = vec[5], ss = vec[6];
35515 switch (pixsize) {
35516 case 8 : {
35517 CImg<ucharT> buf(sizex,sizey);
35518 cimg::fread(buf.data,sizex*sizey,file2);
35519 if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
35520 CImg<T>& img = (*this)[imn];
35521 cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
35522 } break;
35523 case 16 : {
35524 CImg<ushortT> buf(sizex,sizey);
35525 cimg::fread(buf.data,sizex*sizey,file2);
35526 if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
35527 CImg<T>& img = (*this)[imn];
35528 cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
35529 } break;
35530 case 32 : {
35531 CImg<uintT> buf(sizex,sizey);
35532 cimg::fread(buf.data,sizex*sizey,file2);
35533 if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
35534 CImg<T>& img = (*this)[imn];
35535 cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
35536 } break;
35537 default :
35538 cimg::fclose(file);
35539 cimg::fclose(file2);
35540 throw CImgIOException("CImg<%s>::load_parrec() : File '%s', cannot handle image with pixsize = %d bits.",
35541 pixel_type(),filename,pixsize);
35542 }
35543 }
35544 cimg::fclose(file);
35545 cimg::fclose(file2);
35546 if (!size)
35547 throw CImgIOException("CImg<%s>::load_parrec() : File '%s' does not appear to be a valid PAR-REC file.",
35548 pixel_type(),filename);
35549 return *this;
35550 }
35552 static CImgList<T> get_load_parrec(const char *const filename) {
35553 return CImgList<T>().load_parrec(filename);
35554 }
35556 //! Load an image sequence from a YUV file.
35557 CImgList<T>& load_yuv(const char *const filename,
35558 const unsigned int sizex, const unsigned int sizey,
35559 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35560 const unsigned int step_frame=1, const bool yuv2rgb=true) {
35561 return _load_yuv(0,filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35562 }
35564 static CImgList<T> get_load_yuv(const char *const filename,
35565 const unsigned int sizex, const unsigned int sizey=1,
35566 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35567 const unsigned int step_frame=1, const bool yuv2rgb=true) {
35568 return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35569 }
35571 //! Load an image sequence from a YUV file.
35572 CImgList<T>& load_yuv(cimg_std::FILE *const file,
35573 const unsigned int sizex, const unsigned int sizey,
35574 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35575 const unsigned int step_frame=1, const bool yuv2rgb=true) {
35576 return _load_yuv(file,0,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35577 }
35579 static CImgList<T> get_load_yuv(cimg_std::FILE *const file,
35580 const unsigned int sizex, const unsigned int sizey=1,
35581 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35582 const unsigned int step_frame=1, const bool yuv2rgb=true) {
35583 return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
35584 }
35586 CImgList<T>& _load_yuv(cimg_std::FILE *const file, const char *const filename,
35587 const unsigned int sizex, const unsigned int sizey,
35588 const unsigned int first_frame, const unsigned int last_frame,
35589 const unsigned int step_frame, const bool yuv2rgb) {
35590 if (!filename && !file)
35591 throw CImgArgumentException("CImgList<%s>::load_yuv() : Cannot load (null) filename.",
35592 pixel_type());
35593 if (sizex%2 || sizey%2)
35594 throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', image dimensions along X and Y must be "
35595 "even numbers (given are %ux%u)\n",
35596 pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35597 if (!sizex || !sizey)
35598 throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given image sequence size (%u,%u) is invalid",
35599 pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35601 const unsigned int
35602 nfirst_frame = first_frame<last_frame?first_frame:last_frame,
35603 nlast_frame = first_frame<last_frame?last_frame:first_frame,
35604 nstep_frame = step_frame?step_frame:1;
35606 CImg<ucharT> tmp(sizex,sizey,1,3), UV(sizex/2,sizey/2,1,2);
35607 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
35608 bool stopflag = false;
35609 int err;
35610 if (nfirst_frame) {
35611 err = cimg_std::fseek(nfile,nfirst_frame*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
35612 if (err) {
35613 if (!file) cimg::fclose(nfile);
35614 throw CImgIOException("CImgList<%s>::load_yuv() : File '%s' doesn't contain frame number %u "
35615 "(out of range error).",
35616 pixel_type(),filename?filename:"(FILE*)",nfirst_frame);
35617 }
35618 }
35619 unsigned int frame;
35620 for (frame = nfirst_frame; !stopflag && frame<=nlast_frame; frame+=nstep_frame) {
35621 tmp.fill(0);
35622 // *TRY* to read the luminance part, do not replace by cimg::fread !
35623 err = (int)cimg_std::fread((void*)(tmp.data),1,(size_t)(tmp.width*tmp.height),nfile);
35624 if (err!=(int)(tmp.width*tmp.height)) {
35625 stopflag = true;
35626 if (err>0)
35627 cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
35628 " or given image dimensions (%u,%u) are incorrect.",
35629 pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35630 } else {
35631 UV.fill(0);
35632 // *TRY* to read the luminance part, do not replace by cimg::fread !
35633 err = (int)cimg_std::fread((void*)(UV.data),1,(size_t)(UV.size()),nfile);
35634 if (err!=(int)(UV.size())) {
35635 stopflag = true;
35636 if (err>0)
35637 cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
35638 " or given image dimensions (%u,%u) are incorrect.",
35639 pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
35640 } else {
35641 cimg_forXY(UV,x,y) {
35642 const int x2 = x*2, y2 = y*2;
35643 tmp(x2,y2,1) = tmp(x2+1,y2,1) = tmp(x2,y2+1,1) = tmp(x2+1,y2+1,1) = UV(x,y,0);
35644 tmp(x2,y2,2) = tmp(x2+1,y2,2) = tmp(x2,y2+1,2) = tmp(x2+1,y2+1,2) = UV(x,y,1);
35645 }
35646 if (yuv2rgb) tmp.YCbCrtoRGB();
35647 insert(tmp);
35648 if (nstep_frame>1) cimg_std::fseek(nfile,(nstep_frame-1)*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
35649 }
35650 }
35651 }
35652 if (stopflag && nlast_frame!=~0U && frame!=nlast_frame)
35653 cimg::warn("CImgList<%s>::load_yuv() : File '%s', frame %d not reached since only %u frames were found in the file.",
35654 pixel_type(),filename?filename:"(FILE*)",nlast_frame,frame-1,filename);
35655 if (!file) cimg::fclose(nfile);
35656 return *this;
35657 }
35659 //! Load an image from a video file, using ffmpeg libraries.
35660 // This piece of code has been firstly created by David Starweather (starkdg(at)users(dot)sourceforge(dot)net)
35661 // I modified it afterwards for direct inclusion in the library core.
35662 CImgList<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35663 const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false) {
35664 if (!filename)
35665 throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : Cannot load (null) filename.",
35666 pixel_type());
35667 const unsigned int
35668 nfirst_frame = first_frame<last_frame?first_frame:last_frame,
35669 nlast_frame = first_frame<last_frame?last_frame:first_frame,
35670 nstep_frame = step_frame?step_frame:1;
35671 assign();
35673 #ifndef cimg_use_ffmpeg
35674 if ((nfirst_frame || nlast_frame!=~0U || nstep_frame>1) || (resume && (pixel_format || !pixel_format)))
35675 throw CImgArgumentException("CImg<%s>::load_ffmpeg() : File '%s', reading sub-frames from a video file requires the use of ffmpeg.\n"
35676 "('cimg_use_ffmpeg' must be defined).",
35677 pixel_type(),filename);
35678 return load_ffmpeg_external(filename);
35679 #else
35680 const unsigned int ffmpeg_pixfmt = pixel_format?PIX_FMT_RGB24:PIX_FMT_GRAY8;
35681 avcodec_register_all();
35682 av_register_all();
35683 static AVFormatContext *format_ctx = 0;
35684 static AVCodecContext *codec_ctx = 0;
35685 static AVCodec *codec = 0;
35686 static AVFrame *avframe = avcodec_alloc_frame(), *converted_frame = avcodec_alloc_frame();
35687 static int vstream = 0;
35689 if (resume) {
35690 if (!format_ctx || !codec_ctx || !codec || !avframe || !converted_frame)
35691 throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : File '%s', cannot resume due to unallocated FFMPEG structures.",
35692 pixel_type(),filename);
35693 } else {
35694 // Open video file, find main video stream and codec.
35695 if (format_ctx) av_close_input_file(format_ctx);
35696 if (av_open_input_file(&format_ctx,filename,0,0,0)!=0)
35697 throw CImgIOException("CImgList<%s>::load_ffmpeg() : File '%s' cannot be opened.",
35698 pixel_type(),filename);
35699 if (!avframe || !converted_frame || av_find_stream_info(format_ctx)<0) {
35700 av_close_input_file(format_ctx); format_ctx = 0;
35701 cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve stream information.\n"
35702 "Trying with external ffmpeg executable.",
35703 pixel_type(),filename);
35704 return load_ffmpeg_external(filename);
35705 }
35706 #if cimg_debug>=3
35707 dump_format(format_ctx,0,0,0);
35708 #endif
35710 // Special command : Return informations on main video stream.
35711 // as a vector 1x4 containing : (nb_frames,width,height,fps).
35712 if (!first_frame && !last_frame && !step_frame) {
35713 for (vstream = 0; vstream<(int)(format_ctx->nb_streams); ++vstream)
35714 if (format_ctx->streams[vstream]->codec->codec_type==CODEC_TYPE_VIDEO) break;
35715 if (vstream==(int)format_ctx->nb_streams) assign();
35716 else {
35717 CImgList<doubleT> timestamps;
35718 int nb_frames;
35719 AVPacket packet;
35720 // Count frames and store timestamps.
35721 for (nb_frames = 0; av_read_frame(format_ctx,&packet)>=0; av_free_packet(&packet))
35722 if (packet.stream_index==vstream) {
35723 timestamps.insert(CImg<doubleT>::vector((double)packet.pts));
35724 ++nb_frames;
35725 }
35726 // Get frame with, height and fps.
35727 const int
35728 framew = format_ctx->streams[vstream]->codec->width,
35729 frameh = format_ctx->streams[vstream]->codec->height;
35730 const float
35731 num = (float)(format_ctx->streams[vstream]->r_frame_rate).num,
35732 den = (float)(format_ctx->streams[vstream]->r_frame_rate).den,
35733 fps = num/den;
35734 // Return infos as a list.
35735 assign(2);
35736 (*this)[0].assign(1,4).fill((T)nb_frames,(T)framew,(T)frameh,(T)fps);
35737 (*this)[1] = timestamps.get_append('y');
35738 }
35739 av_close_input_file(format_ctx); format_ctx = 0;
35740 return *this;
35741 }
35743 for (vstream = 0; vstream<(int)(format_ctx->nb_streams) &&
35744 format_ctx->streams[vstream]->codec->codec_type!=CODEC_TYPE_VIDEO; ) ++vstream;
35745 if (vstream==(int)format_ctx->nb_streams) {
35746 cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve video stream.\n"
35747 "Trying with external ffmpeg executable.",
35748 pixel_type(),filename);
35749 av_close_input_file(format_ctx); format_ctx = 0;
35750 return load_ffmpeg_external(filename);
35751 }
35752 codec_ctx = format_ctx->streams[vstream]->codec;
35753 codec = avcodec_find_decoder(codec_ctx->codec_id);
35754 if (!codec) {
35755 cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot find video codec.\n"
35756 "Trying with external ffmpeg executable.",
35757 pixel_type(),filename);
35758 return load_ffmpeg_external(filename);
35759 }
35760 if (avcodec_open(codec_ctx,codec)<0) { // Open codec
35761 cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot open video codec.\n"
35762 "Trying with external ffmpeg executable.",
35763 pixel_type(),filename);
35764 return load_ffmpeg_external(filename);
35765 }
35766 }
35768 // Read video frames
35769 const unsigned int numBytes = avpicture_get_size(ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
35770 uint8_t *const buffer = new uint8_t[numBytes];
35771 avpicture_fill((AVPicture *)converted_frame,buffer,ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
35772 const T foo = (T)0;
35773 AVPacket packet;
35774 for (unsigned int frame = 0, next_frame = nfirst_frame; frame<=nlast_frame && av_read_frame(format_ctx,&packet)>=0; ) {
35775 if (packet.stream_index==(int)vstream) {
35776 int decoded = 0;
35777 avcodec_decode_video(codec_ctx,avframe,&decoded,packet.data,packet.size);
35778 if (decoded) {
35779 if (frame==next_frame) {
35780 SwsContext *c = sws_getContext(codec_ctx->width,codec_ctx->height,codec_ctx->pix_fmt,codec_ctx->width,
35781 codec_ctx->height,ffmpeg_pixfmt,1,0,0,0);
35782 sws_scale(c,avframe->data,avframe->linesize,0,codec_ctx->height,converted_frame->data,converted_frame->linesize);
35783 if (ffmpeg_pixfmt==PIX_FMT_RGB24) {
35784 CImg<ucharT> next_image(*converted_frame->data,3,codec_ctx->width,codec_ctx->height,1,true);
35785 insert(next_image._get_permute_axes("yzvx",foo));
35786 } else {
35787 CImg<ucharT> next_image(*converted_frame->data,1,codec_ctx->width,codec_ctx->height,1,true);
35788 insert(next_image._get_permute_axes("yzvx",foo));
35789 }
35790 next_frame+=nstep_frame;
35791 }
35792 ++frame;
35793 }
35794 av_free_packet(&packet);
35795 if (next_frame>nlast_frame) break;
35796 }
35797 }
35798 delete[] buffer;
35799 #endif
35800 return *this;
35801 }
35803 static CImgList<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35804 const unsigned int step_frame=1, const bool pixel_format=true) {
35805 return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format);
35806 }
35808 //! Load an image from a video file (MPEG,AVI) using the external tool 'ffmpeg'.
35809 CImgList<T>& load_ffmpeg_external(const char *const filename) {
35810 if (!filename)
35811 throw CImgArgumentException("CImgList<%s>::load_ffmpeg_external() : Cannot load (null) filename.",
35812 pixel_type());
35813 char command[1024], filetmp[512], filetmp2[512];
35814 cimg_std::FILE *file = 0;
35815 do {
35816 cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
35817 cimg_std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
35818 if ((file=cimg_std::fopen(filetmp2,"rb"))!=0) cimg_std::fclose(file);
35819 } while (file);
35820 cimg_std::sprintf(filetmp2,"%s_%%6d.ppm",filetmp);
35821 #if cimg_OS!=2
35822 cimg_std::sprintf(command,"%s -i \"%s\" %s >/dev/null 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
35823 #else
35824 cimg_std::sprintf(command,"\"%s -i \"%s\" %s\" >NUL 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
35825 #endif
35826 cimg::system(command,0);
35827 const unsigned int odebug = cimg::exception_mode();
35828 cimg::exception_mode() = 0;
35829 assign();
35830 unsigned int i = 1;
35831 for (bool stopflag = false; !stopflag; ++i) {
35832 cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,i);
35833 CImg<T> img;
35834 try { img.load_pnm(filetmp2); }
35835 catch (CImgException&) { stopflag = true; }
35836 if (img) { insert(img); cimg_std::remove(filetmp2); }
35837 }
35838 cimg::exception_mode() = odebug;
35839 if (is_empty())
35840 throw CImgIOException("CImgList<%s>::load_ffmpeg_external() : Failed to open image sequence '%s'.\n"
35841 "Check the filename and if the 'ffmpeg' tool is installed on your system.",
35842 pixel_type(),filename);
35843 return *this;
35844 }
35846 static CImgList<T> get_load_ffmpeg_external(const char *const filename) {
35847 return CImgList<T>().load_ffmpeg_external(filename);
35848 }
35850 //! Load a gzipped list, using external tool 'gunzip'.
35851 CImgList<T>& load_gzip_external(const char *const filename) {
35852 if (!filename)
35853 throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
35854 pixel_type());
35855 char command[1024], filetmp[512], body[512];
35856 const char
35857 *ext = cimg::split_filename(filename,body),
35858 *ext2 = cimg::split_filename(body,0);
35859 cimg_std::FILE *file = 0;
35860 do {
35861 if (!cimg::strcasecmp(ext,"gz")) {
35862 if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
35863 cimg::filenamerand(),ext2);
35864 else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
35865 cimg::filenamerand());
35866 } else {
35867 if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
35868 cimg::filenamerand(),ext);
35869 else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
35870 cimg::filenamerand());
35871 }
35872 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
35873 } while (file);
35874 cimg_std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
35875 cimg::system(command);
35876 if (!(file = cimg_std::fopen(filetmp,"rb"))) {
35877 cimg::fclose(cimg::fopen(filename,"r"));
35878 throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
35879 pixel_type(),filename);
35880 } else cimg::fclose(file);
35881 load(filetmp);
35882 cimg_std::remove(filetmp);
35883 return *this;
35884 }
35886 static CImgList<T> get_load_gzip_external(const char *const filename) {
35887 return CImgList<T>().load_gzip_external(filename);
35888 }
35890 //! Load a 3D object from a .OFF file.
35891 template<typename tf, typename tc>
35892 CImgList<T>& load_off(const char *const filename,
35893 CImgList<tf>& primitives, CImgList<tc>& colors,
35894 const bool invert_faces=false) {
35895 return get_load_off(filename,primitives,colors,invert_faces).transfer_to(*this);
35896 }
35898 template<typename tf, typename tc>
35899 static CImgList<T> get_load_off(const char *const filename,
35900 CImgList<tf>& primitives, CImgList<tc>& colors,
35901 const bool invert_faces=false) {
35902 return CImg<T>().load_off(filename,primitives,colors,invert_faces).get_split('x');
35903 }
35905 //! Load a TIFF file.
35906 CImgList<T>& load_tiff(const char *const filename,
35907 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35908 const unsigned int step_frame=1) {
35909 const unsigned int
35910 nfirst_frame = first_frame<last_frame?first_frame:last_frame,
35911 nstep_frame = step_frame?step_frame:1;
35912 unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
35913 #ifndef cimg_use_tiff
35914 if (nfirst_frame || nlast_frame!=~0U || nstep_frame!=1)
35915 throw CImgArgumentException("CImgList<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
35916 "('cimg_use_tiff' must be defined).",
35917 pixel_type(),filename);
35918 return assign(CImg<T>::get_load_tiff(filename));
35919 #else
35920 TIFF *tif = TIFFOpen(filename,"r");
35921 if (tif) {
35922 unsigned int nb_images = 0;
35923 do ++nb_images; while (TIFFReadDirectory(tif));
35924 if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
35925 cimg::warn("CImgList<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
35926 pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
35927 if (nfirst_frame>=nb_images) return assign();
35928 if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
35929 assign(1+(nlast_frame-nfirst_frame)/nstep_frame);
35930 TIFFSetDirectory(tif,0);
35931 #if cimg_debug>=3
35932 TIFFSetWarningHandler(0);
35933 TIFFSetErrorHandler(0);
35934 #endif
35935 cimglist_for(*this,l) data[l]._load_tiff(tif,nfirst_frame+l*nstep_frame);
35936 TIFFClose(tif);
35937 } else throw CImgException("CImgList<%s>::load_tiff() : File '%s' cannot be opened.",
35938 pixel_type(),filename);
35939 return *this;
35940 #endif
35941 }
35943 static CImgList<T> get_load_tiff(const char *const filename,
35944 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
35945 const unsigned int step_frame=1) {
35946 return CImgList<T>().load_tiff(filename,first_frame,last_frame,step_frame);
35947 }
35949 //! Save an image list into a file.
35950 /**
35951 Depending on the extension of the given filename, a file format is chosen for the output file.
35952 **/
35953 const CImgList<T>& save(const char *const filename, const int number=-1) const {
35954 if (is_empty())
35955 throw CImgInstanceException("CImgList<%s>::save() : File '%s, instance list (%u,%p) is empty.",
35956 pixel_type(),filename?filename:"(null)",size,data);
35957 if (!filename)
35958 throw CImgArgumentException("CImg<%s>::save() : Instance list (%u,%p), specified filename is (null).",
35959 pixel_type(),size,data);
35960 const char *ext = cimg::split_filename(filename);
35961 char nfilename[1024];
35962 const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
35963 #ifdef cimglist_save_plugin
35964 cimglist_save_plugin(fn);
35965 #endif
35966 #ifdef cimglist_save_plugin1
35967 cimglist_save_plugin1(fn);
35968 #endif
35969 #ifdef cimglist_save_plugin2
35970 cimglist_save_plugin2(fn);
35971 #endif
35972 #ifdef cimglist_save_plugin3
35973 cimglist_save_plugin3(fn);
35974 #endif
35975 #ifdef cimglist_save_plugin4
35976 cimglist_save_plugin4(fn);
35977 #endif
35978 #ifdef cimglist_save_plugin5
35979 cimglist_save_plugin5(fn);
35980 #endif
35981 #ifdef cimglist_save_plugin6
35982 cimglist_save_plugin6(fn);
35983 #endif
35984 #ifdef cimglist_save_plugin7
35985 cimglist_save_plugin7(fn);
35986 #endif
35987 #ifdef cimglist_save_plugin8
35988 cimglist_save_plugin8(fn);
35989 #endif
35990 #ifdef cimg_use_tiff
35991 if (!cimg::strcasecmp(ext,"tif") ||
35992 !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
35993 #endif
35994 if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
35995 if (!cimg::strcasecmp(ext,"cimg") || !ext[0]) return save_cimg(fn,false);
35996 if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
35997 if (!cimg::strcasecmp(ext,"avi") ||
35998 !cimg::strcasecmp(ext,"mov") ||
35999 !cimg::strcasecmp(ext,"asf") ||
36000 !cimg::strcasecmp(ext,"divx") ||
36001 !cimg::strcasecmp(ext,"flv") ||
36002 !cimg::strcasecmp(ext,"mpg") ||
36003 !cimg::strcasecmp(ext,"m1v") ||
36004 !cimg::strcasecmp(ext,"m2v") ||
36005 !cimg::strcasecmp(ext,"m4v") ||
36006 !cimg::strcasecmp(ext,"mjp") ||
36007 !cimg::strcasecmp(ext,"mkv") ||
36008 !cimg::strcasecmp(ext,"mpe") ||
36009 !cimg::strcasecmp(ext,"movie") ||
36010 !cimg::strcasecmp(ext,"ogm") ||
36011 !cimg::strcasecmp(ext,"qt") ||
36012 !cimg::strcasecmp(ext,"rm") ||
36013 !cimg::strcasecmp(ext,"vob") ||
36014 !cimg::strcasecmp(ext,"wmv") ||
36015 !cimg::strcasecmp(ext,"xvid") ||
36016 !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
36017 if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
36018 if (size==1) data[0].save(fn,-1); else cimglist_for(*this,l) data[l].save(fn,l);
36019 return *this;
36020 }
36022 //! Save an image sequence, using FFMPEG library.
36023 // This piece of code has been originally written by David. G. Starkweather.
36024 const CImgList<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
36025 const unsigned int fps=25) const {
36026 if (is_empty())
36027 throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', instance list (%u,%p) is empty.",
36028 pixel_type(),filename?filename:"(null)",size,data);
36029 if (!filename)
36030 throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : Instance list (%u,%p), specified filename is (null).",
36031 pixel_type(),size,data);
36032 if (!fps)
36033 throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
36034 pixel_type(),filename);
36035 const unsigned int nlast_frame = last_frame==~0U?size-1:last_frame;
36036 if (first_frame>=size || nlast_frame>=size)
36037 throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
36038 pixel_type(),filename,first_frame,last_frame,size);
36039 for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
36040 throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', images of the sequence have different dimensions.",
36041 pixel_type(),filename);
36043 #ifndef cimg_use_ffmpeg
36044 return save_ffmpeg_external(filename,first_frame,last_frame);
36045 #else
36046 avcodec_register_all();
36047 av_register_all();
36048 const int
36049 frame_dimx = data[first_frame].dimx(),
36050 frame_dimy = data[first_frame].dimy(),
36051 frame_dimv = data[first_frame].dimv();
36052 if (frame_dimv!=1 && frame_dimv!=3)
36053 throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', image[0] (%u,%u,%u,%u,%p) has not 1 or 3 channels.",
36054 pixel_type(),filename,data[0].width,data[0].height,data[0].depth,data[0].dim,data);
36056 PixelFormat dest_pxl_fmt = PIX_FMT_YUV420P;
36057 PixelFormat src_pxl_fmt = (frame_dimv == 3)?PIX_FMT_RGB24:PIX_FMT_GRAY8;
36059 int sws_flags = SWS_FAST_BILINEAR; // Interpolation method (keeping same size images for now).
36060 AVOutputFormat *fmt = 0;
36061 fmt = guess_format(0,filename,0);
36062 if (!fmt) fmt = guess_format("mpeg",0,0); // Default format "mpeg".
36063 if (!fmt)
36064 throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', could not determine file format from filename.",
36065 pixel_type(),filename);
36067 AVFormatContext *oc = 0;
36068 oc = av_alloc_format_context();
36069 if (!oc) // Failed to allocate format context.
36070 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate structure for format context.",
36071 pixel_type(),filename);
36073 AVCodec *codec = 0;
36074 AVFrame *picture = 0;
36075 AVFrame *tmp_pict = 0;
36076 oc->oformat = fmt;
36077 cimg_std::sprintf(oc->filename,"%s",filename);
36079 // Add video stream.
36080 int stream_index = 0;
36081 AVStream *video_str = 0;
36082 if (fmt->video_codec!=CODEC_ID_NONE) {
36083 video_str = av_new_stream(oc,stream_index);
36084 if (!video_str) { // Failed to allocate stream.
36085 av_free(oc);
36086 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate video stream structure.",
36087 pixel_type(),filename);
36088 }
36089 } else { // No codec identified.
36090 av_free(oc);
36091 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no proper codec identified.",
36092 pixel_type(),filename);
36093 }
36095 AVCodecContext *c = video_str->codec;
36096 c->codec_id = fmt->video_codec;
36097 c->codec_type = CODEC_TYPE_VIDEO;
36098 c->bit_rate = 400000;
36099 c->width = frame_dimx;
36100 c->height = frame_dimy;
36101 c->time_base.num = 1;
36102 c->time_base.den = fps;
36103 c->gop_size = 12;
36104 c->pix_fmt = dest_pxl_fmt;
36105 if (c->codec_id == CODEC_ID_MPEG2VIDEO) c->max_b_frames = 2;
36106 if (c->codec_id == CODEC_ID_MPEG1VIDEO) c->mb_decision = 2;
36108 if (av_set_parameters(oc,0)<0) { // Parameters not properly set.
36109 av_free(oc);
36110 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', parameters for avcodec not properly set.",
36111 pixel_type(),filename);
36112 }
36114 // Open codecs and alloc buffers.
36115 codec = avcodec_find_encoder(c->codec_id);
36116 if (!codec) { // Failed to find codec.
36117 av_free(oc);
36118 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no codec found.",
36119 pixel_type(),filename);
36120 }
36121 if (avcodec_open(c,codec)<0) // Failed to open codec.
36122 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to open codec.",
36123 pixel_type(),filename);
36124 tmp_pict = avcodec_alloc_frame();
36125 if (!tmp_pict) { // Failed to allocate memory for tmp_pict frame.
36126 avcodec_close(video_str->codec);
36127 av_free(oc);
36128 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
36129 pixel_type(),filename);
36130 }
36131 tmp_pict->linesize[0] = (src_pxl_fmt==PIX_FMT_RGB24)?3*frame_dimx:frame_dimx;
36132 tmp_pict->type = FF_BUFFER_TYPE_USER;
36133 int tmp_size = avpicture_get_size(src_pxl_fmt,frame_dimx,frame_dimy);
36134 uint8_t *tmp_buffer = (uint8_t*)av_malloc(tmp_size);
36135 if (!tmp_buffer) { // Failed to allocate memory for tmp buffer.
36136 av_free(tmp_pict);
36137 avcodec_close(video_str->codec);
36138 av_free(oc);
36139 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
36140 pixel_type(),filename);
36141 }
36143 // Associate buffer with tmp_pict.
36144 avpicture_fill((AVPicture*)tmp_pict,tmp_buffer,src_pxl_fmt,frame_dimx,frame_dimy);
36145 picture = avcodec_alloc_frame();
36146 if (!picture) { // Failed to allocate picture frame.
36147 av_free(tmp_pict->data[0]);
36148 av_free(tmp_pict);
36149 avcodec_close(video_str->codec);
36150 av_free(oc);
36151 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame.",
36152 pixel_type(),filename);
36153 }
36155 int size = avpicture_get_size(c->pix_fmt,frame_dimx,frame_dimy);
36156 uint8_t *buffer = (uint8_t*)av_malloc(size);
36157 if (!buffer) { // Failed to allocate picture frame buffer.
36158 av_free(picture);
36159 av_free(tmp_pict->data[0]);
36160 av_free(tmp_pict);
36161 avcodec_close(video_str->codec);
36162 av_free(oc);
36163 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame buffer.",
36164 pixel_type(),filename);
36165 }
36167 // Associate the buffer with picture.
36168 avpicture_fill((AVPicture*)picture,buffer,c->pix_fmt,frame_dimx,frame_dimy);
36170 // Open file.
36171 if (!(fmt->flags&AVFMT_NOFILE)) {
36172 if (url_fopen(&oc->pb,filename,URL_WRONLY)<0)
36173 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s' cannot be opened.",
36174 pixel_type(),filename);
36175 }
36177 if (av_write_header(oc)<0)
36178 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', could not write header.",
36179 pixel_type(),filename);
36180 double video_pts;
36181 SwsContext *img_convert_context = 0;
36182 img_convert_context = sws_getContext(frame_dimx,frame_dimy,src_pxl_fmt,
36183 c->width,c->height,c->pix_fmt,sws_flags,0,0,0);
36184 if (!img_convert_context) { // Failed to get swscale context.
36185 // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
36186 av_free(picture->data);
36187 av_free(picture);
36188 av_free(tmp_pict->data[0]);
36189 av_free(tmp_pict);
36190 avcodec_close(video_str->codec);
36191 av_free(oc);
36192 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%', failed to get conversion context.",
36193 pixel_type(),filename);
36194 }
36195 int ret = 0, out_size;
36196 uint8_t *video_outbuf = 0;
36197 int video_outbuf_size = 1000000;
36198 video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);
36199 if (!video_outbuf) {
36200 // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
36201 av_free(picture->data);
36202 av_free(picture);
36203 av_free(tmp_pict->data[0]);
36204 av_free(tmp_pict);
36205 avcodec_close(video_str->codec);
36206 av_free(oc);
36207 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', memory allocation error.",
36208 pixel_type(),filename);
36209 }
36211 // Loop through each desired image in list.
36212 for (unsigned int i = first_frame; i<=nlast_frame; ++i) {
36213 CImg<uint8_t> currentIm = data[i], red, green, blue, gray;
36214 if (src_pxl_fmt == PIX_FMT_RGB24) {
36215 red = currentIm.get_shared_channel(0);
36216 green = currentIm.get_shared_channel(1);
36217 blue = currentIm.get_shared_channel(2);
36218 cimg_forXY(currentIm,X,Y) { // Assign pizel values to data buffer in interlaced RGBRGB ... format.
36219 tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X] = red(X,Y);
36220 tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 1] = green(X,Y);
36221 tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 2] = blue(X,Y);
36222 }
36223 } else {
36224 gray = currentIm.get_shared_channel(0);
36225 cimg_forXY(currentIm,X,Y) tmp_pict->data[0][Y*tmp_pict->linesize[0] + X] = gray(X,Y);
36226 }
36228 if (video_str) video_pts = (video_str->pts.val * video_str->time_base.num)/(video_str->time_base.den);
36229 else video_pts = 0.0;
36230 if (!video_str) break;
36231 if (sws_scale(img_convert_context,tmp_pict->data,tmp_pict->linesize,0,c->height,picture->data,picture->linesize)<0) break;
36232 out_size = avcodec_encode_video(c,video_outbuf,video_outbuf_size,picture);
36233 if (out_size>0) {
36234 AVPacket pkt;
36235 av_init_packet(&pkt);
36236 pkt.pts = av_rescale_q(c->coded_frame->pts,c->time_base,video_str->time_base);
36237 if (c->coded_frame->key_frame) pkt.flags|=PKT_FLAG_KEY;
36238 pkt.stream_index = video_str->index;
36239 pkt.data = video_outbuf;
36240 pkt.size = out_size;
36241 ret = av_write_frame(oc,&pkt);
36242 } else if (out_size<0) break;
36243 if (ret) break; // Error occured in writing frame.
36244 }
36246 // Close codec.
36247 if (video_str) {
36248 avcodec_close(video_str->codec);
36249 av_free(picture->data[0]);
36250 av_free(picture);
36251 av_free(tmp_pict->data[0]);
36252 av_free(tmp_pict);
36253 }
36254 if (av_write_trailer(oc)<0)
36255 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to write trailer.",
36256 pixel_type(),filename);
36257 av_freep(&oc->streams[stream_index]->codec);
36258 av_freep(&oc->streams[stream_index]);
36259 if (!(fmt->flags&AVFMT_NOFILE)) {
36260 /*if (url_fclose(oc->pb)<0)
36261 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to close file.",
36262 pixel_type(),filename);
36263 */
36264 }
36265 av_free(oc);
36266 av_free(video_outbuf);
36267 #endif
36268 return *this;
36269 }
36271 // Save an image sequence into a YUV file (internal).
36272 const CImgList<T>& _save_yuv(cimg_std::FILE *const file, const char *const filename, const bool rgb2yuv) const {
36273 if (is_empty())
36274 throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', instance list (%u,%p) is empty.",
36275 pixel_type(),filename?filename:"(FILE*)",size,data);
36276 if (!file && !filename)
36277 throw CImgArgumentException("CImg<%s>::save_yuv() : Instance list (%u,%p), specified file is (null).",
36278 pixel_type(),size,data);
36279 if ((*this)[0].dimx()%2 || (*this)[0].dimy()%2)
36280 throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', image dimensions must be even numbers (current are %ux%u).",
36281 pixel_type(),filename?filename:"(FILE*)",(*this)[0].dimx(),(*this)[0].dimy());
36283 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
36284 cimglist_for(*this,l) {
36285 CImg<ucharT> YCbCr((*this)[l]);
36286 if (rgb2yuv) YCbCr.RGBtoYCbCr();
36287 cimg::fwrite(YCbCr.data,YCbCr.width*YCbCr.height,nfile);
36288 cimg::fwrite(YCbCr.get_resize(YCbCr.width/2, YCbCr.height/2,1,3,3).ptr(0,0,0,1),
36289 YCbCr.width*YCbCr.height/2,nfile);
36290 }
36291 if (!file) cimg::fclose(nfile);
36292 return *this;
36293 }
36295 //! Save an image sequence into a YUV file.
36296 const CImgList<T>& save_yuv(const char *const filename=0, const bool rgb2yuv=true) const {
36297 return _save_yuv(0,filename,rgb2yuv);
36298 }
36300 //! Save an image sequence into a YUV file.
36301 const CImgList<T>& save_yuv(cimg_std::FILE *const file, const bool rgb2yuv=true) const {
36302 return _save_yuv(file,0,rgb2yuv);
36303 }
36305 //! Save an image list into a .cimg file.
36306 /**
36307 A CImg RAW file is a simple uncompressed binary file that may be used to save list of CImg<T> images.
36308 \param filename : name of the output file.
36309 \return A reference to the current CImgList instance is returned.
36310 **/
36311 const CImgList<T>& _save_cimg(cimg_std::FILE *const file, const char *const filename, const bool compression) const {
36312 if (is_empty())
36313 throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
36314 pixel_type(),filename?filename:"(FILE*)",size,data);
36315 if (!file && !filename)
36316 throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
36317 pixel_type(),size,data);
36318 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
36319 const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little";
36320 if (cimg_std::strstr(ptype,"unsigned")==ptype) cimg_std::fprintf(nfile,"%u unsigned_%s %s_endian\n",size,ptype+9,etype);
36321 else cimg_std::fprintf(nfile,"%u %s %s_endian\n",size,ptype,etype);
36322 cimglist_for(*this,l) {
36323 const CImg<T>& img = data[l];
36324 cimg_std::fprintf(nfile,"%u %u %u %u",img.width,img.height,img.depth,img.dim);
36325 if (img.data) {
36326 CImg<T> tmp;
36327 if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp.data,tmp.size()); }
36328 const CImg<T>& ref = cimg::endianness()?tmp:img;
36329 bool compressed = false;
36330 if (compression) {
36331 #ifdef cimg_use_zlib
36332 const unsigned long siz = sizeof(T)*ref.size();
36333 unsigned long csiz = siz + siz/10 + 16;
36334 Bytef *const cbuf = new Bytef[csiz];
36335 if (compress(cbuf,&csiz,(Bytef*)ref.data,siz)) {
36336 cimg::warn("CImgList<%s>::save_cimg() : File '%s', failed to save compressed data.\n Data will be saved uncompressed.",
36337 pixel_type(),filename?filename:"(FILE*)");
36338 compressed = false;
36339 } else {
36340 cimg_std::fprintf(nfile," #%lu\n",csiz);
36341 cimg::fwrite(cbuf,csiz,nfile);
36342 delete[] cbuf;
36343 compressed = true;
36344 }
36345 #else
36346 cimg::warn("CImgList<%s>::save_cimg() : File '%s', cannot save compressed data unless zlib is used "
36347 "('cimg_use_zlib' must be defined).\n Data will be saved uncompressed.",
36348 pixel_type(),filename?filename:"(FILE*)");
36349 compressed = false;
36350 #endif
36351 }
36352 if (!compressed) {
36353 cimg_std::fputc('\n',nfile);
36354 cimg::fwrite(ref.data,ref.size(),nfile);
36355 }
36356 } else cimg_std::fputc('\n',nfile);
36357 }
36358 if (!file) cimg::fclose(nfile);
36359 return *this;
36360 }
36362 //! Save an image list into a CImg file (RAW binary file + simple header)
36363 const CImgList<T>& save_cimg(cimg_std::FILE *file, const bool compress=false) const {
36364 return _save_cimg(file,0,compress);
36365 }
36367 //! Save an image list into a CImg file (RAW binary file + simple header)
36368 const CImgList<T>& save_cimg(const char *const filename, const bool compress=false) const {
36369 return _save_cimg(0,filename,compress);
36370 }
36372 // Insert the instance image into into an existing .cimg file, at specified coordinates.
36373 const CImgList<T>& _save_cimg(cimg_std::FILE *const file, const char *const filename,
36374 const unsigned int n0,
36375 const unsigned int x0, const unsigned int y0,
36376 const unsigned int z0, const unsigned int v0) const {
36377 #define _cimg_save_cimg_case(Ts,Tss) \
36378 if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \
36379 for (unsigned int l=0; l<lmax; ++l) { \
36380 j = 0; while((i=cimg_std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j]='\0'; \
36381 W = H = D = V = 0; \
36382 if (cimg_std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
36383 throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
36384 pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
36385 if (W*H*D*V>0) { \
36386 if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) cimg_std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
36387 else { \
36388 const CImg<T>& img = (*this)[l-n0]; \
36389 const T *ptrs = img.data; \
36390 const unsigned int \
36391 x1 = x0 + img.width - 1, \
36392 y1 = y0 + img.height - 1, \
36393 z1 = z0 + img.depth - 1, \
36394 v1 = v0 + img.dim - 1, \
36395 nx1 = x1>=W?W-1:x1, \
36396 ny1 = y1>=H?H-1:y1, \
36397 nz1 = z1>=D?D-1:z1, \
36398 nv1 = v1>=V?V-1:v1; \
36399 CImg<Tss> raw(1+nx1-x0); \
36400 const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
36401 if (skipvb) cimg_std::fseek(nfile,skipvb,SEEK_CUR); \
36402 for (unsigned int v=1+nv1-v0; v; --v) { \
36403 const unsigned int skipzb = z0*W*H*sizeof(Tss); \
36404 if (skipzb) cimg_std::fseek(nfile,skipzb,SEEK_CUR); \
36405 for (unsigned int z=1+nz1-z0; z; --z) { \
36406 const unsigned int skipyb = y0*W*sizeof(Tss); \
36407 if (skipyb) cimg_std::fseek(nfile,skipyb,SEEK_CUR); \
36408 for (unsigned int y=1+ny1-y0; y; --y) { \
36409 const unsigned int skipxb = x0*sizeof(Tss); \
36410 if (skipxb) cimg_std::fseek(nfile,skipxb,SEEK_CUR); \
36411 raw.assign(ptrs, raw.width); \
36412 ptrs+=img.width; \
36413 if (endian) cimg::invert_endianness(raw.data,raw.width); \
36414 cimg::fwrite(raw.data,raw.width,nfile); \
36415 const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
36416 if (skipxe) cimg_std::fseek(nfile,skipxe,SEEK_CUR); \
36417 } \
36418 const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \
36419 if (skipye) cimg_std::fseek(nfile,skipye,SEEK_CUR); \
36420 } \
36421 const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \
36422 if (skipze) cimg_std::fseek(nfile,skipze,SEEK_CUR); \
36423 } \
36424 const unsigned int skipve = (V-1-nv1)*W*H*D*sizeof(Tss); \
36425 if (skipve) cimg_std::fseek(nfile,skipve,SEEK_CUR); \
36426 } \
36427 } \
36428 } \
36429 saved = true; \
36430 }
36431 if (is_empty())
36432 throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
36433 pixel_type(),filename?filename:"(FILE*)",size,data);
36434 if (!file && !filename)
36435 throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
36436 pixel_type(),size,data);
36437 typedef unsigned char uchar;
36438 typedef unsigned short ushort;
36439 typedef unsigned int uint;
36440 typedef unsigned long ulong;
36441 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+");
36442 bool saved = false, endian = cimg::endianness();
36443 char tmp[256], str_pixeltype[256], str_endian[256];
36444 unsigned int j, err, N, W, H, D, V;
36445 int i;
36446 j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
36447 err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
36448 if (err<2) {
36449 if (!file) cimg::fclose(nfile);
36450 throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Unknow CImg RAW header.",
36451 pixel_type(),filename?filename:"(FILE*)");
36452 }
36453 if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
36454 else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
36455 const unsigned int lmax = cimg::min(N,n0+size);
36456 _cimg_save_cimg_case("bool",bool);
36457 _cimg_save_cimg_case("unsigned_char",uchar);
36458 _cimg_save_cimg_case("uchar",uchar);
36459 _cimg_save_cimg_case("char",char);
36460 _cimg_save_cimg_case("unsigned_short",ushort);
36461 _cimg_save_cimg_case("ushort",ushort);
36462 _cimg_save_cimg_case("short",short);
36463 _cimg_save_cimg_case("unsigned_int",uint);
36464 _cimg_save_cimg_case("uint",uint);
36465 _cimg_save_cimg_case("int",int);
36466 _cimg_save_cimg_case("unsigned_long",ulong);
36467 _cimg_save_cimg_case("ulong",ulong);
36468 _cimg_save_cimg_case("long",long);
36469 _cimg_save_cimg_case("float",float);
36470 _cimg_save_cimg_case("double",double);
36471 if (!saved) {
36472 if (!file) cimg::fclose(nfile);
36473 throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', cannot save images of pixels coded as '%s'.",
36474 pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
36475 }
36476 if (!file) cimg::fclose(nfile);
36477 return *this;
36478 }
36480 //! Insert the instance image into into an existing .cimg file, at specified coordinates.
36481 const CImgList<T>& save_cimg(const char *const filename,
36482 const unsigned int n0,
36483 const unsigned int x0, const unsigned int y0,
36484 const unsigned int z0, const unsigned int v0) const {
36485 return _save_cimg(0,filename,n0,x0,y0,z0,v0);
36486 }
36488 //! Insert the instance image into into an existing .cimg file, at specified coordinates.
36489 const CImgList<T>& save_cimg(cimg_std::FILE *const file,
36490 const unsigned int n0,
36491 const unsigned int x0, const unsigned int y0,
36492 const unsigned int z0, const unsigned int v0) const {
36493 return _save_cimg(file,0,n0,x0,y0,z0,v0);
36494 }
36496 // Create an empty .cimg file with specified dimensions (internal)
36497 static void _save_empty_cimg(cimg_std::FILE *const file, const char *const filename,
36498 const unsigned int nb,
36499 const unsigned int dx, const unsigned int dy,
36500 const unsigned int dz, const unsigned int dv) {
36501 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
36502 const unsigned int siz = dx*dy*dz*dv*sizeof(T);
36503 cimg_std::fprintf(nfile,"%u %s\n",nb,pixel_type());
36504 for (unsigned int i=nb; i; --i) {
36505 cimg_std::fprintf(nfile,"%u %u %u %u\n",dx,dy,dz,dv);
36506 for (unsigned int off=siz; off; --off) cimg_std::fputc(0,nfile);
36507 }
36508 if (!file) cimg::fclose(nfile);
36509 }
36511 //! Create an empty .cimg file with specified dimensions.
36512 static void save_empty_cimg(const char *const filename,
36513 const unsigned int nb,
36514 const unsigned int dx, const unsigned int dy=1,
36515 const unsigned int dz=1, const unsigned int dv=1) {
36516 return _save_empty_cimg(0,filename,nb,dx,dy,dz,dv);
36517 }
36519 //! Create an empty .cimg file with specified dimensions.
36520 static void save_empty_cimg(cimg_std::FILE *const file,
36521 const unsigned int nb,
36522 const unsigned int dx, const unsigned int dy=1,
36523 const unsigned int dz=1, const unsigned int dv=1) {
36524 return _save_empty_cimg(file,0,nb,dx,dy,dz,dv);
36525 }
36527 //! Save a file in TIFF format.
36528 #ifdef cimg_use_tiff
36529 const CImgList<T>& save_tiff(const char *const filename) const {
36530 if (is_empty())
36531 throw CImgInstanceException("CImgList<%s>::save_tiff() : File '%s', instance list (%u,%p) is empty.",
36532 pixel_type(),filename?filename:"(null)",size,data);
36533 if (!filename)
36534 throw CImgArgumentException("CImgList<%s>::save_tiff() : Specified filename is (null) for instance list (%u,%p).",
36535 pixel_type(),size,data);
36536 TIFF *tif = TIFFOpen(filename,"w");
36537 if (tif) {
36538 for (unsigned int dir=0, l=0; l<size; ++l) {
36539 const CImg<T>& img = (*this)[l];
36540 if (img) {
36541 if (img.depth==1) img._save_tiff(tif,dir++);
36542 else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++);
36543 }
36544 }
36545 TIFFClose(tif);
36546 } else
36547 throw CImgException("CImgList<%s>::save_tiff() : File '%s', error while opening stream for tiff file.",
36548 pixel_type(),filename);
36549 return *this;
36550 }
36551 #endif
36553 //! Save an image list as a gzipped file, using external tool 'gzip'.
36554 const CImgList<T>& save_gzip_external(const char *const filename) const {
36555 if (!filename)
36556 throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
36557 pixel_type());
36558 char command[1024], filetmp[512], body[512];
36559 const char
36560 *ext = cimg::split_filename(filename,body),
36561 *ext2 = cimg::split_filename(body,0);
36562 cimg_std::FILE *file;
36563 do {
36564 if (!cimg::strcasecmp(ext,"gz")) {
36565 if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
36566 cimg::filenamerand(),ext2);
36567 else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
36568 cimg::filenamerand());
36569 } else {
36570 if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
36571 cimg::filenamerand(),ext);
36572 else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
36573 cimg::filenamerand());
36574 }
36575 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
36576 } while (file);
36577 save(filetmp);
36578 cimg_std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
36579 cimg::system(command);
36580 file = cimg_std::fopen(filename,"rb");
36581 if (!file)
36582 throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
36583 pixel_type(),filename);
36584 else cimg::fclose(file);
36585 cimg_std::remove(filetmp);
36586 return *this;
36587 }
36589 //! Save an image list into a OFF file.
36590 template<typename tf, typename tc>
36591 const CImgList<T>& save_off(const char *const filename,
36592 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
36593 get_append('x','y').save_off(filename,primitives,colors,invert_faces);
36594 return *this;
36595 }
36597 //! Save an image list into a OFF file.
36598 template<typename tf, typename tc>
36599 const CImgList<T>& save_off(cimg_std::FILE *const file,
36600 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
36601 get_append('x','y').save_off(file,primitives,colors,invert_faces);
36602 return *this;
36603 }
36605 //! Save an image sequence using the external tool 'ffmpeg'.
36606 const CImgList<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
36607 const char *const codec="mpeg2video") const {
36608 if (is_empty())
36609 throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', instance list (%u,%p) is empty.",
36610 pixel_type(),filename?filename:"(null)",size,data);
36611 if (!filename)
36612 throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : Instance list (%u,%p), specified filename is (null).",
36613 pixel_type(),size,data);
36614 char command[1024], filetmp[512], filetmp2[512];
36615 cimg_std::FILE *file = 0;
36616 const unsigned int nlast_frame = last_frame==~0U?size-1:last_frame;
36617 if (first_frame>=size || nlast_frame>=size)
36618 throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
36619 pixel_type(),filename,first_frame,last_frame,size);
36620 for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
36621 throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', all images of the sequence must be of the same dimension.",
36622 pixel_type(),filename);
36623 do {
36624 cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
36625 cimg_std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
36626 if ((file=cimg_std::fopen(filetmp2,"rb"))!=0) cimg_std::fclose(file);
36627 } while (file);
36628 for (unsigned int l = first_frame; l<=nlast_frame; ++l) {
36629 cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,l+1);
36630 if (data[l].depth>1 || data[l].dim!=3) data[l].get_resize(-100,-100,1,3).save_pnm(filetmp2);
36631 else data[l].save_pnm(filetmp2);
36632 }
36633 #if cimg_OS!=2
36634 cimg_std::sprintf(command,"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\" >/dev/null 2>&1",filetmp,codec,filename);
36635 #else
36636 cimg_std::sprintf(command,"\"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\"\" >NUL 2>&1",filetmp,codec,filename);
36637 #endif
36638 cimg::system(command);
36639 file = cimg_std::fopen(filename,"rb");
36640 if (!file)
36641 throw CImgIOException("CImg<%s>::save_ffmpeg_external() : Failed to save image sequence '%s'.\n\n",
36642 pixel_type(),filename);
36643 else cimg::fclose(file);
36644 cimglist_for(*this,lll) { cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,lll+1); cimg_std::remove(filetmp2); }
36645 return *this;
36646 }
36648 };
36650 /*
36651 #---------------------------------------------
36652 #
36653 # Completion of previously declared functions
36654 #
36655 #----------------------------------------------
36656 */
36658 namespace cimg {
36660 //! Display a dialog box, where a user can click standard buttons.
36661 /**
36662 Up to 6 buttons can be defined in the dialog window.
36663 This function returns when a user clicked one of the button or closed the dialog window.
36664 \param title = Title of the dialog window.
36665 \param msg = Main message displayed inside the dialog window.
36666 \param button1_txt = Label of the 1st button.
36667 \param button2_txt = Label of the 2nd button.
36668 \param button3_txt = Label of the 3rd button.
36669 \param button4_txt = Label of the 4th button.
36670 \param button5_txt = Label of the 5th button.
36671 \param button6_txt = Label of the 6th button.
36672 \param logo = Logo image displayed at the left of the main message. This parameter is optional.
36673 \param centering = Tell to center the dialog window on the screen.
36674 \return The button number (from 0 to 5), or -1 if the dialog window has been closed by the user.
36675 \note If a button text is set to 0, then the corresponding button (and the followings) won't appear in
36676 the dialog box. At least one button is necessary.
36677 **/
36679 template<typename t>
36680 inline int dialog(const char *title, const char *msg,
36681 const char *button1_txt, const char *button2_txt,
36682 const char *button3_txt, const char *button4_txt,
36683 const char *button5_txt, const char *button6_txt,
36684 const CImg<t>& logo, const bool centering = false) {
36685 #if cimg_display!=0
36686 const unsigned char
36687 black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };
36689 // Create buttons and canvas graphics
36690 CImgList<unsigned char> buttons, cbuttons, sbuttons;
36691 if (button1_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button1_txt,black,gray,1,13));
36692 if (button2_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button2_txt,black,gray,1,13));
36693 if (button3_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button3_txt,black,gray,1,13));
36694 if (button4_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button4_txt,black,gray,1,13));
36695 if (button5_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button5_txt,black,gray,1,13));
36696 if (button6_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button6_txt,black,gray,1,13));
36697 }}}}}}
36698 if (!buttons.size)
36699 throw CImgArgumentException("cimg::dialog() : No buttons have been defined. At least one is necessary");
36701 unsigned int bw = 0, bh = 0;
36702 cimglist_for(buttons,l) { bw = cimg::max(bw,buttons[l].width); bh = cimg::max(bh,buttons[l].height); }
36703 bw+=8; bh+=8;
36704 if (bw<64) bw=64;
36705 if (bw>128) bw=128;
36706 if (bh<24) bh=24;
36707 if (bh>48) bh=48;
36709 CImg<unsigned char> button(bw,bh,1,3);
36710 button.draw_rectangle(0,0,bw-1,bh-1,gray);
36711 button.draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white);
36712 button.draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black);
36713 button.draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2);
36714 CImg<unsigned char> sbutton(bw,bh,1,3);
36715 sbutton.draw_rectangle(0,0,bw-1,bh-1,gray);
36716 sbutton.draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black);
36717 sbutton.draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black);
36718 sbutton.draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white);
36719 sbutton.draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black);
36720 sbutton.draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2);
36721 sbutton.draw_line(4,4,bw-5,4,black,1,0xAAAAAAAA,true).draw_line(bw-5,4,bw-5,bh-5,black,1,0xAAAAAAAA,false);
36722 sbutton.draw_line(bw-5,bh-5,4,bh-5,black,1,0xAAAAAAAA,false).draw_line(4,bh-5,4,4,black,1,0xAAAAAAAA,false);
36723 CImg<unsigned char> cbutton(bw,bh,1,3);
36724 cbutton.draw_rectangle(0,0,bw-1,bh-1,black).draw_rectangle(1,1,bw-2,bh-2,gray2).draw_rectangle(2,2,bw-3,bh-3,gray);
36725 cbutton.draw_line(4,4,bw-5,4,black,1,0xAAAAAAAA,true).draw_line(bw-5,4,bw-5,bh-5,black,1,0xAAAAAAAA,false);
36726 cbutton.draw_line(bw-5,bh-5,4,bh-5,black,1,0xAAAAAAAA,false).draw_line(4,bh-5,4,4,black,1,0xAAAAAAAA,false);
36728 cimglist_for(buttons,ll) {
36729 cbuttons.insert(CImg<unsigned char>(cbutton).draw_image(1+(bw-buttons[ll].dimx())/2,1+(bh-buttons[ll].dimy())/2,buttons[ll]));
36730 sbuttons.insert(CImg<unsigned char>(sbutton).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]));
36731 buttons[ll] = CImg<unsigned char>(button).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]);
36732 }
36734 CImg<unsigned char> canvas;
36735 if (msg) canvas = CImg<unsigned char>().draw_text(0,0,msg,black,gray,1,13);
36736 const unsigned int
36737 bwall = (buttons.size-1)*(12+bw) + bw,
36738 w = cimg::max(196U,36+logo.width+canvas.width, 24+bwall),
36739 h = cimg::max(96U,36+canvas.height+bh,36+logo.height+bh),
36740 lx = 12 + (canvas.data?0:((w-24-logo.width)/2)),
36741 ly = (h-12-bh-logo.height)/2,
36742 tx = lx+logo.width+12,
36743 ty = (h-12-bh-canvas.height)/2,
36744 bx = (w-bwall)/2,
36745 by = h-12-bh;
36747 if (canvas.data)
36748 canvas = CImg<unsigned char>(w,h,1,3).
36749 draw_rectangle(0,0,w-1,h-1,gray).
36750 draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
36751 draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black).
36752 draw_image(tx,ty,canvas);
36753 else
36754 canvas = CImg<unsigned char>(w,h,1,3).
36755 draw_rectangle(0,0,w-1,h-1,gray).
36756 draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
36757 draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black);
36758 if (logo.data) canvas.draw_image(lx,ly,logo);
36760 unsigned int xbuttons[6];
36761 cimglist_for(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(xbuttons[lll],by,buttons[lll]); }
36763 // Open window and enter events loop
36764 CImgDisplay disp(canvas,title?title:" ",0,false,centering?true:false);
36765 if (centering) disp.move((CImgDisplay::screen_dimx()-disp.dimx())/2,
36766 (CImgDisplay::screen_dimy()-disp.dimy())/2);
36767 bool stopflag = false, refresh = false;
36768 int oselected = -1, oclicked = -1, selected = -1, clicked = -1;
36769 while (!disp.is_closed && !stopflag) {
36770 if (refresh) {
36771 if (clicked>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[clicked],by,cbuttons[clicked]).display(disp);
36772 else {
36773 if (selected>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[selected],by,sbuttons[selected]).display(disp);
36774 else canvas.display(disp);
36775 }
36776 refresh = false;
36777 }
36778 disp.wait(15);
36779 if (disp.is_resized) disp.resize(disp);
36781 if (disp.button&1) {
36782 oclicked = clicked;
36783 clicked = -1;
36784 cimglist_for(buttons,l)
36785 if (disp.mouse_y>=(int)by && disp.mouse_y<(int)(by+bh) &&
36786 disp.mouse_x>=(int)xbuttons[l] && disp.mouse_x<(int)(xbuttons[l]+bw)) {
36787 clicked = selected = l;
36788 refresh = true;
36789 }
36790 if (clicked!=oclicked) refresh = true;
36791 } else if (clicked>=0) stopflag = true;
36793 if (disp.key) {
36794 oselected = selected;
36795 switch (disp.key) {
36796 case cimg::keyESC : selected=-1; stopflag=true; break;
36797 case cimg::keyENTER : if (selected<0) selected = 0; stopflag = true; break;
36798 case cimg::keyTAB :
36799 case cimg::keyARROWRIGHT :
36800 case cimg::keyARROWDOWN : selected = (selected+1)%buttons.size; break;
36801 case cimg::keyARROWLEFT :
36802 case cimg::keyARROWUP : selected = (selected+buttons.size-1)%buttons.size; break;
36803 }
36804 disp.key = 0;
36805 if (selected!=oselected) refresh = true;
36806 }
36807 }
36808 if (!disp) selected = -1;
36809 return selected;
36810 #else
36811 cimg_std::fprintf(cimg_stdout,"<%s>\n\n%s\n\n",title,msg);
36812 return -1+0*(int)(button1_txt-button2_txt+button3_txt-button4_txt+button5_txt-button6_txt+logo.width+(int)centering);
36813 #endif
36814 }
36816 inline int dialog(const char *title, const char *msg,
36817 const char *button1_txt, const char *button2_txt, const char *button3_txt,
36818 const char *button4_txt, const char *button5_txt, const char *button6_txt,
36819 const bool centering) {
36820 return dialog(title,msg,button1_txt,button2_txt,button3_txt,button4_txt,button5_txt,button6_txt,
36821 CImg<unsigned char>::logo40x38(),centering);
36822 }
36824 // End of cimg:: namespace
36825 }
36827 // End of cimg_library:: namespace
36828 }
36830 #ifdef _cimg_redefine_min
36831 #define min(a,b) (((a)<(b))?(a):(b))
36832 #endif
36833 #ifdef _cimg_redefine_max
36834 #define max(a,b) (((a)>(b))?(a):(b))
36835 #endif
36837 #endif
36838 // Local Variables:
36839 // mode: c++
36840 // End: