~ubuntu-branches/ubuntu/intrepid/digikam/intrepid

« back to all changes in this revision

Viewing changes to digikam/libs/greycstoration/CImg.h

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2008-07-17 20:25:39 UTC
  • mfrom: (1.2.15 upstream) (3.1.2 lenny)
  • Revision ID: james.westby@ubuntu.com-20080717202539-6n7dtirbkoo7qvhd
Tags: 2:0.9.4-1
* New upstream release
  - digiKam 0.9.4 Release Plan (KDE3) ~ 13 July 08 (Closes: #490144)
* DEB_CONFIGURE_EXTRA_FLAGS := --without-included-sqlite3
* Debhelper compatibility level V7
* Install pixmaps in debian/*.install
* Add debian/digikam.lintian-overrides

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 #
3
3
 #  File        : CImg.h
 
4
 #                ( C++ header file )
4
5
 #
5
 
 #  Description : The C++ Template Image Processing Library
 
6
 #  Description : The C++ Template Image Processing Library.
 
7
 #                This file is the main part of the CImg Library project.
6
8
 #                ( http://cimg.sourceforge.net )
7
9
 #
8
10
 #  Copyright   : David Tschumperle
9
11
 #                ( http://www.greyc.ensicaen.fr/~dtschump/ )
10
12
 #
11
 
 #  License     : CeCILL-C
12
 
 #
13
 
 #  This software is governed by the CeCILL-C license under French law and
14
 
 #  abiding by the rules of distribution of free software.  You can  use,
15
 
 #  modify and or redistribute the software under the terms of the CeCILL-C
16
 
 #  license as circulated by CEA, CNRS and INRIA at the following URL
17
 
 #  "http://www.cecill.info".
 
13
 #                Few parts have been written by other people. The complete
 
14
 #                list of contributors is available on the project website.
 
15
 #
 
16
 #  Licenses    : This file is "dual-licensed", you have to choose one
 
17
 #                of the two licenses below to apply on this file.
 
18
 #
 
19
 #                CeCILL-C
 
20
 #                The CeCILL-C license is close to the GNU LGPL.
 
21
 #                ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
 
22
 #
 
23
 #            or  CeCILL v2.0
 
24
 #                The CeCILL license is compatible with the GNU GPL.
 
25
 #                ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
 
26
 #
 
27
 #  This software is governed either by the CeCILL or the CeCILL-C license
 
28
 #  under French law and abiding by the rules of distribution of free software.
 
29
 #  You can  use, modify and or redistribute the software under the terms of
 
30
 #  the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA
 
31
 #  at the following URL : "http://www.cecill.info".
18
32
 #
19
33
 #  As a counterpart to the access to the source code and  rights to copy,
20
34
 #  modify and redistribute granted by the license, users are provided only
34
48
 #  same conditions as regards security.
35
49
 #
36
50
 #  The fact that you are presently reading this means that you have had
37
 
 #  knowledge of the CeCILL-C license and that you accept its terms.
 
51
 #  knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms.
38
52
 #
39
53
*/
 
54
 
 
55
// Define version number of the current file.
 
56
//
40
57
#ifndef cimg_version
41
 
#define cimg_version 1.24
42
 
 
43
 
// Detect Microsoft VC++ 6.0 compiler to get some workarounds afterwards.
44
 
#if defined(_MSC_VER) && _MSC_VER<1300
45
 
#define cimg_use_visualcpp6
46
 
#endif
47
 
 
48
 
// Avoid strange 'deprecated' warning messages with Visual C++ .NET.
49
 
#if defined(_MSC_VER) && _MSC_VER>=1300
50
 
#define _CRT_SECURE_NO_DEPRECATE 1
51
 
#define _CRT_NONSTDC_NO_DEPRECATE 1
52
 
#endif
53
 
 
54
 
// Standard C++ includes.
 
58
#define cimg_version 129
 
59
 
 
60
/*-----------------------------------------------------------
 
61
 #
 
62
 # Test/auto-set CImg configuration variables
 
63
 # and include required headers.
 
64
 #
 
65
 # If you find that default configuration variables are
 
66
 # not adapted, you can override their values before including
 
67
 # the header file "CImg.h" (using the #define directive).
 
68
 #
 
69
 ------------------------------------------------------------*/
 
70
 
 
71
// Include required standard C++ headers.
 
72
//
55
73
#include <cstdio>
56
74
#include <cstdlib>
57
75
#include <cstdarg>
59
77
#include <cmath>
60
78
#include <ctime>
61
79
 
62
 
/*
63
 
 #
64
 
 # Set CImg configuration flags.
65
 
 #
66
 
 # If compilation flags are not adapted to your system,
67
 
 # you may override their values, before including
68
 
 # the header file "CImg.h" (use the #define directive).
69
 
 #
70
 
 */
71
 
 
72
 
// Try to detect the current system and set value of 'cimg_OS'.
 
80
// Operating system configuration.
 
81
//
 
82
// Define 'cimg_OS' to : 0 for an unknown OS (will try to minize library dependancies).
 
83
//                       1 for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...).
 
84
//                       2 for Microsoft Windows.
 
85
//
73
86
#ifndef cimg_OS
74
 
// Unix-like (Linux, Solaris, BSD, MacOSX, Irix,...).
75
 
#if defined(unix)       || defined(__unix)      || defined(__unix__) \
76
 
 || defined(linux)      || defined(__linux)     || defined(__linux__) \
77
 
 || defined(sun)        || defined(__sun) \
78
 
 || defined(BSD)        || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined __DragonFly__ \
79
 
 || defined(__MACOSX__) || defined(__APPLE__) \
80
 
 || defined(sgi)        || defined(__sgi) \
 
87
#if defined(unix)        || defined(__unix)      || defined(__unix__) \
 
88
 || defined(linux)       || defined(__linux)     || defined(__linux__) \
 
89
 || defined(sun)         || defined(__sun) \
 
90
 || defined(BSD)         || defined(__OpenBSD__) || defined(__NetBSD__) \
 
91
 || defined(__FreeBSD__) || defined __DragonFly__ \
 
92
 || defined(sgi)         || defined(__sgi) \
 
93
 || defined(__MACOSX__)  || defined(__APPLE__) \
81
94
 || defined(__CYGWIN__)
82
 
#define cimg_OS            1
83
 
#ifndef cimg_display_type
84
 
#define cimg_display_type  1
85
 
#endif
86
 
#ifndef cimg_color_terminal
87
 
#define cimg_color_terminal
88
 
#endif
89
 
// Windows.
90
 
#elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
91
 
   || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
92
 
#define cimg_OS            2
93
 
#ifndef cimg_display_type
94
 
#define cimg_display_type  2
95
 
#endif
96
 
// Unknown configuration : ask for minimal dependencies (no display).
 
95
#define cimg_OS 1
 
96
#elif defined(_MSC_VER) || defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) \
 
97
   || defined(WIN64)    || defined(_WIN64) || defined(__WIN64__)
 
98
#define cimg_OS 2
97
99
#else
98
 
#define cimg_OS            0
99
 
#ifndef cimg_display_type
100
 
#define cimg_display_type  0
101
 
#endif
102
 
#endif
103
 
#endif
104
 
 
105
 
// Debug configuration.
106
 
//
107
 
// Set 'cimg_debug' to : 0 to remove debug messages (exceptions are still thrown anyway).
108
 
//                       1 to display debug messages on standard error output (console).
109
 
//                       2 to display debug messages with modal windows (default behavior).
110
 
//                       3 to do as 2 + add extra memory access warnings (may slow down the code)
111
 
#ifndef cimg_debug
112
 
#define cimg_debug         2
113
 
#endif
114
 
 
115
 
// Architecture-dependent includes.
 
100
#define cimg_OS 0
 
101
#endif
 
102
#elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2)
 
103
#error CImg Library : Configuration variable 'cimg_OS' is badly defined.
 
104
#error (valid values are '0=unknown OS', '1=Unix-like OS', '2=Microsoft Windows').
 
105
#endif
 
106
 
 
107
// Compiler configuration.
 
108
//
 
109
// Try to detect Microsoft VC++ compilers.
 
110
// (lot of workarounds are needed afterwards to
 
111
//  make CImg working, particularly with VC++ 6.0).
 
112
//
 
113
#ifdef _MSC_VER
 
114
#pragma warning(push)
 
115
#pragma warning(disable:4311)
 
116
#pragma warning(disable:4312)
 
117
#pragma warning(disable:4800)
 
118
#pragma warning(disable:4804)
 
119
#pragma warning(disable:4996)
 
120
#define _CRT_SECURE_NO_DEPRECATE 1
 
121
#define _CRT_NONSTDC_NO_DEPRECATE 1
 
122
#if _MSC_VER<1300
 
123
#define cimg_use_visualcpp6
 
124
#define _WIN32_WINNT 0x0500
 
125
#endif
 
126
#endif
 
127
 
 
128
// Include OS-specific headers.
 
129
//
116
130
#if cimg_OS==1
117
131
#include <sys/time.h>
118
132
#include <unistd.h>
127
141
#endif
128
142
#endif
129
143
 
130
 
// Test if min/max or PI macros are defined.
131
 
#ifdef PI
132
 
#error -------------------------------------------------------------------------------
133
 
#error The macro value 'PI' has been defined prior to the #include "CImg.h" directive.
134
 
#error The CImg Library does not compile with such a macro value defined.
135
 
#error Please (re)define this macro *after* including "CImg.h" if really necessary.
136
 
#error Following error messages are most probably related to this problem.
137
 
#error -------------------------------------------------------------------------------
138
 
#endif
139
 
#ifdef min
140
 
#undef min
141
 
#define cimg_redefine_min
142
 
#endif
143
 
#ifdef max
144
 
#undef max
145
 
#define cimg_redefine_max
146
 
#endif
147
 
 
148
 
// Display-dependent includes.
149
 
#if cimg_display_type==1
 
144
// Output messages configuration.
 
145
//
 
146
// Define 'cimg_debug' to : 0 to hide debug messages (quiet mode, but exceptions are still thrown).
 
147
//                          1 to display debug messages on standard error (stderr).
 
148
//                          2 to display debug messages with dialog windows (default behavior).
 
149
//                          3 to do as 1 + add extra warnings (may slow down the code !).
 
150
//                          4 to do as 2 + add extra warnings (may slow down the code !).
 
151
//
 
152
// Define 'cimg_strict_warnings' to replace warning messages by exception throwns.
 
153
//
 
154
// Define 'cimg_use_vt100' to allow output of color messages (require VT100-compatible terminal).
 
155
//
 
156
#ifndef cimg_debug
 
157
#define cimg_debug 2
 
158
#elif !(cimg_debug==0 || cimg_debug==1 || cimg_debug==2 || cimg_debug==3 || cimg_debug==4)
 
159
#error CImg Library : Configuration variable 'cimg_debug' is badly defined.
 
160
#error (valid values are '0=quiet', '1=stderr', '2=dialog', '3=stderr+warnings', '4=dialog+warnings').
 
161
#endif
 
162
 
 
163
// Display framework configuration.
 
164
//
 
165
// Define 'cimg_display' to : 0 to disable display capabilities.
 
166
//                            1 to use X-Window framework (X11).
 
167
//                            2 to use Microsoft GDI32 framework.
 
168
//                            3 to use Apple Carbon framework.
 
169
//
 
170
#ifndef cimg_display
 
171
#if cimg_OS==0
 
172
#define cimg_display 0
 
173
#elif cimg_OS==1
 
174
#if defined(__MACOSX__) || defined(__APPLE__)
 
175
#define cimg_display 1
 
176
#else
 
177
#define cimg_display 1
 
178
#endif
 
179
#elif cimg_OS==2
 
180
#define cimg_display 2
 
181
#endif
 
182
#elif !(cimg_display==0 || cimg_display==1 || cimg_display==2 || cimg_display==3)
 
183
#error CImg Library : Configuration variable 'cimg_display' is badly defined.
 
184
#error (valid values are '0=disable', '1=X-Window (X11)', '2=Microsoft GDI32', '3=Apple Carbon').
 
185
#endif
 
186
 
 
187
// Include display-specific headers.
 
188
//
 
189
#if cimg_display==1
150
190
#include <X11/Xlib.h>
151
191
#include <X11/Xutil.h>
152
192
#include <X11/keysym.h>
159
199
#ifdef cimg_use_xrandr
160
200
#include <X11/extensions/Xrandr.h>
161
201
#endif
162
 
#endif
163
 
 
164
 
// Configuration for using extra libraries
165
 
//
166
 
// Define 'cimg_use_png', 'cimg_use_jpeg' or 'cimg_use_tiff' to enable native PNG, JPEG or TIFF files support.
167
 
// This requires you link your code with the zlib/png, jpeg or tiff libraries.
168
 
// Without these libraries, PNG,JPEG and TIFF support will be done by the Image Magick's 'convert' tool,
169
 
// or byt the GraphicsMagick 'gm' tool if installed
170
 
// (this is the case on most unix plateforms).
 
202
#elif cimg_display==3
 
203
#include <Carbon/Carbon.h>
 
204
#include <pthread.h>
 
205
#endif
 
206
 
 
207
// OpenMP configuration.
 
208
// (http://www.openmp.org)
 
209
//
 
210
// Define 'cimg_use_openmp' to enable OpenMP support.
 
211
//
 
212
// OpenMP directives can be used in few CImg functions to get
 
213
// advantages of multi-core CPUs. Using OpenMP is not mandatory.
 
214
//
 
215
#ifdef cimg_use_openmp
 
216
#include "omp.h"
 
217
#endif
 
218
 
 
219
// LibPNG configuration.
 
220
// (http://www.libpng.org)
 
221
//
 
222
// Define 'cimg_use_png' to enable LibPNG support.
 
223
//
 
224
// LibPNG can be used in functions 'CImg<T>::{load,save}_png()'
 
225
// to get a builtin support of PNG files. Using LibPNG is not mandatory.
 
226
//
171
227
#ifdef cimg_use_png
172
228
extern "C" {
173
229
#include "png.h"
174
230
}
175
231
#endif
 
232
 
 
233
// LibJPEG configuration.
 
234
// (http://en.wikipedia.org/wiki/Libjpeg)
 
235
//
 
236
// Define 'cimg_use_jpeg' to enable LibJPEG support.
 
237
//
 
238
// LibJPEG can be used in functions 'CImg<T>::{load,save}_jpeg()'
 
239
// to get a builtin support of JPEG files. Using LibJPEG is not mandatory.
 
240
//
176
241
#ifdef cimg_use_jpeg
177
242
extern "C" {
178
243
#include "jpeglib.h"
179
244
}
180
245
#endif
 
246
 
 
247
// LibTIFF configuration.
 
248
// (http://www.libtiff.org)
 
249
//
 
250
// Define 'cimg_use_tiff' to enable LibTIFF support.
 
251
//
 
252
// LibTIFF can be used in functions 'CImg[List]<T>::{load,save}_tiff()'
 
253
// to get a builtin support of TIFF files. Using LibTIFF is not mandatory.
 
254
//
181
255
#ifdef cimg_use_tiff
182
256
extern "C" {
183
257
#include "tiffio.h"
184
258
}
185
259
#endif
 
260
 
 
261
// FFMPEG Avcodec and Avformat libraries configuration.
 
262
// (http://www.ffmpeg.org)
 
263
//
 
264
// Define 'cimg_use_ffmpeg' to enable FFMPEG lib support.
 
265
//
 
266
// Avcodec and Avformat libraries can be used in functions
 
267
// 'CImg[List]<T>::load_ffmpeg()' to get a builtin
 
268
// support of various image sequences files.
 
269
// Using FFMPEG libraries is not mandatory.
 
270
//
 
271
#ifdef cimg_use_ffmpeg
 
272
extern "C" {
 
273
#include "ffmpeg/avformat.h"
 
274
#include "ffmpeg/avcodec.h"
 
275
#include "ffmpeg/swscale.h"
 
276
}
 
277
#endif
 
278
 
 
279
// Zlib configuration
 
280
// (http://www.zlib.net)
 
281
//
 
282
// Define 'cimg_use_zlib' to enable Zlib support.
 
283
//
 
284
// Zlib can be used in functions 'CImg[List]<T>::{load,save}_cimg()'
 
285
// to allow compressed data in '.cimg' files. Using Zlib is not mandatory.
 
286
//
 
287
#ifdef cimg_use_zlib
 
288
extern "C" {
 
289
#include "zlib.h"
 
290
}
 
291
#endif
 
292
 
 
293
// Magick++ configuration.
 
294
// (http://www.imagemagick.org/Magick++)
 
295
//
 
296
// Define 'cimg_use_magick' to enable Magick++ support.
 
297
//
 
298
// Magick++ library can be used in functions 'CImg<T>::{load,save}()'
 
299
// to get a builtin support of various image formats (PNG,JPEG,TIFF,...).
 
300
// Using Magick++ is not mandatory.
 
301
//
186
302
#ifdef cimg_use_magick
187
303
#include "Magick++.h"
188
304
#endif
 
305
 
 
306
// FFTW3 configuration.
 
307
// (http://www.fftw.org)
 
308
//
 
309
// Define 'cimg_use_fftw3' to enable libFFTW3 support.
 
310
//
 
311
// FFTW3 library can be used in functions 'CImg[List]<T>::FFT()' to
 
312
// efficiently compile the Fast Fourier Transform of image data.
 
313
//
189
314
#ifdef cimg_use_fftw3
190
315
extern "C" {
191
316
#include "fftw3.h"
192
317
}
193
318
#endif
 
319
 
 
320
// Board configuration.
 
321
// (http://libboard.sourceforge.net/)
 
322
//
 
323
// Define 'cimg_use_board' to enable Board support.
 
324
//
 
325
// Board library can be used in functions 'CImg<T>::draw_object3d()'
 
326
// to draw objects 3D in vector-graphics canvas that can be saved
 
327
// as .PS or .SVG files afterwards.
 
328
//
 
329
#ifdef cimg_use_board
 
330
#include "Board.h"
 
331
#endif
 
332
 
 
333
// Lapack configuration.
 
334
// (http://www.netlib.org/lapack)
 
335
//
 
336
// Define 'cimg_use_lapack' to enable LAPACK support.
 
337
//
 
338
// Lapack can be used in various CImg functions dealing with
 
339
// matrix computation and algorithms (eigenvalues, inverse, ...).
 
340
// Using Lapack is not mandatory.
 
341
//
194
342
#ifdef cimg_use_lapack
195
343
extern "C" {
196
344
  extern void sgetrf_(int*, int*, float*, int*, int*, int*);
206
354
}
207
355
#endif
208
356
 
209
 
/*
210
 
 #
211
 
 #
212
 
 # Define some useful macros. Macros of the CImg Library are prefixed by 'cimg_'
213
 
 # Documented macros below may be safely used in your own code
214
 
 # (particularly useful for option parsing, image loops and neighborhoods).
215
 
 #
216
 
 #
217
 
 */
218
 
 
219
 
// Macros used to describe the program usage, and retrieve command line arguments
220
 
// (See corresponding module 'Retrieving command line arguments' in the generated documentation).
 
357
// Check if min/max macros are defined.
 
358
//
 
359
// CImg does not compile if macros 'min' or 'max' are defined,
 
360
// because min() and max() functions are also defined in the cimg:: namespace.
 
361
// so it '#undef' these macros if necessary, and restore them to reasonable
 
362
// values at the end of the file.
 
363
//
 
364
#ifdef min
 
365
#undef min
 
366
#define _cimg_redefine_min
 
367
#endif
 
368
#ifdef max
 
369
#undef max
 
370
#define _cimg_redefine_max
 
371
#endif
 
372
 
 
373
// Set the current working directory for native MacOSX bundled applications.
 
374
//
 
375
// By default, MacOS bundled applications set the cwd at the root directory '/',
 
376
// the code below allows to set it to the current exec directory instead when
 
377
// a CImg-based program is executed.
 
378
//
 
379
#if cimg_OS==1 && cimg_display==3
 
380
static struct _cimg_macosx_setcwd {
 
381
  _cimg_macosx_setcwd() {
 
382
    FSRef location;
 
383
    ProcessSerialNumber psn;
 
384
    char filePath[512];
 
385
    if (GetCurrentProcess(&psn)!=noErr) return;
 
386
    if (GetProcessBundleLocation(&psn,&location)!=noErr) return;
 
387
    FSRefMakePath(&location,(UInt8*)filePath,sizeof(filePath)-1);
 
388
    int p = strlen(filePath);
 
389
    while (filePath[p] != '/') --p;
 
390
    filePath[p] = 0;
 
391
    chdir(filePath);
 
392
  }
 
393
} cimg_macosx_setcwd;
 
394
#endif
 
395
 
 
396
/*------------------------------------------------------------------------------
 
397
  #
 
398
  # Define user-friendly macros.
 
399
  #
 
400
  # User macros are prefixed by 'cimg_' and can be used in your own code.
 
401
  # They are particularly useful for option parsing, and image loops creation.
 
402
  #
 
403
  ------------------------------------------------------------------------------*/
 
404
 
 
405
// Define the program usage, and retrieve command line arguments.
 
406
//
221
407
#define cimg_usage(usage) cimg_library::cimg::option((char*)0,argc,argv,(char*)0,usage)
222
408
#define cimg_help(str)    cimg_library::cimg::option((char*)0,argc,argv,str,(char*)0)
223
409
#define cimg_option(name,defaut,usage) cimg_library::cimg::option(name,argc,argv,defaut,usage)
224
 
 
225
 
// Macros used for neighborhood definitions and manipulations.
226
 
// (see module 'Using Image Loops' in the generated documentation).
227
 
#define CImg_2(I,T)   T   I##cc,I##nc=0
228
 
#define CImg_2x2(I,T) T   I##cc,I##nc=0,I##cn,I##nn=0
229
 
#define CImg_3(I,T)   T   I##pp,I##cp,I##np=0
230
 
#define CImg_3x3(I,T) T   I##pp,I##cp,I##np=0,I##pc,I##cc,I##nc=0,I##pn,I##cn,I##nn=0
231
 
#define CImg_4(I,T)   T   I##pp,I##cp,I##np=0,I##ap=0
232
 
#define CImg_4x4(I,T) T   I##pp,I##cp,I##np=0,I##ap=0, \
233
 
                          I##pc,I##cc,I##nc=0,I##ac=0, \
234
 
                          I##pn,I##cn,I##nn=0,I##an=0, \
235
 
                          I##pa,I##ca,I##na=0,I##aa=0
236
 
#define CImg_5(I,T)   T   I##bb,I##pb,I##cb,I##nb=0,I##ab=0
237
 
#define CImg_5x5(I,T) T   I##bb,I##pb,I##cb,I##nb=0,I##ab=0, \
238
 
                          I##bp,I##pp,I##cp,I##np=0,I##ap=0, \
239
 
                          I##bc,I##pc,I##cc,I##nc=0,I##ac=0, \
240
 
                          I##bn,I##pn,I##cn,I##nn=0,I##an=0, \
241
 
                          I##ba,I##pa,I##ca,I##na=0,I##aa=0
242
 
#define CImg_2x2x2(I,T) T I##ccc,I##ncc=0,I##cnc,I##nnc=0, \
243
 
                          I##ccn,I##ncn=0,I##cnn,I##nnn=0
244
 
#define CImg_3x3x3(I,T) T I##ppp,I##cpp,I##npp=0,I##pcp,I##ccp,I##ncp=0,I##pnp,I##cnp,I##nnp=0, \
245
 
                          I##ppc,I##cpc,I##npc=0,I##pcc,I##ccc,I##ncc=0,I##pnc,I##cnc,I##nnc=0, \
246
 
                          I##ppn,I##cpn,I##npn=0,I##pcn,I##ccn,I##ncn=0,I##pnn,I##cnn,I##nnn=0
247
 
 
248
 
#define CImg_2x2_ref(I,T,tab)   T &I##cc=(tab)[0],&I##nc=(tab)[1],&I##cn=(tab)[2],&I##nn=(tab)[3]
249
 
#define CImg_3x3_ref(I,T,tab)   T &I##pp=(tab)[0],&I##cp=(tab)[1],&I##np=(tab)[2], \
250
 
                                  &I##pc=(tab)[3],&I##cc=(tab)[4],&I##nc=(tab)[5], \
251
 
                                  &I##pn=(tab)[6],&I##cn=(tab)[7],&I##nn=(tab)[8]
252
 
#define CImg_4x4_ref(I,T,tab)   T &I##pp=(tab)[0], &I##cp=(tab)[1], &I##np=(tab)[2], &I##ap=(tab)[3], \
253
 
                                  &I##pc=(tab)[4], &I##cc=(tab)[5], &I##nc=(tab)[6], &I##ac=(tab)[7], \
254
 
                                  &I##pn=(tab)[8], &I##cn=(tab)[9], &I##nn=(tab)[10],&I##an=(tab)[11], \
255
 
                                  &I##pa=(tab)[12],&I##ca=(tab)[13],&I##na=(tab)[14],&I##aa=(tab)[15]
256
 
#define CImg_5x5_ref(I,T,tab)   T &I##bb=(tab)[0],&I##pb=(tab)[1],&I##cb=(tab)[2],&I##nb=(tab)[3],&I##ab=(tab)[4], \
257
 
                                  &I##bp=(tab)[5],&I##pp=(tab)[6],&I##cp=(tab)[7],&I##np=(tab)[8],&I##ap=(tab)[9], \
258
 
                                  &I##bc=(tab)[10],&I##pc=(tab)[11],&I##cc=(tab)[12],&I##nc=(tab)[13],&I##ac=(tab)[14], \
259
 
                                  &I##bn=(tab)[15],&I##pn=(tab)[16],&I##cn=(tab)[17],&I##nn=(tab)[18],&I##an=(tab)[19], \
260
 
                                  &I##ba=(tab)[20],&I##pa=(tab)[21],&I##ca=(tab)[22],&I##na=(tab)[23],&I##aa=(tab)[24]
261
 
#define CImg_2x2x2_ref(I,T,tab) T &I##ccc=(tab)[0],&I##ncc=(tab)[1],&I##cnc=(tab)[2],&I##nnc=(tab)[3], \
262
 
                                  &I##ccn=(tab)[4],&I##ncn=(tab)[5],&I##cnn=(tab)[6],&I##nnn=(tab)[7]
263
 
#define CImg_3x3x3_ref(I,T,tab) T &I##ppp=(tab)[0],&I##cpp=(tab)[1],&I##npp=(tab)[2], \
264
 
                                  &I##pcp=(tab)[3],&I##ccp=(tab)[4],&I##ncp=(tab)[5], \
265
 
                                  &I##pnp=(tab)[6],&I##cnp=(tab)[7],&I##nnp=(tab)[8], \
266
 
                                  &I##ppc=(tab)[9],&I##cpc=(tab)[10],&I##npc=(tab)[11], \
267
 
                                  &I##pcc=(tab)[12],&I##ccc=(tab)[13],&I##ncc=(tab)[14], \
268
 
                                  &I##pnc=(tab)[15],&I##cnc=(tab)[16],&I##nnc=(tab)[17], \
269
 
                                  &I##ppn=(tab)[18],&I##cpn=(tab)[19],&I##npn=(tab)[20], \
270
 
                                  &I##pcn=(tab)[21],&I##ccn=(tab)[22],&I##ncn=(tab)[23], \
271
 
                                  &I##pnn=(tab)[24],&I##cnn=(tab)[25],&I##nnn=(tab)[26]
272
 
 
273
 
#define cimg_copy2x2(J,I)   I##cc=J##cc, I##nc=J##nc, I##cn=J##cn, I##nn=J##nn
274
 
#define cimg_copy3x3(J,I)   I##pp=J##pp, I##cp=J##cp, I##np=J##np, \
275
 
                            I##pc=J##pc, I##cc=J##cc, I##nc=J##nc, \
276
 
                            I##pn=J##pn, I##cn=J##cn, I##nn=J##nn
277
 
#define cimg_copy5x5(J,I)   I##bb=J##bb, I##pb=J##pb, I##cb=J##cb, I##nb=J##nb, I##ab=J##ab, \
278
 
                            I##bp=J##bp, I##pp=J##pp, I##cp=J##cp, I##np=J##np, I##ap=J##ap, \
279
 
                            I##bc=J##bc, I##pc=J##pc, I##cc=J##cc, I##nc=J##nc, I##ac=J##ac, \
280
 
                            I##bn=J##bn, I##pn=J##pn, I##cn=J##cn, I##nn=J##nn, I##an=J##an, \
281
 
                            I##ba=J##ba, I##pa=J##pa, I##ca=J##ca, I##na=J##na, I##aa=J##aa
282
 
 
283
 
#define cimg_squaresum2x2(I)   ( I##cc*I##cc + I##nc*I##nc + I##cn*I##cn + I##nn*I##nn )
284
 
#define cimg_squaresum3x3(I)   ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + \
285
 
                                 I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + \
286
 
                                 I##pn*I##pn + I##cn*I##cn + I##nn*I##nn )
287
 
#define cimg_squaresum4x4(I)   ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \
288
 
                                 I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \
289
 
                                 I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \
290
 
                                 I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa )
291
 
#define cimg_squaresum5x5(I)   ( I##bb*I##bb + I##pb*I##pb + I##cb*I##cb + I##nb*I##nb + I##ab*I##ab + \
292
 
                                 I##bp*I##bp + I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \
293
 
                                 I##bc*I##bc + I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \
294
 
                                 I##bn*I##bn + I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \
295
 
                                 I##ba*I##ba + I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa )
296
 
#define cimg_squaresum2x2x2(I) ( I##ccc*I##ccc + I##ncc*I##ncc + I##cnc*I##cnc + I##nnc*I##nnc + \
297
 
                                 I##ccn*I##ccn + I##ncn*I##ncn + I##cnn*I##cnn + I##nnn*I##nnn )
298
 
#define cimg_squaresum3x3x3(I) ( I##ppp*I##ppp + I##cpp*I##cpp + I##npp*I##npp + \
299
 
                                 I##pcp*I##pcp + I##ccp*I##ccp + I##ncp*I##ncp + \
300
 
                                 I##pnp*I##pnp + I##cnp*I##cnp + I##nnp*I##nnp + \
301
 
                                 I##ppc*I##ppc + I##cpc*I##cpc + I##npc*I##npc + \
302
 
                                 I##pcc*I##pcc + I##ccc*I##ccc + I##ncc*I##ncc + \
303
 
                                 I##pnc*I##pnc + I##cnc*I##cnc + I##nnc*I##nnc + \
304
 
                                 I##ppn*I##ppn + I##cpn*I##cpn + I##npn*I##npn + \
305
 
                                 I##pcn*I##pcn + I##ccn*I##ccn + I##ncn*I##ncn + \
306
 
                                 I##pnn*I##pnn + I##cnn*I##cnn + I##nnn*I##nnn )
307
 
 
308
 
#define cimg_corr2x2(I,m)   ( I##cc*(m)(0,0)+I##nc*(m)(1,0)+I##cn*(m)(0,1)+I##nn*(m)(1,1) )
309
 
#define cimg_corr3x3(I,m)   ( I##pp*(m)(0,0)+I##cp*(m)(1,0)+I##np*(m)(2,0) + \
310
 
                              I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1) + \
311
 
                              I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2) )
312
 
#define cimg_corr4x4(I,m)   ( I##pp*(m)(0,0)+I##cp*(m)(1,0)+I##np*(m)(2,0)+I##ap*(m)(3,0) + \
313
 
                              I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1)+I##ac*(m)(3,1) + \
314
 
                              I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2)+I##an*(m)(3,2) + \
315
 
                              I##pa*(m)(0,3)+I##ca*(m)(1,3)+I##na*(m)(2,3)+I##aa*(m)(3,3) )
316
 
#define cimg_corr5x5(I,m)   ( I##bb*(m)(0,0)+I##pb*(m)(1,0)+I##cb*(m)(2,0)+I##nb*(m)(3,0)+I##ab*(m)(4,0) + \
317
 
                              I##bp*(m)(0,1)+I##pp*(m)(1,1)+I##cp*(m)(2,1)+I##np*(m)(3,1)+I##ap*(m)(4,1) + \
318
 
                              I##bc*(m)(0,2)+I##pc*(m)(1,2)+I##cc*(m)(2,2)+I##nc*(m)(3,2)+I##ac*(m)(4,2) + \
319
 
                              I##bn*(m)(0,3)+I##pn*(m)(1,3)+I##cn*(m)(2,3)+I##nn*(m)(3,3)+I##an*(m)(4,3) + \
320
 
                              I##ba*(m)(0,4)+I##pa*(m)(1,4)+I##ca*(m)(2,4)+I##na*(m)(3,4)+I##aa*(m)(4,4) )
321
 
#define cimg_corr2x2x2(I,m) ( I##ccc*(m)(0,0,0)+I##ncc*(m)(1,0,0)+I##cnc*(m)(0,1,0)+I##nnc*(m)(1,1,0) + \
322
 
                              I##ccn*(m)(0,0,1)+I##ncn*(m)(1,0,1)+I##cnn*(m)(0,1,1)+I##nnn*(m)(1,1,1) )
323
 
#define cimg_corr3x3x3(I,m) ( I##ppp*(m)(0,0,0)+I##cpp*(m)(1,0,0)+I##npp*(m)(2,0,0) + \
324
 
                              I##pcp*(m)(0,1,0)+I##ccp*(m)(1,1,0)+I##ncp*(m)(2,1,0) + \
325
 
                              I##pnp*(m)(0,2,0)+I##cnp*(m)(1,2,0)+I##nnp*(m)(2,2,0) + \
326
 
                              I##ppc*(m)(0,0,1)+I##cpc*(m)(1,0,1)+I##npc*(m)(2,0,1) + \
327
 
                              I##pcc*(m)(0,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(2,1,1) + \
328
 
                              I##pnc*(m)(0,2,1)+I##cnc*(m)(1,2,1)+I##nnc*(m)(2,2,1) + \
329
 
                              I##ppn*(m)(0,0,2)+I##cpn*(m)(1,0,2)+I##npn*(m)(2,0,2) + \
330
 
                              I##pcn*(m)(0,1,2)+I##ccn*(m)(1,1,2)+I##ncn*(m)(2,1,2) + \
331
 
                              I##pnn*(m)(0,2,2)+I##cnn*(m)(1,2,2)+I##nnn*(m)(2,2,2) )
332
 
 
333
 
#define cimg_conv2x2(I,m)   ( I##cc*(m)(1,1)+I##nc*(m)(0,1)+I##cn*(m)(1,0)+I##nn*(m)(0,0) )
334
 
#define cimg_conv3x3(I,m)   ( I##pp*(m)(2,2)+I##cp*(m)(1,2)+I##np*(m)(0,2) + \
335
 
                              I##pc*(m)(2,1)+I##cc*(m)(1,1)+I##nc*(m)(0,1) + \
336
 
                              I##pn*(m)(2,0)+I##cn*(m)(1,0)+I##nn*(m)(0,0) )
337
 
#define cimg_conv4x4(I,m)   ( I##pp*(m)(3,3)+I##cp*(m)(2,3)+I##np*(m)(1,3)+I##ap*(m)(0,3) + \
338
 
                              I##pc*(m)(3,2)+I##cc*(m)(2,2)+I##nc*(m)(1,2)+I##ac*(m)(0,2) + \
339
 
                              I##pn*(m)(3,1)+I##cn*(m)(2,1)+I##nn*(m)(1,1)+I##an*(m)(0,1) + \
340
 
                              I##pa*(m)(3,0)+I##ca*(m)(2,0)+I##na*(m)(1,0)+I##aa*(m)(0,0) )
341
 
#define cimg_conv5x5(I,m)   ( I##bb*(m)(4,4)+I##pb*(m)(3,4)+I##cb*(m)(2,4)+I##nb*(m)(1,4)+I##ab*(m)(0,4) + \
342
 
                              I##bp*(m)(4,3)+I##pp*(m)(3,3)+I##cp*(m)(2,3)+I##np*(m)(1,3)+I##ap*(m)(0,3) + \
343
 
                              I##bc*(m)(4,2)+I##pc*(m)(3,2)+I##cc*(m)(2,2)+I##nc*(m)(1,2)+I##ac*(m)(0,2) + \
344
 
                              I##bn*(m)(4,1)+I##pn*(m)(3,1)+I##cn*(m)(2,1)+I##nn*(m)(1,1)+I##an*(m)(0,1) + \
345
 
                              I##ba*(m)(4,0)+I##pa*(m)(3,0)+I##ca*(m)(2,0)+I##na*(m)(1,0)+I##aa*(m)(0,0) )
346
 
#define cimg_conv2x2x2(I,m) ( I##ccc*(m)(1,1,1)+I##ncc*(m)(0,1,1)+I##cnc*(m)(1,0,1)+I##nnc*(m)(0,0,1) + \
347
 
                              I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) )
348
 
#define cimg_conv3x3x3(I,m) ( I##ppp*(m)(2,2,2)+I##cpp*(m)(1,2,2)+I##npp*(m)(0,2,2) + \
349
 
                              I##pcp*(m)(2,1,2)+I##ccp*(m)(1,1,2)+I##ncp*(m)(0,1,2) + \
350
 
                              I##pnp*(m)(2,0,2)+I##cnp*(m)(1,0,2)+I##nnp*(m)(0,0,2) + \
351
 
                              I##ppc*(m)(2,2,1)+I##cpc*(m)(1,2,1)+I##npc*(m)(0,2,1) + \
352
 
                              I##pcc*(m)(2,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(0,1,1) + \
353
 
                              I##pnc*(m)(2,0,1)+I##cnc*(m)(1,0,1)+I##nnc*(m)(0,0,1) + \
354
 
                              I##ppn*(m)(2,2,0)+I##cpn*(m)(1,2,0)+I##npn*(m)(0,2,0) + \
355
 
                              I##pcn*(m)(2,1,0)+I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0) + \
356
 
                              I##pnn*(m)(2,0,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) )
 
410
#define cimg_argument(pos) cimg_library::cimg::argument(pos,argc,argv)
 
411
#define cimg_argument1(pos,s0) cimg_library::cimg::argument(pos,argc,argv,1,s0)
 
412
#define cimg_argument2(pos,s0,s1) cimg_library::cimg::argument(pos,argc,argv,2,s0,s1)
 
413
#define cimg_argument3(pos,s0,s1,s2) cimg_library::cimg::argument(pos,argc,argv,3,s0,s1,s2)
 
414
#define cimg_argument4(pos,s0,s1,s2,s3) cimg_library::cimg::argument(pos,argc,argv,4,s0,s1,s2,s3)
 
415
#define cimg_argument5(pos,s0,s1,s2,s3,s4) cimg_library::cimg::argument(pos,argc,argv,5,s0,s1,s2,s3,s4)
 
416
#define cimg_argument6(pos,s0,s1,s2,s3,s4,s5) cimg_library::cimg::argument(pos,argc,argv,6,s0,s1,s2,s3,s4,s5)
 
417
#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)
 
418
#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)
 
419
#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)
 
420
 
 
421
// Define and manipulate local neighborhoods.
 
422
//
 
423
#define CImg_2x2(I,T) T I[4]; \
 
424
                      T& I##cc = I[0]; T& I##nc = I[1]; \
 
425
                      T& I##cn = I[2]; T& I##nn = I[3]; \
 
426
                      I##cc = I##nc = \
 
427
                      I##cn = I##nn = 0
 
428
 
 
429
#define CImg_3x3(I,T) T I[9]; \
 
430
                      T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \
 
431
                      T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \
 
432
                      T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \
 
433
                      I##pp = I##cp = I##np = \
 
434
                      I##pc = I##cc = I##nc = \
 
435
                      I##pn = I##cn = I##nn = 0
 
436
 
 
437
#define CImg_4x4(I,T) T I[16]; \
 
438
                      T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \
 
439
                      T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \
 
440
                      T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \
 
441
                      T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \
 
442
                      I##pp = I##cp = I##np = I##ap = \
 
443
                      I##pc = I##cc = I##nc = I##ac = \
 
444
                      I##pn = I##cn = I##nn = I##an = \
 
445
                      I##pa = I##ca = I##na = I##aa = 0
 
446
 
 
447
#define CImg_5x5(I,T) T I[25]; \
 
448
                      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]; \
 
449
                      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]; \
 
450
                      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]; \
 
451
                      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]; \
 
452
                      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]; \
 
453
                      I##bb = I##pb = I##cb = I##nb = I##ab = \
 
454
                      I##bp = I##pp = I##cp = I##np = I##ap = \
 
455
                      I##bc = I##pc = I##cc = I##nc = I##ac = \
 
456
                      I##bn = I##pn = I##cn = I##nn = I##an = \
 
457
                      I##ba = I##pa = I##ca = I##na = I##aa = 0
 
458
 
 
459
#define CImg_2x2x2(I,T) T I[8]; \
 
460
                      T& I##ccc = I[0]; T& I##ncc = I[1]; \
 
461
                      T& I##cnc = I[2]; T& I##nnc = I[3]; \
 
462
                      T& I##ccn = I[4]; T& I##ncn = I[5]; \
 
463
                      T& I##cnn = I[6]; T& I##nnn = I[7]; \
 
464
                      I##ccc = I##ncc = \
 
465
                      I##cnc = I##nnc = \
 
466
                      I##ccn = I##ncn = \
 
467
                      I##cnn = I##nnn = 0
 
468
 
 
469
#define CImg_3x3x3(I,T) T I[27]; \
 
470
                      T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \
 
471
                      T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \
 
472
                      T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \
 
473
                      T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \
 
474
                      T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \
 
475
                      T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \
 
476
                      T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \
 
477
                      T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \
 
478
                      T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \
 
479
                      I##ppp = I##cpp = I##npp = \
 
480
                      I##pcp = I##ccp = I##ncp = \
 
481
                      I##pnp = I##cnp = I##nnp = \
 
482
                      I##ppc = I##cpc = I##npc = \
 
483
                      I##pcc = I##ccc = I##ncc = \
 
484
                      I##pnc = I##cnc = I##nnc = \
 
485
                      I##ppn = I##cpn = I##npn = \
 
486
                      I##pcn = I##ccn = I##ncn = \
 
487
                      I##pnn = I##cnn = I##nnn = 0
357
488
 
358
489
#define cimg_get2x2(img,x,y,z,v,I) \
359
 
   I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), \
360
 
   I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v)
 
490
  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)
 
491
 
361
492
#define cimg_get3x3(img,x,y,z,v,I) \
362
 
  I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), \
363
 
  I##pc=(img)(_p##x,    y,z,v), I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), \
364
 
  I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v)
 
493
  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), \
 
494
  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), \
 
495
  I[8] = (img)(_n1##x,_n1##y,z,v)
 
496
 
365
497
#define cimg_get4x4(img,x,y,z,v,I) \
366
 
  I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), I##ap=(img)(_a##x,_p##y,z,v), \
367
 
  I##pc=(img)(_p##x,    y,z,v), I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), I##ac=(img)(_a##x,    y,z,v), \
368
 
  I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v), I##an=(img)(_a##x,_n##y,z,v), \
369
 
  I##pa=(img)(_p##x,_a##y,z,v), I##ca=(img)(x,_a##y,z,v), I##na=(img)(_n##x,_a##y,z,v), I##aa=(img)(_a##x,_a##y,z,v)
 
498
  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), \
 
499
  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), \
 
500
  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), \
 
501
  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)
 
502
 
370
503
#define cimg_get5x5(img,x,y,z,v,I) \
371
 
  I##bb=(img)(_b##x,_b##y,z,v), I##pb=(img)(_p##x,_b##y,z,v), I##cb=(img)(x,_b##y,z,v), I##nb=(img)(_n##x,_b##y,z,v), I##ab=(img)(_a##x,_b##y,z,v), \
372
 
  I##bp=(img)(_b##x,_p##y,z,v), I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), I##ap=(img)(_a##x,_p##y,z,v), \
373
 
  I##bc=(img)(_b##x,    y,z,v), I##pc=(img)(_p##x,    y,z,v), I##cc=(img)(x,    y,z,v), I##nc=(img)(_n##x,    y,z,v), I##ac=(img)(_a##x,    y,z,v), \
374
 
  I##bn=(img)(_b##x,_n##y,z,v), I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v), I##an=(img)(_a##x,_n##y,z,v), \
375
 
  I##ba=(img)(_b##x,_a##y,z,v), I##pa=(img)(_p##x,_a##y,z,v), I##ca=(img)(x,_a##y,z,v), I##na=(img)(_n##x,_a##y,z,v), I##aa=(img)(_a##x,_a##y,z,v)
 
504
  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), \
 
505
  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), \
 
506
  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), \
 
507
  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), \
 
508
  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), \
 
509
  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), \
 
510
  I[24] = (img)(_n2##x,_n2##y,z,v)
 
511
 
 
512
#define cimg_get6x6(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)(_n3##x,_p2##y,z,v), I[6] = (img)(_p2##x,_p1##y,z,v), I[7] = (img)(_p1##x,_p1##y,z,v), \
 
515
 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), \
 
516
 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), \
 
517
 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), \
 
518
 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), \
 
519
 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), \
 
520
 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), \
 
521
 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)
 
522
 
 
523
#define cimg_get7x7(img,x,y,z,v,I) \
 
524
 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), \
 
525
 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), \
 
526
 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), \
 
527
 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), \
 
528
 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), \
 
529
 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), \
 
530
 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), \
 
531
 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), \
 
532
 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), \
 
533
 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), \
 
534
 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), \
 
535
 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), \
 
536
 I[48] = (img)(_n3##x,_n3##y,z,v)
 
537
 
 
538
#define cimg_get8x8(img,x,y,z,v,I) \
 
539
 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), \
 
540
 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), \
 
541
 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), \
 
542
 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), \
 
543
 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), \
 
544
 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), \
 
545
 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), \
 
546
 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), \
 
547
 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), \
 
548
 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), \
 
549
 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), \
 
550
 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), \
 
551
 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), \
 
552
 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), \
 
553
 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), \
 
554
 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);
 
555
 
 
556
#define cimg_get9x9(img,x,y,z,v,I) \
 
557
 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), \
 
558
 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), \
 
559
 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), \
 
560
 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), \
 
561
 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), \
 
562
 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), \
 
563
 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), \
 
564
 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), \
 
565
 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), \
 
566
 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), \
 
567
 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), \
 
568
 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), \
 
569
 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), \
 
570
 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), \
 
571
 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), \
 
572
 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), \
 
573
 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), \
 
574
 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), \
 
575
 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), \
 
576
 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), \
 
577
 I[80] = (img)(_n4##x,_n4##y,z,v)
 
578
 
376
579
#define cimg_get2x2x2(img,x,y,z,v,I) \
377
 
  I##ccc=(img)(x,y,    z,v), I##ncc=(img)(_n##x,y,    z,v), I##cnc=(img)(x,_n##y,    z,v), I##nnc=(img)(_n##x,_n##y,    z,v), \
378
 
  I##ccc=(img)(x,y,_n##z,v), I##ncc=(img)(_n##x,y,_n##z,v), I##cnc=(img)(x,_n##y,_n##z,v), I##nnc=(img)(_n##x,_n##y,_n##z,v)
 
580
  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), \
 
581
  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)
 
582
 
379
583
#define cimg_get3x3x3(img,x,y,z,v,I) \
380
 
  I##ppp=(img)(_p##x,_p##y,_p##z,v), I##cpp=(img)(x,_p##y,_p##z,v), I##npp=(img)(_n##x,_p##y,_p##z,v), \
381
 
  I##pcp=(img)(_p##x,    y,_p##z,v), I##ccp=(img)(x,    y,_p##z,v), I##ncp=(img)(_n##x,    y,_p##z,v), \
382
 
  I##pnp=(img)(_p##x,_n##y,_p##z,v), I##cnp=(img)(x,_n##y,_p##z,v), I##nnp=(img)(_n##x,_n##y,_p##z,v), \
383
 
  I##ppc=(img)(_p##x,_p##y,    z,v), I##cpc=(img)(x,_p##y,    z,v), I##npc=(img)(_n##x,_p##y,    z,v), \
384
 
  I##pcc=(img)(_p##x,    y,    z,v), I##ccc=(img)(x,    y,    z,v), I##ncc=(img)(_n##x,    y,    z,v), \
385
 
  I##pnc=(img)(_p##x,_n##y,    z,v), I##cnc=(img)(x,_n##y,    z,v), I##nnc=(img)(_n##x,_n##y,    z,v), \
386
 
  I##ppn=(img)(_p##x,_p##y,_n##z,v), I##cpn=(img)(x,_p##y,_n##z,v), I##npn=(img)(_n##x,_p##y,_n##z,v), \
387
 
  I##pcn=(img)(_p##x,    y,_n##z,v), I##ccn=(img)(x,    y,_n##z,v), I##ncn=(img)(_n##x,    y,_n##z,v), \
388
 
  I##pnn=(img)(_p##x,_n##y,_n##z,v), I##cnn=(img)(x,_n##y,_n##z,v), I##nnn=(img)(_n##x,_n##y,_n##z,v)
389
 
 
390
 
// Macros used to define special image loops.
391
 
// (see module 'Using Image Loops' in the generated documentation).
392
 
#define cimg_for(img,ptr,T_ptr)   for (T_ptr *ptr=(img).data+(img).size(); (ptr--)>(img).data; )
393
 
#define cimglist_for(list,l)      for (unsigned int l=0; l<(list).size; ++l)
394
 
#define cimglist_apply(list,fn)   cimglist_for(list,__##fn) (list)[__##fn].fn
395
 
#define cimg_foroff(img,off)      for (unsigned int off=0; off<(img).size(); ++off)
396
 
#define cimg_forX(img,x)          for (int x=0; x<(int)((img).width); ++x)
397
 
#define cimg_forY(img,y)          for (int y=0; y<(int)((img).height); ++y)
398
 
#define cimg_forZ(img,z)          for (int z=0; z<(int)((img).depth); ++z)
399
 
#define cimg_forV(img,v)          for (int v=0; v<(int)((img).dim); ++v)
400
 
#define cimg_forXY(img,x,y)       cimg_forY(img,y) cimg_forX(img,x)
401
 
#define cimg_forXZ(img,x,z)       cimg_forZ(img,z) cimg_forX(img,x)
402
 
#define cimg_forYZ(img,y,z)       cimg_forZ(img,z) cimg_forY(img,y)
403
 
#define cimg_forXV(img,x,v)       cimg_forV(img,v) cimg_forX(img,x)
404
 
#define cimg_forYV(img,y,v)       cimg_forV(img,v) cimg_forY(img,y)
405
 
#define cimg_forZV(img,z,v)       cimg_forV(img,v) cimg_forZ(img,z)
406
 
#define cimg_forXYZ(img,x,y,z)    cimg_forZ(img,z) cimg_forXY(img,x,y)
407
 
#define cimg_forXYV(img,x,y,v)    cimg_forV(img,v) cimg_forXY(img,x,y)
408
 
#define cimg_forXZV(img,x,z,v)    cimg_forV(img,v) cimg_forXZ(img,x,z)
409
 
#define cimg_forYZV(img,y,z,v)    cimg_forV(img,v) cimg_forYZ(img,y,z)
 
584
  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), \
 
585
  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), \
 
586
  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), \
 
587
  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), \
 
588
  I[12] = (img)(_p1##x,y,z,v), I[13] = (img)(x,y,z,v), I[14] = (img)(_n1##x,y,z,v), \
 
589
  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), \
 
590
  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), \
 
591
  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), \
 
592
  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)
 
593
 
 
594
// Define various image loops.
 
595
//
 
596
// These macros generally avoid the use of iterators, but you are not forced to used them !
 
597
//
 
598
#define cimg_for(img,ptr,T_ptr) for (T_ptr *ptr = (img).data + (img).size(); (ptr--)>(img).data; )
 
599
#define cimg_foroff(img,off) for (unsigned int off = 0; off<(img).size(); ++off)
 
600
#define cimglist_for(list,l) for (unsigned int l=0; l<(list).size; ++l)
 
601
#define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn
 
602
 
 
603
#define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i)
 
604
#define cimg_forX(img,x) cimg_for1((img).width,x)
 
605
#define cimg_forY(img,y) cimg_for1((img).height,y)
 
606
#define cimg_forZ(img,z) cimg_for1((img).depth,z)
 
607
#define cimg_forV(img,v) cimg_for1((img).dim,v)
 
608
#define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x)
 
609
#define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x)
 
610
#define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y)
 
611
#define cimg_forXV(img,x,v) cimg_forV(img,v) cimg_forX(img,x)
 
612
#define cimg_forYV(img,y,v) cimg_forV(img,v) cimg_forY(img,y)
 
613
#define cimg_forZV(img,z,v) cimg_forV(img,v) cimg_forZ(img,z)
 
614
#define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y)
 
615
#define cimg_forXYV(img,x,y,v) cimg_forV(img,v) cimg_forXY(img,x,y)
 
616
#define cimg_forXZV(img,x,z,v) cimg_forV(img,v) cimg_forXZ(img,x,z)
 
617
#define cimg_forYZV(img,y,z,v) cimg_forV(img,v) cimg_forYZ(img,y,z)
410
618
#define cimg_forXYZV(img,x,y,z,v) cimg_forV(img,v) cimg_forXYZ(img,x,y,z)
411
 
#define cimg_for_insideX(img,x,n)       for (int x=(n); x<(int)((img).width-(n)); ++x)
412
 
#define cimg_for_insideY(img,y,n)       for (int y=(n); y<(int)((img).height-(n)); ++y)
413
 
#define cimg_for_insideZ(img,z,n)       for (int z=(n); z<(int)((img).depth-(n)); ++z)
414
 
#define cimg_for_insideV(img,v,n)       for (int v=(n); v<(int)((img).dim-(n)); ++v)
415
 
#define cimg_for_insideXY(img,x,y,n)    cimg_for_insideY(img,y,n) cimg_for_insideX(img,x,n)
416
 
#define cimg_for_insideXYZ(img,x,y,z,n) cimg_for_insideZ(img,z,n) cimg_for_insideXY(img,x,y,n)
417
 
#define cimg_for_borderX(img,x,n)       for (int x=0; x<(int)((img).width); x==(n)-1?(x=(img).width-(n)): x++)
418
 
#define cimg_for_borderY(img,y,n)       for (int y=0; y<(int)((img).height); y==(n)-1?(x=(img).height-(n)):y++)
419
 
#define cimg_for_borderZ(img,z,n)       for (int z=0; z<(int)((img).depth); z==(n)-1?(x=(img).depth-(n)): z++)
420
 
#define cimg_for_borderV(img,v,n)       for (int v=0; v<(int)((img).dim); v==(n)-1?(x=(img).dim-(n)):   v++)
421
 
#define cimg_for_borderXY(img,x,y,n)    cimg_forY(img,y) for (int x=0; x<(int)((img).width); (y<(n) || y>=(int)((img).height)-(n))?x++: \
422
 
                                                          ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n))))
423
 
#define cimg_for_borderXYZ(img,x,y,z,n) cimg_forYZ(img,y,z) for (int x=0; x<(int)((img).width); (y<(n) || y>=(int)((img).height)-(n) || z<(n) || z>=(int)((img).depth)-(n))?x++: \
424
 
                                                             ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n))))
425
 
#define cimg_for_spiralXY(img,x,y) for (int x=0,y=0,_n##x=1,_n##y=(int)((img).width*(img).height); _n##y; \
426
 
         --_n##y, _n##x += (_n##x>>2)-((!(_n##x&3)?--y:((_n##x&3)==1?(img).width-1-++x:((_n##x&3)==2?(img).height-1-++y:--x))))?0:1)
427
 
 
428
 
 
429
 
#define cimg_for_lineXY(x,y,x0,y0,x1,y1) for (int x=(x0), y=(y0), _sx=1, _sy=1, _steep=0, \
430
 
                                                _dx=(x1)>(x0)?(x1)-(x0):(_sx=-1,(x0)-(x1)), \
431
 
                                                _dy=(y1)>(y0)?(y1)-(y0):(_sy=-1,(y0)-(y1)), \
432
 
                                                _counter=_dx, \
433
 
                                                _err=_dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \
434
 
                                                  _counter>=0; \
435
 
                                                --_counter, x+=_steep? \
436
 
                                                (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \
437
 
                                                (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx))
438
 
 
439
 
#define cimg_for2X(img,x)         for (int x=0,_n##x=1; _n##x<(int)((img).width)   || x==--_n##x; x++, _n##x++)
440
 
#define cimg_for2Y(img,y)         for (int y=0,_n##y=1; _n##y<(int)((img).height)  || y==--_n##y; y++, _n##y++)
441
 
#define cimg_for2Z(img,z)         for (int z=0,_n##z=1; _n##z<(int)((img).depth)   || z==--_n##z; z++, _n##z++)
442
 
#define cimg_for2XY(img,x,y)      cimg_for2Y(img,y) cimg_for2X(img,x)
443
 
#define cimg_for2XZ(img,x,z)      cimg_for2Z(img,z) cimg_for2X(img,x)
444
 
#define cimg_for2YZ(img,y,z)      cimg_for2Z(img,z) cimg_for2Y(img,y)
445
 
#define cimg_for2XYZ(img,x,y,z)   cimg_for2Z(img,z) cimg_for2XY(img,x,y)
446
 
#define cimg_for3X(img,x)         for (int x=0,_p##x=0,_n##x=1; _n##x<(int)((img).width)  || x==--_n##x; _p##x=x++,_n##x++)
447
 
#define cimg_for3Y(img,y)         for (int y=0,_p##y=0,_n##y=1; _n##y<(int)((img).height) || y==--_n##y; _p##y=y++,_n##y++)
448
 
#define cimg_for3Z(img,z)         for (int z=0,_p##z=0,_n##z=1; _n##z<(int)((img).depth)  || z==--_n##z; _p##z=z++,_n##z++)
449
 
#define cimg_for3XY(img,x,y)      cimg_for3Y(img,y) cimg_for3X(img,x)
450
 
#define cimg_for3XZ(img,x,z)      cimg_for3Z(img,z) cimg_for3X(img,x)
451
 
#define cimg_for3YZ(img,y,z)      cimg_for3Z(img,z) cimg_for3Y(img,y)
452
 
#define cimg_for3XYZ(img,x,y,z)   cimg_for3Z(img,z) cimg_for3XY(img,x,y)
453
 
#define cimg_for4X(img,x)         for (int _p##x=0,x=0,_n##x=1,_a##x=2; \
454
 
                                       _a##x<(int)((img).width)  || _n##x==--_a##x || x==(_a##x=--_n##x); \
455
 
                                       _p##x=x++,_n##x++,_a##x++)
456
 
#define cimg_for4Y(img,y)         for (int _p##y=0,y=0,_n##y=1,_a##y=2; \
457
 
                                       _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \
458
 
                                       _p##y=y++,_n##y++,_a##y++)
459
 
#define cimg_for4Z(img,z)         for (int _p##z=0,z=0,_n##z=1,_a##z=2; \
460
 
                                       _a##z<(int)((img).depth)  || _n##z==--_a##z || z==(_a##z=--_n##z); \
461
 
                                       _p##z=z++,_n##z++,_a##z++)
462
 
#define cimg_for4XY(img,x,y)      cimg_for4Y(img,y) cimg_for4X(img,x)
463
 
#define cimg_for4XZ(img,x,z)      cimg_for4Z(img,z) cimg_for4X(img,x)
464
 
#define cimg_for4YZ(img,y,z)      cimg_for4Z(img,z) cimg_for4Y(img,y)
465
 
#define cimg_for4XYZ(img,x,y,z)   cimg_for4Z(img,z) cimg_for4XY(img,x,y)
466
 
#define cimg_for5X(img,x)         for (int _b##x=0,_p##x=0,x=0,_n##x=1,_a##x=2; \
467
 
                                       _a##x<(int)((img).width)  || _n##x==--_a##x || x==(_a##x=--_n##x); \
468
 
                                       _b##x=_p##x,_p##x=x++,_n##x++,_a##x++)
469
 
#define cimg_for5Y(img,y)         for (int _b##y=0,_p##y=0,y=0,_n##y=1,_a##y=2; \
470
 
                                       _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \
471
 
                                       _b##y=_p##y,_p##y=y++,_n##y++,_a##y++)
472
 
#define cimg_for5Z(img,z)         for (int _b##z=0,_p##z=0,z=0,_n##z=1,_a##z=2; \
473
 
                                       _a##z<(int)((img).depth)  || _n##z==--_a##z || z==(_a##z=--_n##z); \
474
 
                                       _b##z=_p##z,_p##z=z++,_n##z++,_a##z++)
475
 
#define cimg_for5XY(img,x,y)      cimg_for5Y(img,y) cimg_for5X(img,x)
476
 
#define cimg_for5XZ(img,x,z)      cimg_for5Z(img,z) cimg_for5X(img,x)
477
 
#define cimg_for5YZ(img,y,z)      cimg_for5Z(img,z) cimg_for5Y(img,y)
478
 
#define cimg_for5XYZ(img,x,y,z)   cimg_for5Z(img,z) cimg_for5XY(img,x,y)
479
 
 
480
 
#define cimg_for2x2(img,x,y,z,v,I) cimg_for2Y(img,y) \
481
 
       for (int _n##x=1, x=(int)((I##cc=(img)(0,    y,z,v)), \
482
 
                                 (I##cn=(img)(0,_n##y,z,v)), \
483
 
                                 0); \
484
 
            (_n##x<(int)((img).width) && ((I##nc=(img)(_n##x,    y,z,v)), \
485
 
                                          (I##nn=(img)(_n##x,_n##y,z,v)), \
486
 
                                          1)) || x==--_n##x; \
487
 
            I##cc=I##nc, I##cn=I##nn, \
488
 
            x++,_n##x++ )
489
 
 
490
 
#define cimg_for3x3(img,x,y,z,v,I) cimg_for3Y(img,y) \
491
 
       for (int _n##x=1, _p##x=(int)((I##cp=I##pp=(img)(0,_p##y,z,v)), \
492
 
                                     (I##cc=I##pc=(img)(0,  y,z,v)), \
493
 
                                     (I##cn=I##pn=(img)(0,_n##y,z,v))), \
494
 
                                     x=_p##x=0; \
495
 
            (_n##x<(int)((img).width) && ((I##np=(img)(_n##x,_p##y,z,v)), \
496
 
                                          (I##nc=(img)(_n##x,    y,z,v)), \
497
 
                                          (I##nn=(img)(_n##x,_n##y,z,v)), \
498
 
                                          1)) || x==--_n##x; \
499
 
              I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, \
500
 
              I##cp=I##np, I##cc=I##nc, I##cn=I##nn, \
501
 
              _p##x=x++,_n##x++ )
502
 
 
503
 
 
504
 
#define cimg_for4x4(img,x,y,z,v,I) cimg_for4Y(img,y) \
505
 
       for (int _a##x=2, _n##x=1, x=(int)((I##cp=I##pp=(img)(0,_p##y,z,v)), \
506
 
                                          (I##cc=I##pc=(img)(0,    y,z,v)), \
507
 
                                          (I##cn=I##pn=(img)(0,_n##y,z,v)), \
508
 
                                          (I##ca=I##pa=(img)(0,_a##y,z,v)), \
509
 
                                          (I##np=(img)(_n##x,_p##y,z,v)), \
510
 
                                          (I##nc=(img)(_n##x,    y,z,v)), \
511
 
                                          (I##nn=(img)(_n##x,_n##y,z,v)), \
512
 
                                          (I##na=(img)(_n##x,_a##y,z,v)), \
513
 
                                          0), _p##x=0; \
514
 
            (_a##x<(int)((img).width) && ((I##ap=(img)(_a##x,_p##y,z,v)), \
515
 
                                          (I##ac=(img)(_a##x,    y,z,v)), \
516
 
                                          (I##an=(img)(_a##x,_n##y,z,v)), \
517
 
                                          (I##aa=(img)(_a##x,_a##y,z,v)), \
518
 
                                          1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \
519
 
              I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca, \
520
 
              I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na, \
521
 
              I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa, \
522
 
              _p##x=x++, _n##x++, _a##x++ )
523
 
 
524
 
#define cimg_for5x5(img,x,y,z,v,I) cimg_for5Y(img,y) \
525
 
       for (int _a##x=2, _n##x=1, _b##x=(int)((I##cb=I##pb=I##bb=(img)(0,_b##y,z,v)), \
526
 
                                              (I##cp=I##pp=I##bp=(img)(0,_p##y,z,v)), \
527
 
                                              (I##cc=I##pc=I##bc=(img)(0,    y,z,v)), \
528
 
                                              (I##cn=I##pn=I##bn=(img)(0,_n##y,z,v)), \
529
 
                                              (I##ca=I##pa=I##ba=(img)(0,_a##y,z,v)), \
530
 
                                              (I##nb=(img)(_n##x,_b##y,z,v)), \
531
 
                                              (I##np=(img)(_n##x,_p##y,z,v)), \
532
 
                                              (I##nc=(img)(_n##x,   y,z,v)), \
533
 
                                              (I##nn=(img)(_n##x,_n##y,z,v)), \
534
 
                                              (I##na=(img)(_n##x,_a##y,z,v))), \
535
 
                                              x=0, _p##x=_b##x=0; \
536
 
            (_a##x<(int)((img).width) && ((I##ab=(img)(_a##x,_b##y,z,v)), \
537
 
                                          (I##ap=(img)(_a##x,_p##y,z,v)), \
538
 
                                          (I##ac=(img)(_a##x,    y,z,v)), \
539
 
                                          (I##an=(img)(_a##x,_n##y,z,v)), \
540
 
                                          (I##aa=(img)(_a##x,_a##y,z,v)), \
541
 
                                          1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \
542
 
              I##bb=I##pb, I##bp=I##pp, I##bc=I##pc, I##bn=I##pn, I##ba=I##pa, \
543
 
              I##pb=I##cb, I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca, \
544
 
              I##cb=I##nb, I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na, \
545
 
              I##nb=I##ab, I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa, \
546
 
              _b##x=_p##x, _p##x=x++, _n##x++, _a##x++ )
547
 
 
548
 
#define cimg_for2x2x2(img,x,y,z,v,I) cimg_for2YZ(img,y,z) \
549
 
       for (int _n##x=1, x=(int)((I##ccc=(img)(0,    y,    z,v)), \
550
 
                                 (I##cnc=(img)(0,_n##y,    z,v)), \
551
 
                                 (I##ccn=(img)(0,    y,_n##z,v)), \
552
 
                                 (I##cnn=(img)(0,_n##y,_n##z,v)), \
553
 
                                 0); \
554
 
            (_n##x<(int)((img).width) && ((I##ncc=(img)(_n##x,    y,    z,v)), \
555
 
                                          (I##nnc=(img)(_n##x,_n##y,    z,v)), \
556
 
                                          (I##ncn=(img)(_n##x,    y,_n##z,v)), \
557
 
                                          (I##nnn=(img)(_n##x,_n##y,_n##z,v)), \
558
 
                                          1)) || x==--_n##x; \
559
 
              I##ccc=I##ncc, I##cnc=I##nnc, \
560
 
              I##ccn=I##ncn, I##cnn=I##nnn, \
561
 
              x++, _n##x++ )
562
 
 
563
 
#define cimg_for3x3x3(img,x,y,z,v,I) cimg_for3YZ(img,y,z) \
564
 
       for (int _n##x=1, _p##x=(int)((I##cpp=I##ppp=(img)(0,_p##y,_p##z,v)), \
565
 
                                     (I##ccp=I##pcp=(img)(0,    y,_p##z,v)), \
566
 
                                     (I##cnp=I##pnp=(img)(0,_n##y,_p##z,v)), \
567
 
                                     (I##cpc=I##ppc=(img)(0,_p##y,    z,v)), \
568
 
                                     (I##ccc=I##pcc=(img)(0,    y,    z,v)), \
569
 
                                     (I##cnc=I##pnc=(img)(0,_n##y,    z,v)), \
570
 
                                     (I##cpn=I##ppn=(img)(0,_p##y,_n##z,v)), \
571
 
                                     (I##ccn=I##pcn=(img)(0,    y,_n##z,v)), \
572
 
                                     (I##cnn=I##pnn=(img)(0,_n##y,_n##z,v))),\
573
 
                                     x=_p##x=0; \
574
 
            (_n##x<(int)((img).width) && ((I##npp=(img)(_n##x,_p##y,_p##z,v)), \
575
 
                                          (I##ncp=(img)(_n##x,    y,_p##z,v)), \
576
 
                                          (I##nnp=(img)(_n##x,_n##y,_p##z,v)), \
577
 
                                          (I##npc=(img)(_n##x,_p##y,    z,v)), \
578
 
                                          (I##ncc=(img)(_n##x,    y,    z,v)), \
579
 
                                          (I##nnc=(img)(_n##x,_n##y,    z,v)), \
580
 
                                          (I##npn=(img)(_n##x,_p##y,_n##z,v)), \
581
 
                                          (I##ncn=(img)(_n##x,    y,_n##z,v)), \
582
 
                                          (I##nnn=(img)(_n##x,_n##y,_n##z,v)), \
583
 
                                          1)) || x==--_n##x; \
584
 
              I##ppp=I##cpp, I##pcp=I##ccp, I##pnp=I##cnp, \
585
 
              I##cpp=I##npp, I##ccp=I##ncp, I##cnp=I##nnp, \
586
 
              I##ppc=I##cpc, I##pcc=I##ccc, I##pnc=I##cnc, \
587
 
              I##cpc=I##npc, I##ccc=I##ncc, I##cnc=I##nnc, \
588
 
              I##ppn=I##cpn, I##pcn=I##ccn, I##pnn=I##cnn, \
589
 
              I##cpn=I##npn, I##ccn=I##ncn, I##cnn=I##nnn, \
590
 
              _p##x=x++, _n##x++ )
591
 
 
592
 
#define _CImg_stdarg(img,a0,a1,N,t) \
593
 
   { unsigned int _siz = (unsigned int)N; \
594
 
     if (_siz--) { \
595
 
       va_list ap; \
596
 
       va_start(ap,a1); \
597
 
       T *ptrd = (img).data; \
598
 
       *(ptrd++) = (T)a0; \
599
 
       if (_siz--) { *(ptrd++) = (T)a1; for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); } \
600
 
       va_end(ap); \
601
 
     }}
602
 
 
603
 
/*
604
 
 #------------------------------------------------
 
619
 
 
620
#define cimg_for_in1(bound,i0,i1,i) \
 
621
 for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound)-1; i<=_max##i; ++i)
 
622
#define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img).width,x0,x1,x)
 
623
#define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img).height,y0,y1,y)
 
624
#define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img).depth,z0,z1,z)
 
625
#define cimg_for_inV(img,v0,v1,v) cimg_for_in1((img).dim,v0,v1,v)
 
626
#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)
 
627
#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)
 
628
#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)
 
629
#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)
 
630
#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)
 
631
#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)
 
632
#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)
 
633
#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)
 
634
#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)
 
635
#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)
 
636
#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)
 
637
#define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img).width-1-(n),x)
 
638
#define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img).height-1-(n),y)
 
639
#define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img).depth-1-(n),z)
 
640
#define cimg_for_insideV(img,v,n) cimg_for_inV(img,n,(img).dim-1-(n),v)
 
641
#define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
 
642
#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)
 
643
#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)
 
644
 
 
645
#define cimg_for_out1(boundi,i0,i1,i) \
 
646
 for (int i = (int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1)+1:i)
 
647
#define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \
 
648
 for (int j = 0; j<(int)(boundj); ++j) \
 
649
 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
 
650
  ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1)+1:i))
 
651
#define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \
 
652
 for (int k = 0; k<(int)(boundk); ++k) \
 
653
 for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
 
654
 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
 
655
  ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1)+1:i))
 
656
#define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \
 
657
 for (int l = 0; l<(int)(boundl); ++l) \
 
658
 for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \
 
659
 for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
 
660
 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); \
 
661
  ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1)+1:i))
 
662
#define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img).width,x0,x1,x)
 
663
#define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img).height,y0,y1,y)
 
664
#define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img).depth,z0,z1,z)
 
665
#define cimg_for_outV(img,v0,v1,v) cimg_for_out1((img).dim,v0,v1,v)
 
666
#define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img).width,(img).height,x0,y0,x1,y1,x,y)
 
667
#define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img).width,(img).depth,x0,z0,x1,z1,x,z)
 
668
#define cimg_for_outXV(img,x0,v0,x1,v1,x,v) cimg_for_out2((img).width,(img).dim,x0,v0,x1,v1,x,v)
 
669
#define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img).height,(img).depth,y0,z0,y1,z1,y,z)
 
670
#define cimg_for_outYV(img,y0,v0,y1,v1,y,v) cimg_for_out2((img).height,(img).dim,y0,v0,y1,v1,y,v)
 
671
#define cimg_for_outZV(img,z0,v0,z1,v1,z,v) cimg_for_out2((img).depth,(img).dim,z0,v0,z1,v1,z,v)
 
672
#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)
 
673
#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)
 
674
#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)
 
675
#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)
 
676
#define cimg_for_outXYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) \
 
677
 cimg_for_out4((img).width,(img).height,(img).depth,(img).dim,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v)
 
678
#define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img).width-1-(n),x)
 
679
#define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img).height-1-(n),y)
 
680
#define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img).depth-1-(n),z)
 
681
#define cimg_for_borderV(img,v,n) cimg_for_outV(img,n,(img).dim-1-(n),v)
 
682
#define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
 
683
#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)
 
684
#define cimg_for_borderXYZV(img,x,y,z,v,n) \
 
685
 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)
 
686
 
 
687
#define cimg_for_spiralXY(img,x,y) \
 
688
 for (int x = 0, y = 0, _n1##x = 1, _n1##y = (int)((img).width*(img).height); _n1##y; \
 
689
      --_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)
 
690
 
 
691
#define cimg_for_lineXY(x,y,x0,y0,x1,y1) \
 
692
 for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \
 
693
      _dx=(x1)>(x0)?(int)(x1)-(int)(x0):(_sx=-1,(int)(x0)-(int)(x1)), \
 
694
      _dy=(y1)>(y0)?(int)(y1)-(int)(y0):(_sy=-1,(int)(y0)-(int)(y1)), \
 
695
      _counter = _dx, \
 
696
      _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \
 
697
      _counter>=0; \
 
698
      --_counter, x+=_steep? \
 
699
      (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \
 
700
      (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx))
 
701
 
 
702
#define cimg_for2(bound,i) \
 
703
 for (int i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1; \
 
704
      _n1##i<(int)(bound) || i==--_n1##i; \
 
705
      ++i, ++_n1##i)
 
706
#define cimg_for2X(img,x) cimg_for2((img).width,x)
 
707
#define cimg_for2Y(img,y) cimg_for2((img).height,y)
 
708
#define cimg_for2Z(img,z) cimg_for2((img).depth,z)
 
709
#define cimg_for2V(img,v) cimg_for2((img).dim,v)
 
710
#define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x)
 
711
#define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x)
 
712
#define cimg_for2XV(img,x,v) cimg_for2V(img,v) cimg_for2X(img,x)
 
713
#define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y)
 
714
#define cimg_for2YV(img,y,v) cimg_for2V(img,v) cimg_for2Y(img,y)
 
715
#define cimg_for2ZV(img,z,v) cimg_for2V(img,v) cimg_for2Z(img,z)
 
716
#define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y)
 
717
#define cimg_for2XZV(img,x,z,v) cimg_for2V(img,v) cimg_for2XZ(img,x,z)
 
718
#define cimg_for2YZV(img,y,z,v) cimg_for2V(img,v) cimg_for2YZ(img,y,z)
 
719
#define cimg_for2XYZV(img,x,y,z,v) cimg_for2V(img,v) cimg_for2XYZ(img,x,y,z)
 
720
 
 
721
#define cimg_for_in2(bound,i0,i1,i) \
 
722
 for (int i = (int)(i0)<0?0:(int)(i0), \
 
723
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
 
724
      i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
 
725
      ++i, ++_n1##i)
 
726
#define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img).width,x0,x1,x)
 
727
#define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img).height,y0,y1,y)
 
728
#define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img).depth,z0,z1,z)
 
729
#define cimg_for_in2V(img,v0,v1,v) cimg_for_in2((img).dim,v0,v1,v)
 
730
#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)
 
731
#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)
 
732
#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)
 
733
#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)
 
734
#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)
 
735
#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)
 
736
#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)
 
737
#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)
 
738
#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)
 
739
#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)
 
740
 
 
741
#define cimg_for3(bound,i) \
 
742
 for (int i = 0, _p1##i = 0, \
 
743
      _n1##i = 1>=(bound)?(int)(bound)-1:1; \
 
744
      _n1##i<(int)(bound) || i==--_n1##i; \
 
745
      _p1##i = i++, ++_n1##i)
 
746
#define cimg_for3X(img,x) cimg_for3((img).width,x)
 
747
#define cimg_for3Y(img,y) cimg_for3((img).height,y)
 
748
#define cimg_for3Z(img,z) cimg_for3((img).depth,z)
 
749
#define cimg_for3V(img,v) cimg_for3((img).dim,v)
 
750
#define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x)
 
751
#define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x)
 
752
#define cimg_for3XV(img,x,v) cimg_for3V(img,v) cimg_for3X(img,x)
 
753
#define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y)
 
754
#define cimg_for3YV(img,y,v) cimg_for3V(img,v) cimg_for3Y(img,y)
 
755
#define cimg_for3ZV(img,z,v) cimg_for3V(img,v) cimg_for3Z(img,z)
 
756
#define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y)
 
757
#define cimg_for3XZV(img,x,z,v) cimg_for3V(img,v) cimg_for3XZ(img,x,z)
 
758
#define cimg_for3YZV(img,y,z,v) cimg_for3V(img,v) cimg_for3YZ(img,y,z)
 
759
#define cimg_for3XYZV(img,x,y,z,v) cimg_for3V(img,v) cimg_for3XYZ(img,x,y,z)
 
760
 
 
761
#define cimg_for_in3(bound,i0,i1,i) \
 
762
 for (int i = (int)(i0)<0?0:(int)(i0), \
 
763
      _p1##i = i-1<0?0:i-1, \
 
764
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
 
765
      i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
 
766
      _p1##i = i++, ++_n1##i)
 
767
#define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img).width,x0,x1,x)
 
768
#define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img).height,y0,y1,y)
 
769
#define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img).depth,z0,z1,z)
 
770
#define cimg_for_in3V(img,v0,v1,v) cimg_for_in3((img).dim,v0,v1,v)
 
771
#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)
 
772
#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)
 
773
#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)
 
774
#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)
 
775
#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)
 
776
#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)
 
777
#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)
 
778
#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)
 
779
#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)
 
780
#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)
 
781
 
 
782
#define cimg_for4(bound,i) \
 
783
 for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1, \
 
784
      _n2##i = 2>=(bound)?(int)(bound)-1:2; \
 
785
      _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
 
786
      _p1##i = i++, ++_n1##i, ++_n2##i)
 
787
#define cimg_for4X(img,x) cimg_for4((img).width,x)
 
788
#define cimg_for4Y(img,y) cimg_for4((img).height,y)
 
789
#define cimg_for4Z(img,z) cimg_for4((img).depth,z)
 
790
#define cimg_for4V(img,v) cimg_for4((img).dim,v)
 
791
#define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x)
 
792
#define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x)
 
793
#define cimg_for4XV(img,x,v) cimg_for4V(img,v) cimg_for4X(img,x)
 
794
#define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y)
 
795
#define cimg_for4YV(img,y,v) cimg_for4V(img,v) cimg_for4Y(img,y)
 
796
#define cimg_for4ZV(img,z,v) cimg_for4V(img,v) cimg_for4Z(img,z)
 
797
#define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y)
 
798
#define cimg_for4XZV(img,x,z,v) cimg_for4V(img,v) cimg_for4XZ(img,x,z)
 
799
#define cimg_for4YZV(img,y,z,v) cimg_for4V(img,v) cimg_for4YZ(img,y,z)
 
800
#define cimg_for4XYZV(img,x,y,z,v) cimg_for4V(img,v) cimg_for4XYZ(img,x,y,z)
 
801
 
 
802
#define cimg_for_in4(bound,i0,i1,i) \
 
803
 for (int i = (int)(i0)<0?0:(int)(i0), \
 
804
      _p1##i = i-1<0?0:i-1, \
 
805
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
 
806
      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
 
807
      i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
 
808
      _p1##i = i++, ++_n1##i, ++_n2##i)
 
809
#define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img).width,x0,x1,x)
 
810
#define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img).height,y0,y1,y)
 
811
#define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img).depth,z0,z1,z)
 
812
#define cimg_for_in4V(img,v0,v1,v) cimg_for_in4((img).dim,v0,v1,v)
 
813
#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)
 
814
#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)
 
815
#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)
 
816
#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)
 
817
#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)
 
818
#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)
 
819
#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)
 
820
#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)
 
821
#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)
 
822
#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)
 
823
 
 
824
#define cimg_for5(bound,i) \
 
825
 for (int i = 0, _p2##i = 0, _p1##i = 0, \
 
826
      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
 
827
      _n2##i = 2>=(bound)?(int)(bound)-1:2; \
 
828
      _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
 
829
      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
 
830
#define cimg_for5X(img,x) cimg_for5((img).width,x)
 
831
#define cimg_for5Y(img,y) cimg_for5((img).height,y)
 
832
#define cimg_for5Z(img,z) cimg_for5((img).depth,z)
 
833
#define cimg_for5V(img,v) cimg_for5((img).dim,v)
 
834
#define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x)
 
835
#define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x)
 
836
#define cimg_for5XV(img,x,v) cimg_for5V(img,v) cimg_for5X(img,x)
 
837
#define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y)
 
838
#define cimg_for5YV(img,y,v) cimg_for5V(img,v) cimg_for5Y(img,y)
 
839
#define cimg_for5ZV(img,z,v) cimg_for5V(img,v) cimg_for5Z(img,z)
 
840
#define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y)
 
841
#define cimg_for5XZV(img,x,z,v) cimg_for5V(img,v) cimg_for5XZ(img,x,z)
 
842
#define cimg_for5YZV(img,y,z,v) cimg_for5V(img,v) cimg_for5YZ(img,y,z)
 
843
#define cimg_for5XYZV(img,x,y,z,v) cimg_for5V(img,v) cimg_for5XYZ(img,x,y,z)
 
844
 
 
845
#define cimg_for_in5(bound,i0,i1,i) \
 
846
 for (int i = (int)(i0)<0?0:(int)(i0), \
 
847
      _p2##i = i-2<0?0:i-2, \
 
848
      _p1##i = i-1<0?0:i-1, \
 
849
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
 
850
      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
 
851
      i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
 
852
      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
 
853
#define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img).width,x0,x1,x)
 
854
#define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img).height,y0,y1,y)
 
855
#define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img).depth,z0,z1,z)
 
856
#define cimg_for_in5V(img,v0,v1,v) cimg_for_in5((img).dim,v0,v1,v)
 
857
#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)
 
858
#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)
 
859
#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)
 
860
#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)
 
861
#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)
 
862
#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)
 
863
#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)
 
864
#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)
 
865
#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)
 
866
#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)
 
867
 
 
868
#define cimg_for6(bound,i) \
 
869
 for (int i = 0, _p2##i = 0, _p1##i = 0, \
 
870
      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
 
871
      _n2##i = 2>=(bound)?(int)(bound)-1:2, \
 
872
      _n3##i = 3>=(bound)?(int)(bound)-1:3; \
 
873
      _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
 
874
      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
 
875
#define cimg_for6X(img,x) cimg_for6((img).width,x)
 
876
#define cimg_for6Y(img,y) cimg_for6((img).height,y)
 
877
#define cimg_for6Z(img,z) cimg_for6((img).depth,z)
 
878
#define cimg_for6V(img,v) cimg_for6((img).dim,v)
 
879
#define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x)
 
880
#define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x)
 
881
#define cimg_for6XV(img,x,v) cimg_for6V(img,v) cimg_for6X(img,x)
 
882
#define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y)
 
883
#define cimg_for6YV(img,y,v) cimg_for6V(img,v) cimg_for6Y(img,y)
 
884
#define cimg_for6ZV(img,z,v) cimg_for6V(img,v) cimg_for6Z(img,z)
 
885
#define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y)
 
886
#define cimg_for6XZV(img,x,z,v) cimg_for6V(img,v) cimg_for6XZ(img,x,z)
 
887
#define cimg_for6YZV(img,y,z,v) cimg_for6V(img,v) cimg_for6YZ(img,y,z)
 
888
#define cimg_for6XYZV(img,x,y,z,v) cimg_for6V(img,v) cimg_for6XYZ(img,x,y,z)
 
889
 
 
890
#define cimg_for_in6(bound,i0,i1,i) \
 
891
 for (int i = (int)(i0)<0?0:(int)(i0), \
 
892
      _p2##i = i-2<0?0:i-2, \
 
893
      _p1##i = i-1<0?0:i-1, \
 
894
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
 
895
      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
 
896
      _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
 
897
      i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
 
898
      _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
 
899
#define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img).width,x0,x1,x)
 
900
#define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img).height,y0,y1,y)
 
901
#define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img).depth,z0,z1,z)
 
902
#define cimg_for_in6V(img,v0,v1,v) cimg_for_in6((img).dim,v0,v1,v)
 
903
#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)
 
904
#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)
 
905
#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)
 
906
#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)
 
907
#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)
 
908
#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)
 
909
#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)
 
910
#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)
 
911
#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)
 
912
#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)
 
913
 
 
914
#define cimg_for7(bound,i) \
 
915
 for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
 
916
      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
 
917
      _n2##i = 2>=(bound)?(int)(bound)-1:2, \
 
918
      _n3##i = 3>=(bound)?(int)(bound)-1:3; \
 
919
      _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
 
920
      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
 
921
#define cimg_for7X(img,x) cimg_for7((img).width,x)
 
922
#define cimg_for7Y(img,y) cimg_for7((img).height,y)
 
923
#define cimg_for7Z(img,z) cimg_for7((img).depth,z)
 
924
#define cimg_for7V(img,v) cimg_for7((img).dim,v)
 
925
#define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x)
 
926
#define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x)
 
927
#define cimg_for7XV(img,x,v) cimg_for7V(img,v) cimg_for7X(img,x)
 
928
#define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y)
 
929
#define cimg_for7YV(img,y,v) cimg_for7V(img,v) cimg_for7Y(img,y)
 
930
#define cimg_for7ZV(img,z,v) cimg_for7V(img,v) cimg_for7Z(img,z)
 
931
#define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y)
 
932
#define cimg_for7XZV(img,x,z,v) cimg_for7V(img,v) cimg_for7XZ(img,x,z)
 
933
#define cimg_for7YZV(img,y,z,v) cimg_for7V(img,v) cimg_for7YZ(img,y,z)
 
934
#define cimg_for7XYZV(img,x,y,z,v) cimg_for7V(img,v) cimg_for7XYZ(img,x,y,z)
 
935
 
 
936
#define cimg_for_in7(bound,i0,i1,i) \
 
937
 for (int i = (int)(i0)<0?0:(int)(i0), \
 
938
      _p3##i = i-3<0?0:i-3, \
 
939
      _p2##i = i-2<0?0:i-2, \
 
940
      _p1##i = i-1<0?0:i-1, \
 
941
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
 
942
      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
 
943
      _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
 
944
      i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
 
945
      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
 
946
#define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img).width,x0,x1,x)
 
947
#define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img).height,y0,y1,y)
 
948
#define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img).depth,z0,z1,z)
 
949
#define cimg_for_in7V(img,v0,v1,v) cimg_for_in7((img).dim,v0,v1,v)
 
950
#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)
 
951
#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)
 
952
#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)
 
953
#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)
 
954
#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)
 
955
#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)
 
956
#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)
 
957
#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)
 
958
#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)
 
959
#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)
 
960
 
 
961
#define cimg_for8(bound,i) \
 
962
 for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
 
963
      _n1##i = 1>=(bound)?(int)(bound)-1:1, \
 
964
      _n2##i = 2>=(bound)?(int)(bound)-1:2, \
 
965
      _n3##i = 3>=(bound)?(int)(bound)-1:3, \
 
966
      _n4##i = 4>=(bound)?(int)(bound)-1:4; \
 
967
      _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
 
968
      i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
 
969
      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
 
970
#define cimg_for8X(img,x) cimg_for8((img).width,x)
 
971
#define cimg_for8Y(img,y) cimg_for8((img).height,y)
 
972
#define cimg_for8Z(img,z) cimg_for8((img).depth,z)
 
973
#define cimg_for8V(img,v) cimg_for8((img).dim,v)
 
974
#define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x)
 
975
#define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x)
 
976
#define cimg_for8XV(img,x,v) cimg_for8V(img,v) cimg_for8X(img,x)
 
977
#define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y)
 
978
#define cimg_for8YV(img,y,v) cimg_for8V(img,v) cimg_for8Y(img,y)
 
979
#define cimg_for8ZV(img,z,v) cimg_for8V(img,v) cimg_for8Z(img,z)
 
980
#define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y)
 
981
#define cimg_for8XZV(img,x,z,v) cimg_for8V(img,v) cimg_for8XZ(img,x,z)
 
982
#define cimg_for8YZV(img,y,z,v) cimg_for8V(img,v) cimg_for8YZ(img,y,z)
 
983
#define cimg_for8XYZV(img,x,y,z,v) cimg_for8V(img,v) cimg_for8XYZ(img,x,y,z)
 
984
 
 
985
#define cimg_for_in8(bound,i0,i1,i) \
 
986
 for (int i = (int)(i0)<0?0:(int)(i0), \
 
987
      _p3##i = i-3<0?0:i-3, \
 
988
      _p2##i = i-2<0?0:i-2, \
 
989
      _p1##i = i-1<0?0:i-1, \
 
990
      _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
 
991
      _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
 
992
      _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
 
993
      _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
 
994
      i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
 
995
      i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
 
996
      _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
 
997
#define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img).width,x0,x1,x)
 
998
#define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img).height,y0,y1,y)
 
999
#define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img).depth,z0,z1,z)
 
1000
#define cimg_for_in8V(img,v0,v1,v) cimg_for_in8((img).dim,v0,v1,v)
 
1001
#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)
 
1002
#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)
 
1003
#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)
 
1004
#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)
 
1005
#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)
 
1006
#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)
 
1007
#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)
 
1008
#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)
 
1009
#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)
 
1010
#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)
 
1011
 
 
1012
#define cimg_for9(bound,i) \
 
1013
  for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
 
1014
       _n1##i = 1>=(int)(bound)?(int)(bound)-1:1, \
 
1015
       _n2##i = 2>=(int)(bound)?(int)(bound)-1:2, \
 
1016
       _n3##i = 3>=(int)(bound)?(int)(bound)-1:3, \
 
1017
       _n4##i = 4>=(int)(bound)?(int)(bound)-1:4; \
 
1018
       _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
 
1019
       i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
 
1020
       _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
 
1021
#define cimg_for9X(img,x) cimg_for9((img).width,x)
 
1022
#define cimg_for9Y(img,y) cimg_for9((img).height,y)
 
1023
#define cimg_for9Z(img,z) cimg_for9((img).depth,z)
 
1024
#define cimg_for9V(img,v) cimg_for9((img).dim,v)
 
1025
#define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x)
 
1026
#define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x)
 
1027
#define cimg_for9XV(img,x,v) cimg_for9V(img,v) cimg_for9X(img,x)
 
1028
#define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y)
 
1029
#define cimg_for9YV(img,y,v) cimg_for9V(img,v) cimg_for9Y(img,y)
 
1030
#define cimg_for9ZV(img,z,v) cimg_for9V(img,v) cimg_for9Z(img,z)
 
1031
#define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y)
 
1032
#define cimg_for9XZV(img,x,z,v) cimg_for9V(img,v) cimg_for9XZ(img,x,z)
 
1033
#define cimg_for9YZV(img,y,z,v) cimg_for9V(img,v) cimg_for9YZ(img,y,z)
 
1034
#define cimg_for9XYZV(img,x,y,z,v) cimg_for9V(img,v) cimg_for9XYZ(img,x,y,z)
 
1035
 
 
1036
#define cimg_for_in9(bound,i0,i1,i) \
 
1037
  for (int i = (int)(i0)<0?0:(int)(i0), \
 
1038
       _p4##i = i-4<0?0:i-4, \
 
1039
       _p3##i = i-3<0?0:i-3, \
 
1040
       _p2##i = i-2<0?0:i-2, \
 
1041
       _p1##i = i-1<0?0:i-1, \
 
1042
       _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
 
1043
       _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
 
1044
       _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
 
1045
       _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
 
1046
       i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
 
1047
       i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
 
1048
       _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
 
1049
#define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img).width,x0,x1,x)
 
1050
#define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img).height,y0,y1,y)
 
1051
#define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img).depth,z0,z1,z)
 
1052
#define cimg_for_in9V(img,v0,v1,v) cimg_for_in9((img).dim,v0,v1,v)
 
1053
#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)
 
1054
#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)
 
1055
#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)
 
1056
#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)
 
1057
#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)
 
1058
#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)
 
1059
#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)
 
1060
#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)
 
1061
#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)
 
1062
#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)
 
1063
 
 
1064
#define cimg_for2x2(img,x,y,z,v,I) \
 
1065
  cimg_for2((img).height,y) for (int x = 0, \
 
1066
   _n1##x = (int)( \
 
1067
   (I[0] = (img)(0,y,z,v)), \
 
1068
   (I[2] = (img)(0,_n1##y,z,v)), \
 
1069
   1>=(img).width?(int)((img).width)-1:1);  \
 
1070
   (_n1##x<(int)((img).width) && ( \
 
1071
   (I[1] = (img)(_n1##x,y,z,v)), \
 
1072
   (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
 
1073
   x==--_n1##x; \
 
1074
   I[0] = I[1], \
 
1075
   I[2] = I[3], \
 
1076
   ++x, ++_n1##x)
 
1077
 
 
1078
#define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,v,I) \
 
1079
  cimg_for_in2((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
 
1080
   _n1##x = (int)( \
 
1081
   (I[0] = (img)(x,y,z,v)), \
 
1082
   (I[2] = (img)(x,_n1##y,z,v)), \
 
1083
   x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
 
1084
   x<=(int)(x1) && ((_n1##x<(int)((img).width) && (  \
 
1085
   (I[1] = (img)(_n1##x,y,z,v)), \
 
1086
   (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
 
1087
   x==--_n1##x); \
 
1088
   I[0] = I[1], \
 
1089
   I[2] = I[3], \
 
1090
   ++x, ++_n1##x)
 
1091
 
 
1092
#define cimg_for3x3(img,x,y,z,v,I) \
 
1093
  cimg_for3((img).height,y) for (int x = 0, \
 
1094
   _p1##x = 0, \
 
1095
   _n1##x = (int)( \
 
1096
   (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
 
1097
   (I[3] = I[4] = (img)(0,y,z,v)), \
 
1098
   (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
 
1099
   1>=(img).width?(int)((img).width)-1:1); \
 
1100
   (_n1##x<(int)((img).width) && ( \
 
1101
   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
 
1102
   (I[5] = (img)(_n1##x,y,z,v)), \
 
1103
   (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
 
1104
   x==--_n1##x; \
 
1105
   I[0] = I[1], I[1] = I[2], \
 
1106
   I[3] = I[4], I[4] = I[5], \
 
1107
   I[6] = I[7], I[7] = I[8], \
 
1108
   _p1##x = x++, ++_n1##x)
 
1109
 
 
1110
#define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,v,I) \
 
1111
  cimg_for_in3((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
 
1112
   _p1##x = x-1<0?0:x-1, \
 
1113
   _n1##x = (int)( \
 
1114
   (I[0] = (img)(_p1##x,_p1##y,z,v)), \
 
1115
   (I[3] = (img)(_p1##x,y,z,v)), \
 
1116
   (I[6] = (img)(_p1##x,_n1##y,z,v)), \
 
1117
   (I[1] = (img)(x,_p1##y,z,v)), \
 
1118
   (I[4] = (img)(x,y,z,v)), \
 
1119
   (I[7] = (img)(x,_n1##y,z,v)), \
 
1120
   x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
 
1121
   x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
 
1122
   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
 
1123
   (I[5] = (img)(_n1##x,y,z,v)), \
 
1124
   (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
 
1125
   x==--_n1##x);            \
 
1126
   I[0] = I[1], I[1] = I[2], \
 
1127
   I[3] = I[4], I[4] = I[5], \
 
1128
   I[6] = I[7], I[7] = I[8], \
 
1129
   _p1##x = x++, ++_n1##x)
 
1130
 
 
1131
#define cimg_for4x4(img,x,y,z,v,I) \
 
1132
  cimg_for4((img).height,y) for (int x = 0, \
 
1133
   _p1##x = 0, \
 
1134
   _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
 
1135
   _n2##x = (int)( \
 
1136
   (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
 
1137
   (I[4] = I[5] = (img)(0,y,z,v)), \
 
1138
   (I[8] = I[9] = (img)(0,_n1##y,z,v)), \
 
1139
   (I[12] = I[13] = (img)(0,_n2##y,z,v)), \
 
1140
   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
 
1141
   (I[6] = (img)(_n1##x,y,z,v)), \
 
1142
   (I[10] = (img)(_n1##x,_n1##y,z,v)), \
 
1143
   (I[14] = (img)(_n1##x,_n2##y,z,v)), \
 
1144
   2>=(img).width?(int)((img).width)-1:2); \
 
1145
   (_n2##x<(int)((img).width) && ( \
 
1146
   (I[3] = (img)(_n2##x,_p1##y,z,v)), \
 
1147
   (I[7] = (img)(_n2##x,y,z,v)), \
 
1148
   (I[11] = (img)(_n2##x,_n1##y,z,v)), \
 
1149
   (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
 
1150
   _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
 
1151
   I[0] = I[1], I[1] = I[2], I[2] = I[3], \
 
1152
   I[4] = I[5], I[5] = I[6], I[6] = I[7], \
 
1153
   I[8] = I[9], I[9] = I[10], I[10] = I[11], \
 
1154
   I[12] = I[13], I[13] = I[14], I[14] = I[15], \
 
1155
   _p1##x = x++, ++_n1##x, ++_n2##x)
 
1156
 
 
1157
#define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,v,I) \
 
1158
  cimg_for_in4((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
 
1159
   _p1##x = x-1<0?0:x-1, \
 
1160
   _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
 
1161
   _n2##x = (int)( \
 
1162
   (I[0] = (img)(_p1##x,_p1##y,z,v)), \
 
1163
   (I[4] = (img)(_p1##x,y,z,v)), \
 
1164
   (I[8] = (img)(_p1##x,_n1##y,z,v)), \
 
1165
   (I[12] = (img)(_p1##x,_n2##y,z,v)), \
 
1166
   (I[1] = (img)(x,_p1##y,z,v)), \
 
1167
   (I[5] = (img)(x,y,z,v)), \
 
1168
   (I[9] = (img)(x,_n1##y,z,v)), \
 
1169
   (I[13] = (img)(x,_n2##y,z,v)), \
 
1170
   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
 
1171
   (I[6] = (img)(_n1##x,y,z,v)), \
 
1172
   (I[10] = (img)(_n1##x,_n1##y,z,v)), \
 
1173
   (I[14] = (img)(_n1##x,_n2##y,z,v)), \
 
1174
   x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
 
1175
   x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
 
1176
   (I[3] = (img)(_n2##x,_p1##y,z,v)), \
 
1177
   (I[7] = (img)(_n2##x,y,z,v)), \
 
1178
   (I[11] = (img)(_n2##x,_n1##y,z,v)), \
 
1179
   (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
 
1180
   _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
 
1181
   I[0] = I[1], I[1] = I[2], I[2] = I[3], \
 
1182
   I[4] = I[5], I[5] = I[6], I[6] = I[7], \
 
1183
   I[8] = I[9], I[9] = I[10], I[10] = I[11], \
 
1184
   I[12] = I[13], I[13] = I[14], I[14] = I[15], \
 
1185
   _p1##x = x++, ++_n1##x, ++_n2##x)
 
1186
 
 
1187
#define cimg_for5x5(img,x,y,z,v,I) \
 
1188
 cimg_for5((img).height,y) for (int x = 0, \
 
1189
   _p2##x = 0, _p1##x = 0, \
 
1190
   _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
 
1191
   _n2##x = (int)( \
 
1192
   (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
 
1193
   (I[5] = I[6] = I[7] = (img)(0,_p1##y,z,v)), \
 
1194
   (I[10] = I[11] = I[12] = (img)(0,y,z,v)), \
 
1195
   (I[15] = I[16] = I[17] = (img)(0,_n1##y,z,v)), \
 
1196
   (I[20] = I[21] = I[22] = (img)(0,_n2##y,z,v)), \
 
1197
   (I[3] = (img)(_n1##x,_p2##y,z,v)), \
 
1198
   (I[8] = (img)(_n1##x,_p1##y,z,v)), \
 
1199
   (I[13] = (img)(_n1##x,y,z,v)), \
 
1200
   (I[18] = (img)(_n1##x,_n1##y,z,v)), \
 
1201
   (I[23] = (img)(_n1##x,_n2##y,z,v)),     \
 
1202
   2>=(img).width?(int)((img).width)-1:2); \
 
1203
   (_n2##x<(int)((img).width) && ( \
 
1204
   (I[4] = (img)(_n2##x,_p2##y,z,v)), \
 
1205
   (I[9] = (img)(_n2##x,_p1##y,z,v)), \
 
1206
   (I[14] = (img)(_n2##x,y,z,v)), \
 
1207
   (I[19] = (img)(_n2##x,_n1##y,z,v)), \
 
1208
   (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
 
1209
   _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
 
1210
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
 
1211
   I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
 
1212
   I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
 
1213
   I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
 
1214
   I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
 
1215
   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
 
1216
 
 
1217
#define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,v,I) \
 
1218
 cimg_for_in5((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
 
1219
   _p2##x = x-2<0?0:x-2, \
 
1220
   _p1##x = x-1<0?0:x-1, \
 
1221
   _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
 
1222
   _n2##x = (int)( \
 
1223
   (I[0] = (img)(_p2##x,_p2##y,z,v)), \
 
1224
   (I[5] = (img)(_p2##x,_p1##y,z,v)), \
 
1225
   (I[10] = (img)(_p2##x,y,z,v)), \
 
1226
   (I[15] = (img)(_p2##x,_n1##y,z,v)), \
 
1227
   (I[20] = (img)(_p2##x,_n2##y,z,v)), \
 
1228
   (I[1] = (img)(_p1##x,_p2##y,z,v)), \
 
1229
   (I[6] = (img)(_p1##x,_p1##y,z,v)), \
 
1230
   (I[11] = (img)(_p1##x,y,z,v)), \
 
1231
   (I[16] = (img)(_p1##x,_n1##y,z,v)), \
 
1232
   (I[21] = (img)(_p1##x,_n2##y,z,v)), \
 
1233
   (I[2] = (img)(x,_p2##y,z,v)), \
 
1234
   (I[7] = (img)(x,_p1##y,z,v)), \
 
1235
   (I[12] = (img)(x,y,z,v)), \
 
1236
   (I[17] = (img)(x,_n1##y,z,v)), \
 
1237
   (I[22] = (img)(x,_n2##y,z,v)), \
 
1238
   (I[3] = (img)(_n1##x,_p2##y,z,v)), \
 
1239
   (I[8] = (img)(_n1##x,_p1##y,z,v)), \
 
1240
   (I[13] = (img)(_n1##x,y,z,v)), \
 
1241
   (I[18] = (img)(_n1##x,_n1##y,z,v)), \
 
1242
   (I[23] = (img)(_n1##x,_n2##y,z,v)), \
 
1243
   x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
 
1244
   x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
 
1245
   (I[4] = (img)(_n2##x,_p2##y,z,v)), \
 
1246
   (I[9] = (img)(_n2##x,_p1##y,z,v)), \
 
1247
   (I[14] = (img)(_n2##x,y,z,v)), \
 
1248
   (I[19] = (img)(_n2##x,_n1##y,z,v)), \
 
1249
   (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
 
1250
   _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
 
1251
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
 
1252
   I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
 
1253
   I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
 
1254
   I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
 
1255
   I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
 
1256
   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
 
1257
 
 
1258
#define cimg_for6x6(img,x,y,z,v,I) \
 
1259
 cimg_for6((img).height,y) for (int x = 0, \
 
1260
   _p2##x = 0, _p1##x = 0, \
 
1261
   _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
 
1262
   _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
 
1263
   _n3##x = (int)( \
 
1264
   (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
 
1265
   (I[6] = I[7] = I[8] = (img)(0,_p1##y,z,v)), \
 
1266
   (I[12] = I[13] = I[14] = (img)(0,y,z,v)), \
 
1267
   (I[18] = I[19] = I[20] = (img)(0,_n1##y,z,v)), \
 
1268
   (I[24] = I[25] = I[26] = (img)(0,_n2##y,z,v)), \
 
1269
   (I[30] = I[31] = I[32] = (img)(0,_n3##y,z,v)), \
 
1270
   (I[3] = (img)(_n1##x,_p2##y,z,v)), \
 
1271
   (I[9] = (img)(_n1##x,_p1##y,z,v)), \
 
1272
   (I[15] = (img)(_n1##x,y,z,v)), \
 
1273
   (I[21] = (img)(_n1##x,_n1##y,z,v)), \
 
1274
   (I[27] = (img)(_n1##x,_n2##y,z,v)), \
 
1275
   (I[33] = (img)(_n1##x,_n3##y,z,v)), \
 
1276
   (I[4] = (img)(_n2##x,_p2##y,z,v)), \
 
1277
   (I[10] = (img)(_n2##x,_p1##y,z,v)), \
 
1278
   (I[16] = (img)(_n2##x,y,z,v)), \
 
1279
   (I[22] = (img)(_n2##x,_n1##y,z,v)), \
 
1280
   (I[28] = (img)(_n2##x,_n2##y,z,v)), \
 
1281
   (I[34] = (img)(_n2##x,_n3##y,z,v)), \
 
1282
   3>=(img).width?(int)((img).width)-1:3); \
 
1283
   (_n3##x<(int)((img).width) && ( \
 
1284
   (I[5] = (img)(_n3##x,_p2##y,z,v)), \
 
1285
   (I[11] = (img)(_n3##x,_p1##y,z,v)), \
 
1286
   (I[17] = (img)(_n3##x,y,z,v)), \
 
1287
   (I[23] = (img)(_n3##x,_n1##y,z,v)), \
 
1288
   (I[29] = (img)(_n3##x,_n2##y,z,v)), \
 
1289
   (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
 
1290
   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \
 
1291
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
 
1292
   I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
 
1293
   I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
 
1294
   I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
 
1295
   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
 
1296
   I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
 
1297
   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
 
1298
 
 
1299
#define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,v,I) \
 
1300
  cimg_for_in6((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \
 
1301
   _p2##x = x-2<0?0:x-2, \
 
1302
   _p1##x = x-1<0?0:x-1, \
 
1303
   _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
 
1304
   _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
 
1305
   _n3##x = (int)( \
 
1306
   (I[0] = (img)(_p2##x,_p2##y,z,v)), \
 
1307
   (I[6] = (img)(_p2##x,_p1##y,z,v)), \
 
1308
   (I[12] = (img)(_p2##x,y,z,v)), \
 
1309
   (I[18] = (img)(_p2##x,_n1##y,z,v)), \
 
1310
   (I[24] = (img)(_p2##x,_n2##y,z,v)), \
 
1311
   (I[30] = (img)(_p2##x,_n3##y,z,v)), \
 
1312
   (I[1] = (img)(_p1##x,_p2##y,z,v)), \
 
1313
   (I[7] = (img)(_p1##x,_p1##y,z,v)), \
 
1314
   (I[13] = (img)(_p1##x,y,z,v)), \
 
1315
   (I[19] = (img)(_p1##x,_n1##y,z,v)), \
 
1316
   (I[25] = (img)(_p1##x,_n2##y,z,v)), \
 
1317
   (I[31] = (img)(_p1##x,_n3##y,z,v)), \
 
1318
   (I[2] = (img)(x,_p2##y,z,v)), \
 
1319
   (I[8] = (img)(x,_p1##y,z,v)), \
 
1320
   (I[14] = (img)(x,y,z,v)), \
 
1321
   (I[20] = (img)(x,_n1##y,z,v)), \
 
1322
   (I[26] = (img)(x,_n2##y,z,v)), \
 
1323
   (I[32] = (img)(x,_n3##y,z,v)), \
 
1324
   (I[3] = (img)(_n1##x,_p2##y,z,v)), \
 
1325
   (I[9] = (img)(_n1##x,_p1##y,z,v)), \
 
1326
   (I[15] = (img)(_n1##x,y,z,v)), \
 
1327
   (I[21] = (img)(_n1##x,_n1##y,z,v)), \
 
1328
   (I[27] = (img)(_n1##x,_n2##y,z,v)), \
 
1329
   (I[33] = (img)(_n1##x,_n3##y,z,v)), \
 
1330
   (I[4] = (img)(_n2##x,_p2##y,z,v)), \
 
1331
   (I[10] = (img)(_n2##x,_p1##y,z,v)), \
 
1332
   (I[16] = (img)(_n2##x,y,z,v)), \
 
1333
   (I[22] = (img)(_n2##x,_n1##y,z,v)), \
 
1334
   (I[28] = (img)(_n2##x,_n2##y,z,v)), \
 
1335
   (I[34] = (img)(_n2##x,_n3##y,z,v)), \
 
1336
   x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
 
1337
   x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
 
1338
   (I[5] = (img)(_n3##x,_p2##y,z,v)), \
 
1339
   (I[11] = (img)(_n3##x,_p1##y,z,v)), \
 
1340
   (I[17] = (img)(_n3##x,y,z,v)), \
 
1341
   (I[23] = (img)(_n3##x,_n1##y,z,v)), \
 
1342
   (I[29] = (img)(_n3##x,_n2##y,z,v)), \
 
1343
   (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
 
1344
   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \
 
1345
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
 
1346
   I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
 
1347
   I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
 
1348
   I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
 
1349
   I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
 
1350
   I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
 
1351
   _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
 
1352
 
 
1353
#define cimg_for7x7(img,x,y,z,v,I) \
 
1354
  cimg_for7((img).height,y) for (int x = 0, \
 
1355
   _p3##x = 0, _p2##x = 0, _p1##x = 0, \
 
1356
   _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
 
1357
   _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
 
1358
   _n3##x = (int)( \
 
1359
   (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
 
1360
   (I[7] = I[8] = I[9] = I[10] = (img)(0,_p2##y,z,v)), \
 
1361
   (I[14] = I[15] = I[16] = I[17] = (img)(0,_p1##y,z,v)), \
 
1362
   (I[21] = I[22] = I[23] = I[24] = (img)(0,y,z,v)), \
 
1363
   (I[28] = I[29] = I[30] = I[31] = (img)(0,_n1##y,z,v)), \
 
1364
   (I[35] = I[36] = I[37] = I[38] = (img)(0,_n2##y,z,v)), \
 
1365
   (I[42] = I[43] = I[44] = I[45] = (img)(0,_n3##y,z,v)), \
 
1366
   (I[4] = (img)(_n1##x,_p3##y,z,v)), \
 
1367
   (I[11] = (img)(_n1##x,_p2##y,z,v)), \
 
1368
   (I[18] = (img)(_n1##x,_p1##y,z,v)), \
 
1369
   (I[25] = (img)(_n1##x,y,z,v)), \
 
1370
   (I[32] = (img)(_n1##x,_n1##y,z,v)), \
 
1371
   (I[39] = (img)(_n1##x,_n2##y,z,v)), \
 
1372
   (I[46] = (img)(_n1##x,_n3##y,z,v)), \
 
1373
   (I[5] = (img)(_n2##x,_p3##y,z,v)), \
 
1374
   (I[12] = (img)(_n2##x,_p2##y,z,v)), \
 
1375
   (I[19] = (img)(_n2##x,_p1##y,z,v)), \
 
1376
   (I[26] = (img)(_n2##x,y,z,v)), \
 
1377
   (I[33] = (img)(_n2##x,_n1##y,z,v)), \
 
1378
   (I[40] = (img)(_n2##x,_n2##y,z,v)), \
 
1379
   (I[47] = (img)(_n2##x,_n3##y,z,v)), \
 
1380
   3>=(img).width?(int)((img).width)-1:3); \
 
1381
   (_n3##x<(int)((img).width) && ( \
 
1382
   (I[6] = (img)(_n3##x,_p3##y,z,v)), \
 
1383
   (I[13] = (img)(_n3##x,_p2##y,z,v)), \
 
1384
   (I[20] = (img)(_n3##x,_p1##y,z,v)), \
 
1385
   (I[27] = (img)(_n3##x,y,z,v)), \
 
1386
   (I[34] = (img)(_n3##x,_n1##y,z,v)), \
 
1387
   (I[41] = (img)(_n3##x,_n2##y,z,v)), \
 
1388
   (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
 
1389
   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \
 
1390
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
 
1391
   I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
 
1392
   I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
 
1393
   I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
 
1394
   I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
 
1395
   I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
 
1396
   I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
 
1397
   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
 
1398
 
 
1399
#define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,v,I) \
 
1400
  cimg_for_in7((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
 
1401
   _p3##x = x-3<0?0:x-3, \
 
1402
   _p2##x = x-2<0?0:x-2, \
 
1403
   _p1##x = x-1<0?0:x-1, \
 
1404
   _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
 
1405
   _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
 
1406
   _n3##x = (int)( \
 
1407
   (I[0] = (img)(_p3##x,_p3##y,z,v)), \
 
1408
   (I[7] = (img)(_p3##x,_p2##y,z,v)), \
 
1409
   (I[14] = (img)(_p3##x,_p1##y,z,v)), \
 
1410
   (I[21] = (img)(_p3##x,y,z,v)), \
 
1411
   (I[28] = (img)(_p3##x,_n1##y,z,v)), \
 
1412
   (I[35] = (img)(_p3##x,_n2##y,z,v)), \
 
1413
   (I[42] = (img)(_p3##x,_n3##y,z,v)), \
 
1414
   (I[1] = (img)(_p2##x,_p3##y,z,v)), \
 
1415
   (I[8] = (img)(_p2##x,_p2##y,z,v)), \
 
1416
   (I[15] = (img)(_p2##x,_p1##y,z,v)), \
 
1417
   (I[22] = (img)(_p2##x,y,z,v)), \
 
1418
   (I[29] = (img)(_p2##x,_n1##y,z,v)), \
 
1419
   (I[36] = (img)(_p2##x,_n2##y,z,v)), \
 
1420
   (I[43] = (img)(_p2##x,_n3##y,z,v)), \
 
1421
   (I[2] = (img)(_p1##x,_p3##y,z,v)), \
 
1422
   (I[9] = (img)(_p1##x,_p2##y,z,v)), \
 
1423
   (I[16] = (img)(_p1##x,_p1##y,z,v)), \
 
1424
   (I[23] = (img)(_p1##x,y,z,v)), \
 
1425
   (I[30] = (img)(_p1##x,_n1##y,z,v)), \
 
1426
   (I[37] = (img)(_p1##x,_n2##y,z,v)), \
 
1427
   (I[44] = (img)(_p1##x,_n3##y,z,v)), \
 
1428
   (I[3] = (img)(x,_p3##y,z,v)), \
 
1429
   (I[10] = (img)(x,_p2##y,z,v)), \
 
1430
   (I[17] = (img)(x,_p1##y,z,v)), \
 
1431
   (I[24] = (img)(x,y,z,v)), \
 
1432
   (I[31] = (img)(x,_n1##y,z,v)), \
 
1433
   (I[38] = (img)(x,_n2##y,z,v)), \
 
1434
   (I[45] = (img)(x,_n3##y,z,v)), \
 
1435
   (I[4] = (img)(_n1##x,_p3##y,z,v)), \
 
1436
   (I[11] = (img)(_n1##x,_p2##y,z,v)), \
 
1437
   (I[18] = (img)(_n1##x,_p1##y,z,v)), \
 
1438
   (I[25] = (img)(_n1##x,y,z,v)), \
 
1439
   (I[32] = (img)(_n1##x,_n1##y,z,v)), \
 
1440
   (I[39] = (img)(_n1##x,_n2##y,z,v)), \
 
1441
   (I[46] = (img)(_n1##x,_n3##y,z,v)), \
 
1442
   (I[5] = (img)(_n2##x,_p3##y,z,v)), \
 
1443
   (I[12] = (img)(_n2##x,_p2##y,z,v)), \
 
1444
   (I[19] = (img)(_n2##x,_p1##y,z,v)), \
 
1445
   (I[26] = (img)(_n2##x,y,z,v)), \
 
1446
   (I[33] = (img)(_n2##x,_n1##y,z,v)), \
 
1447
   (I[40] = (img)(_n2##x,_n2##y,z,v)), \
 
1448
   (I[47] = (img)(_n2##x,_n3##y,z,v)), \
 
1449
   x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
 
1450
   x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
 
1451
   (I[6] = (img)(_n3##x,_p3##y,z,v)), \
 
1452
   (I[13] = (img)(_n3##x,_p2##y,z,v)), \
 
1453
   (I[20] = (img)(_n3##x,_p1##y,z,v)), \
 
1454
   (I[27] = (img)(_n3##x,y,z,v)), \
 
1455
   (I[34] = (img)(_n3##x,_n1##y,z,v)), \
 
1456
   (I[41] = (img)(_n3##x,_n2##y,z,v)), \
 
1457
   (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
 
1458
   _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \
 
1459
   I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
 
1460
   I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
 
1461
   I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
 
1462
   I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
 
1463
   I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
 
1464
   I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
 
1465
   I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
 
1466
   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
 
1467
 
 
1468
#define cimg_for8x8(img,x,y,z,v,I) \
 
1469
  cimg_for8((img).height,y) for (int x = 0, \
 
1470
   _p3##x = 0, _p2##x = 0, _p1##x = 0, \
 
1471
   _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
 
1472
   _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
 
1473
   _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
 
1474
   _n4##x = (int)( \
 
1475
   (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
 
1476
   (I[8] = I[9] = I[10] = I[11] = (img)(0,_p2##y,z,v)), \
 
1477
   (I[16] = I[17] = I[18] = I[19] = (img)(0,_p1##y,z,v)), \
 
1478
   (I[24] = I[25] = I[26] = I[27] = (img)(0,y,z,v)), \
 
1479
   (I[32] = I[33] = I[34] = I[35] = (img)(0,_n1##y,z,v)), \
 
1480
   (I[40] = I[41] = I[42] = I[43] = (img)(0,_n2##y,z,v)), \
 
1481
   (I[48] = I[49] = I[50] = I[51] = (img)(0,_n3##y,z,v)), \
 
1482
   (I[56] = I[57] = I[58] = I[59] = (img)(0,_n4##y,z,v)), \
 
1483
   (I[4] = (img)(_n1##x,_p3##y,z,v)), \
 
1484
   (I[12] = (img)(_n1##x,_p2##y,z,v)), \
 
1485
   (I[20] = (img)(_n1##x,_p1##y,z,v)), \
 
1486
   (I[28] = (img)(_n1##x,y,z,v)), \
 
1487
   (I[36] = (img)(_n1##x,_n1##y,z,v)), \
 
1488
   (I[44] = (img)(_n1##x,_n2##y,z,v)), \
 
1489
   (I[52] = (img)(_n1##x,_n3##y,z,v)), \
 
1490
   (I[60] = (img)(_n1##x,_n4##y,z,v)), \
 
1491
   (I[5] = (img)(_n2##x,_p3##y,z,v)), \
 
1492
   (I[13] = (img)(_n2##x,_p2##y,z,v)), \
 
1493
   (I[21] = (img)(_n2##x,_p1##y,z,v)), \
 
1494
   (I[29] = (img)(_n2##x,y,z,v)), \
 
1495
   (I[37] = (img)(_n2##x,_n1##y,z,v)), \
 
1496
   (I[45] = (img)(_n2##x,_n2##y,z,v)), \
 
1497
   (I[53] = (img)(_n2##x,_n3##y,z,v)), \
 
1498
   (I[61] = (img)(_n2##x,_n4##y,z,v)), \
 
1499
   (I[6] = (img)(_n3##x,_p3##y,z,v)), \
 
1500
   (I[14] = (img)(_n3##x,_p2##y,z,v)), \
 
1501
   (I[22] = (img)(_n3##x,_p1##y,z,v)), \
 
1502
   (I[30] = (img)(_n3##x,y,z,v)), \
 
1503
   (I[38] = (img)(_n3##x,_n1##y,z,v)), \
 
1504
   (I[46] = (img)(_n3##x,_n2##y,z,v)), \
 
1505
   (I[54] = (img)(_n3##x,_n3##y,z,v)), \
 
1506
   (I[62] = (img)(_n3##x,_n4##y,z,v)), \
 
1507
   4>=((img).width)?(int)((img).width)-1:4); \
 
1508
   (_n4##x<(int)((img).width) && ( \
 
1509
   (I[7] = (img)(_n4##x,_p3##y,z,v)), \
 
1510
   (I[15] = (img)(_n4##x,_p2##y,z,v)), \
 
1511
   (I[23] = (img)(_n4##x,_p1##y,z,v)), \
 
1512
   (I[31] = (img)(_n4##x,y,z,v)), \
 
1513
   (I[39] = (img)(_n4##x,_n1##y,z,v)), \
 
1514
   (I[47] = (img)(_n4##x,_n2##y,z,v)), \
 
1515
   (I[55] = (img)(_n4##x,_n3##y,z,v)), \
 
1516
   (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
 
1517
   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
 
1518
   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], \
 
1519
   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], \
 
1520
   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], \
 
1521
   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], \
 
1522
   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], \
 
1523
   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], \
 
1524
   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], \
 
1525
   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], \
 
1526
   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
 
1527
 
 
1528
#define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,v,I) \
 
1529
  cimg_for_in8((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
 
1530
   _p3##x = x-3<0?0:x-3, \
 
1531
   _p2##x = x-2<0?0:x-2, \
 
1532
   _p1##x = x-1<0?0:x-1, \
 
1533
   _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
 
1534
   _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
 
1535
   _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
 
1536
   _n4##x = (int)( \
 
1537
   (I[0] = (img)(_p3##x,_p3##y,z,v)), \
 
1538
   (I[8] = (img)(_p3##x,_p2##y,z,v)), \
 
1539
   (I[16] = (img)(_p3##x,_p1##y,z,v)), \
 
1540
   (I[24] = (img)(_p3##x,y,z,v)), \
 
1541
   (I[32] = (img)(_p3##x,_n1##y,z,v)), \
 
1542
   (I[40] = (img)(_p3##x,_n2##y,z,v)), \
 
1543
   (I[48] = (img)(_p3##x,_n3##y,z,v)), \
 
1544
   (I[56] = (img)(_p3##x,_n4##y,z,v)), \
 
1545
   (I[1] = (img)(_p2##x,_p3##y,z,v)), \
 
1546
   (I[9] = (img)(_p2##x,_p2##y,z,v)), \
 
1547
   (I[17] = (img)(_p2##x,_p1##y,z,v)), \
 
1548
   (I[25] = (img)(_p2##x,y,z,v)), \
 
1549
   (I[33] = (img)(_p2##x,_n1##y,z,v)), \
 
1550
   (I[41] = (img)(_p2##x,_n2##y,z,v)), \
 
1551
   (I[49] = (img)(_p2##x,_n3##y,z,v)), \
 
1552
   (I[57] = (img)(_p2##x,_n4##y,z,v)), \
 
1553
   (I[2] = (img)(_p1##x,_p3##y,z,v)), \
 
1554
   (I[10] = (img)(_p1##x,_p2##y,z,v)), \
 
1555
   (I[18] = (img)(_p1##x,_p1##y,z,v)), \
 
1556
   (I[26] = (img)(_p1##x,y,z,v)), \
 
1557
   (I[34] = (img)(_p1##x,_n1##y,z,v)), \
 
1558
   (I[42] = (img)(_p1##x,_n2##y,z,v)), \
 
1559
   (I[50] = (img)(_p1##x,_n3##y,z,v)), \
 
1560
   (I[58] = (img)(_p1##x,_n4##y,z,v)), \
 
1561
   (I[3] = (img)(x,_p3##y,z,v)), \
 
1562
   (I[11] = (img)(x,_p2##y,z,v)), \
 
1563
   (I[19] = (img)(x,_p1##y,z,v)), \
 
1564
   (I[27] = (img)(x,y,z,v)), \
 
1565
   (I[35] = (img)(x,_n1##y,z,v)), \
 
1566
   (I[43] = (img)(x,_n2##y,z,v)), \
 
1567
   (I[51] = (img)(x,_n3##y,z,v)), \
 
1568
   (I[59] = (img)(x,_n4##y,z,v)), \
 
1569
   (I[4] = (img)(_n1##x,_p3##y,z,v)), \
 
1570
   (I[12] = (img)(_n1##x,_p2##y,z,v)), \
 
1571
   (I[20] = (img)(_n1##x,_p1##y,z,v)), \
 
1572
   (I[28] = (img)(_n1##x,y,z,v)), \
 
1573
   (I[36] = (img)(_n1##x,_n1##y,z,v)), \
 
1574
   (I[44] = (img)(_n1##x,_n2##y,z,v)), \
 
1575
   (I[52] = (img)(_n1##x,_n3##y,z,v)), \
 
1576
   (I[60] = (img)(_n1##x,_n4##y,z,v)), \
 
1577
   (I[5] = (img)(_n2##x,_p3##y,z,v)), \
 
1578
   (I[13] = (img)(_n2##x,_p2##y,z,v)), \
 
1579
   (I[21] = (img)(_n2##x,_p1##y,z,v)), \
 
1580
   (I[29] = (img)(_n2##x,y,z,v)), \
 
1581
   (I[37] = (img)(_n2##x,_n1##y,z,v)), \
 
1582
   (I[45] = (img)(_n2##x,_n2##y,z,v)), \
 
1583
   (I[53] = (img)(_n2##x,_n3##y,z,v)), \
 
1584
   (I[61] = (img)(_n2##x,_n4##y,z,v)), \
 
1585
   (I[6] = (img)(_n3##x,_p3##y,z,v)), \
 
1586
   (I[14] = (img)(_n3##x,_p2##y,z,v)), \
 
1587
   (I[22] = (img)(_n3##x,_p1##y,z,v)), \
 
1588
   (I[30] = (img)(_n3##x,y,z,v)), \
 
1589
   (I[38] = (img)(_n3##x,_n1##y,z,v)), \
 
1590
   (I[46] = (img)(_n3##x,_n2##y,z,v)), \
 
1591
   (I[54] = (img)(_n3##x,_n3##y,z,v)), \
 
1592
   (I[62] = (img)(_n3##x,_n4##y,z,v)), \
 
1593
   x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
 
1594
   x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
 
1595
   (I[7] = (img)(_n4##x,_p3##y,z,v)), \
 
1596
   (I[15] = (img)(_n4##x,_p2##y,z,v)), \
 
1597
   (I[23] = (img)(_n4##x,_p1##y,z,v)), \
 
1598
   (I[31] = (img)(_n4##x,y,z,v)), \
 
1599
   (I[39] = (img)(_n4##x,_n1##y,z,v)), \
 
1600
   (I[47] = (img)(_n4##x,_n2##y,z,v)), \
 
1601
   (I[55] = (img)(_n4##x,_n3##y,z,v)), \
 
1602
   (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
 
1603
   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
 
1604
   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], \
 
1605
   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], \
 
1606
   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], \
 
1607
   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], \
 
1608
   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], \
 
1609
   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], \
 
1610
   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], \
 
1611
   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], \
 
1612
   _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
 
1613
 
 
1614
#define cimg_for9x9(img,x,y,z,v,I) \
 
1615
  cimg_for9((img).height,y) for (int x = 0, \
 
1616
   _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \
 
1617
   _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
 
1618
   _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
 
1619
   _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
 
1620
   _n4##x = (int)( \
 
1621
   (I[0] = I[1] = I[2] = I[3] = I[4] = (img)(0,_p4##y,z,v)), \
 
1622
   (I[9] = I[10] = I[11] = I[12] = I[13] = (img)(0,_p3##y,z,v)), \
 
1623
   (I[18] = I[19] = I[20] = I[21] = I[22] = (img)(0,_p2##y,z,v)), \
 
1624
   (I[27] = I[28] = I[29] = I[30] = I[31] = (img)(0,_p1##y,z,v)), \
 
1625
   (I[36] = I[37] = I[38] = I[39] = I[40] = (img)(0,y,z,v)), \
 
1626
   (I[45] = I[46] = I[47] = I[48] = I[49] = (img)(0,_n1##y,z,v)), \
 
1627
   (I[54] = I[55] = I[56] = I[57] = I[58] = (img)(0,_n2##y,z,v)), \
 
1628
   (I[63] = I[64] = I[65] = I[66] = I[67] = (img)(0,_n3##y,z,v)), \
 
1629
   (I[72] = I[73] = I[74] = I[75] = I[76] = (img)(0,_n4##y,z,v)), \
 
1630
   (I[5] = (img)(_n1##x,_p4##y,z,v)), \
 
1631
   (I[14] = (img)(_n1##x,_p3##y,z,v)), \
 
1632
   (I[23] = (img)(_n1##x,_p2##y,z,v)), \
 
1633
   (I[32] = (img)(_n1##x,_p1##y,z,v)), \
 
1634
   (I[41] = (img)(_n1##x,y,z,v)), \
 
1635
   (I[50] = (img)(_n1##x,_n1##y,z,v)), \
 
1636
   (I[59] = (img)(_n1##x,_n2##y,z,v)), \
 
1637
   (I[68] = (img)(_n1##x,_n3##y,z,v)), \
 
1638
   (I[77] = (img)(_n1##x,_n4##y,z,v)), \
 
1639
   (I[6] = (img)(_n2##x,_p4##y,z,v)), \
 
1640
   (I[15] = (img)(_n2##x,_p3##y,z,v)), \
 
1641
   (I[24] = (img)(_n2##x,_p2##y,z,v)), \
 
1642
   (I[33] = (img)(_n2##x,_p1##y,z,v)), \
 
1643
   (I[42] = (img)(_n2##x,y,z,v)), \
 
1644
   (I[51] = (img)(_n2##x,_n1##y,z,v)), \
 
1645
   (I[60] = (img)(_n2##x,_n2##y,z,v)), \
 
1646
   (I[69] = (img)(_n2##x,_n3##y,z,v)), \
 
1647
   (I[78] = (img)(_n2##x,_n4##y,z,v)), \
 
1648
   (I[7] = (img)(_n3##x,_p4##y,z,v)), \
 
1649
   (I[16] = (img)(_n3##x,_p3##y,z,v)), \
 
1650
   (I[25] = (img)(_n3##x,_p2##y,z,v)), \
 
1651
   (I[34] = (img)(_n3##x,_p1##y,z,v)), \
 
1652
   (I[43] = (img)(_n3##x,y,z,v)), \
 
1653
   (I[52] = (img)(_n3##x,_n1##y,z,v)), \
 
1654
   (I[61] = (img)(_n3##x,_n2##y,z,v)), \
 
1655
   (I[70] = (img)(_n3##x,_n3##y,z,v)), \
 
1656
   (I[79] = (img)(_n3##x,_n4##y,z,v)), \
 
1657
   4>=((img).width)?(int)((img).width)-1:4); \
 
1658
   (_n4##x<(int)((img).width) && ( \
 
1659
   (I[8] = (img)(_n4##x,_p4##y,z,v)), \
 
1660
   (I[17] = (img)(_n4##x,_p3##y,z,v)), \
 
1661
   (I[26] = (img)(_n4##x,_p2##y,z,v)), \
 
1662
   (I[35] = (img)(_n4##x,_p1##y,z,v)), \
 
1663
   (I[44] = (img)(_n4##x,y,z,v)), \
 
1664
   (I[53] = (img)(_n4##x,_n1##y,z,v)), \
 
1665
   (I[62] = (img)(_n4##x,_n2##y,z,v)), \
 
1666
   (I[71] = (img)(_n4##x,_n3##y,z,v)), \
 
1667
   (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
 
1668
   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
 
1669
   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], \
 
1670
   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], \
 
1671
   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], \
 
1672
   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], \
 
1673
   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], \
 
1674
   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], \
 
1675
   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], \
 
1676
   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], \
 
1677
   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], \
 
1678
   _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
 
1679
 
 
1680
#define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,v,I) \
 
1681
  cimg_for_in9((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
 
1682
   _p4##x = x-4<0?0:x-4, \
 
1683
   _p3##x = x-3<0?0:x-3, \
 
1684
   _p2##x = x-2<0?0:x-2, \
 
1685
   _p1##x = x-1<0?0:x-1, \
 
1686
   _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
 
1687
   _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
 
1688
   _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
 
1689
   _n4##x = (int)( \
 
1690
   (I[0] = (img)(_p4##x,_p4##y,z,v)), \
 
1691
   (I[9] = (img)(_p4##x,_p3##y,z,v)), \
 
1692
   (I[18] = (img)(_p4##x,_p2##y,z,v)), \
 
1693
   (I[27] = (img)(_p4##x,_p1##y,z,v)), \
 
1694
   (I[36] = (img)(_p4##x,y,z,v)), \
 
1695
   (I[45] = (img)(_p4##x,_n1##y,z,v)), \
 
1696
   (I[54] = (img)(_p4##x,_n2##y,z,v)), \
 
1697
   (I[63] = (img)(_p4##x,_n3##y,z,v)), \
 
1698
   (I[72] = (img)(_p4##x,_n4##y,z,v)), \
 
1699
   (I[1] = (img)(_p3##x,_p4##y,z,v)), \
 
1700
   (I[10] = (img)(_p3##x,_p3##y,z,v)), \
 
1701
   (I[19] = (img)(_p3##x,_p2##y,z,v)), \
 
1702
   (I[28] = (img)(_p3##x,_p1##y,z,v)), \
 
1703
   (I[37] = (img)(_p3##x,y,z,v)), \
 
1704
   (I[46] = (img)(_p3##x,_n1##y,z,v)), \
 
1705
   (I[55] = (img)(_p3##x,_n2##y,z,v)), \
 
1706
   (I[64] = (img)(_p3##x,_n3##y,z,v)), \
 
1707
   (I[73] = (img)(_p3##x,_n4##y,z,v)), \
 
1708
   (I[2] = (img)(_p2##x,_p4##y,z,v)), \
 
1709
   (I[11] = (img)(_p2##x,_p3##y,z,v)), \
 
1710
   (I[20] = (img)(_p2##x,_p2##y,z,v)), \
 
1711
   (I[29] = (img)(_p2##x,_p1##y,z,v)), \
 
1712
   (I[38] = (img)(_p2##x,y,z,v)), \
 
1713
   (I[47] = (img)(_p2##x,_n1##y,z,v)), \
 
1714
   (I[56] = (img)(_p2##x,_n2##y,z,v)), \
 
1715
   (I[65] = (img)(_p2##x,_n3##y,z,v)), \
 
1716
   (I[74] = (img)(_p2##x,_n4##y,z,v)), \
 
1717
   (I[3] = (img)(_p1##x,_p4##y,z,v)), \
 
1718
   (I[12] = (img)(_p1##x,_p3##y,z,v)), \
 
1719
   (I[21] = (img)(_p1##x,_p2##y,z,v)), \
 
1720
   (I[30] = (img)(_p1##x,_p1##y,z,v)), \
 
1721
   (I[39] = (img)(_p1##x,y,z,v)), \
 
1722
   (I[48] = (img)(_p1##x,_n1##y,z,v)), \
 
1723
   (I[57] = (img)(_p1##x,_n2##y,z,v)), \
 
1724
   (I[66] = (img)(_p1##x,_n3##y,z,v)), \
 
1725
   (I[75] = (img)(_p1##x,_n4##y,z,v)), \
 
1726
   (I[4] = (img)(x,_p4##y,z,v)), \
 
1727
   (I[13] = (img)(x,_p3##y,z,v)), \
 
1728
   (I[22] = (img)(x,_p2##y,z,v)), \
 
1729
   (I[31] = (img)(x,_p1##y,z,v)), \
 
1730
   (I[40] = (img)(x,y,z,v)), \
 
1731
   (I[49] = (img)(x,_n1##y,z,v)), \
 
1732
   (I[58] = (img)(x,_n2##y,z,v)), \
 
1733
   (I[67] = (img)(x,_n3##y,z,v)), \
 
1734
   (I[76] = (img)(x,_n4##y,z,v)), \
 
1735
   (I[5] = (img)(_n1##x,_p4##y,z,v)), \
 
1736
   (I[14] = (img)(_n1##x,_p3##y,z,v)), \
 
1737
   (I[23] = (img)(_n1##x,_p2##y,z,v)), \
 
1738
   (I[32] = (img)(_n1##x,_p1##y,z,v)), \
 
1739
   (I[41] = (img)(_n1##x,y,z,v)), \
 
1740
   (I[50] = (img)(_n1##x,_n1##y,z,v)), \
 
1741
   (I[59] = (img)(_n1##x,_n2##y,z,v)), \
 
1742
   (I[68] = (img)(_n1##x,_n3##y,z,v)), \
 
1743
   (I[77] = (img)(_n1##x,_n4##y,z,v)), \
 
1744
   (I[6] = (img)(_n2##x,_p4##y,z,v)), \
 
1745
   (I[15] = (img)(_n2##x,_p3##y,z,v)), \
 
1746
   (I[24] = (img)(_n2##x,_p2##y,z,v)), \
 
1747
   (I[33] = (img)(_n2##x,_p1##y,z,v)), \
 
1748
   (I[42] = (img)(_n2##x,y,z,v)), \
 
1749
   (I[51] = (img)(_n2##x,_n1##y,z,v)), \
 
1750
   (I[60] = (img)(_n2##x,_n2##y,z,v)), \
 
1751
   (I[69] = (img)(_n2##x,_n3##y,z,v)), \
 
1752
   (I[78] = (img)(_n2##x,_n4##y,z,v)), \
 
1753
   (I[7] = (img)(_n3##x,_p4##y,z,v)), \
 
1754
   (I[16] = (img)(_n3##x,_p3##y,z,v)), \
 
1755
   (I[25] = (img)(_n3##x,_p2##y,z,v)), \
 
1756
   (I[34] = (img)(_n3##x,_p1##y,z,v)), \
 
1757
   (I[43] = (img)(_n3##x,y,z,v)), \
 
1758
   (I[52] = (img)(_n3##x,_n1##y,z,v)), \
 
1759
   (I[61] = (img)(_n3##x,_n2##y,z,v)), \
 
1760
   (I[70] = (img)(_n3##x,_n3##y,z,v)), \
 
1761
   (I[79] = (img)(_n3##x,_n4##y,z,v)), \
 
1762
   x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
 
1763
   x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
 
1764
   (I[8] = (img)(_n4##x,_p4##y,z,v)), \
 
1765
   (I[17] = (img)(_n4##x,_p3##y,z,v)), \
 
1766
   (I[26] = (img)(_n4##x,_p2##y,z,v)), \
 
1767
   (I[35] = (img)(_n4##x,_p1##y,z,v)), \
 
1768
   (I[44] = (img)(_n4##x,y,z,v)), \
 
1769
   (I[53] = (img)(_n4##x,_n1##y,z,v)), \
 
1770
   (I[62] = (img)(_n4##x,_n2##y,z,v)), \
 
1771
   (I[71] = (img)(_n4##x,_n3##y,z,v)), \
 
1772
   (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
 
1773
   _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
 
1774
   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], \
 
1775
   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], \
 
1776
   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], \
 
1777
   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], \
 
1778
   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], \
 
1779
   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], \
 
1780
   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], \
 
1781
   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], \
 
1782
   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], \
 
1783
   _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
 
1784
 
 
1785
#define cimg_for2x2x2(img,x,y,z,v,I) \
 
1786
 cimg_for2((img).depth,z) cimg_for2((img).height,y) for (int x = 0, \
 
1787
   _n1##x = (int)( \
 
1788
   (I[0] = (img)(0,y,z,v)), \
 
1789
   (I[2] = (img)(0,_n1##y,z,v)), \
 
1790
   (I[4] = (img)(0,y,_n1##z,v)), \
 
1791
   (I[6] = (img)(0,_n1##y,_n1##z,v)), \
 
1792
   1>=(img).width?(int)((img).width)-1:1); \
 
1793
   (_n1##x<(int)((img).width) && ( \
 
1794
   (I[1] = (img)(_n1##x,y,z,v)), \
 
1795
   (I[3] = (img)(_n1##x,_n1##y,z,v)), \
 
1796
   (I[5] = (img)(_n1##x,y,_n1##z,v)), \
 
1797
   (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
 
1798
   x==--_n1##x; \
 
1799
   I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
 
1800
   ++x, ++_n1##x)
 
1801
 
 
1802
#define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
 
1803
 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), \
 
1804
   _n1##x = (int)( \
 
1805
   (I[0] = (img)(x,y,z,v)), \
 
1806
   (I[2] = (img)(x,_n1##y,z,v)), \
 
1807
   (I[4] = (img)(x,y,_n1##z,v)), \
 
1808
   (I[6] = (img)(x,_n1##y,_n1##z,v)), \
 
1809
   x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
 
1810
   x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
 
1811
   (I[1] = (img)(_n1##x,y,z,v)), \
 
1812
   (I[3] = (img)(_n1##x,_n1##y,z,v)), \
 
1813
   (I[5] = (img)(_n1##x,y,_n1##z,v)), \
 
1814
   (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
 
1815
   x==--_n1##x); \
 
1816
   I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
 
1817
   ++x, ++_n1##x)
 
1818
 
 
1819
#define cimg_for3x3x3(img,x,y,z,v,I) \
 
1820
 cimg_for3((img).depth,z) cimg_for3((img).height,y) for (int x = 0, \
 
1821
   _p1##x = 0, \
 
1822
   _n1##x = (int)( \
 
1823
   (I[0] = I[1] = (img)(0,_p1##y,_p1##z,v)), \
 
1824
   (I[3] = I[4] = (img)(0,y,_p1##z,v)),  \
 
1825
   (I[6] = I[7] = (img)(0,_n1##y,_p1##z,v)), \
 
1826
   (I[9] = I[10] = (img)(0,_p1##y,z,v)), \
 
1827
   (I[12] = I[13] = (img)(0,y,z,v)), \
 
1828
   (I[15] = I[16] = (img)(0,_n1##y,z,v)), \
 
1829
   (I[18] = I[19] = (img)(0,_p1##y,_n1##z,v)), \
 
1830
   (I[21] = I[22] = (img)(0,y,_n1##z,v)), \
 
1831
   (I[24] = I[25] = (img)(0,_n1##y,_n1##z,v)), \
 
1832
   1>=(img).width?(int)((img).width)-1:1); \
 
1833
   (_n1##x<(int)((img).width) && ( \
 
1834
   (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
 
1835
   (I[5] = (img)(_n1##x,y,_p1##z,v)), \
 
1836
   (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
 
1837
   (I[11] = (img)(_n1##x,_p1##y,z,v)), \
 
1838
   (I[14] = (img)(_n1##x,y,z,v)), \
 
1839
   (I[17] = (img)(_n1##x,_n1##y,z,v)), \
 
1840
   (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
 
1841
   (I[23] = (img)(_n1##x,y,_n1##z,v)), \
 
1842
   (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
 
1843
   x==--_n1##x; \
 
1844
   I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
 
1845
   I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
 
1846
   I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
 
1847
   _p1##x = x++, ++_n1##x)
 
1848
 
 
1849
#define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
 
1850
 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), \
 
1851
   _p1##x = x-1<0?0:x-1, \
 
1852
   _n1##x = (int)( \
 
1853
   (I[0] = (img)(_p1##x,_p1##y,_p1##z,v)), \
 
1854
   (I[3] = (img)(_p1##x,y,_p1##z,v)),  \
 
1855
   (I[6] = (img)(_p1##x,_n1##y,_p1##z,v)), \
 
1856
   (I[9] = (img)(_p1##x,_p1##y,z,v)), \
 
1857
   (I[12] = (img)(_p1##x,y,z,v)), \
 
1858
   (I[15] = (img)(_p1##x,_n1##y,z,v)), \
 
1859
   (I[18] = (img)(_p1##x,_p1##y,_n1##z,v)), \
 
1860
   (I[21] = (img)(_p1##x,y,_n1##z,v)), \
 
1861
   (I[24] = (img)(_p1##x,_n1##y,_n1##z,v)), \
 
1862
   (I[1] = (img)(x,_p1##y,_p1##z,v)), \
 
1863
   (I[4] = (img)(x,y,_p1##z,v)),  \
 
1864
   (I[7] = (img)(x,_n1##y,_p1##z,v)), \
 
1865
   (I[10] = (img)(x,_p1##y,z,v)), \
 
1866
   (I[13] = (img)(x,y,z,v)), \
 
1867
   (I[16] = (img)(x,_n1##y,z,v)), \
 
1868
   (I[19] = (img)(x,_p1##y,_n1##z,v)), \
 
1869
   (I[22] = (img)(x,y,_n1##z,v)), \
 
1870
   (I[25] = (img)(x,_n1##y,_n1##z,v)), \
 
1871
   x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
 
1872
   x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
 
1873
   (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
 
1874
   (I[5] = (img)(_n1##x,y,_p1##z,v)), \
 
1875
   (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
 
1876
   (I[11] = (img)(_n1##x,_p1##y,z,v)), \
 
1877
   (I[14] = (img)(_n1##x,y,z,v)), \
 
1878
   (I[17] = (img)(_n1##x,_n1##y,z,v)), \
 
1879
   (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
 
1880
   (I[23] = (img)(_n1##x,y,_n1##z,v)), \
 
1881
   (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
 
1882
   x==--_n1##x); \
 
1883
   I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
 
1884
   I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
 
1885
   I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
 
1886
   _p1##x = x++, ++_n1##x)
 
1887
 
 
1888
/*------------------------------------------------
605
1889
 #
606
1890
 #
607
1891
 #  Definition of the cimg_library:: namespace
608
1892
 #
609
1893
 #
610
 
 #------------------------------------------------
611
 
 */
612
 
 
613
 
//! Namespace that encompasses all classes and functions of the %CImg library.
 
1894
 -------------------------------------------------*/
 
1895
//! This namespace encompasses all classes and functions of the %CImg library.
614
1896
/**
615
 
   This namespace is defined to avoid class names collisions that could happen
616
 
   with the include of other C++ header files. Anyway, it should not happen
617
 
   very often and you may start most of your programs with
 
1897
   This namespace is defined to avoid functions and class names collisions
 
1898
   that could happen with the include of other C++ header files.
 
1899
   Anyway, it should not happen often and you should reasonnably start most of your
 
1900
   %CImg-based programs with
618
1901
   \code
619
1902
   #include "CImg.h"
620
1903
   using namespace cimg_library;
621
1904
   \endcode
622
 
   to simplify the declaration of %CImg Library objects variables afterwards.
 
1905
   to simplify the declaration of %CImg Library variables afterwards.
623
1906
**/
624
 
 
625
1907
namespace cimg_library {
626
1908
 
627
 
  // Define the CImg classes.
 
1909
  // Declare the only four classes of the CImg Library.
 
1910
  //
628
1911
  template<typename T=float> struct CImg;
629
1912
  template<typename T=float> struct CImgList;
630
 
  struct CImgStats;
631
1913
  struct CImgDisplay;
632
1914
  struct CImgException;
633
1915
 
 
1916
  // (Pre)declare the cimg namespace.
 
1917
  // This is not the complete namespace declaration. It only contains some
 
1918
  // necessary stuffs to ensure a correct declaration order of classes and functions
 
1919
  // defined afterwards.
 
1920
  //
634
1921
  namespace cimg {
635
1922
 
636
 
    // The bodies of the functions below are defined afterwards
 
1923
#ifdef cimg_use_vt100
 
1924
    const char t_normal[] = { 0x1b,'[','0',';','0',';','0','m','\0' };
 
1925
    const char t_red[]    = { 0x1b,'[','4',';','3','1',';','5','9','m','\0' };
 
1926
    const char t_bold[]   = { 0x1b,'[','1','m','\0' };
 
1927
    const char t_purple[] = { 0x1b,'[','0',';','3','5',';','5','9','m','\0' };
 
1928
    const char t_green[]  = { 0x1b,'[','0',';','3','2',';','5','9','m','\0' };
 
1929
#else
 
1930
    const char t_normal[] = { '\0' };
 
1931
    const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal,
 
1932
      *const t_purple = cimg::t_normal, *const t_green = cimg::t_normal;
 
1933
#endif
 
1934
 
637
1935
    inline void info();
638
1936
 
639
 
    inline unsigned int& exception_mode();
 
1937
    //! Get/set the current CImg exception mode.
 
1938
    /**
 
1939
       The way error messages are handled by CImg can be changed dynamically, using this function.
 
1940
       Possible values are :
 
1941
       - 0 to hide debug messages (quiet mode, but exceptions are still thrown).
 
1942
       - 1 to display debug messages on standard error (stderr).
 
1943
       - 2 to display debug messages in modal windows (default behavior).
 
1944
       - 3 to do as 1 + add extra warnings (may slow down the code !).
 
1945
       - 4 to do as 2 + add extra warnings (may slow down the code !).
 
1946
     **/
 
1947
    inline unsigned int& exception_mode() { static unsigned int mode = cimg_debug; return mode; }
640
1948
 
641
1949
    inline int dialog(const char *title, const char *msg, const char *button1_txt="OK",
642
1950
                      const char *button2_txt=0, const char *button3_txt=0,
659
1967
                                 CImgList<tp>& points, CImgList<tf>& primitives);
660
1968
  }
661
1969
 
662
 
  /*
663
 
   #----------------------------------------------
664
 
   #
 
1970
  /*----------------------------------------------
665
1971
   #
666
1972
   # Definition of the CImgException structures
667
1973
   #
668
 
   #
669
 
   #----------------------------------------------
670
 
   */
671
 
 
672
 
  // Never use the following macro in your own code !
673
 
#define cimg_exception_err(etype,disp_flag) \
674
 
  std::va_list ap; \
675
 
  va_start(ap,format); \
676
 
  std::vsprintf(message,format,ap); \
677
 
  va_end(ap); \
678
 
  if (cimg::exception_mode()>=1) { \
679
 
    if (cimg::exception_mode()>=2 && disp_flag) { \
680
 
      try { cimg::dialog(etype,message,"Abort"); } \
681
 
      catch (CImgException&) { std::fprintf(stderr,"\n# %s :\n%s\n\n",etype,message); } \
682
 
    } else std::fprintf(stderr,"\n# %s :\n%s\n\n",etype,message); \
683
 
  } \
684
 
  if (cimg::exception_mode()>=3) cimg_library::cimg::info(); \
685
 
 
686
 
  //! Class which is thrown when an error occured during a %CImg library function call.
 
1974
   ----------------------------------------------*/
 
1975
  //! Instances of this class are thrown when errors occur during a %CImg library function call.
687
1976
  /**
688
 
 
689
 
      \section ex1 Overview
 
1977
     \section ex1 Overview
690
1978
 
691
1979
      CImgException is the base class of %CImg exceptions.
692
1980
      Exceptions are thrown by the %CImg Library when an error occured in a %CImg library function call.
749
2037
      \endcode
750
2038
  **/
751
2039
  struct CImgException {
 
2040
#define _cimg_exception_err(etype,disp_flag) \
 
2041
  std::va_list ap; va_start(ap,format); std::vsprintf(message,format,ap); va_end(ap); \
 
2042
  switch (cimg::exception_mode()) { \
 
2043
  case 0: break; \
 
2044
  case 2: case 4: try { cimg::dialog(etype,message,"Abort"); } catch (CImgException&) { \
 
2045
    std::fprintf(stderr,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
 
2046
  } break; \
 
2047
  default: std::fprintf(stderr,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
 
2048
  } \
 
2049
  if (cimg::exception_mode()>=3) cimg_library::cimg::info();
 
2050
 
752
2051
    char message[1024]; //!< Message associated with the error that thrown the exception.
753
2052
    CImgException() { message[0]='\0'; }
754
 
    CImgException(const char *format,...) { cimg_exception_err("CImgException",true); }
 
2053
    CImgException(const char *format, ...) { _cimg_exception_err("CImgException",true); }
755
2054
  };
756
2055
 
757
2056
  // The \ref CImgInstanceException class is used to throw an exception related
758
2057
  // to a non suitable instance encountered in a library function call.
759
 
  struct CImgInstanceException : public CImgException {
760
 
    CImgInstanceException(const char *format,...) { cimg_exception_err("CImgInstanceException",true); }
 
2058
  struct CImgInstanceException: public CImgException {
 
2059
    CImgInstanceException(const char *format, ...) { _cimg_exception_err("CImgInstanceException",true); }
761
2060
  };
762
2061
 
763
2062
  // The \ref CImgArgumentException class is used to throw an exception related
764
2063
  // to invalid arguments encountered in a library function call.
765
 
  struct CImgArgumentException : public CImgException {
766
 
    CImgArgumentException(const char *format,...) { cimg_exception_err("CImgArgumentException",true); }
 
2064
  struct CImgArgumentException: public CImgException {
 
2065
    CImgArgumentException(const char *format, ...) { _cimg_exception_err("CImgArgumentException",true); }
767
2066
  };
768
2067
 
769
2068
  // The \ref CImgIOException class is used to throw an exception related
770
2069
  // to Input/Output file problems encountered in a library function call.
771
 
  struct CImgIOException : public CImgException {
772
 
    CImgIOException(const char *format,...) { cimg_exception_err("CImgIOException",true); }
 
2070
  struct CImgIOException: public CImgException {
 
2071
    CImgIOException(const char *format, ...) { _cimg_exception_err("CImgIOException",true); }
773
2072
  };
774
2073
 
775
2074
  // The CImgDisplayException class is used to throw an exception related to display problems
776
2075
  // encountered in a library function call.
777
 
  struct CImgDisplayException : public CImgException {
778
 
    CImgDisplayException(const char *format,...) { cimg_exception_err("CImgDisplayException",false); }
779
 
  };
780
 
 
781
 
  /*
782
 
   #-------------------------------------
783
 
   #
 
2076
  struct CImgDisplayException: public CImgException {
 
2077
    CImgDisplayException(const char *format, ...) { _cimg_exception_err("CImgDisplayException",false); }
 
2078
  };
 
2079
 
 
2080
  // The CImgWarningException class is used to throw an exception for warnings
 
2081
  // encountered in a library function call.
 
2082
  struct CImgWarningException: public CImgException {
 
2083
    CImgWarningException(const char *format, ...) { _cimg_exception_err("CImgWarningException",false); }
 
2084
  };
 
2085
 
 
2086
  /*-------------------------------------
784
2087
   #
785
2088
   # Definition of the namespace 'cimg'
786
2089
   #
787
 
   #
788
 
   #-------------------------------------
789
 
   */
790
 
 
 
2090
   --------------------------------------*/
791
2091
  //! Namespace that encompasses \a low-level functions and variables of the %CImg Library.
792
2092
  /**
793
2093
     Most of the functions and variables within this namespace are used by the library for low-level processing.
794
2094
     Nevertheless, documented variables and functions of this namespace may be used safely in your own source code.
795
2095
 
796
2096
     \warning Never write <tt>using namespace cimg_library::cimg;</tt> in your source code, since a lot of functions of the
797
 
     <tt>cimg::</tt> namespace have prototypes similar to standard C functions defined in the global namespace <tt>::</tt>.
 
2097
     <tt>cimg::</tt> namespace have prototypes similar to standard C functions that could defined in the global namespace <tt>::</tt>.
798
2098
  **/
799
2099
  namespace cimg {
800
2100
 
801
 
    // Define the trait that will be used to determine the best data type to work with.
802
 
    // Considered types are : bool, uchar, char, short, ushort, int, uint, long, ulong, float and double.
803
 
    // Two rules applies there :
804
 
    // - largest of two integer types is an integer type.
805
 
    // - largest of integer/float type is a float type.
806
 
    template<typename T,typename t> struct largest          { typedef T type; };
807
 
    template<> struct largest<bool,unsigned char>           { typedef unsigned char type; };
808
 
    template<> struct largest<bool,char>                    { typedef char type; };
809
 
    template<> struct largest<bool,unsigned short>          { typedef unsigned short type; };
810
 
    template<> struct largest<bool,short>                   { typedef short type; };
811
 
    template<> struct largest<bool,unsigned int>            { typedef unsigned int type; };
812
 
    template<> struct largest<bool,int>                     { typedef int type; };
813
 
    template<> struct largest<bool,unsigned long>           { typedef unsigned long type; };
814
 
    template<> struct largest<bool,long>                    { typedef long type; };
815
 
    template<> struct largest<bool,float>                   { typedef float type; };
816
 
    template<> struct largest<bool,double>                  { typedef double type; };
817
 
    template<> struct largest<unsigned char,char>           { typedef short type; };
818
 
    template<> struct largest<unsigned char,unsigned short> { typedef unsigned short type; };
819
 
    template<> struct largest<unsigned char,short>          { typedef short type; };
820
 
    template<> struct largest<unsigned char,unsigned int>   { typedef unsigned int type; };
821
 
    template<> struct largest<unsigned char,int>            { typedef int type; };
822
 
    template<> struct largest<unsigned char,unsigned long>  { typedef unsigned long type; };
823
 
    template<> struct largest<unsigned char,long>           { typedef long type; };
824
 
    template<> struct largest<unsigned char,float>          { typedef float type; };
825
 
    template<> struct largest<unsigned char,double>         { typedef double type; };
826
 
    template<> struct largest<char,unsigned char>           { typedef short type; };
827
 
    template<> struct largest<char,unsigned short>          { typedef int type; };
828
 
    template<> struct largest<char,short>                   { typedef short type; };
829
 
    template<> struct largest<char,unsigned int>            { typedef long type; };
830
 
    template<> struct largest<char,int>                     { typedef int type; };
831
 
    template<> struct largest<char,unsigned long>           { typedef long type; };
832
 
    template<> struct largest<char,long>                    { typedef long type; };
833
 
    template<> struct largest<char,float>                   { typedef float type; };
834
 
    template<> struct largest<char,double>                  { typedef double type; };
835
 
    template<> struct largest<unsigned short,char>          { typedef int type; };
836
 
    template<> struct largest<unsigned short,short>         { typedef int type; };
837
 
    template<> struct largest<unsigned short,unsigned int>  { typedef unsigned int type; };
838
 
    template<> struct largest<unsigned short,int>           { typedef int type; };
839
 
    template<> struct largest<unsigned short,unsigned long> { typedef unsigned long type; };
840
 
    template<> struct largest<unsigned short,long>          { typedef long type; };
841
 
    template<> struct largest<unsigned short,float>         { typedef float type; };
842
 
    template<> struct largest<unsigned short,double>        { typedef double type; };
843
 
    template<> struct largest<short,unsigned short>         { typedef int type; };
844
 
    template<> struct largest<short,unsigned int>           { typedef long type; };
845
 
    template<> struct largest<short,int>                    { typedef int type; };
846
 
    template<> struct largest<short,unsigned long>          { typedef long type; };
847
 
    template<> struct largest<short,long>                   { typedef long type; };
848
 
    template<> struct largest<short,float>                  { typedef float type; };
849
 
    template<> struct largest<short,double>                 { typedef double type; };
850
 
    template<> struct largest<unsigned int,char>            { typedef long type; };
851
 
    template<> struct largest<unsigned int,short>           { typedef long type; };
852
 
    template<> struct largest<unsigned int,int>             { typedef long type; };
853
 
    template<> struct largest<unsigned int,unsigned long>   { typedef unsigned long type; };
854
 
    template<> struct largest<unsigned int,long>            { typedef long type; };
855
 
    template<> struct largest<unsigned int,float>           { typedef float type; };
856
 
    template<> struct largest<unsigned int,double>          { typedef double type; };
857
 
    template<> struct largest<int,unsigned int>             { typedef long type; };
858
 
    template<> struct largest<int,unsigned long>            { typedef long type; };
859
 
    template<> struct largest<int,long>                     { typedef long type; };
860
 
    template<> struct largest<int,float>                    { typedef float type; };
861
 
    template<> struct largest<int,double>                   { typedef double type; };
862
 
    template<> struct largest<unsigned long,char>           { typedef long type; };
863
 
    template<> struct largest<unsigned long,short>          { typedef long type; };
864
 
    template<> struct largest<unsigned long,int>            { typedef long type; };
865
 
    template<> struct largest<unsigned long,long>           { typedef long type; };
866
 
    template<> struct largest<unsigned long,float>          { typedef float type; };
867
 
    template<> struct largest<unsigned long,double>         { typedef double type; };
868
 
    template<> struct largest<long,float>                   { typedef float type; };
869
 
    template<> struct largest<long,double>                  { typedef double type; };
870
 
    template<> struct largest<float,double>                 { typedef double type; };
871
 
 
872
 
    template<typename t1, typename t2, typename t3> struct largest2 {
873
 
      typedef typename largest<t1,typename largest<t2,t3>::type>::type type;
874
 
    };
875
 
 
 
2101
    // Define the traits that will be used to determine the best data type to work with.
 
2102
    //
876
2103
    template<typename T> struct type {
877
 
      static T min()  { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); }
878
 
      static T max()  { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); }
 
2104
      static const char* string() {
 
2105
        static const char* s[] = { "unknown",   "unknown8",   "unknown16",  "unknown24",
 
2106
                                   "unknown32", "unknown40",  "unknown48",  "unknown56",
 
2107
                                   "unknown64", "unknown72",  "unknown80",  "unknown88",
 
2108
                                   "unknown96", "unknown104", "unknown112", "unknown120",
 
2109
                                   "unknown128" };
 
2110
        return s[(sizeof(T)<17)?sizeof(T):0];
 
2111
      }
879
2112
      static bool is_float() { return false; }
880
 
      static const char* id() {
881
 
        static const char *const s = "unknown",
882
 
          s1 = "unknown8", s2 = "unknown16", s3 = "unknown24", s4 = "unknown32",
883
 
          s5 = "unknown40", s6 = "unknown48", s7 = "unknown56", s8 = "unknown64",
884
 
          s9 = "unknown72", s10 = "unknown80", s11 = "unknown88", s12 = "unknown96",
885
 
          s13 = "unknown104", s14 = "unknown112", s15 = "unknown120", s16 = "unknown128";
886
 
        switch (sizeof(T)) {
887
 
        case 1: return s1; case 2: return s2; case 3: return s3; case 4: return s4;
888
 
        case 5: return s5; case 6: return s6; case 7: return s7; case 8: return s8;
889
 
        case 9: return s9; case 10: return s10; case 11: return s11; case 12: return s12;
890
 
        case 13: return s13; case 14: return s14; case 15: return s15; case 16: return s16;
891
 
        default: return s;
892
 
        }
893
 
        return s;
894
 
      }
 
2113
      static T min() { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); }
 
2114
      static T max() { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); }
 
2115
      static const char* format() { return "%s"; }
 
2116
      static const char* format(const T val) { static const char *s = "unknown"; return s; }
895
2117
    };
 
2118
 
896
2119
    template<> struct type<bool> {
 
2120
      static const char* string() { static const char *const s = "bool"; return s; }
 
2121
      static bool is_float() { return false; }
897
2122
      static bool min() { return false; }
898
2123
      static bool max() { return true; }
899
 
      static bool is_float() { return false; }
900
 
      static const char* id() { static const char *const s = "bool"; return s; }
 
2124
      static const char* format() { return "%s"; }
 
2125
      static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; }
901
2126
    };
 
2127
 
902
2128
    template<> struct type<unsigned char> {
 
2129
      static const char* string() { static const char *const s = "unsigned char"; return s; }
 
2130
      static bool is_float() { return false; }
903
2131
      static unsigned char min() { return 0; }
904
2132
      static unsigned char max() { return (unsigned char)~0U; }
905
 
      static bool is_float() { return false; }
906
 
      static const char* id() { static const char *const s = "unsigned char"; return s; }
 
2133
      static const char* format() { return "%u"; }
 
2134
      static unsigned int format(const unsigned char val) { return (unsigned int)val; }
907
2135
    };
 
2136
 
908
2137
    template<> struct type<char> {
 
2138
      static const char* string() { static const char *const s = "char"; return s; }
 
2139
      static bool is_float() { return false; }
909
2140
      static char min() { return (char)(-1L<<(8*sizeof(char)-1)); }
910
2141
      static char max() { return ~((char)(-1L<<(8*sizeof(char)-1))); }
911
 
      static bool is_float() { return false; }
912
 
      static const char* id() { static const char *const s = "char"; return s; }
 
2142
      static const char* format() { return "%d"; }
 
2143
      static int format(const char val) { return (int)val; }
913
2144
    };
 
2145
 
914
2146
    template<> struct type<unsigned short> {
 
2147
      static const char* string() { static const char *const s = "unsigned short"; return s; }
 
2148
      static bool is_float() { return false; }
915
2149
      static unsigned short min() { return 0; }
916
2150
      static unsigned short max() { return (unsigned short)~0U; }
917
 
      static bool is_float() { return false; }
918
 
      static const char* id() { static const char *const s = "unsigned short"; return s; }
 
2151
      static const char* format() { return "%u"; }
 
2152
      static unsigned int format(const unsigned short val) { return (unsigned int)val; }
919
2153
    };
 
2154
 
920
2155
    template<> struct type<short> {
 
2156
      static const char* string() { static const char *const s = "short"; return s; }
 
2157
      static bool is_float() { return false; }
921
2158
      static short min() { return (short)(-1L<<(8*sizeof(short)-1)); }
922
2159
      static short max() { return ~((short)(-1L<<(8*sizeof(short)-1))); }
923
 
      static bool is_float() { return false; }
924
 
      static const char* id() { static const char *const s = "short"; return s; }
 
2160
      static const char* format() { return "%d"; }
 
2161
      static int format(const short val) { return (int)val; }
925
2162
    };
 
2163
 
926
2164
    template<> struct type<unsigned int> {
 
2165
      static const char* string() { static const char *const s = "unsigned int"; return s; }
 
2166
      static bool is_float() { return false; }
927
2167
      static unsigned int min() { return 0; }
928
2168
      static unsigned int max() { return (unsigned int)~0U; }
929
 
      static bool is_float() { return false; }
930
 
      static const char* id() { static const char *const s = "unsigned int"; return s; }
 
2169
      static const char* format() { return "%u"; }
 
2170
      static unsigned int format(const unsigned int val) { return val; }
931
2171
    };
 
2172
 
932
2173
    template<> struct type<int> {
 
2174
      static const char* string() { static const char *const s = "int"; return s; }
 
2175
      static bool is_float() { return false; }
933
2176
      static int min() { return (int)(-1L<<(8*sizeof(int)-1)); }
934
2177
      static int max() { return ~((int)(-1L<<(8*sizeof(int)-1))); }
935
 
      static bool is_float() { return false; }
936
 
      static const char* id() { static const char *const s = "int"; return s; }
 
2178
      static const char* format() { return "%d"; }
 
2179
      static int format(const int val) { return val; }
937
2180
    };
 
2181
 
938
2182
    template<> struct type<unsigned long> {
 
2183
      static const char* string() { static const char *const s = "unsigned long"; return s; }
 
2184
      static bool is_float() { return false; }
939
2185
      static unsigned long min() { return 0; }
940
2186
      static unsigned long max() { return (unsigned long)~0UL; }
941
 
      static bool is_float() { return false; }
942
 
      static const char* id() { static const char *const s = "unsigned long"; return s; }
 
2187
      static const char* format() { return "%lu"; }
 
2188
      static unsigned long format(const unsigned long val) { return val; }
943
2189
    };
 
2190
 
944
2191
    template<> struct type<long> {
 
2192
      static const char* string() { static const char *const s = "long"; return s; }
 
2193
      static bool is_float() { return false; }
945
2194
      static long min() { return (long)(-1L<<(8*sizeof(long)-1)); }
946
2195
      static long max() { return ~((long)(-1L<<(8*sizeof(long)-1))); }
947
 
      static bool is_float() { return false; }
948
 
      static const char* id() { static const char *const s = "long"; return s; }
 
2196
      static const char* format() { return "%ld"; }
 
2197
      static long format(const long val) { return val; }
949
2198
    };
 
2199
 
950
2200
    template<> struct type<float> {
 
2201
      static const char* string() { static const char *const s = "float"; return s; }
 
2202
      static bool is_float() { return true; }
951
2203
      static float min() { return -3.4E38f; }
952
2204
      static float max() { return  3.4E38f; }
953
 
      static bool is_float() { return true; }
954
 
      static const char* id() { static const char *const s = "float"; return s; }
 
2205
      static const char* format() { return "%g"; }
 
2206
      static double format(const float val) { return (double)val; }
955
2207
    };
 
2208
 
956
2209
    template<> struct type<double> {
 
2210
      static const char* string() { static const char *const s = "double"; return s; }
 
2211
      static bool is_float() { return true; }
957
2212
      static double min() { return -1.7E308; }
958
2213
      static double max() { return  1.7E308; }
959
 
      static bool is_float() { return true; }
960
 
      static const char* id() { static const char *const s = "double"; return s; }
961
 
    };
962
 
 
963
 
    template<typename T, typename t> struct last { typedef t type; };
 
2214
      static const char* format() { return "%g"; }
 
2215
      static double format(const double val) { return val; }
 
2216
    };
 
2217
 
 
2218
    template<typename T, typename t> struct superset { typedef T type; };
 
2219
    template<> struct superset<bool,unsigned char> { typedef unsigned char type; };
 
2220
    template<> struct superset<bool,char> { typedef char type; };
 
2221
    template<> struct superset<bool,unsigned short> { typedef unsigned short type; };
 
2222
    template<> struct superset<bool,short> { typedef short type; };
 
2223
    template<> struct superset<bool,unsigned int> { typedef unsigned int type; };
 
2224
    template<> struct superset<bool,int> { typedef int type; };
 
2225
    template<> struct superset<bool,unsigned long> { typedef unsigned long type; };
 
2226
    template<> struct superset<bool,long> { typedef long type; };
 
2227
    template<> struct superset<bool,float> { typedef float type; };
 
2228
    template<> struct superset<bool,double> { typedef double type; };
 
2229
    template<> struct superset<unsigned char,char> { typedef short type; };
 
2230
    template<> struct superset<unsigned char,unsigned short> { typedef unsigned short type; };
 
2231
    template<> struct superset<unsigned char,short> { typedef short type; };
 
2232
    template<> struct superset<unsigned char,unsigned int> { typedef unsigned int type; };
 
2233
    template<> struct superset<unsigned char,int> { typedef int type; };
 
2234
    template<> struct superset<unsigned char,unsigned long> { typedef unsigned long type; };
 
2235
    template<> struct superset<unsigned char,long> { typedef long type; };
 
2236
    template<> struct superset<unsigned char,float> { typedef float type; };
 
2237
    template<> struct superset<unsigned char,double> { typedef double type; };
 
2238
    template<> struct superset<char,unsigned char> { typedef short type; };
 
2239
    template<> struct superset<char,unsigned short> { typedef int type; };
 
2240
    template<> struct superset<char,short> { typedef short type; };
 
2241
    template<> struct superset<char,unsigned int> { typedef long type; };
 
2242
    template<> struct superset<char,int> { typedef int type; };
 
2243
    template<> struct superset<char,unsigned long> { typedef long type; };
 
2244
    template<> struct superset<char,long> { typedef long type; };
 
2245
    template<> struct superset<char,float> { typedef float type; };
 
2246
    template<> struct superset<char,double> { typedef double type; };
 
2247
    template<> struct superset<unsigned short,char> { typedef int type; };
 
2248
    template<> struct superset<unsigned short,short> { typedef int type; };
 
2249
    template<> struct superset<unsigned short,unsigned int> { typedef unsigned int type; };
 
2250
    template<> struct superset<unsigned short,int> { typedef int type; };
 
2251
    template<> struct superset<unsigned short,unsigned long> { typedef unsigned long type; };
 
2252
    template<> struct superset<unsigned short,long> { typedef long type; };
 
2253
    template<> struct superset<unsigned short,float> { typedef float type; };
 
2254
    template<> struct superset<unsigned short,double> { typedef double type; };
 
2255
    template<> struct superset<short,unsigned short> { typedef int type; };
 
2256
    template<> struct superset<short,unsigned int> { typedef long type; };
 
2257
    template<> struct superset<short,int> { typedef int type; };
 
2258
    template<> struct superset<short,unsigned long> { typedef long type; };
 
2259
    template<> struct superset<short,long> { typedef long type; };
 
2260
    template<> struct superset<short,float> { typedef float type; };
 
2261
    template<> struct superset<short,double> { typedef double type; };
 
2262
    template<> struct superset<unsigned int,char> { typedef long type; };
 
2263
    template<> struct superset<unsigned int,short> { typedef long type; };
 
2264
    template<> struct superset<unsigned int,int> { typedef long type; };
 
2265
    template<> struct superset<unsigned int,unsigned long> { typedef unsigned long type; };
 
2266
    template<> struct superset<unsigned int,long> { typedef long type; };
 
2267
    template<> struct superset<unsigned int,float> { typedef float type; };
 
2268
    template<> struct superset<unsigned int,double> { typedef double type; };
 
2269
    template<> struct superset<int,unsigned int> { typedef long type; };
 
2270
    template<> struct superset<int,unsigned long> { typedef long type; };
 
2271
    template<> struct superset<int,long> { typedef long type; };
 
2272
    template<> struct superset<int,float> { typedef float type; };
 
2273
    template<> struct superset<int,double> { typedef double type; };
 
2274
    template<> struct superset<unsigned long,char> { typedef long type; };
 
2275
    template<> struct superset<unsigned long,short> { typedef long type; };
 
2276
    template<> struct superset<unsigned long,int> { typedef long type; };
 
2277
    template<> struct superset<unsigned long,long> { typedef long type; };
 
2278
    template<> struct superset<unsigned long,float> { typedef float type; };
 
2279
    template<> struct superset<unsigned long,double> { typedef double type; };
 
2280
    template<> struct superset<long,float> { typedef float type; };
 
2281
    template<> struct superset<long,double> { typedef double type; };
 
2282
    template<> struct superset<float,double> { typedef double type; };
 
2283
 
 
2284
    template<typename t1, typename t2, typename t3> struct superset2 {
 
2285
      typedef typename superset<t1, typename superset<t2,t3>::type>::type type;
 
2286
    };
 
2287
 
 
2288
    template<typename t1, typename t2, typename t3, typename t4> struct superset3 {
 
2289
      typedef typename superset<t1, typename superset2<t2,t3,t4>::type>::type type;
 
2290
    };
 
2291
 
 
2292
    template<typename t1, typename t2> struct last { typedef t2 type; };
 
2293
 
 
2294
#define _cimg_Tuchar  typename cimg::superset<T,unsigned char>::type
 
2295
#define _cimg_Tint    typename cimg::superset<T,int>::type
 
2296
#define _cimg_Tfloat  typename cimg::superset<T,float>::type
 
2297
#define _cimg_Tdouble typename cimg::superset<T,double>::type
 
2298
#define _cimg_Tt      typename cimg::superset<T,t>::type
964
2299
 
965
2300
    // Define internal library variables.
966
 
#if cimg_display_type==1
 
2301
    //
 
2302
#if cimg_display==1
967
2303
    struct X11info {
968
2304
      volatile unsigned int nb_wins;
969
 
      pthread_mutex_t* mutex;
970
2305
      pthread_t*       event_thread;
971
2306
      CImgDisplay*     wins[1024];
972
2307
      Display*         display;
981
2316
      unsigned int curr_resolution;
982
2317
      unsigned int nb_resolutions;
983
2318
#endif
984
 
      X11info():nb_wins(0),mutex(0),event_thread(0),display(0),
 
2319
      X11info():nb_wins(0),event_thread(0),display(0),
985
2320
                nb_bits(0),gc(0),blue_first(false),byte_order(false),shm_enabled(false) {
986
2321
#ifdef cimg_use_xrandr
987
2322
        resolutions = 0;
998
2333
    inline X11info& X11attr() { static X11info val; return val; }
999
2334
#endif
1000
2335
 
1001
 
#elif cimg_display_type==2
 
2336
#elif cimg_display==2
1002
2337
    struct Win32info {
1003
2338
      HANDLE wait_event;
1004
2339
      Win32info() { wait_event = CreateEvent(0,FALSE,FALSE,0); }
1010
2345
#else
1011
2346
    inline Win32info& Win32attr() { static Win32info val; return val; }
1012
2347
#endif
1013
 
#endif
1014
 
 
1015
 
    inline unsigned int& exception_mode() { static unsigned int mode = cimg_debug; return mode; }
1016
 
 
1017
 
#ifdef cimg_color_terminal
1018
 
    const char t_normal[] = { 0x1b,'[','0',';','0',';','0','m','\0' };
1019
 
    const char t_red[]    = { 0x1b,'[','4',';','3','1',';','5','9','m','\0' };
1020
 
    const char t_bold[]   = { 0x1b,'[','1','m','\0' };
1021
 
    const char t_purple[] = { 0x1b,'[','0',';','3','5',';','5','9','m','\0' };
 
2348
 
 
2349
#elif cimg_display==3
 
2350
    struct CarbonInfo {
 
2351
      MPCriticalRegionID windowListCR; // Protects access to the list of windows
 
2352
      int windowCount;                 // Count of displays used on the screen
 
2353
      pthread_t event_thread;          // The background event thread
 
2354
      MPSemaphoreID sync_event;        // Event used to perform tasks synchronizations
 
2355
      MPSemaphoreID wait_event;        // Event used to notify that new events occured on the display
 
2356
      MPQueueID com_queue;             // The message queue
 
2357
      CarbonInfo(): windowCount(0),event_thread(0),sync_event(0),com_queue(0) {
 
2358
        if (MPCreateCriticalRegion(&windowListCR) != noErr) // Create the critical region
 
2359
          throw CImgDisplayException("MPCreateCriticalRegion failed.");
 
2360
        if (MPCreateSemaphore(1, 0, &sync_event) != noErr) // Create the inter-thread sync object
 
2361
          throw CImgDisplayException("MPCreateSemaphore failed.");
 
2362
        if (MPCreateSemaphore(1, 0, &wait_event) != noErr) // Create the event sync object
 
2363
          throw CImgDisplayException("MPCreateSemaphore failed.");
 
2364
        if (MPCreateQueue(&com_queue) != noErr) // Create the shared queue
 
2365
          throw CImgDisplayException("MPCreateQueue failed.");
 
2366
      }
 
2367
      ~CarbonInfo() {
 
2368
        if (event_thread != 0) { // Terminates the resident thread, if needed
 
2369
          pthread_cancel(event_thread);
 
2370
          pthread_join(event_thread, NULL);
 
2371
          event_thread = 0;
 
2372
        }
 
2373
        if (MPDeleteCriticalRegion(windowListCR) != noErr) // Delete the critical region
 
2374
          throw CImgDisplayException("MPDeleteCriticalRegion failed.");
 
2375
        if (MPDeleteSemaphore(wait_event) != noErr) // Delete the event sync event
 
2376
          throw CImgDisplayException("MPDeleteEvent failed.");
 
2377
        if (MPDeleteSemaphore(sync_event) != noErr) // Delete the inter-thread sync event
 
2378
          throw CImgDisplayException("MPDeleteEvent failed.");
 
2379
        if (MPDeleteQueue(com_queue) != noErr) // Delete the shared queue
 
2380
          throw CImgDisplayException("MPDeleteQueue failed.");
 
2381
      }
 
2382
    };
 
2383
#if defined(cimg_module)
 
2384
    CarbonInfo& CarbonAttr();
 
2385
#elif defined(cimg_main)
 
2386
    CarbonInfo CarbonAttr() { static CarbonInfo val; return val; }
1022
2387
#else
1023
 
    const char t_normal[] = { '\0' };
1024
 
    const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal, *const t_purple = cimg::t_normal;
 
2388
    inline CarbonInfo& CarbonAttr() { static CarbonInfo val; return val; }
 
2389
#endif
1025
2390
#endif
1026
2391
 
1027
 
#if cimg_display_type==1
1028
 
    // Keycodes for X11-based graphical systems
 
2392
#if cimg_display==1
 
2393
    // Keycodes for X11-based graphical systems.
 
2394
    //
1029
2395
    const unsigned int keyESC        = XK_Escape;
1030
2396
    const unsigned int keyF1         = XK_F1;
1031
2397
    const unsigned int keyF2         = XK_F2;
1114
2480
    const unsigned int keyPADMUL     = XK_KP_Multiply;
1115
2481
    const unsigned int keyPADDIV     = XK_KP_Divide;
1116
2482
 
1117
 
#elif (cimg_display_type==2 && cimg_OS==2)
1118
 
    // Keycodes for Windows-OS
 
2483
#elif cimg_display==2
 
2484
    // Keycodes for Windows.
 
2485
    //
1119
2486
    const unsigned int keyESC        = VK_ESCAPE;
1120
2487
    const unsigned int keyF1         = VK_F1;
1121
2488
    const unsigned int keyF2         = VK_F2;
1203
2570
    const unsigned int keyPADSUB     = VK_SUBTRACT;
1204
2571
    const unsigned int keyPADMUL     = VK_MULTIPLY;
1205
2572
    const unsigned int keyPADDIV     = VK_DIVIDE;
 
2573
 
 
2574
#elif cimg_display==3
 
2575
    // Keycodes for MacOSX, when using the Carbon framework.
 
2576
    //
 
2577
    const unsigned int keyESC        = kEscapeCharCode;
 
2578
    const unsigned int keyF1         = 2U;
 
2579
    const unsigned int keyF2         = 3U;
 
2580
    const unsigned int keyF3         = 4U;
 
2581
    const unsigned int keyF4         = 5U;
 
2582
    const unsigned int keyF5         = 6U;
 
2583
    const unsigned int keyF6         = 7U;
 
2584
    const unsigned int keyF7         = 8U;
 
2585
    const unsigned int keyF8         = 9U;
 
2586
    const unsigned int keyF9         = 10U;
 
2587
    const unsigned int keyF10        = 11U;
 
2588
    const unsigned int keyF11        = 12U;
 
2589
    const unsigned int keyF12        = 13U;
 
2590
    const unsigned int keyPAUSE      = 14U;
 
2591
    const unsigned int key1          = '1';
 
2592
    const unsigned int key2          = '2';
 
2593
    const unsigned int key3          = '3';
 
2594
    const unsigned int key4          = '4';
 
2595
    const unsigned int key5          = '5';
 
2596
    const unsigned int key6          = '6';
 
2597
    const unsigned int key7          = '7';
 
2598
    const unsigned int key8          = '8';
 
2599
    const unsigned int key9          = '9';
 
2600
    const unsigned int key0          = '0';
 
2601
    const unsigned int keyBACKSPACE  = kBackspaceCharCode;
 
2602
    const unsigned int keyINSERT     = 26U;
 
2603
    const unsigned int keyHOME       = kHomeCharCode;
 
2604
    const unsigned int keyPAGEUP     = kPageUpCharCode;
 
2605
    const unsigned int keyTAB        = kTabCharCode;
 
2606
    const unsigned int keyQ          = 'q';
 
2607
    const unsigned int keyW          = 'w';
 
2608
    const unsigned int keyE          = 'e';
 
2609
    const unsigned int keyR          = 'r';
 
2610
    const unsigned int keyT          = 't';
 
2611
    const unsigned int keyY          = 'y';
 
2612
    const unsigned int keyU          = 'u';
 
2613
    const unsigned int keyI          = 'i';
 
2614
    const unsigned int keyO          = 'o';
 
2615
    const unsigned int keyP          = 'p';
 
2616
    const unsigned int keyDELETE     = kDeleteCharCode;
 
2617
    const unsigned int keyEND        = kEndCharCode;
 
2618
    const unsigned int keyPAGEDOWN   = kPageDownCharCode;
 
2619
    const unsigned int keyCAPSLOCK   = 43U;
 
2620
    const unsigned int keyA          = 'a';
 
2621
    const unsigned int keyS          = 's';
 
2622
    const unsigned int keyD          = 'd';
 
2623
    const unsigned int keyF          = 'f';
 
2624
    const unsigned int keyG          = 'g';
 
2625
    const unsigned int keyH          = 'h';
 
2626
    const unsigned int keyJ          = 'j';
 
2627
    const unsigned int keyK          = 'k';
 
2628
    const unsigned int keyL          = 'l';
 
2629
    const unsigned int keyENTER      = kEnterCharCode;
 
2630
    const unsigned int keySHIFTLEFT  = 54U; //Macintosh modifier key, emulated
 
2631
    const unsigned int keyZ          = 'z';
 
2632
    const unsigned int keyX          = 'x';
 
2633
    const unsigned int keyC          = 'c';
 
2634
    const unsigned int keyV          = 'v';
 
2635
    const unsigned int keyB          = 'b';
 
2636
    const unsigned int keyN          = 'n';
 
2637
    const unsigned int keyM          = 'm';
 
2638
    const unsigned int keySHIFTRIGHT = 62U; //Macintosh modifier key, emulated
 
2639
    const unsigned int keyARROWUP    = kUpArrowCharCode;
 
2640
    const unsigned int keyCTRLLEFT   = 64U; //Macintosh modifier key, emulated
 
2641
    const unsigned int keyAPPLEFT    = 65U; //Macintosh modifier key, emulated
 
2642
    const unsigned int keySPACE      = kSpaceCharCode;
 
2643
    const unsigned int keyALTGR      = 67U; //Macintosh modifier key, emulated
 
2644
    const unsigned int keyAPPRIGHT   = 68U; //Aliased on keyAPPLEFT
 
2645
    const unsigned int keyMENU       = 69U;
 
2646
    const unsigned int keyCTRLRIGHT  = 70U; //Macintosh modifier key, emulated
 
2647
    const unsigned int keyARROWLEFT  = kLeftArrowCharCode;
 
2648
    const unsigned int keyARROWDOWN  = kDownArrowCharCode;
 
2649
    const unsigned int keyARROWRIGHT = kRightArrowCharCode;
 
2650
    const unsigned int keyPAD0       = 74U;
 
2651
    const unsigned int keyPAD1       = 75U;
 
2652
    const unsigned int keyPAD2       = 76U;
 
2653
    const unsigned int keyPAD3       = 77U;
 
2654
    const unsigned int keyPAD4       = 78U;
 
2655
    const unsigned int keyPAD5       = 79U;
 
2656
    const unsigned int keyPAD6       = 80U;
 
2657
    const unsigned int keyPAD7       = 81U;
 
2658
    const unsigned int keyPAD8       = 82U;
 
2659
    const unsigned int keyPAD9       = 83U;
 
2660
    const unsigned int keyPADADD     = 84U;
 
2661
    const unsigned int keyPADSUB     = 85U;
 
2662
    const unsigned int keyPADMUL     = 86U;
 
2663
    const unsigned int keyPADDIV     = 87U;
 
2664
 
1206
2665
#else
1207
 
    // Define unknow keycodes when no display
 
2666
    // Define unknow keycodes when no display are available.
 
2667
    // (should rarely be used then !).
 
2668
    //
1208
2669
    const unsigned int keyESC        = 1U;
1209
2670
    const unsigned int keyF1         = 2U;
1210
2671
    const unsigned int keyF2         = 3U;
1294
2755
    const unsigned int keyPADDIV     = 87U;
1295
2756
#endif
1296
2757
 
1297
 
    const double PI = 3.14159265358979323846;   //!< Definition of the mathematical constant PI
 
2758
    const double valuePI = 3.14159265358979323846;   //!< Definition of the mathematical constant PI
1298
2759
 
1299
2760
    // Definition of a 7x11 font, used to return a default font for drawing text.
1300
2761
    const unsigned int font7x11[7*11*256/32] = {
1400
2861
      0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040
1401
2862
    };
1402
2863
 
1403
 
    // Definition of a 8x17 font
 
2864
    // Definition of a 8x17 font.
1404
2865
    const unsigned int font8x17[8*17*256/32] = {
1405
2866
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
1406
2867
      0x0,0x0,0x0,0x2400,0x2400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20081834,0x1c0000,0x20081800,0x20081800,0x342008,
1467
2928
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
1468
2929
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
1469
2930
 
1470
 
    // Definition of a 10x19 font
 
2931
    // Definition of a 10x19 font.
1471
2932
    const unsigned int font10x19[10*19*256/32] = {
1472
2933
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
1473
2934
      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,
1562
3023
      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,
1563
3024
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
1564
3025
 
1565
 
    // Definition of a 12x24 font
 
3026
    // Definition of a 12x24 font.
1566
3027
     const unsigned int font12x24[12*24*256/32] = {
1567
3028
       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
1568
3029
       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,
1701
3162
       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
1702
3163
       0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
1703
3164
 
1704
 
    // Definition of a 16x32 font
 
3165
    // Definition of a 16x32 font.
1705
3166
    const unsigned int font16x32[16*32*256/32] = {
1706
3167
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
1707
3168
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
1935
3396
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
1936
3397
      0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
1937
3398
 
1938
 
    // Definition of a 19x38 font
 
3399
    // Definition of a 19x38 font.
1939
3400
    const unsigned int font19x38[19*38*256/32] = {
1940
3401
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
1941
3402
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2261
3722
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2262
3723
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
2263
3724
 
2264
 
    // Definition of a 29x57 font
 
3725
    // Definition of a 29x57 font.
2265
3726
    const unsigned int font29x57[29*57*256/32] = {
2266
3727
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2267
3728
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2972
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,0x0,0x0,0x0,0x0,
2973
4434
      0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
2974
4435
 
2975
 
    // Definition of a 40x38 'danger' color logo
 
4436
    // Definition of a 40x38 'danger' color logo.
2976
4437
    const unsigned char logo40x38[4576] = {
2977
4438
      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,
2978
4439
      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,
2999
4460
      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,
3000
4461
      200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0};
3001
4462
 
3002
 
    // Display a warning message.
3003
 
    inline void warn(const char *format,...) {
 
4463
    //! Display a warning message.
 
4464
    /**
 
4465
        \param format is a C-string describing the format of the message, as in <tt>std::printf()</tt>.
 
4466
    **/
 
4467
    inline void warn(const char *format, ...) {
3004
4468
      if (cimg::exception_mode()>=1) {
 
4469
        char message[8192];
3005
4470
        std::va_list ap;
3006
4471
        va_start(ap,format);
3007
 
        std::fprintf(stderr,"\n<CImg Warning> ");
3008
 
        std::vfprintf(stderr,format,ap);
3009
 
        std::fputc('\n',stderr);
 
4472
        std::vsprintf(message,format,ap);
3010
4473
        va_end(ap);
3011
 
      }
3012
 
    }
3013
 
 
 
4474
#ifdef cimg_strict_warnings
 
4475
        throw CImgWarningException(message);
 
4476
#else
 
4477
        std::fprintf(stderr,"\n%s# CImg Warning%s :\n%s\n",cimg::t_red,cimg::t_normal,message);
 
4478
#endif
 
4479
      }
 
4480
    }
 
4481
 
 
4482
    // Execute an external system command.
 
4483
    /**
 
4484
       \note This function is similar to <tt>std::system()</tt>
 
4485
       and is here because using the <tt>std::</tt> version on
 
4486
       Windows may open undesired consoles.
 
4487
     **/
 
4488
    inline void system(const char *command, const char *module_name=0) {
 
4489
#if cimg_OS==2
 
4490
      PROCESS_INFORMATION pi;
 
4491
      STARTUPINFO si;
 
4492
      std::memset(&pi, 0, sizeof(PROCESS_INFORMATION));
 
4493
      std::memset(&si, 0, sizeof(STARTUPINFO));
 
4494
      GetStartupInfo(&si);
 
4495
      si.cb = sizeof(si);
 
4496
      si.wShowWindow = SW_HIDE;
 
4497
      si.dwFlags |= SW_HIDE;
 
4498
      const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);
 
4499
      if (res) {
 
4500
        WaitForSingleObject(pi.hProcess, INFINITE);
 
4501
        CloseHandle(pi.hThread);
 
4502
        CloseHandle(pi.hProcess);
 
4503
      } else
 
4504
#endif
 
4505
      std::system(command);
 
4506
      command = module_name = 0;
 
4507
    }
 
4508
 
 
4509
    //! Exchange values of variables \p a and \p b.
 
4510
    template<typename T> inline void swap(T& a, T& b) { T t = a; a = b; b = t; }
 
4511
 
 
4512
    //! Exchange values of variables (\p a1,\p a2) and (\p b1,\p b2).
 
4513
    template<typename T1, typename T2> inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) {
 
4514
      cimg::swap(a1,b1); cimg::swap(a2,b2);
 
4515
    }
 
4516
 
 
4517
    //! Exchange values of variables (\p a1,\p a2,\p a3) and (\p b1,\p b2,\p b3).
 
4518
    template<typename T1, typename T2, typename T3> inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) {
 
4519
      cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3);
 
4520
    }
 
4521
 
 
4522
    //! Exchange values of variables (\p a1,\p a2,...,\p a4) and (\p b1,\p b2,...,\p b4).
 
4523
    template<typename T1, typename T2, typename T3, typename T4>
 
4524
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) {
 
4525
      cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);
 
4526
    }
 
4527
 
 
4528
    //! Exchange values of variables (\p a1,\p a2,...,\p a5) and (\p b1,\p b2,...,\p b5).
 
4529
    template<typename T1, typename T2, typename T3, typename T4, typename T5>
 
4530
    inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) {
 
4531
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);
 
4532
    }
 
4533
 
 
4534
    //! Exchange values of variables (\p a1,\p a2,...,\p a6) and (\p b1,\p b2,...,\p b6).
 
4535
    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
 
4536
    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) {
 
4537
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
 
4538
    }
 
4539
 
 
4540
    //! Exchange values of variables (\p a1,\p a2,...,\p a7) and (\p b1,\p b2,...,\p b7).
 
4541
    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
 
4542
    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,
 
4543
                     T7& a7, T7& b7) {
 
4544
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);
 
4545
    }
 
4546
 
 
4547
    //! Exchange values of variables (\p a1,\p a2,...,\p a8) and (\p b1,\p b2,...,\p b8).
 
4548
    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
 
4549
    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,
 
4550
                     T7& a7, T7& b7, T8& a8, T8& b8) {
 
4551
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);
 
4552
    }
 
4553
 
 
4554
    //! Return the current endianness of the CPU.
 
4555
    /**
 
4556
       \return \c false for "Little Endian", \c true for "Big Endian".
 
4557
    **/
 
4558
    inline bool endianness() {
 
4559
      const int x = 1;
 
4560
      return ((unsigned char*)&x)[0]?false:true;
 
4561
    }
 
4562
 
 
4563
    //! Invert endianness of a memory buffer.
 
4564
    template<typename T> inline void invert_endianness(T* const buffer, const unsigned int size) {
 
4565
      switch (sizeof(T)) {
 
4566
      case 1: break;
 
4567
      case 2: { for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer; ) {
 
4568
        const unsigned short val = *(--ptr);
 
4569
        *ptr = (unsigned short)((val>>8)|((val<<8)));
 
4570
      }} break;
 
4571
      case 4: { for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer; ) {
 
4572
        const unsigned int val = *(--ptr);
 
4573
        *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24);
 
4574
      }} break;
 
4575
      default: { for (T* ptr = buffer+size; ptr>buffer; ) {
 
4576
        unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);
 
4577
        for (int i=0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe));
 
4578
      }}
 
4579
      }
 
4580
    }
 
4581
 
 
4582
    //! Invert endianness of a single variable.
 
4583
    template<typename T> inline T& invert_endianness(T& a) {
 
4584
      invert_endianness(&a,1);
 
4585
      return a;
 
4586
    }
 
4587
 
 
4588
    //! Get the value of a system timer with a millisecond precision.
 
4589
    inline unsigned long time() {
 
4590
#if cimg_OS==1
 
4591
      struct timeval st_time;
 
4592
      gettimeofday(&st_time,0);
 
4593
      return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
 
4594
#elif cimg_OS==2
 
4595
      static SYSTEMTIME st_time;
 
4596
      GetSystemTime(&st_time);
 
4597
      return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
 
4598
#else
 
4599
      return 0;
 
4600
#endif
 
4601
    }
 
4602
 
 
4603
    //! Sleep for a certain numbers of milliseconds.
 
4604
    /**
 
4605
       This function frees the CPU ressources during the sleeping time.
 
4606
       It may be used to temporize your program properly, without wasting CPU time.
 
4607
    **/
 
4608
    inline void sleep(const unsigned int milliseconds) {
 
4609
#if cimg_OS==1
 
4610
      struct timespec tv;
 
4611
      tv.tv_sec = milliseconds/1000;
 
4612
      tv.tv_nsec = (milliseconds%1000)*1000000;
 
4613
      nanosleep(&tv,0);
 
4614
#elif cimg_OS==2
 
4615
      Sleep(milliseconds);
 
4616
#endif
 
4617
    }
 
4618
 
 
4619
    inline unsigned int _sleep(const unsigned int milliseconds, unsigned long& timer) {
 
4620
      if (!timer) timer = cimg::time();
 
4621
      const unsigned long current_time = cimg::time();
 
4622
      if (current_time>=timer+milliseconds) { timer = current_time; return 0; }
 
4623
      const unsigned long time_diff = timer + milliseconds - current_time;
 
4624
      timer = current_time + time_diff;
 
4625
      cimg::sleep(time_diff);
 
4626
      return (unsigned int)time_diff;
 
4627
    }
 
4628
 
 
4629
    //! Wait for a certain number of milliseconds since the last call.
 
4630
    /**
 
4631
       This function is equivalent to sleep() but the waiting time is computed with regard to the last call
 
4632
       of wait(). It may be used to temporize your program properly.
 
4633
    **/
 
4634
    inline unsigned int wait(const unsigned int milliseconds) {
 
4635
      static unsigned long timer = 0;
 
4636
      if (!timer) timer = cimg::time();
 
4637
      return _sleep(milliseconds,timer);
 
4638
    }
 
4639
 
 
4640
    // Use a specific srand initialization to avoid multi-threading problems
 
4641
    // (executed only one time for a single program).
 
4642
    inline void srand() {
 
4643
      static bool first_time = true;
 
4644
      if (first_time) {
 
4645
        std::srand(cimg::time());
 
4646
        unsigned char *const rand_mem = new unsigned char[1+std::rand()%2048];
 
4647
        std::srand((unsigned int)(std::rand() + (unsigned long)rand_mem));
 
4648
        delete[] rand_mem;
 
4649
        first_time = false;
 
4650
      }
 
4651
    }
 
4652
 
 
4653
    //! Return a left bitwise-rotated number.
 
4654
    template<typename T> inline const T rol(const T a, const unsigned int n=1) {
 
4655
      return n?(T)((a<<n)|(a>>((sizeof(T)<<3)-n))):a;
 
4656
    }
 
4657
 
 
4658
    //! Return a right bitwise-rotated number.
 
4659
    template<typename T> inline const T ror(const T a, const unsigned int n=1) {
 
4660
      return n?(T)((a>>n)|(a<<((sizeof(T)<<3)-n))):a;
 
4661
    }
 
4662
 
 
4663
    //! Return the absolute value of a number.
 
4664
    /**
 
4665
       \note This function is different from <tt>std::abs()</tt> or <tt>std::fabs()</tt>
 
4666
       because it is able to consider a variable of any type, without cast needed.
 
4667
    **/
 
4668
    template<typename T> inline T abs(const T a) {
 
4669
      return a>=0?a:-a;
 
4670
    }
 
4671
    inline bool abs(const bool a) {
 
4672
      return a;
 
4673
    }
 
4674
    inline unsigned char abs(const unsigned char a) {
 
4675
      return a;
 
4676
    }
 
4677
    inline unsigned short abs(const unsigned short a) {
 
4678
      return a;
 
4679
    }
 
4680
    inline unsigned int abs(const unsigned int a) {
 
4681
      return a;
 
4682
    }
 
4683
    inline unsigned long abs(const unsigned long a) {
 
4684
      return a;
 
4685
    }
 
4686
    inline double abs(const double a) {
 
4687
      return std::fabs(a);
 
4688
    }
 
4689
    inline float abs(const float a) {
 
4690
      return (float)std::fabs((double)a);
 
4691
    }
 
4692
    inline int abs(const int a) {
 
4693
      return std::abs(a);
 
4694
    }
 
4695
 
 
4696
    //! Return the square of a number.
 
4697
    template<typename T> inline T sqr(const T val) {
 
4698
      return val*val;
 
4699
    }
 
4700
 
 
4701
    //! Return 1 + log_10(x).
3014
4702
    inline int xln(const int x) {
3015
4703
      return x>0?(int)(1+std::log10((double)x)):1;
3016
4704
    }
3017
4705
 
 
4706
    //! Return the minimum value between two numbers.
 
4707
    template<typename t1, typename t2>
 
4708
    inline typename cimg::superset<t1,t2>::type min(const t1& a, const t2& b) {
 
4709
      typedef typename cimg::superset<t1,t2>::type t1t2;
 
4710
      return (t1t2)(a<=b?a:b);
 
4711
    }
 
4712
 
 
4713
    //! Return the minimum value between three numbers.
 
4714
    template<typename t1, typename t2, typename t3>
 
4715
    inline typename cimg::superset2<t1,t2,t3>::type min(const t1& a, const t2& b, const t3& c) {
 
4716
      typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
 
4717
      return (t1t2t3)cimg::min(cimg::min(a,b),c);
 
4718
    }
 
4719
 
 
4720
    //! Return the minimum value between four numbers.
 
4721
    template<typename t1, typename t2, typename t3, typename t4>
 
4722
    inline typename cimg::superset3<t1,t2,t3,t4>::type min(const t1& a, const t2& b, const t3& c, const t4& d) {
 
4723
      typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
 
4724
      return (t1t2t3t4)cimg::min(cimg::min(a,b,c),d);
 
4725
    }
 
4726
 
 
4727
    //! Return the maximum value between two numbers.
 
4728
    template<typename t1, typename t2>
 
4729
    inline typename cimg::superset<t1,t2>::type max(const t1& a, const t2& b) {
 
4730
      typedef typename cimg::superset<t1,t2>::type t1t2;
 
4731
      return (t1t2)(a>=b?a:b);
 
4732
    }
 
4733
 
 
4734
    //! Return the maximum value between three numbers.
 
4735
    template<typename t1, typename t2, typename t3>
 
4736
    inline typename cimg::superset2<t1,t2,t3>::type max(const t1& a, const t2& b, const t3& c) {
 
4737
      typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
 
4738
      return (t1t2t3)cimg::max(cimg::max(a,b),c);
 
4739
    }
 
4740
 
 
4741
    //! Return the maximum value between four numbers.
 
4742
    template<typename t1, typename t2, typename t3, typename t4>
 
4743
    inline typename cimg::superset3<t1,t2,t3,t4>::type max(const t1& a, const t2& b, const t3& c, const t4& d) {
 
4744
      typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
 
4745
      return (t1t2t3t4)cimg::max(cimg::max(a,b,c),d);
 
4746
    }
 
4747
 
 
4748
    //! Return the sign of a number.
 
4749
    template<typename T> inline T sign(const T x) {
 
4750
      return (x<0)?(T)(-1):(x==0?(T)0:(T)1);
 
4751
    }
 
4752
 
 
4753
    //! Return the nearest power of 2 higher than a given number.
 
4754
    template<typename T> inline unsigned long nearest_pow2(const T x) {
 
4755
      unsigned long i = 1;
 
4756
      while (x>i) i<<=1;
 
4757
      return i;
 
4758
    }
 
4759
 
 
4760
    //! Return the modulo of a number.
 
4761
    /**
 
4762
       \note This modulo function accepts negative and floating-points modulo numbers, as well as
 
4763
       variable of any type.
 
4764
    **/
 
4765
    template<typename T> inline T mod(const T& x, const T& m) {
 
4766
      const double dx = (double)x, dm = (double)m;
 
4767
      if (x<0) { return (T)(dm+dx+dm*std::floor(-dx/dm)); }
 
4768
      return (T)(dx-dm*std::floor(dx/dm));
 
4769
    }
 
4770
    inline int mod(const char x, const char m) {
 
4771
      return x>=0?x%m:(x%m?m+x%m:0);
 
4772
    }
 
4773
    inline int mod(const short x, const short m) {
 
4774
      return x>=0?x%m:(x%m?m+x%m:0);
 
4775
    }
 
4776
    inline int mod(const int x, const int m) {
 
4777
      return x>=0?x%m:(x%m?m+x%m:0);
 
4778
    }
 
4779
    inline int mod(const long x, const long m) {
 
4780
      return x>=0?x%m:(x%m?m+x%m:0);
 
4781
    }
 
4782
    inline int mod(const unsigned char x, const unsigned char m) {
 
4783
      return x%m;
 
4784
    }
 
4785
    inline int mod(const unsigned short x, const unsigned short m) {
 
4786
      return x%m;
 
4787
    }
 
4788
    inline int mod(const unsigned int x, const unsigned int m) {
 
4789
      return x%m;
 
4790
    }
 
4791
    inline int mod(const unsigned long x, const unsigned long m) {
 
4792
      return x%m;
 
4793
    }
 
4794
 
 
4795
    //! Return the minmod of two numbers.
 
4796
    /**
 
4797
       <i>minmod(\p a,\p b)</i> is defined to be :
 
4798
       - <i>minmod(\p a,\p b) = min(\p a,\p b)</i>, if \p a and \p b have the same sign.
 
4799
       - <i>minmod(\p a,\p b) = 0</i>, if \p a and \p b have different signs.
 
4800
    **/
 
4801
    template<typename T> inline T minmod(const T a, const T b) {
 
4802
      return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));
 
4803
    }
 
4804
 
 
4805
    //! Return a random variable between [0,1] with respect to an uniform distribution.
 
4806
    inline double rand() {
 
4807
      return (double)std::rand()/RAND_MAX;
 
4808
    }
 
4809
 
 
4810
    //! Return a random variable between [-1,1] with respect to an uniform distribution.
 
4811
    inline double crand() {
 
4812
      return 1-2*cimg::rand();
 
4813
    }
 
4814
 
 
4815
    //! Return a random variable following a gaussian distribution and a standard deviation of 1.
 
4816
    inline double grand() {
 
4817
      double x1, w;
 
4818
      do {
 
4819
        const double x2 = 2*cimg::rand()-1.0;
 
4820
        x1 = 2*cimg::rand()-1.0;
 
4821
        w = x1*x1 + x2*x2;
 
4822
      } while (w<=0 || w>=1.0);
 
4823
      return x1*std::sqrt((-2*std::log(w))/w);
 
4824
    }
 
4825
 
 
4826
    //! Return a rounded number.
 
4827
    /**
 
4828
       \param x is the number to be rounded.
 
4829
       \param y is the rounding precision.
 
4830
       \param round_type defines the type of rounding (0=nearest, 1=backward, 2=forward).
 
4831
    **/
 
4832
    inline double round(const double x, const double y, const unsigned int round_type=0) {
 
4833
      if (y<=0) return x;
 
4834
      const double delta = cimg::mod(x,y);
 
4835
      if (delta==0.0) return x;
 
4836
      const double
 
4837
        backward = x - delta,
 
4838
        forward = backward + y;
 
4839
      return round_type==1?backward:(round_type==2?forward:(2*delta<y?backward:forward));
 
4840
    }
 
4841
 
 
4842
    inline double _pythagore(double a, double b) {
 
4843
      const double absa = cimg::abs(a), absb = cimg::abs(b);
 
4844
      if (absa>absb) { const double tmp = absb/absa; return absa*std::sqrt(1.0+tmp*tmp); }
 
4845
      else { const double tmp = absa/absb; return (absb==0?0:absb*std::sqrt(1.0+tmp*tmp)); }
 
4846
    }
 
4847
 
 
4848
    //! Remove the 'case' of an ASCII character.
3018
4849
    inline char uncase(const char x) {
3019
4850
      return (char)((x<'A'||x>'Z')?x:x-'A'+'a');
3020
4851
    }
3021
4852
 
 
4853
    //! Remove the 'case' of a C string.
 
4854
    /**
 
4855
       Acts in-place.
 
4856
    **/
 
4857
    inline void uncase(char *const string) {
 
4858
      if (string) for (char *ptr = string; *ptr; ++ptr) *ptr = uncase(*ptr);
 
4859
    }
 
4860
 
 
4861
    //! Read a float number from a C-string.
 
4862
    /**
 
4863
       \note This function is quite similar to <tt>std::atof()</tt>,
 
4864
       but that it allows the retrieval of fractions as in "1/2".
 
4865
    **/
3022
4866
    inline float atof(const char *str) {
3023
4867
      float x = 0,y = 1;
3024
4868
      if (!str) return 0; else { std::sscanf(str,"%g/%g",&x,&y); return x/y; }
3025
4869
    }
3026
4870
 
 
4871
    //! Compute the length of a C-string.
 
4872
    /**
 
4873
       \note This function is similar to <tt>std::strlen()</tt>
 
4874
       and is here because some old compilers do not
 
4875
       define the <tt>std::</tt> version.
 
4876
     **/
3027
4877
    inline int strlen(const char *s) {
3028
 
      if (s) { int k; for (k=0; s[k]; ++k) ; return k; }
 
4878
      if (s) { int k; for (k = 0; s[k]; ++k) ; return k; }
3029
4879
      return -1;
3030
4880
    }
3031
4881
 
 
4882
    //! Compare the first \p n characters of two C-strings.
 
4883
    /**
 
4884
       \note This function is similar to <tt>std::strncmp()</tt>
 
4885
       and is here because some old compilers do not
 
4886
       define the <tt>std::</tt> version.
 
4887
    **/
3032
4888
    inline int strncmp(const char *s1, const char *s2, const int l) {
3033
 
      if (s1 && s2) { int n = 0; for (int k=0; k<l; ++k) n+=std::abs(s1[k] - s2[k]); return n; }
 
4889
      if (s1 && s2) { int n = 0; for (int k = 0; k<l; ++k) n+=std::abs(s1[k] - s2[k]); return n; }
3034
4890
      return 0;
3035
4891
    }
3036
4892
 
 
4893
    //! Compare the first \p n characters of two C-strings, ignoring the case.
 
4894
    /**
 
4895
       \note This function is similar to <tt>std::strncasecmp()</tt>
 
4896
       and is here because some old compilers do not
 
4897
       define the <tt>std::</tt> version.
 
4898
    **/
3037
4899
    inline int strncasecmp(const char *s1, const char *s2, const int l) {
3038
 
      if (s1 && s2) { int n = 0; for (int k=0; k<l; ++k) n+=std::abs(uncase(s1[k])-uncase(s2[k])); return n; }
 
4900
      if (s1 && s2) { int n = 0; for (int k = 0; k<l; ++k) n+=std::abs(uncase(s1[k])-uncase(s2[k])); return n; }
3039
4901
      return 0;
3040
4902
    }
3041
4903
 
 
4904
    //! Compare two C-strings.
 
4905
    /**
 
4906
       \note This function is similar to <tt>std::strcmp()</tt>
 
4907
       and is here because some old compilers do not
 
4908
       define the <tt>std::</tt> version.
 
4909
    **/
3042
4910
    inline int strcmp(const char *s1, const char *s2) {
3043
4911
      const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
3044
4912
      return cimg::strncmp(s1,s2,1+(l1<l2?l1:l2));
3045
4913
    }
3046
4914
 
 
4915
    //! Compare two C-strings, ignoring the case.
 
4916
    /**
 
4917
       \note This function is similar to <tt>std::strcasecmp()</tt>
 
4918
       and is here because some old compilers do not
 
4919
       define the <tt>std::</tt> version.
 
4920
    **/
3047
4921
    inline int strcasecmp(const char *s1, const char *s2) {
3048
4922
      const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
3049
4923
      return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2));
3050
4924
    }
3051
4925
 
 
4926
    //! Find a character in a C-string.
3052
4927
    inline int strfind(const char *s, const char c) {
3053
4928
      if (s) {
3054
4929
        int l; for (l=cimg::strlen(s); l>=0 && s[l]!=c; --l) ;
3057
4932
      return -1;
3058
4933
    }
3059
4934
 
 
4935
    //! Compute the basename of a filename.
3060
4936
    inline const char* basename(const char *s)  {
3061
4937
      return (cimg_OS!=2)?(s?s+1+cimg::strfind(s,'/'):0):(s?s+1+cimg::strfind(s,'\\'):0);
3062
4938
    }
3063
4939
 
3064
 
    inline void system(const char *command, const char *module_name=0) {
3065
 
#if cimg_OS==2
3066
 
      PROCESS_INFORMATION pi;
3067
 
      STARTUPINFO si;
3068
 
      std::memset(&pi, 0, sizeof(PROCESS_INFORMATION));
3069
 
      std::memset(&si, 0, sizeof(STARTUPINFO));
3070
 
      GetStartupInfo(&si);
3071
 
      si.cb = sizeof(si);
3072
 
      si.wShowWindow = SW_HIDE;
3073
 
      si.dwFlags |= SW_HIDE;
3074
 
      const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);
3075
 
      if (res) {
3076
 
        WaitForSingleObject(pi.hProcess, INFINITE);
3077
 
        CloseHandle(pi.hThread);
3078
 
        CloseHandle(pi.hProcess);
3079
 
      } else
3080
 
#endif
3081
 
      std::system(command);
3082
 
      command = module_name = 0;
 
4940
    // Generate a random filename.
 
4941
    inline const char* filenamerand() {
 
4942
      static char id[9] = { 0,0,0,0,0,0,0,0,0 };
 
4943
      cimg::srand();
 
4944
      for (unsigned int k=0; k<8; ++k) {
 
4945
        const int v = (int)std::rand()%3;
 
4946
        id[k] = (char)(v==0?('0'+(std::rand()%10)):(v==1?('a'+(std::rand()%26)):('A'+(std::rand()%26))));
 
4947
      }
 
4948
      return id;
3083
4949
    }
3084
4950
 
3085
 
    // Convert filename into windows-style (without spaces)
3086
 
#if cimg_OS==2
 
4951
    // Convert filename into a Windows-style filename.
3087
4952
    inline void winformat_string(char *const s) {
3088
4953
      if (s && s[0]) {
 
4954
#if cimg_OS==2
3089
4955
        char *const ns = new char[MAX_PATH];
3090
 
        GetShortPathNameA(s,ns,MAX_PATH);
3091
 
        std::strcpy(s,ns);
 
4956
        if (GetShortPathNameA(s,ns,MAX_PATH)) std::strcpy(s,ns);
 
4957
#endif
3092
4958
      }
3093
4959
    }
 
4960
 
 
4961
    //! Return path to store temporary files.
 
4962
    /**
 
4963
       If you are running on a standard Unix or Windows system, this function should return a correct path
 
4964
       where temporary files can be stored. If such a path is not auto-detected by this function,
 
4965
       you can define the macro \c cimg_temporary_path with a correct path, before including <tt>CImg.h</tt>
 
4966
       in your program :
 
4967
       \code
 
4968
       #define cimg_temporary_path "/users/thatsme/tmp"
 
4969
       #include "CImg.h"
 
4970
 
 
4971
       int main() {
 
4972
         CImg<> img("my_image.jpg");   // Read a JPEG image file (using the defined temporary path).
 
4973
         return 0;
 
4974
       }
 
4975
       \endcode
 
4976
 
 
4977
       A temporary path is necessary to load and save compressed image formats, when using external
 
4978
       tool such as \c convert or \c medcon. It is not necessary if you link your code with
 
4979
       built-in libraries (such as libpng, libjpeg, libmagick, ...)
 
4980
    **/
 
4981
    inline const char* temporary_path() {
 
4982
#define _cimg_test_temporary_path(p) \
 
4983
      if (!path_found) { \
 
4984
        std::sprintf(st_temporary_path,"%s",p);                         \
 
4985
        std::sprintf(tmp,"%s%s%s",st_temporary_path,cimg_OS==2?"\\":"/",filetmp); \
 
4986
        if ((file=std::fopen(tmp,"wb"))!=0) { std::fclose(file); std::remove(tmp); path_found = true; } \
 
4987
      }
 
4988
      static char *st_temporary_path = 0;
 
4989
      if (!st_temporary_path) {
 
4990
        st_temporary_path = new char[1024];
 
4991
        std::memset(st_temporary_path,0,1024);
 
4992
        bool path_found = false;
 
4993
        char tmp[1024], filetmp[512];
 
4994
        std::FILE *file = 0;
 
4995
        std::sprintf(filetmp,"%s.tmp",cimg::filenamerand());
 
4996
#ifdef cimg_temporary_path
 
4997
        _cimg_test_temporary_path(cimg_temporary_path);
 
4998
#endif
 
4999
        char *tmpPath = getenv("TMP");
 
5000
        if (tmpPath==NULL) { tmpPath = getenv("TEMP"); winformat_string(tmpPath); }
 
5001
        if (tmpPath!=NULL) _cimg_test_temporary_path(tmpPath);
 
5002
#if cimg_OS==2
 
5003
        _cimg_test_temporary_path("C:\\WINNT\\Temp");
 
5004
        _cimg_test_temporary_path("C:\\WINDOWS\\Temp");
 
5005
        _cimg_test_temporary_path("C:\\Temp");
 
5006
        _cimg_test_temporary_path("C:");
 
5007
        _cimg_test_temporary_path("D:\\WINNT\\Temp");
 
5008
        _cimg_test_temporary_path("D:\\WINDOWS\\Temp");
 
5009
        _cimg_test_temporary_path("D:\\Temp");
 
5010
        _cimg_test_temporary_path("D:");
3094
5011
#else
3095
 
    inline void winformat_string(char *const) {}
 
5012
        _cimg_test_temporary_path("/tmp");
 
5013
        _cimg_test_temporary_path("/var/tmp");
3096
5014
#endif
 
5015
        if (!path_found) {
 
5016
          st_temporary_path[0]='\0';
 
5017
          std::strcpy(tmp,filetmp);
 
5018
          if ((file=std::fopen(tmp,"wb"))!=0) { std::fclose(file); std::remove(tmp); path_found = true; }
 
5019
        }
 
5020
        if (!path_found)
 
5021
          throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n"
 
5022
                                "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n"
 
5023
                                "#define cimg_temporary_path \"path\" (before including 'CImg.h')");
 
5024
      }
 
5025
      return st_temporary_path;
 
5026
    }
3097
5027
 
3098
5028
    // Return path to the "Program files/" directory (windows only).
3099
5029
    /**
3105
5035
      static char *st_programfiles_path = 0;
3106
5036
      if (!st_programfiles_path) {
3107
5037
        st_programfiles_path = new char[MAX_PATH];
 
5038
        std::memset(st_programfiles_path,0,MAX_PATH);
3108
5039
        // Note : in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler).
3109
5040
#if !defined(__INTEL_COMPILER)
3110
5041
        if (!SHGetSpecialFolderPathA(0,st_programfiles_path,0x0026,false)) {
3139
5070
       \endcode
3140
5071
 
3141
5072
       Note that non compressed image formats can be read without installing ImageMagick.
3142
 
 
3143
 
       \sa temporary_path(), get_load_imagemagick(), load_imagemagick(), save_imagemagick().
3144
5073
    **/
3145
5074
    inline const char* imagemagick_path() {
3146
5075
      static char *st_imagemagick_path = 0;
3147
5076
      if (!st_imagemagick_path) {
3148
5077
        st_imagemagick_path = new char[1024];
 
5078
        std::memset(st_imagemagick_path,0,1024);
3149
5079
        bool path_found = false;
3150
5080
        std::FILE *file = 0;
3151
5081
#ifdef cimg_imagemagick_path
3152
 
        std::strcpy(st_imagemagick_path,cimg_imagemagick_path);
 
5082
        std::strncpy(st_imagemagick_path,cimg_imagemagick_path,1023);
3153
5083
        if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3154
5084
#endif
3155
5085
#if cimg_OS==2
3158
5088
          std::sprintf(st_imagemagick_path,".\\convert.exe");
3159
5089
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3160
5090
        }
3161
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3162
 
          std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%u-Q\\convert.exe",pf_path,k);
3163
 
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3164
 
        }}
3165
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3166
 
          std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%u\\convert.exe",pf_path,k);
3167
 
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3168
 
        }}
3169
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3170
 
          std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%u-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k);
3171
 
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3172
 
        }}
3173
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3174
 
          std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%u\\VISUA~1\\BIN\\convert.exe",pf_path,k);
3175
 
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3176
 
        }}
3177
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3178
 
          std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%u-Q\\convert.exe",k);
3179
 
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3180
 
        }}
3181
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3182
 
          std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%u\\convert.exe",k);
3183
 
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3184
 
        }}
3185
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3186
 
          std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%u-Q\\VISUA~1\\BIN\\convert.exe",k);
3187
 
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3188
 
        }}
3189
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3190
 
          std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%u\\VISUA~1\\BIN\\convert.exe",k);
3191
 
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3192
 
        }}
3193
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3194
 
          std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%u-Q\\convert.exe",k);
3195
 
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3196
 
        }}
3197
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3198
 
          std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%u\\convert.exe",k);
3199
 
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3200
 
        }}
3201
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3202
 
          std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%u-Q\\VISUA~1\\BIN\\convert.exe",k);
3203
 
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3204
 
        }}
3205
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3206
 
          std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%u\\VISUA~1\\BIN\\convert.exe",k);
 
5091
        { for (int k=32; k>=10 && !path_found; --k) {
 
5092
          std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k);
 
5093
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5094
        }}
 
5095
        { for (int k=9; k>=0 && !path_found; --k) {
 
5096
          std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k);
 
5097
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5098
        }}
 
5099
        { for (int k=32; k>=0 && !path_found; --k) {
 
5100
          std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k);
 
5101
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5102
        }}
 
5103
        { for (int k=32; k>=10 && !path_found; --k) {
 
5104
          std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k);
 
5105
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5106
        }}
 
5107
        { for (int k=9; k>=0 && !path_found; --k) {
 
5108
          std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k);
 
5109
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5110
        }}
 
5111
        { for (int k=32; k>=0 && !path_found; --k) {
 
5112
          std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k);
 
5113
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5114
        }}
 
5115
        { for (int k=32; k>=10 && !path_found; --k) {
 
5116
          std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%.2d-\\convert.exe",k);
 
5117
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5118
        }}
 
5119
        { for (int k=9; k>=0 && !path_found; --k) {
 
5120
          std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%d-Q\\convert.exe",k);
 
5121
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5122
        }}
 
5123
        { for (int k=32; k>=0 && !path_found; --k) {
 
5124
          std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%d\\convert.exe",k);
 
5125
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5126
        }}
 
5127
        { for (int k=32; k>=10 && !path_found; --k) {
 
5128
          std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
 
5129
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5130
        }}
 
5131
        { for (int k=9; k>=0 && !path_found; --k) {
 
5132
          std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
 
5133
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5134
        }}
 
5135
        { for (int k=32; k>=0 && !path_found; --k) {
 
5136
          std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
 
5137
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5138
        }}
 
5139
        { for (int k=32; k>=10 && !path_found; --k) {
 
5140
          std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%.2d-\\convert.exe",k);
 
5141
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5142
        }}
 
5143
        { for (int k=9; k>=0 && !path_found; --k) {
 
5144
          std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%d-Q\\convert.exe",k);
 
5145
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5146
        }}
 
5147
        { for (int k=32; k>=0 && !path_found; --k) {
 
5148
          std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%d\\convert.exe",k);
 
5149
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5150
        }}
 
5151
        { for (int k=32; k>=10 && !path_found; --k) {
 
5152
          std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
 
5153
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5154
        }}
 
5155
        { for (int k=9; k>=0 && !path_found; --k) {
 
5156
          std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
 
5157
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5158
        }}
 
5159
        { for (int k=32; k>=0 && !path_found; --k) {
 
5160
          std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
3207
5161
          if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3208
5162
        }}
3209
5163
        if (!path_found) std::strcpy(st_imagemagick_path,"convert.exe");
3238
5192
       \endcode
3239
5193
 
3240
5194
       Note that non compressed image formats can be read without installing ImageMagick.
3241
 
 
3242
 
       \sa temporary_path(), get_load_imagemagick(), load_imagemagick(), save_imagemagick().
3243
5195
    **/
3244
5196
    inline const char* graphicsmagick_path() {
3245
5197
      static char *st_graphicsmagick_path = 0;
3246
5198
      if (!st_graphicsmagick_path) {
3247
5199
        st_graphicsmagick_path = new char[1024];
 
5200
        std::memset(st_graphicsmagick_path,0,1024);
3248
5201
        bool path_found = false;
3249
5202
        std::FILE *file = 0;
3250
5203
#ifdef cimg_graphicsmagick_path
3257
5210
          std::sprintf(st_graphicsmagick_path,".\\gm.exe");
3258
5211
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3259
5212
        }
3260
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3261
 
          std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%u-Q\\gm.exe",pf_path,k);
3262
 
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3263
 
        }}
3264
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3265
 
          std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%u\\gm.exe",pf_path,k);
3266
 
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3267
 
        }}
3268
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3269
 
          std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%u-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k);
3270
 
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3271
 
        }}
3272
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3273
 
          std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%u\\VISUA~1\\BIN\\gm.exe",pf_path,k);
3274
 
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3275
 
        }}
3276
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3277
 
          std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%u-Q\\gm.exe",k);
3278
 
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3279
 
        }}
3280
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3281
 
          std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%u\\gm.exe",k);
3282
 
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3283
 
        }}
3284
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3285
 
          std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%u-Q\\VISUA~1\\BIN\\gm.exe",k);
3286
 
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3287
 
        }}
3288
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3289
 
          std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%u\\VISUA~1\\BIN\\gm.exe",k);
3290
 
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3291
 
        }}
3292
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3293
 
          std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%u-Q\\gm.exe",k);
3294
 
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3295
 
        }}
3296
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3297
 
          std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%u\\gm.exe",k);
3298
 
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3299
 
        }}
3300
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3301
 
          std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%u-Q\\VISUA~1\\BIN\\gm.exe",k);
3302
 
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3303
 
        }}
3304
 
        { for (unsigned int k=0; k<=9 && !path_found; ++k) {
3305
 
          std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%u\\VISUA~1\\BIN\\gm.exe",k);
 
5213
        { for (int k=32; k>=10 && !path_found; --k) {
 
5214
          std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k);
 
5215
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5216
        }}
 
5217
        { for (int k=9; k>=0 && !path_found; --k) {
 
5218
          std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k);
 
5219
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5220
        }}
 
5221
        { for (int k=32; k>=0 && !path_found; --k) {
 
5222
          std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k);
 
5223
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5224
        }}
 
5225
        { for (int k=32; k>=10 && !path_found; --k) {
 
5226
          std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k);
 
5227
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5228
        }}
 
5229
        { for (int k=9; k>=0 && !path_found; --k) {
 
5230
          std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k);
 
5231
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5232
        }}
 
5233
        { for (int k=32; k>=0 && !path_found; --k) {
 
5234
          std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k);
 
5235
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5236
        }}
 
5237
        { for (int k=32; k>=10 && !path_found; --k) {
 
5238
          std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%.2d-\\gm.exe",k);
 
5239
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5240
        }}
 
5241
        { for (int k=9; k>=0 && !path_found; --k) {
 
5242
          std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%d-Q\\gm.exe",k);
 
5243
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5244
        }}
 
5245
        { for (int k=32; k>=0 && !path_found; --k) {
 
5246
          std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%d\\gm.exe",k);
 
5247
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5248
        }}
 
5249
        { for (int k=32; k>=10 && !path_found; --k) {
 
5250
          std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
 
5251
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5252
        }}
 
5253
        { for (int k=9; k>=0 && !path_found; --k) {
 
5254
          std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
 
5255
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5256
        }}
 
5257
        { for (int k=32; k>=0 && !path_found; --k) {
 
5258
          std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
 
5259
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5260
        }}
 
5261
        { for (int k=32; k>=10 && !path_found; --k) {
 
5262
          std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%.2d-\\gm.exe",k);
 
5263
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5264
        }}
 
5265
        { for (int k=9; k>=0 && !path_found; --k) {
 
5266
          std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%d-Q\\gm.exe",k);
 
5267
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5268
        }}
 
5269
        { for (int k=32; k>=0 && !path_found; --k) {
 
5270
          std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%d\\gm.exe",k);
 
5271
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5272
        }}
 
5273
        { for (int k=32; k>=10 && !path_found; --k) {
 
5274
          std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
 
5275
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5276
        }}
 
5277
        { for (int k=9; k>=0 && !path_found; --k) {
 
5278
          std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
 
5279
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5280
        }}
 
5281
        { for (int k=32; k>=0 && !path_found; --k) {
 
5282
          std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
3306
5283
          if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; }
3307
5284
        }}
3308
5285
        if (!path_found) std::strcpy(st_graphicsmagick_path,"gm.exe");
3337
5314
       \endcode
3338
5315
 
3339
5316
       Note that \c medcon is only needed if you want to read DICOM image formats.
3340
 
 
3341
 
       \sa temporary_path(), get_load_dicom(), load_dicom().
3342
5317
    **/
3343
5318
    inline const char* medcon_path() {
3344
5319
      static char *st_medcon_path = 0;
3345
5320
      if (!st_medcon_path) {
3346
5321
        st_medcon_path = new char[1024];
 
5322
        std::memset(st_medcon_path,0,1024);
3347
5323
        bool path_found = false;
3348
5324
        std::FILE *file = 0;
3349
5325
#ifdef cimg_medcon_path
3381
5357
      return st_medcon_path;
3382
5358
    }
3383
5359
 
3384
 
    //! Return path to store temporary files.
3385
 
    /**
3386
 
       If you are running on a standard Unix or Windows system, this function should return a correct path
3387
 
       where temporary files can be stored. If such a path is not auto-detected by this function,
3388
 
       you can define the macro \c cimg_temporary_path with a correct path, before including <tt>CImg.h</tt>
3389
 
       in your program :
3390
 
       \code
3391
 
       #define cimg_temporary_path "/users/thatsme/tmp"
3392
 
       #include "CImg.h"
3393
 
 
3394
 
       int main() {
3395
 
         CImg<> img("my_image.jpg");   // Read a JPEG image file (using the defined temporay path).
3396
 
         return 0;
3397
 
       }
3398
 
       \endcode
3399
 
 
3400
 
       A temporary path is necessary to load and save compressed image formats, using \c convert
3401
 
       or \c medcon.
3402
 
 
3403
 
       \sa imagemagick_path(), get_load_imagemagick(), load_imagemagick(), save_imagemagick(), get_load_dicom(), load_dicom().
3404
 
    **/
3405
 
    inline const char* temporary_path() {
3406
 
 
3407
 
#define cimg_test_temporary_path(p) \
3408
 
      if (!path_found) { \
3409
 
        std::sprintf(st_temporary_path,"%s", p); \
3410
 
        std::sprintf(tmp,"%s%s%s",st_temporary_path,cimg_OS==2?"\\":"/",filetmp); \
3411
 
        if ((file=std::fopen(tmp,"wb"))!=0) { std::fclose(file); std::remove(tmp); path_found = true; } \
3412
 
      }
3413
 
 
3414
 
      static char *st_temporary_path = 0;
3415
 
      if (!st_temporary_path) {
3416
 
        st_temporary_path = new char[1024];
3417
 
        bool path_found = false;
3418
 
        char tmp[1024], filetmp[512];
3419
 
        std::FILE *file = 0;
3420
 
        std::sprintf(filetmp,"CImg%.4d.tmp",std::rand()%10000);
3421
 
#ifdef cimg_temporary_path
3422
 
        cimg_test_temporary_path(cimg_temporary_path);
3423
 
#endif
3424
 
        char *tmpPath = getenv("TMP");
3425
 
        if (tmpPath==NULL) { tmpPath = getenv("TEMP"); winformat_string(tmpPath); }
3426
 
        if (tmpPath!=NULL) cimg_test_temporary_path(tmpPath);
3427
 
#if cimg_OS==2
3428
 
        cimg_test_temporary_path("C:\\WINNT\\Temp");
3429
 
        cimg_test_temporary_path("C:\\WINDOWS\\Temp");
3430
 
        cimg_test_temporary_path("C:\\Temp");
3431
 
        cimg_test_temporary_path("C:");
3432
 
        cimg_test_temporary_path("D:\\WINNT\\Temp");
3433
 
        cimg_test_temporary_path("D:\\WINDOWS\\Temp");
3434
 
        cimg_test_temporary_path("D:\\Temp");
3435
 
        cimg_test_temporary_path("D:");
3436
 
#else
3437
 
        cimg_test_temporary_path("/tmp");
3438
 
        cimg_test_temporary_path("/var/tmp");
3439
 
#endif
3440
 
        if (!path_found) {
3441
 
          st_temporary_path[0]='\0';
3442
 
          std::strcpy(tmp,filetmp);
3443
 
          if ((file=std::fopen(tmp,"wb"))!=0) { std::fclose(file); std::remove(tmp); path_found = true; }
3444
 
        }
3445
 
        if (!path_found)
3446
 
          throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n"
3447
 
                                "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n"
3448
 
                                "#define cimg_temporary_path \"path\" (before including 'CImg.h')");
3449
 
      }
3450
 
      return st_temporary_path;
3451
 
    }
3452
 
 
3453
 
    inline const char *filename_split(const char *const filename, char *const body=0) {
 
5360
    //! Return path to the 'ffmpeg' command.
 
5361
    inline const char *ffmpeg_path() {
 
5362
      static char *st_ffmpeg_path = 0;
 
5363
      if (!st_ffmpeg_path) {
 
5364
        st_ffmpeg_path = new char[1024];
 
5365
        std::memset(st_ffmpeg_path,0,1024);
 
5366
        bool path_found = false;
 
5367
#ifdef cimg_ffmpeg_path
 
5368
        std::FILE *file = 0;
 
5369
        std::strcpy(st_ffmpeg_path,cimg_ffmpeg_path);
 
5370
        if ((file = std::fopen(st_ffmpeg_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5371
#endif
 
5372
        if (!path_found) std::strcpy(st_ffmpeg_path,"ffmpeg");
 
5373
      }
 
5374
      return st_ffmpeg_path;
 
5375
    }
 
5376
 
 
5377
    //! Return path to the 'gzip' command.
 
5378
    inline const char *gzip_path() {
 
5379
      static char *st_gzip_path = 0;
 
5380
      if (!st_gzip_path) {
 
5381
        st_gzip_path = new char[1024];
 
5382
        std::memset(st_gzip_path,0,1024);
 
5383
        bool path_found = false;
 
5384
#ifdef cimg_gzip_path
 
5385
        std::FILE *file = 0;
 
5386
        std::strcpy(st_gzip_path,cimg_gzip_path);
 
5387
        if ((file = std::fopen(st_gzip_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5388
#endif
 
5389
        if (!path_found) std::strcpy(st_gzip_path,"gzip");
 
5390
      }
 
5391
      return st_gzip_path;
 
5392
    }
 
5393
 
 
5394
    //! Return path to the 'gunzip' command.
 
5395
    inline const char *gunzip_path() {
 
5396
      static char *st_gunzip_path = 0;
 
5397
      if (!st_gunzip_path) {
 
5398
        st_gunzip_path = new char[1024];
 
5399
        std::memset(st_gunzip_path,0,1024);
 
5400
        bool path_found = false;
 
5401
#ifdef cimg_gunzip_path
 
5402
        std::FILE *file = 0;
 
5403
        std::strcpy(st_gunzip_path,cimg_gunzip_path);
 
5404
        if ((file = std::fopen(st_gunzip_path,"r"))!=0) { std::fclose(file); path_found = true; }
 
5405
#endif
 
5406
        if (!path_found) std::strcpy(st_gunzip_path,"gunzip");
 
5407
      }
 
5408
      return st_gunzip_path;
 
5409
    }
 
5410
 
 
5411
    //! Split a filename into two strings 'body' and 'extension'.
 
5412
    inline const char *split_filename(const char *const filename, char *const body=0) {
3454
5413
      if (!filename) { if (body) body[0]='\0'; return 0; }
3455
5414
      int l = cimg::strfind(filename,'.');
3456
5415
      if (l>=0) { if (body) { std::strncpy(body,filename,l); body[l]='\0'; }}
3458
5417
      return filename+l+1;
3459
5418
    }
3460
5419
 
 
5420
    //! Create a numbered version of a filename.
3461
5421
    inline char* filename_number(const char *const filename, const int number, const unsigned int n, char *const string) {
3462
5422
      if (!filename) { if (string) string[0]='\0'; return 0; }
3463
5423
      char format[1024],body[1024];
3464
 
      const char *ext = cimg::filename_split(filename,body);
 
5424
      const char *ext = cimg::split_filename(filename,body);
3465
5425
      if (n>0) std::sprintf(format,"%s_%%.%ud.%s",body,n,ext);
3466
5426
      else std::sprintf(format,"%s_%%d.%s",body,ext);
3467
5427
      std::sprintf(string,format,number);
3468
5428
      return string;
3469
5429
    }
3470
5430
 
 
5431
    //! Open a file, and check for possible errors.
3471
5432
    inline std::FILE *fopen(const char *const path, const char *const mode) {
3472
5433
      if(!path || !mode)
3473
5434
        throw CImgArgumentException("cimg::fopen() : File '%s' cannot be opened with mode '%s'.",
3480
5441
      return dest;
3481
5442
    }
3482
5443
 
 
5444
    //! Close a file, and check for possible errors.
3483
5445
    inline int fclose(std::FILE *file) {
3484
5446
      if (!file) warn("cimg::fclose() : Can't close (null) file");
3485
5447
      if (!file || file==stdin || file==stdout) return 0;
3488
5450
      return errn;
3489
5451
    }
3490
5452
 
 
5453
    //! Read file data, and check for possible errors.
3491
5454
    template<typename T> inline int fread(T *const ptr, const unsigned int nmemb, std::FILE *stream) {
3492
5455
      if (!ptr || nmemb<=0 || !stream)
3493
5456
        throw CImgArgumentException("cimg::fread() : Can't read %u x %u bytes of file pointer '%p' in buffer '%p'",
3504
5467
      return alread;
3505
5468
    }
3506
5469
 
 
5470
    //! Write data to a file, and check for possible errors.
3507
5471
    template<typename T> inline int fwrite(const T *ptr, const unsigned int nmemb, std::FILE *stream) {
3508
5472
      if (!ptr || !stream)
3509
5473
        throw CImgArgumentException("cimg::fwrite() : Can't write %u x %u bytes of file pointer '%p' from buffer '%p'",
3521
5485
      return alwrite;
3522
5486
    }
3523
5487
 
3524
 
    // Exchange the values of variables \p a and \p b
3525
 
    template<typename T> inline void swap(T& a,T& b) { T t=a; a=b; b=t; }
3526
 
    template<typename T1,typename T2> inline void swap(T1& a1,T1& b1,T2& a2,T2& b2) {
3527
 
      cimg::swap(a1,b1); cimg::swap(a2,b2);
3528
 
    }
3529
 
    template<typename T1,typename T2,typename T3> inline void swap(T1& a1,T1& b1,T2& a2,T2& b2,T3& a3,T3& b3) {
3530
 
      cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3);
3531
 
    }
3532
 
    template<typename T1,typename T2,typename T3,typename T4>
3533
 
    inline void swap(T1& a1,T1& b1,T2& a2,T2& b2,T3& a3,T3& b3,T4& a4,T4& b4) {
3534
 
      cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);
3535
 
    }
3536
 
    template<typename T1,typename T2,typename T3,typename T4,typename T5>
3537
 
    inline void swap(T1& a1,T1& b1,T2& a2,T2& b2,T3& a3,T3& b3,T4& a4,T4& b4,T5& a5,T5& b5) {
3538
 
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);
3539
 
    }
3540
 
    template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6>
3541
 
    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) {
3542
 
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
3543
 
    }
3544
 
    template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7>
3545
 
    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,
3546
 
                     T7& a7,T7& b7) {
3547
 
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);
3548
 
    }
3549
 
    template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8>
3550
 
    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,
3551
 
                     T7& a7,T7& b7,T8& a8,T8& b8) {
3552
 
      cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);
3553
 
    }
3554
 
 
3555
 
    template<typename T> inline void endian_swap(T* const buffer, const unsigned int size) {
3556
 
      switch (sizeof(T)) {
3557
 
      case 1: break;
3558
 
      case 2: {
3559
 
        for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer; ) {
3560
 
          const unsigned short val = *(--ptr);
3561
 
          *ptr = (unsigned short)((val>>8)|((val<<8)));
3562
 
        }
3563
 
      } break;
3564
 
      case 4: {
3565
 
        for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer; ) {
3566
 
          const unsigned int val = *(--ptr);
3567
 
          *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24);
3568
 
        }
3569
 
      } break;
3570
 
      default: {
3571
 
        for (T* ptr = buffer+size; ptr>buffer; ) {
3572
 
          unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);
3573
 
          for (int i=0; i<(int)sizeof(T)/2; ++i) cimg::swap(*(pb++),*(--pe));
3574
 
        } break;
3575
 
      }
3576
 
      }
3577
 
    }
3578
 
    template<typename T> inline T& endian_swap(T& a) { endian_swap(&a,1); return a; }
3579
 
 
3580
5488
    inline const char* option(const char *const name, const int argc, char **argv,
3581
5489
                              const char *defaut, const char *const usage=0) {
3582
 
      static bool first=true, visu=false;
 
5490
      static bool first = true, visu = false;
3583
5491
      const char *res = 0;
3584
5492
      if (first) {
3585
5493
        first=false;
3597
5505
      }
3598
5506
      if (name) {
3599
5507
        if (argc>0) {
3600
 
          int k = 0,i;
 
5508
          int k = 0;
3601
5509
          while (k<argc && cimg::strcmp(argv[k],name)) ++k;
3602
 
          i=k;
3603
 
          res=(k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
 
5510
          res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
3604
5511
        } else res = defaut;
3605
5512
        if (visu && usage) std::fprintf(stderr,"    %s%-8s%s = %-12s : %s%s%s\n",
3606
 
                                        cimg::t_bold,name,cimg::t_normal,res?res:"0",cimg::t_purple,usage,cimg::t_normal);
 
5513
                                        cimg::t_bold,name,cimg::t_normal,res?res:"0",cimg::t_green,usage,cimg::t_normal);
3607
5514
      }
3608
5515
      return res;
3609
5516
    }
3657
5564
      return res;
3658
5565
    }
3659
5566
 
3660
 
    //! Return \c false for little endian CPUs (Intel), \c true for big endian CPUs (Motorola).
3661
 
    inline bool endian() {
3662
 
      const int x=1;
3663
 
      return ((unsigned char*)&x)[0]?false:true;
 
5567
    inline const char* argument(const unsigned int nb, const int argc, char **argv, const unsigned int nb_singles=0, ...) {
 
5568
      for (int k=1, pos=0; k<argc;) {
 
5569
        const char *const item = argv[k];
 
5570
        bool option = (*item=='-'), single_option = false;
 
5571
        if (option) {
 
5572
          va_list ap;
 
5573
          va_start(ap,nb_singles);
 
5574
          for (unsigned int i=0; i<nb_singles; ++i) if (!cimg::strcasecmp(item,va_arg(ap,char*))) { single_option = true; break; }
 
5575
          va_end(ap);
 
5576
        }
 
5577
        if (option) { ++k; if (!single_option) ++k; }
 
5578
        else { if (pos++==(int)nb) return item; else ++k; }
 
5579
      }
 
5580
      return 0;
3664
5581
    }
3665
5582
 
3666
5583
    //! Print informations about %CImg environement variables.
3669
5586
    **/
3670
5587
    inline void info() {
3671
5588
      char tmp[1024] = { 0 };
3672
 
      std::fprintf(stderr,"\n %sCImg Library %g%s, compiled %s ( %s ) with the following flags :\n\n",
3673
 
                   cimg::t_red,cimg_version,cimg::t_normal,__DATE__,__TIME__);
3674
 
 
3675
 
      std::fprintf(stderr,"  > CPU endianness :         %s%s Endian%s\n",
3676
 
                   cimg::t_bold,
3677
 
                   cimg::endian()?"Big":"Little",
3678
 
                   cimg::t_normal);
 
5589
      std::fprintf(stderr,"\n %sCImg Library %d.%d.%d%s, compiled %s ( %s ) with the following flags :\n\n",
 
5590
                   cimg::t_red,cimg_version/100,(cimg_version%100)/10,cimg_version%10,cimg::t_normal,__DATE__,__TIME__);
3679
5591
 
3680
5592
      std::fprintf(stderr,"  > Operating System :       %s%-13s%s %s('cimg_OS'=%d)%s\n",
3681
5593
                   cimg::t_bold,
3682
5594
                   cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"),
3683
 
                   cimg::t_normal,cimg::t_purple,
 
5595
                   cimg::t_normal,cimg::t_green,
3684
5596
                   cimg_OS,
3685
5597
                   cimg::t_normal);
3686
5598
 
 
5599
      std::fprintf(stderr,"  > CPU endianness :         %s%s Endian%s\n",
 
5600
                   cimg::t_bold,
 
5601
                   cimg::endianness()?"Big":"Little",
 
5602
                   cimg::t_normal);
 
5603
 
3687
5604
#ifdef cimg_use_visualcpp6
3688
5605
      std::fprintf(stderr,"  > Using Visual C++ 6.0 :       %s%-13s%s %s('cimg_use_visualcpp6' defined)%s\n",
3689
 
                   cimg::t_bold,"Yes",cimg::t_normal,cimg::t_purple,cimg::t_normal);
3690
 
#endif
3691
 
 
3692
 
      std::fprintf(stderr,"  > Display type :           %s%-13s%s %s('cimg_display_type'=%d)%s\n",
3693
 
                   cimg::t_bold,
3694
 
                   cimg_display_type==0?"No display":(cimg_display_type==1?"X11":(cimg_display_type==2?"Windows GDI":"Unknow")),
3695
 
                   cimg::t_normal,cimg::t_purple,
3696
 
                   cimg_display_type,
3697
 
                   cimg::t_normal);
3698
 
 
3699
 
      std::fprintf(stderr,"  > Color terminal :         %s%-13s%s %s('cimg_color_terminal' %s)%s\n",
3700
 
                   cimg::t_bold,
3701
 
#ifdef cimg_color_terminal
3702
 
                   "Yes",cimg::t_normal,cimg::t_purple,"defined",
3703
 
#else
3704
 
                   "No",cimg::t_normal,cimg::t_purple,"undefined",
3705
 
#endif
3706
 
                   cimg::t_normal);
 
5606
                   cimg::t_bold,"Yes",cimg::t_normal,cimg::t_green,cimg::t_normal);
 
5607
#endif
3707
5608
 
3708
5609
      std::fprintf(stderr,"  > Debug messages :         %s%-13s%s %s('cimg_debug'=%d)%s\n",
3709
5610
                   cimg::t_bold,
3710
 
                   cimg_debug==0?"No":(cimg_debug==1 || cimg_debug==2?"Yes":(cimg_debug==3?"Yes+":"Unknown")),
3711
 
                   cimg::t_normal,cimg::t_purple,
 
5611
                   cimg_debug==0?"Quiet":(cimg_debug==1?"Stderr":(cimg_debug==2?"Dialog":(cimg_debug==3?"Stderr+Warnings":"Dialog+Warnings"))),
 
5612
                   cimg::t_normal,cimg::t_green,
3712
5613
                   cimg_debug,
3713
5614
                   cimg::t_normal);
3714
5615
 
3715
 
#if cimg_display_type==1
 
5616
      std::fprintf(stderr,"  > Stricts warnings :       %s%-13s%s %s('cimg_strict_warnings' %s)%s\n",
 
5617
                   cimg::t_bold,
 
5618
#ifdef cimg_strict_warnings
 
5619
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
 
5620
#else
 
5621
                   "No",cimg::t_normal,cimg::t_green,"undefined",
 
5622
#endif
 
5623
                   cimg::t_normal);
 
5624
 
 
5625
      std::fprintf(stderr,"  > Using VT100 messages :   %s%-13s%s %s('cimg_use_vt100' %s)%s\n",
 
5626
                   cimg::t_bold,
 
5627
#ifdef cimg_use_vt100
 
5628
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
 
5629
#else
 
5630
                   "No",cimg::t_normal,cimg::t_green,"undefined",
 
5631
#endif
 
5632
                   cimg::t_normal);
 
5633
 
 
5634
      std::fprintf(stderr,"  > Display type :           %s%-13s%s %s('cimg_display'=%d)%s\n",
 
5635
                   cimg::t_bold,
 
5636
                   cimg_display==0?"No display":
 
5637
                   (cimg_display==1?"X11":
 
5638
                    (cimg_display==2?"Windows GDI":
 
5639
                     (cimg_display==3?"Carbon":"Unknow"))),
 
5640
                   cimg::t_normal,cimg::t_green,
 
5641
                   cimg_display,
 
5642
                   cimg::t_normal);
 
5643
 
 
5644
#if cimg_display==1
3716
5645
      std::fprintf(stderr,"  > Using XShm for X11 :     %s%-13s%s %s('cimg_use_xshm' %s)%s\n",
3717
5646
                   cimg::t_bold,
3718
5647
#ifdef cimg_use_xshm
3719
 
                   "Yes",cimg::t_normal,cimg::t_purple,"defined",
 
5648
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
3720
5649
#else
3721
 
                   "No",cimg::t_normal,cimg::t_purple,"undefined",
 
5650
                   "No",cimg::t_normal,cimg::t_green,"undefined",
3722
5651
#endif
3723
5652
                   cimg::t_normal);
3724
5653
 
3725
5654
      std::fprintf(stderr,"  > Using XRand for X11 :    %s%-13s%s %s('cimg_use_xrandr' %s)%s\n",
3726
5655
                   cimg::t_bold,
3727
5656
#ifdef cimg_use_xrandr
3728
 
                   "Yes",cimg::t_normal,cimg::t_purple,"defined",
3729
 
#else
3730
 
                   "No",cimg::t_normal,cimg::t_purple,"undefined",
3731
 
#endif
3732
 
                   cimg::t_normal);
3733
 
#endif
3734
 
 
 
5657
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
 
5658
#else
 
5659
                   "No",cimg::t_normal,cimg::t_green,"undefined",
 
5660
#endif
 
5661
                   cimg::t_normal);
 
5662
#endif
 
5663
      std::fprintf(stderr,"  > Using OpenMP :           %s%-13s%s %s('cimg_use_openmp' %s)%s\n",
 
5664
                   cimg::t_bold,
 
5665
#ifdef cimg_use_openmp
 
5666
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
 
5667
#else
 
5668
                   "No",cimg::t_normal,cimg::t_green,"undefined",
 
5669
#endif
 
5670
                   cimg::t_normal);
3735
5671
      std::fprintf(stderr,"  > Using PNG library :      %s%-13s%s %s('cimg_use_png' %s)%s\n",
3736
5672
                   cimg::t_bold,
3737
5673
#ifdef cimg_use_png
3738
 
                   "Yes",cimg::t_normal,cimg::t_purple,"defined",
 
5674
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
3739
5675
#else
3740
 
                   "No",cimg::t_normal,cimg::t_purple,"undefined",
 
5676
                   "No",cimg::t_normal,cimg::t_green,"undefined",
3741
5677
#endif
3742
5678
                   cimg::t_normal);
3743
5679
      std::fprintf(stderr,"  > Using JPEG library :     %s%-13s%s %s('cimg_use_jpeg' %s)%s\n",
3744
5680
                   cimg::t_bold,
3745
5681
#ifdef cimg_use_jpeg
3746
 
                   "Yes",cimg::t_normal,cimg::t_purple,"defined",
 
5682
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
3747
5683
#else
3748
 
                   "No",cimg::t_normal,cimg::t_purple,"undefined",
 
5684
                   "No",cimg::t_normal,cimg::t_green,"undefined",
3749
5685
#endif
3750
5686
                   cimg::t_normal);
3751
5687
 
3752
5688
      std::fprintf(stderr,"  > Using TIFF library :     %s%-13s%s %s('cimg_use_tiff' %s)%s\n",
3753
5689
                   cimg::t_bold,
3754
5690
#ifdef cimg_use_tiff
3755
 
                   "Yes",cimg::t_normal,cimg::t_purple,"defined",
 
5691
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
3756
5692
#else
3757
 
                   "No",cimg::t_normal,cimg::t_purple,"undefined",
 
5693
                   "No",cimg::t_normal,cimg::t_green,"undefined",
3758
5694
#endif
3759
5695
                   cimg::t_normal);
3760
5696
 
3761
5697
      std::fprintf(stderr,"  > Using Magick++ library : %s%-13s%s %s('cimg_use_magick' %s)%s\n",
3762
5698
                   cimg::t_bold,
3763
5699
#ifdef cimg_use_magick
3764
 
                   "Yes",cimg::t_normal,cimg::t_purple,"defined",
 
5700
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
3765
5701
#else
3766
 
                   "No",cimg::t_normal,cimg::t_purple,"undefined",
 
5702
                   "No",cimg::t_normal,cimg::t_green,"undefined",
3767
5703
#endif
3768
5704
                   cimg::t_normal);
3769
5705
 
3770
5706
      std::fprintf(stderr,"  > Using FFTW3 library :    %s%-13s%s %s('cimg_use_fftw3' %s)%s\n",
3771
5707
                   cimg::t_bold,
3772
5708
#ifdef cimg_use_fftw3
3773
 
                   "Yes",cimg::t_normal,cimg::t_purple,"defined",
 
5709
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
3774
5710
#else
3775
 
                   "No",cimg::t_normal,cimg::t_purple,"undefined",
 
5711
                   "No",cimg::t_normal,cimg::t_green,"undefined",
3776
5712
#endif
3777
5713
                   cimg::t_normal);
3778
5714
 
3779
5715
      std::fprintf(stderr,"  > Using LAPACK library :   %s%-13s%s %s('cimg_use_lapack' %s)%s\n",
3780
5716
                   cimg::t_bold,
3781
5717
#ifdef cimg_use_lapack
3782
 
                   "Yes",cimg::t_normal,cimg::t_purple,"defined",
 
5718
                   "Yes",cimg::t_normal,cimg::t_green,"defined",
3783
5719
#else
3784
 
                   "No",cimg::t_normal,cimg::t_purple,"undefined",
 
5720
                   "No",cimg::t_normal,cimg::t_green,"undefined",
3785
5721
#endif
3786
5722
                   cimg::t_normal);
3787
5723
 
3791
5727
                   tmp,
3792
5728
                   cimg::t_normal,
3793
5729
#ifdef cimg_imagemagick_path
3794
 
                   cimg::t_purple,"=\""cimg_imagemagick_path"\"",
 
5730
                   cimg::t_green,"=\""cimg_imagemagick_path"\"",
3795
5731
#else
3796
 
                   cimg::t_purple," undefined",
 
5732
                   cimg::t_green," undefined",
3797
5733
#endif
3798
5734
                   cimg::t_normal);
3799
5735
 
3803
5739
                   tmp,
3804
5740
                   cimg::t_normal,
3805
5741
#ifdef cimg_graphicsmagick_path
3806
 
                   cimg::t_purple,"=\""cimg_graphicsmagick_path"\"",
 
5742
                   cimg::t_green,"=\""cimg_graphicsmagick_path"\"",
3807
5743
#else
3808
 
                   cimg::t_purple," undefined",
 
5744
                   cimg::t_green," undefined",
3809
5745
#endif
3810
5746
                   cimg::t_normal);
3811
5747
 
3815
5751
                   tmp,
3816
5752
                   cimg::t_normal,
3817
5753
#ifdef cimg_medcon_path
3818
 
                   cimg::t_purple,"=\""cimg_medcon_path"\"",
 
5754
                   cimg::t_green,"=\""cimg_medcon_path"\"",
3819
5755
#else
3820
 
                   cimg::t_purple," undefined",
 
5756
                   cimg::t_green," undefined",
3821
5757
#endif
3822
5758
                   cimg::t_normal);
3823
5759
 
3827
5763
                   tmp,
3828
5764
                   cimg::t_normal,
3829
5765
#ifdef cimg_temporary_path
3830
 
                   cimg::t_purple,"=\""cimg_temporary_path"\"",
 
5766
                   cimg::t_green,"=\""cimg_temporary_path"\"",
3831
5767
#else
3832
 
                   cimg::t_purple," undefined",
 
5768
                   cimg::t_green," undefined",
3833
5769
#endif
3834
5770
                   cimg::t_normal);
3835
5771
 
3836
5772
      std::fprintf(stderr,"\n");
3837
5773
    }
3838
5774
 
3839
 
    //! Get the value of a system timer with a millisecond precision.
3840
 
    inline unsigned long time() {
3841
 
#if cimg_OS==1
3842
 
      struct timeval st_time;
3843
 
      gettimeofday(&st_time,0);
3844
 
      return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
3845
 
#elif cimg_OS==2
3846
 
      static SYSTEMTIME st_time;
3847
 
      GetSystemTime(&st_time);
3848
 
      return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
3849
 
#else
3850
 
      return 0;
3851
 
#endif
3852
 
    }
3853
 
 
3854
 
    //! Sleep for a certain numbers of milliseconds.
3855
 
    /**
3856
 
       This function frees the CPU ressources during the sleeping time.
3857
 
       It may be used to temporize your program properly, without wasting CPU time.
3858
 
       \sa wait(), time().
3859
 
    **/
3860
 
    inline void sleep(const unsigned int milliseconds) {
3861
 
#if cimg_OS==1
3862
 
      struct timespec tv;
3863
 
      tv.tv_sec = milliseconds/1000;
3864
 
      tv.tv_nsec = (milliseconds%1000)*1000000;
3865
 
      nanosleep(&tv,0);
3866
 
#elif cimg_OS==2
3867
 
      Sleep(milliseconds);
3868
 
#endif
3869
 
    }
3870
 
 
3871
 
    inline unsigned int wait(const unsigned int milliseconds, unsigned long& timer) {
3872
 
      if (!timer) timer = cimg::time();
3873
 
      const unsigned long current_time = cimg::time();
3874
 
      if (current_time>=timer+milliseconds) { timer = current_time; return 0; }
3875
 
      const unsigned long time_diff = timer + milliseconds - current_time;
3876
 
      timer = current_time + time_diff;
3877
 
      cimg::sleep(time_diff);
3878
 
      return (unsigned int)time_diff;
3879
 
    }
3880
 
 
3881
 
    //! Wait for a certain number of milliseconds since the last call.
3882
 
    /**
3883
 
       This function is equivalent to sleep() but the waiting time is computed with regard to the last call
3884
 
       of wait(). It may be used to temporize your program properly.
3885
 
       \sa sleep(), time().
3886
 
    **/
3887
 
    inline unsigned int wait(const unsigned int milliseconds) {
3888
 
      static unsigned long timer = 0;
3889
 
      if (!timer) timer = cimg::time();
3890
 
      return wait(milliseconds,timer);
3891
 
    }
3892
 
 
3893
 
    template<typename T> inline const T rol(const T& a, const unsigned int n=1) {
3894
 
      return n?(T)((a<<n)|(a>>((sizeof(T)<<3)-n))):a;
3895
 
    }
3896
 
 
3897
 
    template<typename T> inline const T ror(const T& a, const unsigned int n=1) {
3898
 
      return n?(T)((a>>n)|(a<<((sizeof(T)<<3)-n))):a;
3899
 
    }
3900
 
 
3901
 
    //! Return the absolute value of \p a
3902
 
    template<typename T> inline T abs(const T& a)     { return a>=0?a:-a; }
3903
 
    inline bool abs(const bool a)                     { return a; }
3904
 
    inline unsigned char abs(const unsigned char a)   { return a; }
3905
 
    inline unsigned short abs(const unsigned short a) { return a; }
3906
 
    inline unsigned int abs(const unsigned int a)     { return a; }
3907
 
    inline unsigned long abs(const unsigned long a)   { return a; }
3908
 
    inline double abs(const double a)                 { return std::fabs(a); }
3909
 
    inline float abs(const float a)                   { return (float)std::fabs((double)a); }
3910
 
    inline int abs(const int a)                       { return std::abs(a); }
3911
 
 
3912
 
    //! Return the minimum between \p a and \p b.
3913
 
    template<typename T> inline const T& min(const T& a, const T& b) {
3914
 
      return a<=b?a:b;
3915
 
    }
3916
 
 
3917
 
    //! Return the minimum between \p a,\p b and \a c.
3918
 
    template<typename T> inline const T& min(const T& a, const T& b, const T& c) {
3919
 
      return cimg::min(cimg::min(a,b),c);
3920
 
    }
3921
 
 
3922
 
    //! Return the minimum between \p a,\p b,\p c and \p d.
3923
 
    template<typename T> inline const T& min(const T& a, const T& b, const T& c, const T& d) {
3924
 
      return cimg::min(cimg::min(a,b,c),d);
3925
 
    }
3926
 
 
3927
 
    //! Return the maximum between \p a and \p b.
3928
 
    template<typename T> inline const T& max(const T& a, const T& b) {
3929
 
      return a>=b?a:b;
3930
 
    }
3931
 
 
3932
 
    //! Return the maximum between \p a,\p b and \p c.
3933
 
    template<typename T> inline const T& max(const T& a, const T& b, const T& c) {
3934
 
      return cimg::max(cimg::max(a,b),c);
3935
 
    }
3936
 
 
3937
 
    //! Return the maximum between \p a,\p b,\p c and \p d.
3938
 
    template<typename T> inline const T& max(const T& a, const T& b, const T& c, const T& d) {
3939
 
      return cimg::max(cimg::max(a,b,c),d);
3940
 
    }
3941
 
 
3942
 
    //! Return the sign of \p x.
3943
 
    template<typename T> inline T sign(const T& x) {
3944
 
      return (x<0)?(T)(-1):(x==0?(T)0:(T)1);
3945
 
    }
3946
 
 
3947
 
    //! Return the nearest power of 2 higher than \p x.
3948
 
    template<typename T> inline unsigned long nearest_pow2(const T& x) {
3949
 
      unsigned long i=1;
3950
 
      while (x>i) i<<=1;
3951
 
      return i;
3952
 
    }
3953
 
 
3954
 
    //! Return \p x modulo \p m (generic modulo).
3955
 
    /**
3956
 
       This modulo function accepts negative and floating-points modulo numbers \p m.
3957
 
    **/
3958
 
    template<typename T> inline T mod(const T& x, const T& m) {
3959
 
      const double dx = (double)x, dm = (double)m;
3960
 
      if (x<0) { return (T)(dm+dx+dm*std::floor(-dx/dm)); }
3961
 
      return (T)(dx-dm*std::floor(dx/dm));
3962
 
    }
3963
 
    inline int mod(const char x, const char m) {
3964
 
      return x>=0?x%m:(x%m?m+x%m:0);
3965
 
    }
3966
 
    inline int mod(const short x, const short m) {
3967
 
      return x>=0?x%m:(x%m?m+x%m:0);
3968
 
    }
3969
 
    inline int mod(const int x, const int m) {
3970
 
      return x>=0?x%m:(x%m?m+x%m:0);
3971
 
    }
3972
 
    inline int mod(const long x, const long m) {
3973
 
      return x>=0?x%m:(x%m?m+x%m:0);
3974
 
    }
3975
 
    inline int mod(const unsigned char x, const unsigned char m) {
3976
 
      return x%m;
3977
 
    }
3978
 
    inline int mod(const unsigned short x, const unsigned short m) {
3979
 
      return x%m;
3980
 
    }
3981
 
    inline int mod(const unsigned int x, const unsigned int m) {
3982
 
      return x%m;
3983
 
    }
3984
 
    inline int mod(const unsigned long x, const unsigned long m) {
3985
 
      return x%m;
3986
 
    }
3987
 
 
3988
 
    //! Return minmod(\p a,\p b).
3989
 
    /**
3990
 
       The operator minmod(\p a,\p b) is defined to be :
3991
 
       - minmod(\p a,\p b) = min(\p a,\p b), if (\p a * \p b)>0.
3992
 
       - minmod(\p a,\p b) = 0,              if (\p a * \p b)<=0
3993
 
    **/
3994
 
    template<typename T> inline T minmod(const T& a, const T& b) {
3995
 
      return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));
3996
 
    }
3997
 
 
3998
 
    //! Return a random variable between [0,1], followin a uniform distribution.
3999
 
    inline double rand() {
4000
 
      return (double)std::rand()/RAND_MAX;
4001
 
    }
4002
 
 
4003
 
    //! Return a random variable between [-1,1], following a uniform distribution.
4004
 
    inline double crand() {
4005
 
      return 1-2*cimg::rand();
4006
 
    }
4007
 
 
4008
 
    //! Return a random variable following a gaussian distribution and a standard deviation of 1.
4009
 
    inline double grand() {
4010
 
      return std::sqrt(-2*std::log((double)(1e-10 + (1-2e-10)*cimg::rand())))*std::cos((double)(2*PI*cimg::rand()));
4011
 
    }
4012
 
 
4013
 
    //! Return a rounded number
4014
 
    inline double round(const double x, const double y, const unsigned int round_type=0) {
4015
 
      if (y<=0) return x;
4016
 
      const double delta = cimg::mod(x,y);
4017
 
      if (delta==0.0) return x;
4018
 
      const double
4019
 
        backward = x-delta,
4020
 
        forward = backward+y;
4021
 
      return round_type==1?backward:(round_type==2?forward:(2*delta<y?backward:forward));
4022
 
    }
4023
 
 
4024
 
    inline double pythagore(double a, double b) {
4025
 
      const double absa = cimg::abs(a), absb = cimg::abs(b);
4026
 
      if (absa>absb) { const double tmp = absb/absa; return absa*std::sqrt(1.0+tmp*tmp); }
4027
 
      else { const double tmp = absa/absb; return (absb==0?0:absb*std::sqrt(1.0+tmp*tmp)); }
4028
 
    }
4029
 
 
 
5775
    // Declare LAPACK function signatures if necessary.
 
5776
    //
4030
5777
#ifdef cimg_use_lapack
4031
 
    template<typename T> inline void getrf(int& N, T *lapA, int *IPIV, int &INFO) {
 
5778
    template<typename T> inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) {
4032
5779
      dgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
4033
5780
    }
4034
 
    inline void getrf(int& N, float *lapA, int *IPIV, int &INFO) {
 
5781
 
 
5782
    inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) {
4035
5783
      sgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
4036
5784
    }
4037
 
    template<typename T> inline void getri(int& N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {
 
5785
 
 
5786
    template<typename T> inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {
4038
5787
      dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
4039
5788
    }
4040
 
    inline void getri(int& N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) {
 
5789
 
 
5790
    inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) {
4041
5791
      sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
4042
5792
    }
4043
 
    template<typename T> inline void gesvd(char& JOB, int& M, int& N, T *lapA, int& MN,
4044
 
                                           T *lapS, T *lapU, T *lapV, T *WORK, int& LWORK, int& INFO) {
 
5793
 
 
5794
    template<typename T> inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN,
 
5795
                                           T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) {
4045
5796
      dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
4046
5797
    }
4047
 
    inline void gesvd(char& JOB, int& M, int& N, float *lapA, int& MN,
4048
 
                      float *lapS, float *lapU, float *lapV, float *WORK, int& LWORK, int& INFO) {
 
5798
 
 
5799
    inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN,
 
5800
                      float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) {
4049
5801
      sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
4050
5802
    }
4051
 
    template<typename T> inline void getrs(char &TRANS, int& N, T *lapA, int *IPIV, T *lapB, int& INFO) {
 
5803
 
 
5804
    template<typename T> inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) {
4052
5805
      int one = 1;
4053
5806
      dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
4054
5807
    }
4055
 
    inline void getrs(char &TRANS, int& N, float *lapA, int *IPIV, float *lapB, int& INFO) {
 
5808
 
 
5809
    inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) {
4056
5810
      int one = 1;
4057
5811
      sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
4058
5812
    }
4059
 
    template<typename T> inline void syev(char &JOB, char &UPLO, int& N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {
 
5813
 
 
5814
    template<typename T> inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {
4060
5815
      dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
4061
5816
    }
4062
 
    inline void syev(char &JOB, char &UPLO, int& N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) {
 
5817
 
 
5818
    inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) {
4063
5819
      ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
4064
5820
    }
4065
5821
#endif
4067
5823
    // End of the 'cimg' namespace
4068
5824
  }
4069
5825
 
4070
 
  /*
4071
 
   #------------------------------------------------
4072
 
   #
4073
 
   #
4074
 
   #
4075
 
   # Definition of common arithmetical operations
4076
 
   #
4077
 
   #
4078
 
   #
4079
 
   #------------------------------------------------
4080
 
   */
 
5826
  /*------------------------------------------------
 
5827
   #
 
5828
   #
 
5829
   #   Definition of mathematical operators and
 
5830
   #   external functions.
 
5831
   #
 
5832
   #
 
5833
   -------------------------------------------------*/
 
5834
  //
 
5835
  // These functions are extern to any classes and can be used for a "Matlab-style" programming,
 
5836
  // such as writting :
 
5837
  //                     blur(img,10);
 
5838
  // instead of          img.blur(10);
 
5839
  //
4081
5840
 
4082
5841
#ifdef cimg_use_visualcpp6
4083
 
  template<typename t> inline CImg<t> operator+(const CImg<t>& img, const t& val) {
 
5842
  template<typename t> inline CImg<t> operator+(const CImg<t>& img, const t val) {
4084
5843
    return CImg<t>(img,false)+=val;
4085
5844
  }
4086
5845
#else
4087
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator+(const CImg<t1>& img, const t2& val) {
4088
 
    typedef typename cimg::largest<t1,t2>::type restype;
4089
 
    return CImg<restype>(img,false)+=val;
 
5846
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const t2 val) {
 
5847
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5848
    return CImg<t1t2>(img,false)+=val;
4090
5849
 }
4091
5850
#endif
4092
5851
 
4093
5852
#ifdef cimg_use_visualcpp6
4094
 
  template<typename t> inline CImg<t> operator+(const t& val, const CImg<t>& img) {
4095
 
    return img+val;
 
5853
  template<typename t> inline CImg<t> operator+(const t val, const CImg<t>& img) {
 
5854
    return img + val;
4096
5855
  }
4097
5856
#else
4098
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator+(const t1& val, const CImg<t2>& img) {
4099
 
    return img+val;
 
5857
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImg<t2>& img) {
 
5858
    return img + val;
4100
5859
  }
4101
5860
#endif
4102
5861
 
4103
5862
#ifdef cimg_use_visualcpp6
4104
 
  template<typename t> inline CImgList<t> operator+(const CImgList<t>& list, const t& val) {
 
5863
  template<typename t> inline CImgList<t> operator+(const CImgList<t>& list, const t val) {
4105
5864
    return CImgList<t>(list)+=val;
4106
5865
  }
4107
5866
#else
4108
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator+(const CImgList<t1>& list, const t2& val) {
4109
 
    typedef typename cimg::largest<t1,t2>::type restype;
4110
 
    return CImgList<restype>(list)+=val;
 
5867
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const t2 val) {
 
5868
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5869
    return CImgList<t1t2>(list)+=val;
4111
5870
  }
4112
5871
#endif
4113
5872
 
4114
5873
#ifdef cimg_use_visualcpp6
4115
 
  template<typename t> inline CImgList<t> operator+(const t& val, const CImgList<t>& list) {
4116
 
    return list+val;
 
5874
  template<typename t> inline CImgList<t> operator+(const t val, const CImgList<t>& list) {
 
5875
    return list + val;
4117
5876
  }
4118
5877
#else
4119
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator+(const t1& val, const CImgList<t2>& list) {
4120
 
    return list+val;
 
5878
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImgList<t2>& list) {
 
5879
    return list + val;
4121
5880
  }
4122
5881
#endif
4123
5882
 
4124
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator+(const CImg<t1>& img1, const CImg<t2>& img2) {
4125
 
    typedef typename cimg::largest<t1,t2>::type restype;
4126
 
    return CImg<restype>(img1,false)+=img2;
4127
 
  }
4128
 
 
4129
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator+(const CImg<t1>& img, const CImgList<t2>& list) {
4130
 
    typedef typename cimg::largest<t1,t2>::type restype;
4131
 
    return CImgList<restype>(list)+=img;
4132
 
  }
4133
 
 
4134
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator+(const CImgList<t1>& list, const CImg<t2>& img) {
4135
 
    return img+list;
4136
 
  }
4137
 
 
4138
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator+(const CImgList<t1>& list1, const CImgList<t2>& list2) {
4139
 
    typedef typename cimg::largest<t1,t2>::type restype;
4140
 
    return CImgList<restype>(list1)+=list2;
 
5883
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img1, const CImg<t2>& img2) {
 
5884
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5885
    return CImg<t1t2>(img1,false)+=img2;
 
5886
  }
 
5887
 
 
5888
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const CImgList<t2>& list) {
 
5889
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5890
    return CImgList<t1t2>(list)+=img;
 
5891
  }
 
5892
 
 
5893
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const CImg<t2>& img) {
 
5894
    return img + list;
 
5895
  }
 
5896
 
 
5897
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list1, const CImgList<t2>& list2) {
 
5898
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5899
    return CImgList<t1t2>(list1)+=list2;
4141
5900
  }
4142
5901
 
4143
5902
#ifdef cimg_use_visualcpp6
4144
 
  template<typename t> inline CImg<t> operator-(const CImg<t>& img, const t& val) {
 
5903
  template<typename t> inline CImg<t> operator-(const CImg<t>& img, const t val) {
4145
5904
    return CImg<t>(img,false)-=val;
4146
5905
  }
4147
5906
#else
4148
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator-(const CImg<t1>& img, const t2& val) {
4149
 
    typedef typename cimg::largest<t1,t2>::type restype;
4150
 
    return CImg<restype>(img,false)-=val;
 
5907
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const t2 val) {
 
5908
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5909
    return CImg<t1t2>(img,false)-=val;
4151
5910
  }
4152
5911
#endif
4153
5912
 
4154
5913
#ifdef cimg_use_visualcpp6
4155
 
  template<typename t> inline CImg<t> operator-(const t& val, const CImg<t>& img) {
 
5914
  template<typename t> inline CImg<t> operator-(const t val, const CImg<t>& img) {
4156
5915
    return CImg<t>(img.width,img.height,img.depth,img.dim,val)-=img;
4157
5916
  }
4158
5917
#else
4159
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator-(const t1& val, const CImg<t2>& img) {
4160
 
    typedef typename cimg::largest<t1,t2>::type restype;
4161
 
    return CImg<restype>(img.width,img.height,img.depth,img.dim,(restype)val)-=img;
 
5918
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImg<t2>& img) {
 
5919
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5920
    return CImg<t1t2>(img.width,img.height,img.depth,img.dim,(t1t2)val)-=img;
4162
5921
  }
4163
5922
#endif
4164
5923
 
4165
5924
#ifdef cimg_use_visualcpp6
4166
 
  template<typename t> inline CImgList<t> operator-(const CImgList<t>& list, const t& val) {
 
5925
  template<typename t> inline CImgList<t> operator-(const CImgList<t>& list, const t val) {
4167
5926
    return CImgList<t>(list)-=val;
4168
5927
  }
4169
5928
#else
4170
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator-(const CImgList<t1>& list, const t2& val) {
4171
 
    typedef typename cimg::largest<t1,t2>::type restype;
4172
 
    return CImgList<restype>(list)-=val;
 
5929
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const t2 val) {
 
5930
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5931
    return CImgList<t1t2>(list)-=val;
4173
5932
  }
4174
5933
#endif
4175
5934
 
4176
5935
#ifdef cimg_use_visualcpp6
4177
 
  template<typename t> inline CImgList<double> operator-(const t& val, const CImgList<t>& list) {
 
5936
  template<typename t> inline CImgList<double> operator-(const t val, const CImgList<t>& list) {
4178
5937
    CImgList<t> res(list.size);
4179
 
    cimglist_for(res,l) res[l] = val-list[l];
 
5938
    cimglist_for(res,l) res[l] = val - list[l];
4180
5939
    return res;
4181
5940
  }
4182
5941
#else
4183
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator-(const t1& val, const CImgList<t2>& list) {
4184
 
    typedef typename cimg::largest<t1,t2>::type restype;
4185
 
    CImgList<restype> res(list.size);
4186
 
    cimglist_for(res,l) res[l] = val-list[l];
 
5942
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImgList<t2>& list) {
 
5943
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5944
    CImgList<t1t2> res(list.size);
 
5945
    cimglist_for(res,l) res[l] = val - list[l];
4187
5946
    return res;
4188
5947
  }
4189
5948
#endif
4190
5949
 
4191
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator-(const CImg<t1>& img1, const CImg<t2>& img2) {
4192
 
    typedef typename cimg::largest<t1,t2>::type restype;
4193
 
    return CImg<restype>(img1,false)-=img2;
 
5950
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img1, const CImg<t2>& img2) {
 
5951
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5952
    return CImg<t1t2>(img1,false)-=img2;
4194
5953
  }
4195
5954
 
4196
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator-(const CImg<t1>& img, const CImgList<t2>& list) {
4197
 
    typedef typename cimg::largest<t1,t2>::type restype;
4198
 
    CImgList<restype> res(list.size);
4199
 
    cimglist_for(res,l) res[l] = img-list[l];
 
5955
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const CImgList<t2>& list) {
 
5956
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5957
    CImgList<t1t2> res(list.size);
 
5958
    cimglist_for(res,l) res[l] = img - list[l];
4200
5959
    return res;
4201
5960
  }
4202
5961
 
4203
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator-(const CImgList<t1>& list, const CImg<t2>& img) {
4204
 
    typedef typename cimg::largest<t1,t2>::type restype;
4205
 
    return CImgList<restype>(list)-=img;
 
5962
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const CImg<t2>& img) {
 
5963
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5964
    return CImgList<t1t2>(list)-=img;
4206
5965
  }
4207
5966
 
4208
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator-(const CImgList<t1>& list1, const CImgList<t2>& list2) {
4209
 
    typedef typename cimg::largest<t1,t2>::type restype;
4210
 
    return CImgList<restype>(list1)-=list2;
 
5967
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list1, const CImgList<t2>& list2) {
 
5968
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5969
    return CImgList<t1t2>(list1)-=list2;
4211
5970
  }
4212
5971
 
4213
5972
#ifdef cimg_use_visualcpp6
4215
5974
    return CImg<t>(img,false)*=val;
4216
5975
  }
4217
5976
#else
4218
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator*(const CImg<t1>& img, const t2& val) {
4219
 
    typedef typename cimg::largest<t1,t2>::type restype;
4220
 
    return CImg<restype>(img,false)*=val;
 
5977
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const t2 val) {
 
5978
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
5979
    return CImg<t1t2>(img,false)*=val;
4221
5980
  }
4222
5981
#endif
4223
5982
 
4226
5985
    return img*val;
4227
5986
  }
4228
5987
#else
4229
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator*(const t1& val, const CImg<t2>& img) {
 
5988
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImg<t2>& img) {
4230
5989
    return img*val;
4231
5990
  }
4232
5991
#endif
4236
5995
    return CImgList<t>(list)*=val;
4237
5996
  }
4238
5997
#else
4239
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator*(const CImgList<t1>& list, const t2& val) {
4240
 
    typedef typename cimg::largest<t1,t2>::type restype;
4241
 
    return CImgList<restype>(list)*=val;
 
5998
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const t2 val) {
 
5999
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
6000
    return CImgList<t1t2>(list)*=val;
4242
6001
  }
4243
6002
#endif
4244
6003
 
4247
6006
    return list*val;
4248
6007
  }
4249
6008
#else
4250
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator*(const t1& val, const CImgList<t2>& list) {
 
6009
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImgList<t2>& list) {
4251
6010
    return list*val;
4252
6011
  }
4253
6012
#endif
4254
6013
 
4255
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator*(const CImg<t1>& img1, const CImg<t2>& img2) {
4256
 
    typedef typename cimg::largest<t1,t2>::type restype;
 
6014
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img1, const CImg<t2>& img2) {
 
6015
    typedef typename cimg::superset<t1,t2>::type t1t2;
4257
6016
    if (img1.width!=img2.height)
4258
6017
      throw CImgArgumentException("operator*() : can't multiply a matrix (%ux%u) by a matrix (%ux%u)",
4259
6018
                                  img1.width,img1.height,img2.width,img2.height);
4260
 
    CImg<restype> res(img2.width,img1.height);
4261
 
    restype val;
 
6019
    CImg<t1t2> res(img2.width,img1.height);
 
6020
    t1t2 val;
 
6021
#ifdef cimg_use_openmp
 
6022
#pragma omp parallel for if (img1.size()>=1000 && img2.size()>=1000) private(val)
 
6023
#endif
4262
6024
    cimg_forXY(res,i,j) { val = 0; cimg_forX(img1,k) val+=img1(k,j)*img2(i,k); res(i,j) = val; }
4263
6025
    return res;
4264
6026
  }
4265
6027
 
4266
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator*(const CImg<t1>& img, const CImgList<t2>& list) {
4267
 
    typedef typename cimg::largest<t1,t2>::type restype;
4268
 
    CImgList<restype> res(list.size);
 
6028
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const CImgList<t2>& list) {
 
6029
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
6030
    CImgList<t1t2> res(list.size);
4269
6031
    cimglist_for(res,l) res[l] = img*list[l];
4270
6032
    return res;
4271
6033
  }
4272
6034
 
4273
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator*(const CImgList<t1>& list, const CImg<t2>& img) {
4274
 
    typedef typename cimg::largest<t1,t2>::type restype;
4275
 
    CImgList<restype> res(list.size);
 
6035
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const CImg<t2>& img) {
 
6036
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
6037
    CImgList<t1t2> res(list.size);
4276
6038
    cimglist_for(res,l) res[l] = list[l]*img;
4277
6039
    return res;
4278
6040
  }
4279
6041
 
4280
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator*(const CImgList<t1>& list1, const CImgList<t2>& list2) {
4281
 
    typedef typename cimg::largest<t1,t2>::type restype;
4282
 
    CImgList<restype> res(cimg::min(list1.size,list2.size));
 
6042
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list1, const CImgList<t2>& list2) {
 
6043
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
6044
    CImgList<t1t2> res(cimg::min(list1.size,list2.size));
4283
6045
    cimglist_for(res,l) res[l] = list1[l]*list2[l];
4284
6046
    return res;
4285
6047
  }
4289
6051
    return CImg<t>(img,false)/=val;
4290
6052
  }
4291
6053
#else
4292
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator/(const CImg<t1>& img, const t2& val) {
4293
 
    typedef typename cimg::largest<t1,t2>::type restype;
4294
 
    return CImg<restype>(img,false)/=val;
 
6054
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const t2 val) {
 
6055
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
6056
    return CImg<t1t2>(img,false)/=val;
4295
6057
  }
4296
6058
#endif
4297
6059
 
4298
6060
#ifdef cimg_use_visualcpp6
4299
6061
  template<typename t> inline CImg<t> operator/(const double val, CImg<t>& img) {
4300
 
    return val*img.get_inverse();
 
6062
    return val*img.get_invert();
4301
6063
  }
4302
6064
#else
4303
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator/(const t1& val, CImg<t2>& img) {
4304
 
    return val*img.get_inverse();
 
6065
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator/(const t1 val, CImg<t2>& img) {
 
6066
    return val*img.get_invert();
4305
6067
  }
4306
6068
#endif
4307
6069
 
4310
6072
    return CImgList<t>(list)/=val;
4311
6073
  }
4312
6074
#else
4313
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator/(const CImgList<t1>& list, const t2& val) {
4314
 
    typedef typename cimg::largest<t1,t2>::type restype;
4315
 
    return CImgList<restype>(list)/=val;
 
6075
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const t2 val) {
 
6076
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
6077
    return CImgList<t1t2>(list)/=val;
4316
6078
  }
4317
6079
#endif
4318
6080
 
4323
6085
    return res;
4324
6086
  }
4325
6087
#else
4326
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator/(const t1& val, const CImgList<t2>& list) {
4327
 
    typedef typename cimg::largest<t1,t2>::type restype;
4328
 
    CImgList<restype> res(list.size);
 
6088
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const t1 val, const CImgList<t2>& list) {
 
6089
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
6090
    CImgList<t1t2> res(list.size);
4329
6091
    cimglist_for(res,l) res[l] = val/list[l];
4330
6092
    return res;
4331
6093
  }
4332
6094
#endif
4333
6095
 
4334
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator/(const CImg<t1>& img1, const CImg<t2>& img2) {
4335
 
    typedef typename cimg::largest<t1,t2>::type restype;
4336
 
    return CImg<restype>(img1,false)*=img2.get_inverse();
 
6096
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img1, const CImg<t2>& img2) {
 
6097
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
6098
    return CImg<t1t2>(img1,false)*=img2.get_invert();
4337
6099
  }
4338
6100
 
4339
 
  template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator/(const CImg<t1>& img, const CImgList<t2>& list) {
4340
 
    typedef typename cimg::largest<t1,t2>::type restype;
4341
 
    CImgList<restype> res(list.size);
 
6101
  template<typename t1, typename t2> inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const CImgList<t2>& list) {
 
6102
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
6103
    CImgList<t1t2> res(list.size);
4342
6104
    cimglist_for(res,l) res[l] = img/list[l];
4343
6105
    return res;
4344
6106
  }
4345
6107
 
4346
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator/(const CImgList<t1>& list, const CImg<t2>& img) {
4347
 
    typedef typename cimg::largest<t1,t2>::type restype;
4348
 
    return CImgList<restype>(list)/=img;
4349
 
  }
4350
 
 
4351
 
  template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator/(const CImgList<t1>& list1, const CImgList<t2>& list2) {
4352
 
    typedef typename cimg::largest<t1,t2>::type restype;
4353
 
    return CImgList<restype>(list1)/=list2;
4354
 
  }
4355
 
 
4356
 
  /*
4357
 
   #----------------------------------------
4358
 
   #
4359
 
   #
4360
 
   #
4361
 
   # Definition of the CImgStats structure
4362
 
   #
4363
 
   #
4364
 
   #
4365
 
   #----------------------------------------
4366
 
   */
4367
 
  //! Class used to compute basic statistics on pixel values of a \ref CImg image.
4368
 
  /**
4369
 
      Constructing a CImgStats instance from an image CImg<T> or a list CImgList<T>
4370
 
      will compute the minimum, maximum and average pixel values of the input object.
4371
 
      Optionally, the variance of the pixel values can be computed.
4372
 
      Coordinates of the pixels whose values are minimum and maximum are also stored.
4373
 
      The example below shows how to use CImgStats objects to retrieve simple statistics of an image :
4374
 
      \code
4375
 
      const CImg<float> img("my_image.jpg");                 // Read JPEG image file.
4376
 
      const CImgStats stats(img);                            // Compute basic statistics on the image.
4377
 
      stats.print("My statistics");                          // Display statistics.
4378
 
      std::printf("Max-Min = %lf",stats.max-stats.min);      // Compute the difference between extremum values.
4379
 
      \endcode
4380
 
 
4381
 
      Note that statistics are computed by considering the set of \a scalar values of the image pixels.
4382
 
      No vector-valued statistics are computed.
4383
 
  **/
4384
 
  struct CImgStats {
4385
 
    double min;                 //!< Minimum of the pixel values.
4386
 
    double max;                 //!< Maximum of the pixel values.
4387
 
    double mean;                //!< Mean of the pixel values.
4388
 
    double variance;            //!< Variance of the pixel values.
4389
 
    int xmin;                   //!< X-coordinate of the pixel with minimum value.
4390
 
    int ymin;                   //!< Y-coordinate of the pixel with minimum value.
4391
 
    int zmin;                   //!< Z-coordinate of the pixel with minimum value.
4392
 
    int vmin;                   //!< V-coordinate of the pixel with minimum value.
4393
 
    int lmin;                   //!< Image number (for a list) containing the minimum pixel.
4394
 
    int xmax;                   //!< X-coordinate of the pixel with maximum value.
4395
 
    int ymax;                   //!< Y-coordinate of the pixel with maximum value.
4396
 
    int zmax;                   //!< Z-coordinate of the pixel with maximum value.
4397
 
    int vmax;                   //!< V-coordinate of the pixel with maximum value.
4398
 
    int lmax;                   //!< Image number (for a list) containing the maximum pixel.
4399
 
 
4400
 
#ifdef cimgstats_plugin
4401
 
#include cimgstats_plugin
4402
 
#endif
4403
 
 
4404
 
    //! Default constructor.
4405
 
    CImgStats():min(0),max(0),mean(0),variance(0),xmin(-1),ymin(-1),zmin(-1),vmin(-1),lmin(-1),
4406
 
                xmax(-1),ymax(-1),zmax(-1),vmax(-1),lmax(-1) {}
4407
 
 
4408
 
    //! In-place version of the default constructor
4409
 
    CImgStats& assign() {
4410
 
      min = max = mean = variance = 0;
4411
 
      xmin = ymin = zmin = vmin = lmin = xmax = ymax = zmax = vmax = lmax = -1;
4412
 
      return *this;
4413
 
    }
4414
 
 
4415
 
    //! Copy constructor.
4416
 
    CImgStats(const CImgStats& stats) {
4417
 
      assign(stats);
4418
 
    };
4419
 
 
4420
 
    //! In-place version of the copy constructor.
4421
 
    CImgStats& assign(const CImgStats& stats) {
4422
 
      min = stats.min;
4423
 
      max = stats.max;
4424
 
      mean = stats.mean;
4425
 
      variance = stats.variance;
4426
 
      xmin = stats.xmin; ymin = stats.ymin; zmin = stats.zmin; vmin = stats.vmin; lmin = stats.lmin;
4427
 
      xmax = stats.xmax; ymax = stats.ymax; zmax = stats.zmax; vmax = stats.vmax; lmax = stats.lmax;
4428
 
      return *this;
4429
 
    }
4430
 
 
4431
 
    //! Constructor that computes statistics of an input image \p img.
4432
 
    /**
4433
 
        \param img The input image.
4434
 
        \param compute_variance If true, the \c variance field is computed, else it is set to 0.
4435
 
    **/
4436
 
    template<typename T> CImgStats(const CImg<T>& img, const bool compute_variance=true) {
4437
 
      assign(img,compute_variance);
4438
 
    }
4439
 
 
4440
 
    //! In-place version of the previous constructor.
4441
 
    template<typename T> CImgStats& assign(const CImg<T>& img, const bool compute_variance=true) {
4442
 
      if (!img)
4443
 
        throw CImgArgumentException("CImgStats::CImgStats() : Specified input image (%u,%u,%u,%u,%p) is empty.",
4444
 
                                    img.width,img.height,img.depth,img.dim,img.data);
4445
 
      mean = variance = 0;
4446
 
      lmin = lmax = -1;
4447
 
      T pmin=img[0], pmax=pmin, *ptrmin=img.data, *ptrmax=ptrmin;
4448
 
      cimg_for(img,ptr,T) {
4449
 
        const T& a=*ptr;
4450
 
        mean+=(double)a;
4451
 
        if (a<pmin) { pmin=a; ptrmin = ptr; }
4452
 
        if (a>pmax) { pmax=a; ptrmax = ptr; }
4453
 
      }
4454
 
      mean/=img.size();
4455
 
      min=(double)pmin;
4456
 
      max=(double)pmax;
4457
 
      unsigned long offmin = (unsigned long)(ptrmin-img.data), offmax = (unsigned long)(ptrmax-img.data);
4458
 
      const unsigned long whz = img.width*img.height*img.depth, wh = img.width*img.height;
4459
 
      vmin = offmin/whz; offmin%=whz; zmin = offmin/wh; offmin%=wh; ymin = offmin/img.width; xmin = offmin%img.width;
4460
 
      vmax = offmax/whz; offmax%=whz; zmax = offmax/wh; offmax%=wh; ymax = offmax/img.width; xmax = offmax%img.width;
4461
 
      if (compute_variance) {
4462
 
        cimg_for(img,ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; }
4463
 
        const unsigned int siz = img.size();
4464
 
        if (siz>1) variance/=(siz-1); else variance = 0;
4465
 
      }
4466
 
      return *this;
4467
 
    }
4468
 
 
4469
 
    //! Constructor that computes statistics of an input image list \p list.
4470
 
    /**
4471
 
       \param list The input list of images.
4472
 
       \param compute_variance If true, the \c variance field is computed, else it is set to 0.
4473
 
    **/
4474
 
    template<typename T> CImgStats(const CImgList<T>& list, const bool compute_variance=true) {
4475
 
      assign(list,compute_variance);
4476
 
    }
4477
 
 
4478
 
    //! In-place version of the previous constructor.
4479
 
    template<typename T> CImgStats& assign(const CImgList<T>& list, const bool compute_variance=true) {
4480
 
      if (!list)
4481
 
        throw CImgArgumentException("CImgStats::CImgStats() : Specified input list (%u,%p) is empty.",
4482
 
                                    list.size,list.data);
4483
 
      mean = variance = lmin = lmax = 0;
4484
 
      T pmin = list[0][0], pmax = pmin, *ptrmin = list[0].data, *ptrmax = ptrmin;
4485
 
      int psize = 0;
4486
 
      cimglist_for(list,l) {
4487
 
        cimg_for(list[l],ptr,T) {
4488
 
          const T& a=*ptr;
4489
 
          mean+=(double)a;
4490
 
          if (a<pmin) { pmin=a; ptrmin = ptr; lmin = l; }
4491
 
          if (a>pmax) { pmax=a; ptrmax = ptr; lmax = l; }
4492
 
        }
4493
 
        psize+=list[l].size();
4494
 
      }
4495
 
      mean/=psize;
4496
 
      min=(double)pmin;
4497
 
      max=(double)pmax;
4498
 
      const CImg<T> &imin = list[lmin], &imax = list[lmax];
4499
 
      unsigned long offmin = (ptrmin-imin.data), offmax = (ptrmax-imax.data);
4500
 
      const unsigned long whz1 = imin.width*imin.height*imin.depth, wh1 = imin.width*imin.height;
4501
 
      vmin = offmin/whz1; offmin%=whz1; zmin = offmin/wh1; offmin%=wh1; ymin = offmin/imin.width; xmin = offmin%imin.width;
4502
 
      const unsigned long whz2 = imax.width*imax.height*imax.depth, wh2 = imax.width*imax.height;
4503
 
      vmax = offmax/whz2; offmax%=whz2; zmax = offmax/wh2; offmax%=wh2; ymax = offmax/imax.width; xmax = offmax%imax.width;
4504
 
      if (compute_variance) {
4505
 
        cimglist_for(list,l) cimg_for(list[l],ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; }
4506
 
        if (psize>1) variance/=(psize-1); else variance = 0;
4507
 
      }
4508
 
      return *this;
4509
 
    }
4510
 
 
4511
 
    //! Assignment operator.
4512
 
    CImgStats& operator=(const CImgStats& stats) {
4513
 
      return assign(stats);
4514
 
    }
4515
 
 
4516
 
    //! Return true if the current instance contains valid statistics
4517
 
    bool is_empty() const {
4518
 
      return (xmin>=0 && ymin>=0 && zmin>=0 && vmin>=0 && xmax>=0 && ymax>=0 && zmax>=0 && vmax>=0);
4519
 
    }
4520
 
 
4521
 
    //! Casting operator
4522
 
    operator bool() const {
4523
 
      return !is_empty();
4524
 
    }
4525
 
 
4526
 
    //! Print the current statistics.
4527
 
    /**
4528
 
       Printing is done on the standard error output.
4529
 
    **/
4530
 
    const CImgStats& print(const char* title=0) const {
4531
 
      if (lmin>=0 && lmax>=0)
4532
 
        std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, "
4533
 
                     "pmin=[%d](%d,%d,%d,%d), pmax=[%d](%d,%d,%d,%d) }\n",
4534
 
                     title?title:"CImgStats",(void*)this,min,mean,variance,max,
4535
 
                     lmin,xmin,ymin,zmin,vmin,lmax,xmax,ymax,zmax,vmax);
4536
 
      else
4537
 
        std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, "
4538
 
                     "pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d) }\n",
4539
 
                     title?title:"CImgStats",(void*)this,min,mean,variance,max,
4540
 
                     xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax);
4541
 
      return *this;
4542
 
    }
4543
 
 
4544
 
  };
4545
 
 
4546
 
  /*
4547
 
   #-------------------------------------------
 
6108
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const CImg<t2>& img) {
 
6109
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
6110
    return CImgList<t1t2>(list)/=img;
 
6111
  }
 
6112
 
 
6113
  template<typename t1, typename t2> inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list1, const CImgList<t2>& list2) {
 
6114
    typedef typename cimg::superset<t1,t2>::type t1t2;
 
6115
    return CImgList<t1t2>(list1)/=list2;
 
6116
  }
 
6117
 
 
6118
  template<typename T, typename t> inline CImg<T> apply(const CImg<T>& instance, t& func) {
 
6119
    return instance.get_apply(func);
 
6120
  }
 
6121
 
 
6122
  template<typename T, typename t> inline CImg<_cimg_Tt> mul(const CImg<T>& instance, const CImg<t>& img) {
 
6123
    return instance.get_mul(img);
 
6124
  }
 
6125
 
 
6126
  template<typename T, typename t> inline CImg<_cimg_Tt> div(const CImg<T>& instance, const CImg<t>& img) {
 
6127
    return instance.get_div(img);
 
6128
  }
 
6129
 
 
6130
  template<typename T, typename t> inline CImg<_cimg_Tt> max(const CImg<T>& instance, const CImg<t>& img) {
 
6131
    return instance.get_max(img);
 
6132
  }
 
6133
 
 
6134
  template<typename T> inline CImg<T> max(const CImg<T>& instance, const T val) {
 
6135
    return instance.get_max(val);
 
6136
  }
 
6137
 
 
6138
  template<typename T, typename t> inline CImg<_cimg_Tt> min(const CImg<T>& instance, const CImg<t>& img) {
 
6139
    return instance.get_min(img);
 
6140
  }
 
6141
 
 
6142
  template<typename T> inline CImg<typename cimg::last<T,double>::type> stats(const CImg<T>& instance) {
 
6143
    return instance.get_stats();
 
6144
  }
 
6145
 
 
6146
  template<typename T> inline CImg<T> min(const CImg<T>& instance, const T val) {
 
6147
    return instance.get_min(val);
 
6148
  }
 
6149
 
 
6150
  template<typename T> inline CImg<_cimg_Tfloat> sqr(const CImg<T>& instance) {
 
6151
    return instance.get_sqr();
 
6152
  }
 
6153
 
 
6154
  template<typename T> inline CImg<_cimg_Tfloat> sqrt(const CImg<T>& instance) {
 
6155
    return instance.get_sqrt();
 
6156
  }
 
6157
 
 
6158
  template<typename T> inline CImg<_cimg_Tfloat> exp(const CImg<T>& instance) {
 
6159
    return instance.get_exp();
 
6160
  }
 
6161
 
 
6162
  template<typename T> inline CImg<_cimg_Tfloat> log(const CImg<T>& instance) {
 
6163
    return instance.get_log();
 
6164
  }
 
6165
 
 
6166
  template<typename T> inline CImg<_cimg_Tfloat> log10(const CImg<T>& instance) {
 
6167
    return instance.get_log10();
 
6168
  }
 
6169
 
 
6170
  template<typename T> inline CImg<_cimg_Tfloat> pow(const CImg<T>& instance, const double p) {
 
6171
    return instance.get_pow(p);
 
6172
  }
 
6173
 
 
6174
  template<typename T, typename t> inline CImg<_cimg_Tfloat> pow(const CImg<T>& instance, const CImg<t>& img) {
 
6175
    return instance.get_pow(img);
 
6176
  }
 
6177
 
 
6178
  template<typename T> inline CImg<_cimg_Tfloat> abs(const CImg<T>& instance) {
 
6179
    return instance.get_abs();
 
6180
  }
 
6181
 
 
6182
  template<typename T> inline CImg<_cimg_Tfloat> cos(const CImg<T>& instance) {
 
6183
    return instance.get_cos();
 
6184
  }
 
6185
 
 
6186
  template<typename T> inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) {
 
6187
    return instance.get_sin();
 
6188
  }
 
6189
 
 
6190
  template<typename T> inline CImg<_cimg_Tfloat> tan(const CImg<T>& instance) {
 
6191
    return instance.get_tan();
 
6192
  }
 
6193
 
 
6194
  template<typename T> inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) {
 
6195
    return instance.get_acos();
 
6196
  }
 
6197
 
 
6198
  template<typename T> inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) {
 
6199
    return instance.get_asin();
 
6200
  }
 
6201
 
 
6202
  template<typename T> inline CImg<_cimg_Tfloat> atan(const CImg<T>& instance) {
 
6203
    return instance.get_atan();
 
6204
  }
 
6205
 
 
6206
  template<typename T> inline CImg<T> round(const CImg<T>& instance, const float x, const unsigned int round_type=0) {
 
6207
    return instance.get_round(x,round_type);
 
6208
  }
 
6209
 
 
6210
  template<typename T> inline CImg<T> rand(const CImg<T>& instance, const T val_min, const T val_max) {
 
6211
    return instance.get_rand(val_min,val_max);
 
6212
  }
 
6213
 
 
6214
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val) {
 
6215
    return instance.get_fill(val);
 
6216
  }
 
6217
 
 
6218
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1) {
 
6219
    return instance.get_fill(val0,val1);
 
6220
  }
 
6221
 
 
6222
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2) {
 
6223
    return instance.get_fill(val0,val1,val2);
 
6224
  }
 
6225
 
 
6226
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3) {
 
6227
    return instance.get_fill(val0,val1,val2,val3);
 
6228
  }
 
6229
 
 
6230
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6231
                                           const T val4) {
 
6232
    return instance.get_fill(val0,val1,val2,val3,val4);
 
6233
  }
 
6234
 
 
6235
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6236
                                           const T val4, const T val5) {
 
6237
    return instance.get_fill(val0,val1,val2,val3,val4,val5);
 
6238
  }
 
6239
 
 
6240
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6241
                                           const T val4, const T val5, const T val6) {
 
6242
    return instance.get_fill(val0,val1,val2,val3,val4,val5,val6);
 
6243
  }
 
6244
 
 
6245
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6246
                                           const T val4, const T val5, const T val6, const T val7) {
 
6247
    return instance.get_fill(val0,val1,val2,val3,val4,val5,val6,val7);
 
6248
  }
 
6249
 
 
6250
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6251
                                           const T val4, const T val5, const T val6, const T val7, const T val8) {
 
6252
    return instance.get_fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);
 
6253
  }
 
6254
 
 
6255
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6256
                                           const T val4, const T val5, const T val6, const T val7, const T val8, const T val9) {
 
6257
    return instance.get_fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);
 
6258
  }
 
6259
 
 
6260
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6261
                                           const T val4, const T val5, const T val6, const T val7, const T val8, const T val9,
 
6262
                                           const T val10) {
 
6263
    return instance.get_fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10);
 
6264
  }
 
6265
 
 
6266
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6267
                                           const T val4, const T val5, const T val6, const T val7, const T val8, const T val9,
 
6268
                                           const T val10, const T val11) {
 
6269
    return instance.get_fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11);
 
6270
  }
 
6271
 
 
6272
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6273
                                           const T val4, const T val5, const T val6, const T val7, const T val8, const T val9,
 
6274
                                           const T val10, const T val11, const T val12) {
 
6275
    return instance.get_fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12);
 
6276
  }
 
6277
 
 
6278
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6279
                                           const T val4, const T val5, const T val6, const T val7, const T val8, const T val9,
 
6280
                                           const T val10, const T val11, const T val12, const T val13) {
 
6281
    return instance.get_fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13);
 
6282
  }
 
6283
 
 
6284
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6285
                                           const T val4, const T val5, const T val6, const T val7, const T val8, const T val9,
 
6286
                                           const T val10, const T val11, const T val12, const T val13, const T val14) {
 
6287
    return instance.get_fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14);
 
6288
  }
 
6289
 
 
6290
  template<typename T> inline CImg<T> fill(const CImg<T>& instance, const T val0, const T val1, const T val2, const T val3,
 
6291
                                           const T val4, const T val5, const T val6, const T val7, const T val8, const T val9,
 
6292
                                           const T val10, const T val11, const T val12, const T val13, const T val14, const T val15) {
 
6293
    return instance.get_fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14,val15);
 
6294
  }
 
6295
 
 
6296
  template<typename T, int N> inline CImg<T> fill(const CImg<T>& instance, const int val0, ...) {
 
6297
    CImg<T> res(instance,false);
 
6298
    va_list ap;
 
6299
    va_start(ap,val0);
 
6300
    res.template _fill<N,int>(val0,ap);
 
6301
    va_end(ap);
 
6302
    return res;
 
6303
  }
 
6304
 
 
6305
  template<typename T, int N> inline CImg<T> fill(const CImg<T>& instance, const double val0, ...) {
 
6306
    CImg<T> res(instance,false);
 
6307
    va_list ap;
 
6308
    va_start(ap,val0);
 
6309
    res.template _fill<N,double>(val0,ap);
 
6310
    va_end(ap);
 
6311
    return res;
 
6312
  }
 
6313
 
 
6314
  template<typename T> inline CImg<T> normalize(const CImg<T>& instance, const T a, const T b) {
 
6315
    return instance.get_normalize(a,b);
 
6316
  }
 
6317
 
 
6318
  template<typename T> inline CImg<T> cut(const CImg<T>& instance, const T a, const T b) {
 
6319
    return instance.get_cut(a,b);
 
6320
  }
 
6321
 
 
6322
  template<typename T> inline CImg<T> quantize(const CImg<T>& instance, const unsigned int n=256, const bool keep_range=true) {
 
6323
    return instance.get_quantize(n,keep_range);
 
6324
  }
 
6325
 
 
6326
  template<typename T> inline CImg<T> threshold(const CImg<T>& instance, const T thres) {
 
6327
    return instance.get_threshold(thres);
 
6328
  }
 
6329
 
 
6330
  template<typename T> inline CImg<T> rotate(const CImg<T>& instance, const float angle, const unsigned int cond=3) {
 
6331
    return instance.get_rotate(angle,cond);
 
6332
  }
 
6333
 
 
6334
  template<typename T> inline CImg<T> rotate(const CImg<T>& instance, const float angle, const float cx, const float cy,
 
6335
                                             const float zoom=1, const unsigned int cond=3) {
 
6336
    return instance.get_rotate(angle,cx,cy,zoom,cond);
 
6337
  }
 
6338
 
 
6339
  template<typename T> inline CImg<T> resize(const CImg<T>& instance,
 
6340
                                             const int pdx=-100, const int pdy=-100, const int pdz=-100, const int pdv=-100,
 
6341
                                             const int interpolation_type=1, const int border_condition=-1, const bool center=false) {
 
6342
    return instance.get_resize(pdx,pdy,pdz,pdv,interpolation_type,border_condition,center);
 
6343
  }
 
6344
 
 
6345
  template<typename T, typename t> inline CImg<T> resize(const CImg<T>& instance, const CImg<t>& src,
 
6346
                                                         const int interpolation_type=1, const int border_condition=-1,
 
6347
                                                         const bool center=false) {
 
6348
    return instance.get_resize(src,interpolation_type,border_condition,center);
 
6349
  }
 
6350
 
 
6351
  template<typename T> inline CImg<T> resize(const CImg<T>& instance, const CImgDisplay& disp,
 
6352
                                             const int interpolation_type=1, const int border_condition=-1, const bool center=false) {
 
6353
    return instance.get_resize(disp,interpolation_type,border_condition,center);
 
6354
  }
 
6355
 
 
6356
  template<typename T, typename t> inline CImg<t> permute_axes(const CImg<T>& instance, const char *permut, const t& pixel_type) {
 
6357
    return instance.get_permute_axes(instance,permut,pixel_type);
 
6358
  }
 
6359
 
 
6360
  template<typename T> inline CImg<T> permute_axes(const CImg<T>& instance, const char *permut="vxyz") {
 
6361
    return instance.get_permute_axes(instance,permut);
 
6362
  }
 
6363
 
 
6364
  template<typename T> inline CImg<T> resize_halfXY(const CImg<T>& instance) {
 
6365
    return instance.get_resize_halfXY();
 
6366
  }
 
6367
 
 
6368
  template<typename T> inline CImg<T> resize_doubleXY(const CImg<T>& instance) {
 
6369
    return instance.get_resize_doubleXY();
 
6370
  }
 
6371
 
 
6372
  template<typename T> inline CImg<T> resize_tripleXY(const CImg<T>& instance) {
 
6373
    return instance.get_resize_tripleXY();
 
6374
  }
 
6375
 
 
6376
  template<typename T> inline CImg<T> crop(const CImg<T>& instance, const int x0, const int y0, const int z0, const int v0,
 
6377
                                           const int x1, const int y1, const int z1, const int v1,
 
6378
                                           const bool border_condition=false) {
 
6379
    return instance.get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition);
 
6380
  }
 
6381
 
 
6382
  template<typename T> inline CImg<T> crop(const CImg<T>& instance, const int x0, const int y0, const int z0,
 
6383
                                           const int x1, const int y1, const int z1,
 
6384
                                           const bool border_condition=false) {
 
6385
    return instance.get_crop(x0,y0,z0,x1,y1,z1,border_condition);
 
6386
  }
 
6387
 
 
6388
  template<typename T> inline CImg<T> crop(const CImg<T>& instance, const int x0, const int y0,
 
6389
                                           const int x1, const int y1,
 
6390
                                           const bool border_condition=false) {
 
6391
    return instance.get_crop(x0,y0,x1,y1,border_condition);
 
6392
  }
 
6393
 
 
6394
  template<typename T> inline CImg<T> crop(const CImg<T>& instance, const int x0, const int x1,
 
6395
                                           const bool border_condition=false) {
 
6396
    return instance.get_crop(x0,x1,border_condition);
 
6397
  }
 
6398
 
 
6399
  template<typename T> inline CImg<T> columns(const CImg<T>& instance, const unsigned int x0, const unsigned int x1) {
 
6400
    return instance.get_columns(x0,x1);
 
6401
  }
 
6402
 
 
6403
  template<typename T> inline CImg<T> column(const CImg<T>& instance, const unsigned int x0) {
 
6404
    return instance.get_column(x0);
 
6405
  }
 
6406
 
 
6407
  template<typename T> inline CImg<T> lines(const CImg<T>& instance, const unsigned int y0, const unsigned int y1) {
 
6408
    return instance.get_lines(y0,y1);
 
6409
  }
 
6410
 
 
6411
  template<typename T> inline CImg<T> line(const CImg<T>& instance, const unsigned int y0) {
 
6412
    return instance.get_line(y0);
 
6413
  }
 
6414
 
 
6415
  template<typename T> inline CImg<T> slices(const CImg<T>& instance, const unsigned int z0, const unsigned int z1) {
 
6416
    return instance.get_slices(z0,z1);
 
6417
  }
 
6418
 
 
6419
  template<typename T> inline CImg<T> slice(const CImg<T>& instance, const unsigned int z0) {
 
6420
    return instance.get_slice(z0);
 
6421
  }
 
6422
 
 
6423
  template<typename T> inline CImg<T> channels(const CImg<T>& instance, const unsigned int v0, const unsigned int v1) {
 
6424
    return instance.get_channels(v0,v1);
 
6425
  }
 
6426
 
 
6427
  template<typename T> inline CImg<T> channel(const CImg<T>& instance, const unsigned int v0) {
 
6428
    return instance.get_channel(v0);
 
6429
  }
 
6430
 
 
6431
  template<typename T> inline CImg<T> shared_points(CImg<T>& instance, const unsigned int x0, const unsigned int x1,
 
6432
                                                    const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) {
 
6433
    return instance.get_shared_points(x0,x1,y0,z0,v0);
 
6434
  }
 
6435
 
 
6436
  template<typename T> inline CImg<T> shared_points(const CImg<T>& instance, const unsigned int x0, const unsigned int x1,
 
6437
                                                    const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) {
 
6438
    return instance.get_shared_points(x0,x1,y0,z0,v0);
 
6439
  }
 
6440
 
 
6441
  template<typename T> inline CImg<T> shared_lines(CImg<T>& instance, const unsigned int y0, const unsigned int y1,
 
6442
                                                   const unsigned int z0=0, const unsigned int v0=0) {
 
6443
    return instance.get_shared_lines(y0,y1,z0,v0);
 
6444
  }
 
6445
 
 
6446
  template<typename T> inline CImg<T> shared_lines(const CImg<T>& instance, const unsigned int y0, const unsigned int y1,
 
6447
                                                   const unsigned int z0=0, const unsigned int v0=0) {
 
6448
    return instance.get_shared_lines(y0,y1,z0,v0);
 
6449
  }
 
6450
 
 
6451
  template<typename T> inline CImg<T> shared_line(CImg<T>& instance,
 
6452
                                                  const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) {
 
6453
    return instance.get_shared_line(y0,z0,v0);
 
6454
  }
 
6455
 
 
6456
  template<typename T> inline CImg<T> shared_line(const CImg<T>& instance,
 
6457
                                                  const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) {
 
6458
    return instance.get_shared_line(y0,z0,v0);
 
6459
  }
 
6460
 
 
6461
  template<typename T> inline CImg<T> shared_planes(CImg<T>& instance,
 
6462
                                                    const unsigned int z0, const unsigned int z1, const unsigned int v0=0) {
 
6463
    return instance.get_shared_planes(z0,z1,v0);
 
6464
  }
 
6465
 
 
6466
  template<typename T> inline CImg<T> shared_planes(const CImg<T>& instance,
 
6467
                                                    const unsigned int z0, const unsigned int z1, const unsigned int v0=0) {
 
6468
    return instance.get_shared_planes(z0,z1,v0);
 
6469
  }
 
6470
 
 
6471
  template<typename T> inline CImg<T> shared_plane(CImg<T>& instance, const unsigned int z0, const unsigned int v0=0) {
 
6472
    return instance.get_shared_plane(z0,v0);
 
6473
  }
 
6474
 
 
6475
  template<typename T> inline CImg<T> shared_plane(const CImg<T>& instance, const unsigned int z0, const unsigned int v0=0) {
 
6476
    return instance.get_shared_plane(z0,v0);
 
6477
  }
 
6478
 
 
6479
  template<typename T> inline CImg<T> shared_channels(CImg<T>& instance, const unsigned int v0, const unsigned int v1) {
 
6480
    return instance.get_shared_channels(v0,v1);
 
6481
  }
 
6482
 
 
6483
  template<typename T> inline CImg<T> shared_channels(const CImg<T>& instance, const unsigned int v0, const unsigned int v1) {
 
6484
    return instance.get_shared_channels(v0,v1);
 
6485
  }
 
6486
 
 
6487
  template<typename T> inline CImg<T> shared_channel(CImg<T>& instance, const unsigned int v0) {
 
6488
    return instance.get_shared_channel(v0);
 
6489
  }
 
6490
 
 
6491
  template<typename T> inline CImg<T> shared_channel(const CImg<T>& instance, const unsigned int v0) {
 
6492
    return instance.get_shared_channel(v0);
 
6493
  }
 
6494
 
 
6495
  template<typename T> inline CImg<T> shared(CImg<T>& instance) {
 
6496
    return instance.get_shared();
 
6497
  }
 
6498
 
 
6499
  template<typename T> inline CImg<T> shared(const CImg<T>& instance) {
 
6500
    return instance.get_shared();
 
6501
  }
 
6502
 
 
6503
  template<typename T> inline CImg<T> mirror(const CImg<T>& instance, const char axe='x') {
 
6504
    return instance.get_mirror(axe);
 
6505
  }
 
6506
 
 
6507
  template<typename T> inline CImg<T> translate(const CImg<T>& instance, const int deltax, const int deltay=0, const int deltaz=0,
 
6508
                                                const int deltav=0, const int border_condition=0) {
 
6509
    return instance.get_translate(deltax,deltay,deltaz,deltav,border_condition);
 
6510
  }
 
6511
 
 
6512
  template<typename T> inline CImg<T> projections2d(const CImg<T>& instance,
 
6513
                                                    const unsigned int x0, const unsigned int y0, const unsigned int z0,
 
6514
                                                    const int dx=-100, const int dy=-100, const int dz=-100) {
 
6515
    return instance.get_projections2d(x0,y0,z0,dx,dy,dz);
 
6516
  }
 
6517
 
 
6518
  template<typename T> inline CImg<typename cimg::last<T,float>::type>
 
6519
  histogram(const CImg<T>& instance, const unsigned int nblevels=256, const T val_min=(T)0, const T val_max=(T)0) {
 
6520
    return instance.get_histogram(nblevels,val_min,val_max);
 
6521
  }
 
6522
 
 
6523
  template<typename T> inline CImg<T> equalize_histogram(const CImg<T>& instance,
 
6524
                                                         const unsigned int nblevels=256, const T val_min=(T)0, const T val_max=(T)0) {
 
6525
    return instance.get_equalize_histogram(nblevels,val_min,val_max);
 
6526
  }
 
6527
 
 
6528
  template<typename T> inline CImg<typename cimg::last<T,unsigned int>::type> label_regions(const CImg<T>& instance) {
 
6529
    return instance.get_label_regions();
 
6530
  }
 
6531
 
 
6532
  template<typename T> inline CImg<_cimg_Tfloat> norm_pointwise(const CImg<T>& instance, int norm_type=2) {
 
6533
    return instance.get_norm_pointwise(norm_type);
 
6534
  }
 
6535
 
 
6536
  template<typename T> inline CImg<_cimg_Tfloat> orientation_pointwise(const CImg<T>& instance) {
 
6537
    return instance.get_orientation_pointwise();
 
6538
  }
 
6539
 
 
6540
  template<typename T> inline CImgList<T> split(const CImg<T>& instance, const char axe='x', const unsigned int nb=0) {
 
6541
    return instance.get_split(axe,nb);
 
6542
  }
 
6543
 
 
6544
  template<typename T> inline CImg<T> append(const CImg<T>& instance, const CImg<T>& img, const char axis='x', const char align='c') {
 
6545
    return instance.get_append(img,axis,align);
 
6546
  }
 
6547
 
 
6548
  template<typename T> inline CImgList<_cimg_Tfloat> gradientXY(const CImg<T>& instance, const int scheme=0) {
 
6549
    return instance.get_gradientXY(scheme);
 
6550
  }
 
6551
 
 
6552
  template<typename T> inline CImgList<_cimg_Tfloat> gradientXYZ(const CImg<T>& instance, const int scheme=0) {
 
6553
    return instance.get_gradientXYZ(scheme);
 
6554
  }
 
6555
 
 
6556
  template<typename T> inline CImg<_cimg_Tfloat> structure_tensorXY(const CImg<T>& instance, const int scheme=1) {
 
6557
    return instance.get_structure_tensorXY(scheme);
 
6558
  }
 
6559
 
 
6560
  template<typename T> inline CImg<_cimg_Tfloat> structure_tensorXYZ(const CImg<T>& instance, const int scheme=1) {
 
6561
    return instance.get_structure_tensorXYZ(scheme);
 
6562
  }
 
6563
 
 
6564
  template<typename T> inline CImg<_cimg_Tfloat>
 
6565
  distance_function(const CImg<T>& instance, const unsigned int nb_iter=100, const float band_size=0.0f, const float precision=0.5f) {
 
6566
    return instance.get_distance_function(nb_iter,band_size,precision);
 
6567
  }
 
6568
 
 
6569
  template<typename T, typename t> inline CImg<_cimg_Tfloat>
 
6570
  dijkstra(const CImg<T>& instance, const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) {
 
6571
    return instance.get_dijkstra(starting_node,ending_node,previous);
 
6572
  }
 
6573
 
 
6574
  template<typename T, typename t> inline CImg<_cimg_Tfloat>
 
6575
  dijkstra(const CImg<T>& instance, const unsigned int starting_node, const unsigned int ending_node=~0U) {
 
6576
    return instance.get_dijkstra(starting_node,ending_node);
 
6577
  }
 
6578
 
 
6579
  template<typename T, typename t> inline CImg<t> RGBtoLUT(const CImg<T>& instance, const CImg<t>& palette,
 
6580
                                                           const bool dithering=true, const bool indexing=false) {
 
6581
    return instance.get_RGBtoLUT(palette,dithering,indexing);
 
6582
  }
 
6583
 
 
6584
  template<typename T> inline CImg<_cimg_Tuchar> RGBtoLUT(const CImg<T>& instance,
 
6585
                                                          const bool dithering=true, const bool indexing=false) {
 
6586
    return instance.get_RGBtoLUT(dithering,indexing);
 
6587
  }
 
6588
 
 
6589
  template<typename T, typename t> inline CImg<t> LUTtoRGB(const CImg<T>& instance, const CImg<t>& palette) {
 
6590
    return instance.get_LUTtoRGB(palette);
 
6591
  }
 
6592
 
 
6593
  template<typename T> inline CImg<_cimg_Tuchar> LUTtoRGB(const CImg<T>& instance) {
 
6594
    return instance.get_LUTtoRGB();
 
6595
  }
 
6596
 
 
6597
  template<typename T> inline CImg<_cimg_Tfloat> RGBtoHSV(const CImg<T>& instance) {
 
6598
    return instance.get_RGBtoHSV();
 
6599
  }
 
6600
 
 
6601
  template<typename T> inline CImg<_cimg_Tfloat> HSVtoRGB(const CImg<T>& instance) {
 
6602
    return instance.get_HSVtoRGB();
 
6603
  }
 
6604
 
 
6605
  template<typename T> inline CImg<_cimg_Tfloat> RGBtoHSL(const CImg<T>& instance) {
 
6606
    return instance.get_RGBtoHSL();
 
6607
  }
 
6608
 
 
6609
  template<typename T> inline CImg<_cimg_Tuchar> HSLtoRGB(const CImg<T>& instance) {
 
6610
    return instance.get_HSLtoRGB();
 
6611
  }
 
6612
 
 
6613
  template<typename T> inline CImg<_cimg_Tfloat> RGBtoHSI(const CImg<T>& instance) {
 
6614
    return instance.get_RGBtoHSI();
 
6615
  }
 
6616
 
 
6617
  template<typename T> inline CImg<_cimg_Tuchar> HSItoRGB(const CImg<T>& instance) {
 
6618
    return instance.get_HSItoRGB();
 
6619
  }
 
6620
 
 
6621
  template<typename T> inline CImg<_cimg_Tuchar> RGBtoYCbCr(const CImg<T>& instance) {
 
6622
    return instance.get_RGBtoYCbCr();
 
6623
  }
 
6624
 
 
6625
  template<typename T> inline CImg<_cimg_Tuchar> YCbCrtoRGB(const CImg<T>& instance) {
 
6626
    return instance.get_YCbCrtoRGB();
 
6627
  }
 
6628
 
 
6629
  template<typename T> inline CImg<_cimg_Tfloat> RGBtoYUV(const CImg<T>& instance) {
 
6630
    return instance.get_RGBtoYUV();
 
6631
  }
 
6632
 
 
6633
  template<typename T> inline CImg<_cimg_Tuchar> YUVtoRGB(const CImg<T>& instance) {
 
6634
    return instance.get_YUVtoRGB();
 
6635
  }
 
6636
 
 
6637
  template<typename T> inline CImg<_cimg_Tfloat> RGBtoXYZ(const CImg<T>& instance) {
 
6638
    return instance.get_RGBtoXYZ();
 
6639
  }
 
6640
 
 
6641
  template<typename T> inline CImg<_cimg_Tuchar> XYZtoRGB(const CImg<T>& instance) {
 
6642
    return instance.get_XYZtoRGB();
 
6643
  }
 
6644
 
 
6645
  template<typename T> inline CImg<_cimg_Tfloat> RGBtoCMY(const CImg<T>& instance) {
 
6646
    return instance.get_RGBtoCMY();
 
6647
  }
 
6648
 
 
6649
  template<typename T> inline CImg<_cimg_Tuchar> CMYtoRGB(const CImg<T>& instance) {
 
6650
    return instance.get_CMYtoRGB();
 
6651
  }
 
6652
 
 
6653
  template<typename T> inline CImg<_cimg_Tfloat> CMYtoCMYK(const CImg<T>& instance) {
 
6654
    return instance.get_CMYtoCMYK();
 
6655
  }
 
6656
 
 
6657
  template<typename T> inline CImg<_cimg_Tfloat> CMYKtoCMY(const CImg<T>& instance) {
 
6658
    return instance.get_CMYKtoCMY();
 
6659
  }
 
6660
 
 
6661
  template<typename T> inline CImg<_cimg_Tfloat> RGBtoCMYK(const CImg<T>& instance) {
 
6662
    return instance.get_RGBtoCMYK();
 
6663
  }
 
6664
 
 
6665
  template<typename T> inline CImg<_cimg_Tuchar> CMYKtoRGB(const CImg<T>& instance) {
 
6666
    return instance.get_CMYKtoRGB();
 
6667
  }
 
6668
 
 
6669
  template<typename T> inline CImg<_cimg_Tfloat> XYZtoLab(const CImg<T>& instance) {
 
6670
    return instance.get_XYZtoLab();
 
6671
  }
 
6672
 
 
6673
  template<typename T> inline CImg<_cimg_Tfloat> LabtoXYZ(const CImg<T>& instance) {
 
6674
    return instance.get_LabtoXYZ();
 
6675
  }
 
6676
 
 
6677
  template<typename T> inline CImg<_cimg_Tfloat> XYZtoxyY(const CImg<T>& instance) {
 
6678
    return instance.get_XYZtoxyY();
 
6679
  }
 
6680
 
 
6681
  template<typename T> inline CImg<_cimg_Tfloat> xyYtoXYZ(const CImg<T>& instance) {
 
6682
    return instance.get_xyYtoXYZ();
 
6683
  }
 
6684
 
 
6685
  template<typename T> inline CImg<_cimg_Tfloat> RGBtoLab(const CImg<T>& instance) {
 
6686
    return instance.get_RGBtoLab();
 
6687
  }
 
6688
 
 
6689
  template<typename T> inline CImg<_cimg_Tuchar> LabtoRGB(const CImg<T>& instance) {
 
6690
    return instance.get_LabtoRGB();
 
6691
  }
 
6692
 
 
6693
  template<typename T> inline CImg<_cimg_Tfloat> RGBtoxyY(const CImg<T>& instance) {
 
6694
    return instance.get_RGBtoxyY();
 
6695
  }
 
6696
 
 
6697
  template<typename T> inline CImg<_cimg_Tuchar> xyYtoRGB(const CImg<T>& instance) {
 
6698
    return instance.get_xyYtoRGB();
 
6699
  }
 
6700
 
 
6701
  template<typename T> inline CImg<T> RGBtoBayer(const CImg<T>& instance, const bool even_mode=true) {
 
6702
    return instance.get_RGBtoBayer(even_mode);
 
6703
  }
 
6704
 
 
6705
  template<typename T> inline CImg<T> BayertoRGB(const CImg<T>& instance, const unsigned int interpolation_type=3, const bool even_mode=true) {
 
6706
    return instance.get_BayertoRGB(interpolation_type,even_mode);
 
6707
  }
 
6708
 
 
6709
  template<typename T, typename t> inline CImg<_cimg_Tt>
 
6710
  correlate(const CImg<T>& instance, const CImg<t>& mask, const unsigned int cond=1, const bool weighted_correl=false) {
 
6711
    return instance.get_correlate(mask,cond,weighted_correl);
 
6712
  }
 
6713
 
 
6714
  template<typename T, typename t> inline CImg<_cimg_Tt>
 
6715
  convolve(const CImg<T>& instance, const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) {
 
6716
    return instance.get_convolve(mask,cond,weighted_convol);
 
6717
  }
 
6718
 
 
6719
  template<typename T, typename t> inline CImg<_cimg_Tt>
 
6720
  erode(const CImg<T>& instance, const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) {
 
6721
    return instance.get_erode(mask,cond,weighted_erosion);
 
6722
  }
 
6723
 
 
6724
  template<typename T> inline CImg<T> erode(const CImg<T>& instance, const unsigned int n, const unsigned int cond=1) {
 
6725
    return instance.get_erode(n,cond);
 
6726
  }
 
6727
 
 
6728
  template<typename T, typename t> inline CImg<_cimg_Tt>
 
6729
  dilate(const CImg<T>& instance, const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) {
 
6730
    return instance.get_dilate(mask,cond,weighted_dilatation);
 
6731
  }
 
6732
 
 
6733
  template<typename T> inline CImg<T> dilate(const CImg<T>& instance, const unsigned int n, const unsigned int cond=1) {
 
6734
    return instance.get_dilate(n,cond);
 
6735
  }
 
6736
 
 
6737
  template<typename T> inline CImg<T> noise(const CImg<T>& instance, const double sigma=-20, const unsigned int ntype=0) {
 
6738
    return instance.get_noise(sigma,ntype);
 
6739
  }
 
6740
 
 
6741
  template<typename T> inline CImg<_cimg_Tfloat>
 
6742
  deriche(const CImg<T>& instance, const float sigma, const int order=0, const char axe='x', const bool cond=true) {
 
6743
    return instance.get_deriche(sigma,order,axe,cond);
 
6744
  }
 
6745
 
 
6746
  template<typename T> inline CImg<_cimg_Tfloat>
 
6747
  blur(const CImg<T>& instance, const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) {
 
6748
    return instance.get_blur(sigmax,sigmay,sigmaz,cond);
 
6749
  }
 
6750
 
 
6751
  template<typename T> inline CImg<_cimg_Tfloat>
 
6752
  blur(const CImg<T>& instance, const float sigma, const bool cond=true) {
 
6753
    return instance.get_blur(sigma,cond);
 
6754
  }
 
6755
 
 
6756
  template<typename T, typename t> inline CImg<T> blur_anisotropic(const CImg<T>& instance, const CImg<t>& G, const float amplitude=60.0f,
 
6757
                                                                   const float dl=0.8f, const float da=30.0f,
 
6758
                                                                   const float gauss_prec=2.0f, const unsigned int interpolation_type=0,
 
6759
                                                                   const bool fast_approx=true) {
 
6760
    return instance.get_blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
 
6761
  }
 
6762
 
 
6763
  template<typename T, typename tm> inline CImg<T> blur_anisotropic(const CImg<T>& instance, const CImg<tm>& mask,
 
6764
                                                                    const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 
6765
                                                                    const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
 
6766
                                                                    const float da=30.0f, const float gauss_prec=2.0f,
 
6767
                                                                    const unsigned int interpolation_type=0, const bool fast_approx=true,
 
6768
                                                                    const float geom_factor=1.0f) {
 
6769
    return instance.get_blur_anisotropic(mask,amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
 
6770
  }
 
6771
 
 
6772
  template<typename T> inline CImg<T> blur_anisotropic(const CImg<T>& instance, const float amplitude, const float sharpness=0.7f,
 
6773
                                                       const float anisotropy=0.3f,
 
6774
                                                       const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
 
6775
                                                       const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation_type=0,
 
6776
                                                       const bool fast_approx=true, const float geom_factor=1.0f) {
 
6777
    return instance.get_blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
 
6778
  }
 
6779
 
 
6780
  template<typename T> inline CImg<T> blur_bilateral(const CImg<T>& instance,
 
6781
                                                     const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
 
6782
                                                     const int bgridx, const int bgridy, const int bgridz, const int bgridr,
 
6783
                                                     const bool interpolation_type=true) {
 
6784
    return instance.get_blur_bilateral(sigmax,sigmay,sigmaz,sigmar,bgridx,bgridy,bgridz,bgridr,interpolation_type);
 
6785
  }
 
6786
 
 
6787
  template<typename T> inline CImg<T> blur_bilateral(const CImg<T>& instance,
 
6788
                                                     const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
 
6789
                                                     const bool interpolation_type=true) {
 
6790
    return instance.get_blur_bilateral(sigmas,sigmar,bgrids,bgridr,interpolation_type);
 
6791
  }
 
6792
 
 
6793
  template<typename T> inline CImg<T> blur_patch(const CImg<T>& instance, const unsigned int patch_size=3,
 
6794
                                                 const float sigma_p=10.0f, const float sigma_s=10.0f,
 
6795
                                                 const unsigned int lookup_size=4, const bool fast_approx=true) {
 
6796
    return instance.get_blur_patch(patch_size,sigma_p,sigma_s,lookup_size,fast_approx);
 
6797
  }
 
6798
 
 
6799
  template<typename T> inline CImgList<_cimg_Tfloat> FFT(const CImg<T>& instance, const char axe, const bool invert=false) {
 
6800
    return instance.get_FFT(axe,invert);
 
6801
  }
 
6802
 
 
6803
  template<typename T> inline CImgList<_cimg_Tfloat> FFT(const CImg<T>& instance, const bool invert=false) {
 
6804
    return instance.get_FFT(invert);
 
6805
  }
 
6806
 
 
6807
  template<typename T> inline CImg<T> blur_median(const CImg<T>& instance, const unsigned int n=3) {
 
6808
    return instance.get_blur_median(n);
 
6809
  }
 
6810
 
 
6811
  template<typename T> inline CImg<T> sharpen(const CImg<T>& instance, const float amplitude=50.0f, const float edge=1.0f,
 
6812
                                              const float alpha=0.0f, const float sigma=0.0f) {
 
6813
    return instance.get_sharpen(amplitude,edge,alpha,sigma);
 
6814
  }
 
6815
 
 
6816
  template<typename T> inline CImg<_cimg_Tfloat>
 
6817
  haar(const CImg<T>& instance, const char axis, const bool invert=false, const unsigned int nb_scales=1) {
 
6818
    return instance.get_haar(axis,invert,nb_scales);
 
6819
  }
 
6820
 
 
6821
  template<typename T> inline CImg<_cimg_Tfloat>
 
6822
  haar(const CImg<T>& instance, const bool invert=false, const unsigned int nb_scales=1) {
 
6823
    return instance.get_haar(invert,nb_scales);
 
6824
  }
 
6825
 
 
6826
  template<typename T> inline CImg<_cimg_Tfloat>
 
6827
  displacement_field(const CImg<T>& instance, const CImg<T>& target,
 
6828
                     const float smooth=0.1f, const float precision=0.1f,
 
6829
                     const unsigned int nb_scales=0, const unsigned int itermax=10000) {
 
6830
    return instance.get_displacement_field(target,smooth,precision,nb_scales,itermax);
 
6831
  }
 
6832
 
 
6833
  template<typename T> inline CImg<T> matrix(const CImg<T>& instance) {
 
6834
    return instance.get_matrix();
 
6835
  }
 
6836
 
 
6837
  template<typename T> inline CImg<T> tensor(const CImg<T>& instance) {
 
6838
    return instance.get_tensor();
 
6839
  }
 
6840
 
 
6841
  template<typename T> inline CImg<T> unroll(const CImg<T>& instance, const char axe='x') {
 
6842
    return instance.get_unroll(axe);
 
6843
  }
 
6844
 
 
6845
  template<typename T> inline CImg<T> diagonal(const CImg<T>& instance) {
 
6846
    return instance.get_diagonal();
 
6847
  }
 
6848
 
 
6849
  template<typename T> inline CImg<T> identity_matrix(const CImg<T>& instance) {
 
6850
    return instance.get_identity_matrix();
 
6851
  }
 
6852
 
 
6853
  template<typename T> inline CImg<T> sequence(const CImg<T>& instance, const T a0, const T a1) {
 
6854
    return instance.get_sequence(a0,a1);
 
6855
  }
 
6856
 
 
6857
  template<typename T> inline CImg<T> vector_at(const CImg<T>& instance, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
 
6858
    return instance.get_vector_at(x,y,z);
 
6859
  }
 
6860
 
 
6861
  template<typename T> inline CImg<T> matrix_at(const CImg<T>& instance, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
 
6862
    return instance.get_matrix_at(x,y,z);
 
6863
  }
 
6864
 
 
6865
  template<typename T> inline CImg<T> tensor_at(const CImg<T>& instance, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
 
6866
    return instance.get_tensor_at(x,y,z);
 
6867
  }
 
6868
 
 
6869
  template<typename T> inline CImg<T> transpose(const CImg<T>& instance) {
 
6870
    return instance.get_transpose();
 
6871
  }
 
6872
 
 
6873
  template<typename T> inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance, const bool use_LU=true) {
 
6874
    return instance.get_invert(use_LU);
 
6875
  }
 
6876
 
 
6877
  template<typename T> inline CImg<_cimg_Tfloat> pseudoinvert(const CImg<T>& instance) {
 
6878
    return instance.get_pseudoinvert();
 
6879
  }
 
6880
 
 
6881
  template<typename T, typename t> inline CImg<_cimg_Tt> cross(const CImg<T>& instance, const CImg<t>& img) {
 
6882
    return instance.get_cross(img);
 
6883
  }
 
6884
 
 
6885
  template<typename T> inline CImgList<_cimg_Tfloat> SVD(const CImg<T>& instance, const bool sorting=true) {
 
6886
    return instance.get_SVD(sorting);
 
6887
  }
 
6888
 
 
6889
  template<typename T, typename t> inline CImg<typename cimg::superset2<T,t,float>::type> solve(const CImg<T>& instance, const CImg<t>& A) {
 
6890
    return instance.get_solve(A);
 
6891
  }
 
6892
 
 
6893
  template<typename T> inline CImgList<_cimg_Tfloat> eigen(const CImg<T>& instance) {
 
6894
    return instance.get_eigen();
 
6895
  }
 
6896
 
 
6897
  template<typename T> inline CImgList<_cimg_Tfloat> symmetric_eigen(const CImg<T>& instance) {
 
6898
    return instance.get_symmetric_eigen();
 
6899
  }
 
6900
 
 
6901
  template<typename T, typename t> inline CImg<T> sort(const CImg<T>& instance, CImg<t>& permutations, const bool increasing=true) {
 
6902
    return instance.get_sort(permutations,increasing);
 
6903
  }
 
6904
 
 
6905
  template<typename T> inline CImg<T> sort(const CImg<T>& instance, const bool increasing=true) {
 
6906
    return instance.get_sort(increasing);
 
6907
  }
 
6908
 
 
6909
  template<typename T, typename t> inline CImg<T> permute(const CImg<T>& instance, const CImg<t>& permutation) {
 
6910
    return instance.get_permute(permutation);
 
6911
  }
 
6912
 
 
6913
  template<typename T> inline CImg<typename cimg::last<T,int>::type>
 
6914
  coordinates(const CImg<T>& instance, const int coords_type, CImgDisplay &disp,
 
6915
              unsigned int *const XYZ=0, const unsigned char *const color=0) {
 
6916
    return instance.get_coordinates(coords_type,disp,XYZ,color);
 
6917
  }
 
6918
 
 
6919
  template<typename T, typename t> inline CImgList<_cimg_Tt>
 
6920
  insert(const CImgList<T>& instance, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) {
 
6921
    return instance.get_insert(img,pos,shared);
 
6922
  }
 
6923
 
 
6924
  template<typename T, typename t> inline CImgList<_cimg_Tt>
 
6925
  insert(const CImgList<T>& instance, const unsigned int n, const CImg<t>& img,
 
6926
         const unsigned int pos=~0U, const bool shared=false) {
 
6927
    return instance.get_insert(n,img,pos,shared);
 
6928
  }
 
6929
 
 
6930
  template<typename T, typename t> inline CImgList<_cimg_Tt>
 
6931
  insert(const CImgList<T>& instance, const CImgList<t>& list, const unsigned int pos=~0U, int shared=0) {
 
6932
    return instance.get_insert(list,pos,shared);
 
6933
  }
 
6934
 
 
6935
  template<typename T, typename t> inline CImgList<_cimg_Tt>
 
6936
  insert(const CImgList<T>& instance, const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const int shared=0) {
 
6937
    return instance.insert(n,list,pos,shared);
 
6938
  }
 
6939
 
 
6940
  template<typename T> inline CImgList<T> remove(const CImgList<T>& instance, const unsigned int pos) {
 
6941
    return instance.get_remove(pos);
 
6942
  }
 
6943
 
 
6944
  template<typename T> inline CImgList<T> remove(const CImgList<T>& instance) {
 
6945
    return instance.get_remove();
 
6946
  }
 
6947
 
 
6948
  template<typename T> inline CImgList<T> reverse(const CImgList<T>& instance) {
 
6949
    return instance.get_reverse();
 
6950
  }
 
6951
 
 
6952
  template<typename T> inline CImgList<T> crop(const CImgList<T>& instance, const unsigned int i0, const unsigned int i1,
 
6953
                                               const bool shared=false) {
 
6954
    return instance.get_crop(i0,i1,shared);
 
6955
  }
 
6956
 
 
6957
  template<typename T> inline CImgList<T> crop(const CImgList<T>& instance, const unsigned int i0, const unsigned int i1,
 
6958
                                               const int x0, const int y0, const int z0, const int v0,
 
6959
                                               const int x1, const int y1, const int z1, const int v1) {
 
6960
    return instance.get_crop(i0,i1,x0,y0,z0,v0,x1,y1,z1,v1);
 
6961
  }
 
6962
 
 
6963
  template<typename T> inline CImgList<T> crop(const CImgList<T>& instance, const unsigned int i0, const unsigned int i1,
 
6964
                                               const int x0, const int y0, const int z0,
 
6965
                                               const int x1, const int y1, const int z1) {
 
6966
    return instance.get_crop(i0,i1,x0,y0,z0,x1,y1,z1);
 
6967
  }
 
6968
 
 
6969
  template<typename T> inline CImgList<T> crop(const CImgList<T>& instance, const unsigned int i0, const unsigned int i1,
 
6970
                                               const int x0, const int y0,
 
6971
                                               const int x1, const int y1) {
 
6972
    return instance.get_crop(i0,i1,x0,y0,x1,y1);
 
6973
  }
 
6974
 
 
6975
  template<typename T> inline CImgList<T> crop(const CImgList<T>& instance, const unsigned int i0, const unsigned int i1,
 
6976
                                               const int x0, const int x1) {
 
6977
    return instance.get_crop(i0,i1,x0,x1);
 
6978
  }
 
6979
 
 
6980
  template<typename T> inline CImgList<_cimg_Tfloat>
 
6981
  FFT(const CImgList<T>& instance, const char axe, const bool invert=false) {
 
6982
    return instance.get_FFT(axe,invert);
 
6983
  }
 
6984
 
 
6985
  template<typename T> inline CImgList<_cimg_Tfloat>
 
6986
  FFT(const CImgList<T>& instance, const bool invert=false) {
 
6987
    return instance.get_FFT(invert);
 
6988
  }
 
6989
 
 
6990
  template<typename T> inline CImgList<T> split(const CImgList<T>& instance, const char axe='x') {
 
6991
    return instance.get_split(axe);
 
6992
  }
 
6993
 
 
6994
  template<typename T> inline CImg<T> append(const CImgList<T>& instance, const char axe='x', const char align='c') {
 
6995
    return instance.get_append(axe,align);
 
6996
  }
 
6997
 
 
6998
  template<typename T> inline CImgList<T> crop_font(const CImgList<T>& instance) {
 
6999
    return instance.get_crop_font();
 
7000
  }
 
7001
 
 
7002
  /*-------------------------------------------
4548
7003
   #
4549
7004
   #
4550
7005
   #
4552
7007
   #
4553
7008
   #
4554
7009
   #
4555
 
   #-------------------------------------------
4556
 
   */
 
7010
   --------------------------------------------*/
4557
7011
 
4558
7012
  //! This class represents a window which can display \ref CImg images and handles mouse and keyboard events.
4559
7013
  /**
4575
7029
    //! Normalization type used for the display
4576
7030
    unsigned int normalization;
4577
7031
 
4578
 
    //! Range of events detected by the display
4579
 
    unsigned int events;
4580
 
 
4581
7032
    //! Display title
4582
7033
    char* title;
4583
7034
 
4626
7077
    //! Event state of the window
4627
7078
    volatile bool is_event;
4628
7079
 
 
7080
    //! Current state of the corresponding key (exists for all referenced keys).
 
7081
    volatile bool is_keyESC;
 
7082
    volatile bool is_keyF1;
 
7083
    volatile bool is_keyF2;
 
7084
    volatile bool is_keyF3;
 
7085
    volatile bool is_keyF4;
 
7086
    volatile bool is_keyF5;
 
7087
    volatile bool is_keyF6;
 
7088
    volatile bool is_keyF7;
 
7089
    volatile bool is_keyF8;
 
7090
    volatile bool is_keyF9;
 
7091
    volatile bool is_keyF10;
 
7092
    volatile bool is_keyF11;
 
7093
    volatile bool is_keyF12;
 
7094
    volatile bool is_keyPAUSE;
 
7095
    volatile bool is_key1;
 
7096
    volatile bool is_key2;
 
7097
    volatile bool is_key3;
 
7098
    volatile bool is_key4;
 
7099
    volatile bool is_key5;
 
7100
    volatile bool is_key6;
 
7101
    volatile bool is_key7;
 
7102
    volatile bool is_key8;
 
7103
    volatile bool is_key9;
 
7104
    volatile bool is_key0;
 
7105
    volatile bool is_keyBACKSPACE;
 
7106
    volatile bool is_keyINSERT;
 
7107
    volatile bool is_keyHOME;
 
7108
    volatile bool is_keyPAGEUP;
 
7109
    volatile bool is_keyTAB;
 
7110
    volatile bool is_keyQ;
 
7111
    volatile bool is_keyW;
 
7112
    volatile bool is_keyE;
 
7113
    volatile bool is_keyR;
 
7114
    volatile bool is_keyT;
 
7115
    volatile bool is_keyY;
 
7116
    volatile bool is_keyU;
 
7117
    volatile bool is_keyI;
 
7118
    volatile bool is_keyO;
 
7119
    volatile bool is_keyP;
 
7120
    volatile bool is_keyDELETE;
 
7121
    volatile bool is_keyEND;
 
7122
    volatile bool is_keyPAGEDOWN;
 
7123
    volatile bool is_keyCAPSLOCK;
 
7124
    volatile bool is_keyA;
 
7125
    volatile bool is_keyS;
 
7126
    volatile bool is_keyD;
 
7127
    volatile bool is_keyF;
 
7128
    volatile bool is_keyG;
 
7129
    volatile bool is_keyH;
 
7130
    volatile bool is_keyJ;
 
7131
    volatile bool is_keyK;
 
7132
    volatile bool is_keyL;
 
7133
    volatile bool is_keyENTER;
 
7134
    volatile bool is_keySHIFTLEFT;
 
7135
    volatile bool is_keyZ;
 
7136
    volatile bool is_keyX;
 
7137
    volatile bool is_keyC;
 
7138
    volatile bool is_keyV;
 
7139
    volatile bool is_keyB;
 
7140
    volatile bool is_keyN;
 
7141
    volatile bool is_keyM;
 
7142
    volatile bool is_keySHIFTRIGHT;
 
7143
    volatile bool is_keyARROWUP;
 
7144
    volatile bool is_keyCTRLLEFT;
 
7145
    volatile bool is_keyAPPLEFT;
 
7146
    volatile bool is_keySPACE;
 
7147
    volatile bool is_keyALTGR;
 
7148
    volatile bool is_keyAPPRIGHT;
 
7149
    volatile bool is_keyMENU;
 
7150
    volatile bool is_keyCTRLRIGHT;
 
7151
    volatile bool is_keyARROWLEFT;
 
7152
    volatile bool is_keyARROWDOWN;
 
7153
    volatile bool is_keyARROWRIGHT;
 
7154
    volatile bool is_keyPAD0;
 
7155
    volatile bool is_keyPAD1;
 
7156
    volatile bool is_keyPAD2;
 
7157
    volatile bool is_keyPAD3;
 
7158
    volatile bool is_keyPAD4;
 
7159
    volatile bool is_keyPAD5;
 
7160
    volatile bool is_keyPAD6;
 
7161
    volatile bool is_keyPAD7;
 
7162
    volatile bool is_keyPAD8;
 
7163
    volatile bool is_keyPAD9;
 
7164
    volatile bool is_keyPADADD;
 
7165
    volatile bool is_keyPADSUB;
 
7166
    volatile bool is_keyPADMUL;
 
7167
    volatile bool is_keyPADDIV;
 
7168
 
4629
7169
    //! Fullscreen state of the display
4630
7170
    bool is_fullscreen;
4631
7171
 
4635
7175
#ifdef cimgdisplay_plugin
4636
7176
#include cimgdisplay_plugin
4637
7177
#endif
 
7178
#ifdef cimgdisplay_plugin1
 
7179
#include cimgdisplay_plugin1
 
7180
#endif
 
7181
#ifdef cimgdisplay_plugin2
 
7182
#include cimgdisplay_plugin2
 
7183
#endif
 
7184
#ifdef cimgdisplay_plugin3
 
7185
#include cimgdisplay_plugin3
 
7186
#endif
 
7187
#ifdef cimgdisplay_plugin4
 
7188
#include cimgdisplay_plugin4
 
7189
#endif
 
7190
#ifdef cimgdisplay_plugin5
 
7191
#include cimgdisplay_plugin5
 
7192
#endif
 
7193
#ifdef cimgdisplay_plugin6
 
7194
#include cimgdisplay_plugin6
 
7195
#endif
 
7196
#ifdef cimgdisplay_plugin7
 
7197
#include cimgdisplay_plugin7
 
7198
#endif
 
7199
#ifdef cimgdisplay_plugin8
 
7200
#include cimgdisplay_plugin8
 
7201
#endif
4638
7202
 
4639
7203
    //! Create an empty display window.
4640
7204
    CImgDisplay():
4641
 
      width(0),height(0),normalization(0),events(0),title(0),
 
7205
      width(0),height(0),normalization(0),title(0),
4642
7206
      window_x(0),window_y(0),window_width(0),window_height(0),
4643
7207
      mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
4644
7208
      is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
4645
7209
      min(0),max(0) {}
4646
7210
 
4647
7211
    //! Create a display window with a specified size \p pwidth x \p height.
4648
 
    /** \param dimw       : Width of the display window.
4649
 
        \param dimh       : Height of the display window.
4650
 
        \param title      : Title of the display window.
4651
 
        \param normalization_type  : Normalization type of the display window (see CImgDisplay::normalize).
4652
 
        \param events_type : Type of events handled by the display window.
 
7212
    /** \param dimw Width of the display window.
 
7213
        \param dimh Height of the display window.
 
7214
        \param title Title of the display window.
 
7215
        \param normalization_type Normalization type of the display window (0=none, 1=always, 2=once).
4653
7216
        \param fullscreen_flag : Fullscreen mode.
4654
7217
        \param closed_flag : Initially visible mode.
4655
7218
        A black image will be initially displayed in the display window.
4656
7219
    **/
4657
7220
    CImgDisplay(const unsigned int dimw, const unsigned int dimh, const char *title=0,
4658
 
                const unsigned int normalization_type=3, const unsigned int events_type=3,
 
7221
                const unsigned int normalization_type=3,
4659
7222
                const bool fullscreen_flag=false, const bool closed_flag=false):
4660
 
      width(0),height(0),normalization(0),events(0),title(0),
 
7223
      width(0),height(0),normalization(0),title(0),
4661
7224
      window_x(0),window_y(0),window_width(0),window_height(0),
4662
7225
      mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
4663
7226
      is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
4664
7227
      min(0),max(0) {
4665
 
      assign(dimw,dimh,title,normalization_type,events_type,fullscreen_flag,closed_flag);
 
7228
      assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
4666
7229
    }
4667
7230
 
4668
7231
    //! Create a display window from an image.
4669
7232
    /** \param img : Image that will be used to create the display window.
4670
7233
        \param title : Title of the display window
4671
7234
        \param normalization_type : Normalization type of the display window.
4672
 
        \param events_type : Type of events handled by the display window.
4673
7235
        \param fullscreen_flag : Fullscreen mode.
4674
7236
        \param closed_flag : Initially visible mode.
4675
7237
    **/
4676
7238
    template<typename T>
4677
7239
    CImgDisplay(const CImg<T>& img, const char *title=0,
4678
 
                const unsigned int normalization_type=3, const unsigned int events_type=3,
 
7240
                const unsigned int normalization_type=3,
4679
7241
                const bool fullscreen_flag=false, const bool closed_flag=false):
4680
 
      width(0),height(0),normalization(0),events(0),title(0),
 
7242
      width(0),height(0),normalization(0),title(0),
4681
7243
      window_x(0),window_y(0),window_width(0),window_height(0),
4682
7244
      mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
4683
7245
      is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
4684
 
      assign(img,title,normalization_type,events_type,fullscreen_flag,closed_flag);
 
7246
      assign(img,title,normalization_type,fullscreen_flag,closed_flag);
4685
7247
    }
4686
7248
 
4687
7249
    //! Create a display window from an image list.
4688
7250
    /** \param list : The list of images to display.
4689
7251
        \param title : Title of the display window
4690
7252
        \param normalization_type : Normalization type of the display window.
4691
 
        \param events_type : Type of events handled by the display window.
4692
7253
        \param fullscreen_flag : Fullscreen mode.
4693
7254
        \param closed_flag : Initially visible mode.
4694
7255
    **/
4695
7256
    template<typename T>
4696
7257
    CImgDisplay(const CImgList<T>& list, const char *title=0,
4697
 
                const unsigned int normalization_type=3, const unsigned int events_type=3,
 
7258
                const unsigned int normalization_type=3,
4698
7259
                const bool fullscreen_flag=false, const bool closed_flag=false):
4699
 
      width(0),height(0),normalization(0),events(0),title(0),
 
7260
      width(0),height(0),normalization(0),title(0),
4700
7261
      window_x(0),window_y(0),window_width(0),window_height(0),
4701
7262
      mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
4702
7263
      is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
4703
 
      assign(list,title,normalization_type,events_type,fullscreen_flag,closed_flag);
 
7264
      assign(list,title,normalization_type,fullscreen_flag,closed_flag);
4704
7265
    }
4705
7266
 
4706
7267
    //! Create a display window by copying another one.
4707
 
    /** \param win   : Display window to copy.
4708
 
        \param title : Title of the new display window.
 
7268
    /**
 
7269
        \param disp  : Display window to copy.
4709
7270
    **/
4710
7271
    CImgDisplay(const CImgDisplay& disp):
4711
 
      width(0),height(0),normalization(0),events(0),title(0),
 
7272
      width(0),height(0),normalization(0),title(0),
4712
7273
      window_x(0),window_y(0),window_width(0),window_height(0),
4713
7274
      mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
4714
7275
      is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
4715
7276
      assign(disp);
4716
7277
    }
4717
7278
 
4718
 
    //! Destructor
 
7279
    //! Destructor.
4719
7280
    ~CImgDisplay() {
4720
7281
      assign();
4721
7282
    }
4722
7283
 
4723
 
    //! Assignment operator
 
7284
    //! Assignment operator.
4724
7285
    CImgDisplay& operator=(const CImgDisplay& disp) {
4725
7286
      return assign(disp);
4726
7287
    }
4727
7288
 
4728
 
    //! Return true is display is empty
 
7289
    //! Return true is display is empty.
4729
7290
    bool is_empty() const {
4730
7291
      return (!width || !height);
4731
7292
    }
4732
7293
 
4733
 
    //! Return false if display is empty
 
7294
    //! Return true if display is not empty.
4734
7295
    operator bool() const {
4735
7296
      return !is_empty();
4736
7297
    }
4737
7298
 
4738
 
    //! Return display width
 
7299
    //! Return display width.
4739
7300
    int dimx() const {
4740
7301
      return (int)width;
4741
7302
    }
4742
7303
 
4743
 
    //! Return display height
 
7304
    //! Return display height.
4744
7305
    int dimy() const {
4745
7306
      return (int)height;
4746
7307
    }
4747
7308
 
4748
 
    //! Return display window width
 
7309
    //! Return display window width.
4749
7310
    int window_dimx() const {
4750
7311
      return (int)window_width;
4751
7312
    }
4752
7313
 
4753
 
    //! Return display window height
 
7314
    //! Return display window height.
4754
7315
    int window_dimy() const {
4755
7316
      return (int)window_height;
4756
7317
    }
4757
7318
 
4758
 
    //! Return X-coordinate of the window
 
7319
    //! Return X-coordinate of the window.
4759
7320
    int window_posx() const {
4760
7321
      return window_x;
4761
7322
    }
4762
7323
 
4763
 
    //! Return Y-coordinate of the window
 
7324
    //! Return Y-coordinate of the window.
4764
7325
    int window_posy() const {
4765
7326
      return window_y;
4766
7327
    }
4767
7328
 
4768
7329
    //! Synchronized waiting function. Same as cimg::wait().
4769
 
    /** \see cimg::wait()
4770
 
     **/
4771
7330
    CImgDisplay& wait(const unsigned int milliseconds) {
4772
 
      cimg::wait(milliseconds, timer);
 
7331
      cimg::_sleep(milliseconds,timer);
4773
7332
      return *this;
4774
7333
    }
4775
7334
 
4776
 
    //! Wait for an event occuring on the current display
 
7335
    //! Wait for an event occuring on the current display.
4777
7336
    CImgDisplay& wait() {
4778
7337
      if (!is_empty()) wait(*this);
4779
7338
      return *this;
4780
7339
    }
4781
7340
 
4782
 
    //! Wait for any event occuring on the display \c disp1
 
7341
    //! Wait for any event occuring on the display \c disp1.
4783
7342
    static void wait(CImgDisplay& disp1) {
4784
7343
      disp1.is_event = 0;
4785
7344
      while (!disp1.is_event) wait_all();
4786
7345
    }
4787
7346
 
4788
 
    //! Wait for any event occuring either on the display \c disp1 or \c disp2
 
7347
    //! Wait for any event occuring either on the display \c disp1 or \c disp2.
4789
7348
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2) {
4790
7349
      disp1.is_event = disp2.is_event = 0;
4791
7350
      while (!disp1.is_event && !disp2.is_event) wait_all();
4792
7351
    }
4793
7352
 
4794
 
    //! Wait for any event occuring either on the display \c disp1, \c disp2 or \c disp3
 
7353
    //! Wait for any event occuring either on the display \c disp1, \c disp2 or \c disp3.
4795
7354
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) {
4796
7355
      disp1.is_event = disp2.is_event = disp3.is_event = 0;
4797
7356
      while (!disp1.is_event && !disp2.is_event && !disp3.is_event) wait_all();
4798
7357
    }
4799
7358
 
4800
 
    //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3 or \c disp4
 
7359
    //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3 or \c disp4.
4801
7360
    static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) {
4802
7361
      disp1.is_event = disp2.is_event = disp3.is_event = disp4.is_event = 0;
4803
7362
      while (!disp1.is_event && !disp2.is_event && !disp3.is_event && !disp4.is_event) wait_all();
4804
7363
    }
4805
7364
 
4806
 
    //! Return the frame per second rate
 
7365
    //! Return the frame per second rate.
4807
7366
    float frames_per_second() {
4808
7367
      if (!fps_timer) fps_timer = cimg::time();
4809
7368
      const float delta = (cimg::time()-fps_timer)/1000.0f;
4823
7382
        \param axe      : The axe used to append the image for visualization. Can be 'x' (default),'y','z' or 'v'.
4824
7383
        \param align : Defines the relative alignment of images when displaying images of different sizes.
4825
7384
        Can be '\p c' (centered, which is the default), '\p p' (top alignment) and '\p n' (bottom aligment).
4826
 
 
4827
 
        \see CImg::get_append()
4828
7385
    **/
4829
7386
    template<typename T> CImgDisplay& display(const CImgList<T>& list, const char axe='x', const char align='c') {
4830
7387
      return display(list.get_append(axe,align));
4844
7401
    /** \param img    : Input image. \p image.width and \p image.height give the new dimensions of the display window.
4845
7402
        \param redraw : If \p true (default), the current displayed image in the display window will
4846
7403
        be bloc-interpolated to fit the new dimensions. If \p false, a black image will be drawn in the resized window.
4847
 
        \see CImgDisplay::is_resized, CImgDisplay::resizedimx(), CImgDisplay::resizedimy()
4848
7404
    **/
4849
7405
    template<typename T> CImgDisplay& resize(const CImg<T>& img, const bool redraw=true) {
4850
7406
      return resize(img.width,img.height,redraw);
4851
7407
    }
4852
7408
 
4853
 
    //! Resize a display window using the size of the given display \p disp
 
7409
    //! Resize a display window using the size of the given display \p disp.
4854
7410
    CImgDisplay& resize(const CImgDisplay& disp, const bool redraw=true) {
4855
7411
      return resize(disp.width,disp.height,redraw);
4856
7412
    }
4861
7417
      return *this;
4862
7418
    }
4863
7419
 
4864
 
    //! Display a 3d object
4865
 
    template<typename tp, typename tf, typename T, typename to>
 
7420
    //! Display a 3d object.
 
7421
    template<typename tp, typename tf, typename tc, typename to>
4866
7422
    CImgDisplay& display_object3d(const tp& points, const CImgList<tf>& primitives,
4867
 
                                  const CImgList<T>& colors, const to& opacities,
 
7423
                                  const CImgList<tc>& colors, const to& opacities,
4868
7424
                                  const bool centering=true,
4869
7425
                                  const int render_static=4, const int render_motion=1,
4870
 
                                  const bool double_sided=false,
4871
 
                                  const float focale=500.0f, const float ambient_light=0.05f,
 
7426
                                  const bool double_sided=false, const float focale=500.0f,
 
7427
                                  const float specular_light=0.2f, const float specular_shine=0.1f,
4872
7428
                                  const bool display_axes=true, float *const pose_matrix=0) {
4873
 
      CImg<T>(width,height,1,3,0).display_object3d(points,primitives,colors,opacities,*this,
4874
 
                                                   centering,render_static,render_motion,
4875
 
                                                   double_sided,focale,ambient_light,
4876
 
                                                   display_axes,pose_matrix);
4877
 
      return *this;
4878
 
    }
4879
 
 
4880
 
    //! Display a 3D object.
4881
 
    template<typename tp, typename tf, typename T>
4882
 
    CImgDisplay& display_object3d(const tp& points, const CImgList<tf>& primitives,
4883
 
                                  const CImgList<T>& colors,
4884
 
                                  const bool centering=true,
4885
 
                                  const int render_static=4, const int render_motion=1,
4886
 
                                  const bool double_sided=false,
4887
 
                                  const float focale=500.0f, const float ambient_light=0.05f,
4888
 
                                  const bool display_axes=true,
4889
 
                                  float *const pose_matrix=0,
4890
 
                                  const float opacity=1.0f) {
4891
 
      typedef typename cimg::largest<T,float>::type to;
4892
 
      CImg<T>(width,height,1,3,0).display_object3d(points,primitives,colors,
4893
 
                                                   CImg<to>::vector((to)opacity),
4894
 
                                                   *this,centering,render_static,render_motion,
4895
 
                                                   double_sided,focale,ambient_light,display_axes,pose_matrix);
4896
 
      return *this;
4897
 
    }
4898
 
 
4899
 
    //! Toggle fullscreen mode
4900
 
    CImgDisplay& toggle_fullscreen() {
4901
 
      return assign(width,height,title,normalization,events,!is_fullscreen,is_closed);
 
7429
      CImg<tc>(width,height,1,3,0).display_object3d(points,primitives,colors,opacities,*this,
 
7430
                                                    centering,render_static,render_motion,
 
7431
                                                    double_sided,focale,specular_light,specular_shine,
 
7432
                                                    display_axes,pose_matrix);
 
7433
      return *this;
 
7434
    }
 
7435
 
 
7436
    //! Display a 3D object.
 
7437
    template<typename tp, typename tf, typename tc>
 
7438
    CImgDisplay& display_object3d(const tp& points, const CImgList<tf>& primitives,
 
7439
                                  const CImgList<tc>& colors,
 
7440
                                  const bool centering=true,
 
7441
                                  const int render_static=4, const int render_motion=1,
 
7442
                                  const bool double_sided=false, const float focale=500.0f,
 
7443
                                  const float specular_light=0.2f, const float specular_shine=0.1f,
 
7444
                                  const bool display_axes=true,
 
7445
                                  float *const pose_matrix=0,
 
7446
                                  const float opacity=1.0f) {
 
7447
      typedef typename cimg::last<tc,float>::type t_float;
 
7448
      return display_object3d(points,primitives,colors,CImg<t_float>::vector(opacity),
 
7449
                              centering,render_static,render_motion,double_sided,focale,
 
7450
                              specular_light,specular_shine,display_axes,pose_matrix);
 
7451
    }
 
7452
 
 
7453
    //! Display a 3D object.
 
7454
    template<typename tp, typename tf>
 
7455
    CImgDisplay& display_object3d(const tp& points, const CImgList<tf>& primitives,
 
7456
                                  const bool centering=true,
 
7457
                                  const int render_static=4, const int render_motion=1,
 
7458
                                  const bool double_sided=false, const float focale=500.0f,
 
7459
                                  const float specular_light=0.2f, const float specular_shine=0.1f,
 
7460
                                  const bool display_axes=true,
 
7461
                                  float *const pose_matrix=0,
 
7462
                                  const float opacity=1.0f) {
 
7463
      static const CImg<typename cimg::last<tp,unsigned char>::type> empty;
 
7464
      return display_object3d(points,primitives,empty,
 
7465
                              centering,render_static,render_motion,double_sided,focale,
 
7466
                              specular_light,specular_shine,display_axes,pose_matrix,opacity);
 
7467
      return *this;
 
7468
    }
 
7469
 
 
7470
    //! Set fullscreen mode.
 
7471
    CImgDisplay& fullscreen(const bool redraw=true) {
 
7472
      if (is_empty() || is_fullscreen) return *this;
 
7473
      return toggle_fullscreen(redraw);
 
7474
    }
 
7475
 
 
7476
    //! Set normal screen mode.
 
7477
    CImgDisplay& normalscreen(const bool redraw=true) {
 
7478
      if (is_empty() || !is_fullscreen) return *this;
 
7479
      return toggle_fullscreen(redraw);
4902
7480
    }
4903
7481
 
4904
7482
    // Inner routine used for fast resizing of buffer to display size.
4918
7496
        for (unsigned int x=0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); }
4919
7497
        ++y;
4920
7498
        unsigned int dy=*(poffy++);
4921
 
        for (;!dy && y<hd; std::memcpy(ptrd, ptrd-wd, sizeof(t)*wd), ++y, ptrd+=wd, dy=*(poffy++));
 
7499
        for (;!dy && y<hd; std::memcpy(ptrd, ptrd-wd, sizeof(t)*wd), ++y, ptrd+=wd, dy=*(poffy++)) {}
4922
7500
        ptrs+=dy;
4923
7501
      }}
4924
7502
      delete[] offx; delete[] offy;
4925
7503
    }
4926
7504
 
4927
 
    //! Clear mouse and key states of the current display.
 
7505
    //! Clear all events of the current display.
4928
7506
    CImgDisplay& flush() {
4929
7507
      std::memset((void*)buttons,0,512*sizeof(unsigned int));
4930
7508
      std::memset((void*)keys,0,512*sizeof(unsigned int));
4931
7509
      std::memset((void*)released_keys,0,512*sizeof(unsigned int));
 
7510
      is_keyESC = is_keyF1 = is_keyF2 = is_keyF3 = is_keyF4 = is_keyF5 = is_keyF6 = is_keyF7 = is_keyF8 = is_keyF9 =
 
7511
        is_keyF10 = is_keyF11 = is_keyF12 = is_keyPAUSE = is_key1 = is_key2 = is_key3 = is_key4 = is_key5 = is_key6 =
 
7512
        is_key7 = is_key8 = is_key9 = is_key0 = is_keyBACKSPACE = is_keyINSERT = is_keyHOME = is_keyPAGEUP = is_keyTAB =
 
7513
        is_keyQ = is_keyW = is_keyE = is_keyR = is_keyT = is_keyY = is_keyU = is_keyI = is_keyO = is_keyP = is_keyDELETE =
 
7514
        is_keyEND = is_keyPAGEDOWN = is_keyCAPSLOCK = is_keyA = is_keyS = is_keyD = is_keyF = is_keyG = is_keyH = is_keyJ =
 
7515
        is_keyK = is_keyL = is_keyENTER = is_keySHIFTLEFT = is_keyZ = is_keyX = is_keyC = is_keyV = is_keyB = is_keyN =
 
7516
        is_keyM = is_keySHIFTRIGHT = is_keyARROWUP = is_keyCTRLLEFT = is_keyAPPLEFT = is_keySPACE = is_keyALTGR = is_keyAPPRIGHT =
 
7517
        is_keyMENU = is_keyCTRLRIGHT = is_keyARROWLEFT = is_keyARROWDOWN = is_keyARROWRIGHT = is_keyPAD0 = is_keyPAD1 = is_keyPAD2 =
 
7518
        is_keyPAD3 = is_keyPAD4 = is_keyPAD5 = is_keyPAD6 = is_keyPAD7 = is_keyPAD8 = is_keyPAD9 = is_keyPADADD = is_keyPADSUB =
 
7519
        is_keyPADMUL = is_keyPADDIV = false;
 
7520
      is_resized = is_moved = is_event = false;
 
7521
      fps_timer = fps_frames = timer = wheel = 0;
4932
7522
      mouse_x = mouse_y = -1;
 
7523
      fps_fps = 0;
4933
7524
      return *this;
4934
7525
    }
4935
7526
 
 
7527
    // Update 'is_key' fields.
 
7528
    void update_iskey(const unsigned int key, const bool pressed=true) {
 
7529
#define _cimg_iskey_case(k) if (key==cimg::key##k) is_key##k = pressed;
 
7530
      _cimg_iskey_case(ESC); _cimg_iskey_case(F1); _cimg_iskey_case(F2); _cimg_iskey_case(F3);
 
7531
      _cimg_iskey_case(F4); _cimg_iskey_case(F5); _cimg_iskey_case(F6); _cimg_iskey_case(F7);
 
7532
      _cimg_iskey_case(F8); _cimg_iskey_case(F9); _cimg_iskey_case(F10); _cimg_iskey_case(F11);
 
7533
      _cimg_iskey_case(F12); _cimg_iskey_case(PAUSE); _cimg_iskey_case(1); _cimg_iskey_case(2);
 
7534
      _cimg_iskey_case(3); _cimg_iskey_case(4); _cimg_iskey_case(5); _cimg_iskey_case(6);
 
7535
      _cimg_iskey_case(7); _cimg_iskey_case(8); _cimg_iskey_case(9); _cimg_iskey_case(0);
 
7536
      _cimg_iskey_case(BACKSPACE); _cimg_iskey_case(INSERT); _cimg_iskey_case(HOME);
 
7537
      _cimg_iskey_case(PAGEUP); _cimg_iskey_case(TAB); _cimg_iskey_case(Q); _cimg_iskey_case(W);
 
7538
      _cimg_iskey_case(E); _cimg_iskey_case(R); _cimg_iskey_case(T); _cimg_iskey_case(Y);
 
7539
      _cimg_iskey_case(U); _cimg_iskey_case(I); _cimg_iskey_case(O); _cimg_iskey_case(P);
 
7540
      _cimg_iskey_case(DELETE); _cimg_iskey_case(END); _cimg_iskey_case(PAGEDOWN);
 
7541
      _cimg_iskey_case(CAPSLOCK); _cimg_iskey_case(A); _cimg_iskey_case(S); _cimg_iskey_case(D);
 
7542
      _cimg_iskey_case(F); _cimg_iskey_case(G); _cimg_iskey_case(H); _cimg_iskey_case(J);
 
7543
      _cimg_iskey_case(K); _cimg_iskey_case(L); _cimg_iskey_case(ENTER);
 
7544
      _cimg_iskey_case(SHIFTLEFT); _cimg_iskey_case(Z); _cimg_iskey_case(X); _cimg_iskey_case(C);
 
7545
      _cimg_iskey_case(V); _cimg_iskey_case(B); _cimg_iskey_case(N); _cimg_iskey_case(M);
 
7546
      _cimg_iskey_case(SHIFTRIGHT); _cimg_iskey_case(ARROWUP); _cimg_iskey_case(CTRLLEFT);
 
7547
      _cimg_iskey_case(APPLEFT); _cimg_iskey_case(SPACE); _cimg_iskey_case(ALTGR);
 
7548
      _cimg_iskey_case(APPRIGHT); _cimg_iskey_case(MENU); _cimg_iskey_case(CTRLRIGHT);
 
7549
      _cimg_iskey_case(ARROWLEFT); _cimg_iskey_case(ARROWDOWN); _cimg_iskey_case(ARROWRIGHT);
 
7550
      _cimg_iskey_case(PAD0); _cimg_iskey_case(PAD1); _cimg_iskey_case(PAD2);
 
7551
      _cimg_iskey_case(PAD3); _cimg_iskey_case(PAD4); _cimg_iskey_case(PAD5);
 
7552
      _cimg_iskey_case(PAD6); _cimg_iskey_case(PAD7); _cimg_iskey_case(PAD8);
 
7553
      _cimg_iskey_case(PAD9); _cimg_iskey_case(PADADD); _cimg_iskey_case(PADSUB);
 
7554
      _cimg_iskey_case(PADMUL); _cimg_iskey_case(PADDIV);
 
7555
    }
 
7556
 
4936
7557
    //! Test if any key has been pressed.
4937
7558
    bool is_key(const bool remove=false) {
4938
7559
      for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs) { if (remove) *ptrs = 0; return true; }
5002
7623
      return is_key(seq,9,remove);
5003
7624
    }
5004
7625
 
5005
 
    //! Test if a key sequence has been typed
 
7626
    //! Test if a key sequence has been typed.
5006
7627
    bool is_key(const unsigned int *const keyseq, const unsigned int N, const bool remove=true) {
5007
7628
      if (keyseq && N) {
5008
7629
        const unsigned int *const ps_end = keyseq+N-1, k = *ps_end, *const pk_end = (unsigned int*)keys+1+512-N;
5021
7642
      return false;
5022
7643
    }
5023
7644
 
 
7645
    // Find the good width and height of a window to display an image (internal routine).
 
7646
#define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,false),CImgDisplay::_fitscreen(dx,dy,dz,true)
 
7647
    static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1,
 
7648
                                   const bool return_last=false) {
 
7649
      unsigned int nw = dx + (dz>1?dz:0), nh = dy + (dz>1?dz:0);
 
7650
      const unsigned int
 
7651
        sw = CImgDisplay::screen_dimx(), sh = CImgDisplay::screen_dimy(),
 
7652
        mw = sw/8, mh = sh/8, Mw = sw*7/8, Mh = sh*7/8;
 
7653
      if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0); nw = mw; }
 
7654
      if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0); nh = mh; }
 
7655
      if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0); nw = Mw; }
 
7656
      if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0); nh = Mh; }
 
7657
      if (nw<16) nw = 16;
 
7658
      if (nh<16) nh = 16;
 
7659
      if (return_last) return nh;
 
7660
      return nw;
 
7661
    }
 
7662
 
5024
7663
    // When no display available
5025
7664
    //---------------------------
5026
 
#if cimg_display_type==0
 
7665
#if cimg_display==0
5027
7666
 
5028
7667
    //! Return the width of the screen resolution.
5029
7668
    static int screen_dimx() {
5035
7674
      return 0;
5036
7675
    }
5037
7676
 
5038
 
    // In-place version of the destructor (should not be used by the user).
 
7677
    //! Wait for a window event in any CImg window.
 
7678
    static void wait_all() {}
 
7679
 
 
7680
    //! In-place version of the destructor.
5039
7681
    CImgDisplay& assign() {
5040
7682
      return *this;
5041
7683
    }
5042
7684
 
5043
 
    //! In-place version of the previous constructor
 
7685
    //! In-place version of the previous constructor.
5044
7686
    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
5045
 
                        const unsigned int normalization_type=3, const unsigned int events_type=3,
 
7687
                        const unsigned int normalization_type=3,
5046
7688
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
5047
 
      throw CImgDisplayException("CImgDisplay() : Display has been required but is not available (cimg_display_type=0)");
5048
 
      fps_timer = 0*(unsigned long)(dimw + dimh + title + normalization_type + events_type + (int)fullscreen_flag + (int)closed_flag);
 
7689
      throw CImgDisplayException("CImgDisplay() : Display has been required but is not available (cimg_display=0)");
 
7690
      fps_timer = 0*(unsigned long)(dimw + dimh + title + normalization_type + (int)fullscreen_flag + (int)closed_flag);
5049
7691
      return *this;
5050
7692
    }
5051
7693
 
5052
 
    //! In-place version of the previous constructor
 
7694
    //! In-place version of the previous constructor.
5053
7695
    template<typename T> CImgDisplay& assign(const CImg<T>& img, const char *title=0,
5054
 
                                             const unsigned int normalization_type=3, const unsigned int events_type=3,
 
7696
                                             const unsigned int normalization_type=3,
5055
7697
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
5056
 
      fps_timer = 0*(unsigned long)(img.width + title + normalization_type + events_type + (int)fullscreen_flag + (int)closed_flag);
 
7698
      fps_timer = 0*(unsigned long)(img.width + title + normalization_type + (int)fullscreen_flag + (int)closed_flag);
5057
7699
      return assign(0,0);
5058
7700
    }
5059
7701
 
5060
 
    //! In-place version of the previous constructor
 
7702
    //! In-place version of the previous constructor.
5061
7703
    template<typename T> CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
5062
 
                                             const unsigned int normalization_type=3, const unsigned int events_type=3,
 
7704
                                             const unsigned int normalization_type=3,
5063
7705
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
5064
 
      fps_timer = 0*(unsigned long)(list.size + title + normalization_type + events_type + (int)fullscreen_flag + (int)closed_flag);
 
7706
      fps_timer = 0*(unsigned long)(list.size + title + normalization_type + (int)fullscreen_flag + (int)closed_flag);
5065
7707
      return assign(0,0);
5066
7708
    }
5067
7709
 
5068
 
    //! In-place version of the previous constructor
 
7710
    //! In-place version of the previous constructor.
5069
7711
    CImgDisplay& assign(const CImgDisplay &disp) {
5070
7712
      return assign(disp.width,disp.height);
5071
7713
    }
5072
7714
 
5073
 
    //! Display an image in a window.
5074
 
    template<typename T> CImgDisplay& display(const CImg<T>& img) {
5075
 
      fps_timer = 0*img.width;
5076
 
      return *this;
5077
 
    }
5078
 
 
5079
 
    //! Resize window
 
7715
    //! Resize window.
5080
7716
    CImgDisplay& resize(const int width, const int height, const bool redraw=true) {
5081
7717
      fps_timer = 0*width*height*(int)redraw;
5082
7718
      return *this;
5083
7719
    }
5084
7720
 
5085
 
    //! Move window
 
7721
    //! Toggle fullscreen mode.
 
7722
    CImgDisplay& toggle_fullscreen(const bool redraw=true) {
 
7723
      fps_timer = (int)redraw*0;
 
7724
      return *this;
 
7725
    }
 
7726
 
 
7727
    //! Show a closed display.
 
7728
    CImgDisplay& show() {
 
7729
      return *this;
 
7730
    }
 
7731
 
 
7732
    //! Close a visible display.
 
7733
    CImgDisplay& close() {
 
7734
      return *this;
 
7735
    }
 
7736
 
 
7737
    //! Move window.
5086
7738
    CImgDisplay& move(const int posx, const int posy) {
5087
7739
      fps_timer = 0*posx*posy;
5088
7740
      return *this;
5089
7741
    }
5090
7742
 
5091
 
    //! Move mouse pointer to a specific location
 
7743
    //! Show mouse pointer.
 
7744
    CImgDisplay& show_mouse() {
 
7745
      return *this;
 
7746
    }
 
7747
 
 
7748
    //! Hide mouse pointer.
 
7749
    CImgDisplay& hide_mouse() {
 
7750
      return *this;
 
7751
    }
 
7752
 
 
7753
    //! Move mouse pointer to a specific location.
5092
7754
    CImgDisplay& set_mouse(const int posx, const int posy) {
5093
7755
      fps_timer = 0*posx*posy;
5094
7756
      return *this;
5095
7757
    }
5096
7758
 
5097
 
    //! Hide mouse pointer
5098
 
    CImgDisplay& hide_mouse() {
5099
 
      return *this;
5100
 
    }
5101
 
 
5102
 
    //! Show mouse pointer
5103
 
    CImgDisplay& show_mouse() {
5104
 
      return *this;
5105
 
    }
5106
 
 
5107
 
    //! Wait for a window event in any CImg window
5108
 
    static void wait_all() {}
5109
 
 
5110
 
    //! Show a closed display
5111
 
    CImgDisplay& show() {
5112
 
      return *this;
5113
 
    }
5114
 
 
5115
 
    //! Close a visible display
5116
 
    CImgDisplay& close() {
5117
 
      return *this;
5118
 
    }
5119
 
 
5120
 
    //! Set the window title
5121
 
    CImgDisplay& set_title(const char *format,...) {
 
7759
    //! Set the window title.
 
7760
    CImgDisplay& set_title(const char *format, ...) {
5122
7761
      fps_timer = 0*(unsigned long)format;
5123
7762
      return *this;
5124
7763
    }
5125
7764
 
5126
 
    //! Re-paint image content in window
 
7765
    //! Display an image in a window.
 
7766
    template<typename T> CImgDisplay& display(const CImg<T>& img) {
 
7767
      fps_timer = 0*img.width;
 
7768
      return *this;
 
7769
    }
 
7770
 
 
7771
    //! Re-paint image content in window.
5127
7772
    CImgDisplay& paint() {
5128
7773
      return *this;
5129
7774
    }
5130
7775
 
5131
 
    //! Render image buffer into GDI native image format
 
7776
    //! Render image buffer into GDI native image format.
5132
7777
    template<typename T> CImgDisplay& render(const CImg<T>& img) {
5133
7778
      fps_timer = 0*img.width;
5134
7779
      return *this;
5142
7787
 
5143
7788
    // X11-based display
5144
7789
    //-------------------
5145
 
#elif cimg_display_type==1
 
7790
#elif cimg_display==1
 
7791
    Atom wm_delete_window, wm_delete_protocol;
 
7792
    Window window, background_window;
 
7793
    Colormap colormap;
 
7794
    XImage *image;
5146
7795
    void *data;
5147
 
    Window window;
5148
 
    Window background_window;
5149
 
    XImage *image;
5150
 
    Colormap colormap;
5151
 
    Atom wm_delete_window, wm_delete_protocol;
5152
7796
#ifdef cimg_use_xshm
5153
7797
    XShmSegmentInfo *shminfo;
5154
7798
#endif
5156
7800
    static int screen_dimx() {
5157
7801
      int res = 0;
5158
7802
      if (!cimg::X11attr().display) {
5159
 
        Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0"));
5160
 
        if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimx() : Can't open X11 display");
 
7803
        Display *disp = XOpenDisplay((std::getenv("DISPLAY")?std::getenv("DISPLAY"):":0.0"));
 
7804
        if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimx() : Can't open X11 display.");
5161
7805
        res = DisplayWidth(disp,DefaultScreen(disp));
5162
7806
        XCloseDisplay(disp);
5163
7807
      } else {
5175
7819
      int res = 0;
5176
7820
      if (!cimg::X11attr().display) {
5177
7821
        Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0"));
5178
 
        if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimy() : Can't open X11 display");
 
7822
        if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimy() : Can't open X11 display.");
5179
7823
        res = DisplayHeight(disp,DefaultScreen(disp));
5180
7824
        XCloseDisplay(disp);
5181
7825
      } else {
5182
7826
#ifdef cimg_use_xrandr
5183
7827
        if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
5184
 
          res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height; else
 
7828
          res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height;
 
7829
        else
5185
7830
#endif
5186
 
            res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
 
7831
          res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
5187
7832
      }
5188
7833
      return res;
5189
7834
    }
5190
7835
 
5191
 
    CImgDisplay& assign() {
5192
 
      if (!is_empty()) {
5193
 
        pthread_mutex_lock(cimg::X11attr().mutex);
5194
 
 
5195
 
        // Remove display window from event thread list
5196
 
        unsigned int i;
5197
 
        for (i=0; i<cimg::X11attr().nb_wins && cimg::X11attr().wins[i]!=this; ++i);
5198
 
        for (; i<cimg::X11attr().nb_wins-1; ++i) cimg::X11attr().wins[i]=cimg::X11attr().wins[i+1];
5199
 
        --cimg::X11attr().nb_wins;
5200
 
 
5201
 
        // Destroy window, image, colormap and title
5202
 
        if (is_fullscreen) _desinit_fullscreen();
5203
 
        XDestroyWindow(cimg::X11attr().display,window);
5204
 
        window = 0;
5205
 
#ifdef cimg_use_xshm
5206
 
        if (shminfo) {
5207
 
          XShmDetach(cimg::X11attr().display, shminfo);
5208
 
          XDestroyImage(image);
5209
 
          shmdt(shminfo->shmaddr);
5210
 
          shmctl(shminfo->shmid,IPC_RMID,0);
5211
 
          delete shminfo;
5212
 
          shminfo = 0;
5213
 
        } else
5214
 
#endif
5215
 
          XDestroyImage(image);
5216
 
        data = 0;
5217
 
        image = 0;
5218
 
        if (cimg::X11attr().nb_bits==8) XFreeColormap(cimg::X11attr().display,colormap);
5219
 
        colormap = 0;
5220
 
        XSync(cimg::X11attr().display, False);
5221
 
 
5222
 
        // Reset display variables
5223
 
        if (title) delete[] title;
5224
 
        width = height = normalization = events = 0;
5225
 
        is_fullscreen = is_resized = is_moved = is_event = false;
5226
 
        is_closed = true;
5227
 
        title = 0;
5228
 
        window_x = window_y = window_width = window_height = mouse_x = mouse_y = wheel = 0;
5229
 
        std::memset((void*)buttons,0,512*sizeof(unsigned int));
5230
 
        std::memset((void*)keys,0,512*sizeof(unsigned int));
5231
 
        std::memset((void*)released_keys,0,512*sizeof(unsigned int));
5232
 
        min = max = 0;
5233
 
 
5234
 
        // End event thread and close display if necessary
5235
 
        if (!cimg::X11attr().nb_wins) {
5236
 
 
5237
 
          // Kill event thread
5238
 
          pthread_cancel(*cimg::X11attr().event_thread);
5239
 
          pthread_mutex_unlock(cimg::X11attr().mutex);
5240
 
          pthread_join(*cimg::X11attr().event_thread,0);
5241
 
          delete cimg::X11attr().event_thread;
5242
 
          cimg::X11attr().event_thread = 0;
5243
 
          pthread_mutex_destroy(cimg::X11attr().mutex);
5244
 
          delete cimg::X11attr().mutex;
5245
 
          cimg::X11attr().mutex = 0;
5246
 
          XSync(cimg::X11attr().display, False);
5247
 
          XCloseDisplay(cimg::X11attr().display);
5248
 
          cimg::X11attr().display = 0;
5249
 
          delete cimg::X11attr().gc;
5250
 
          cimg::X11attr().gc = 0;
5251
 
        } else pthread_mutex_unlock(cimg::X11attr().mutex);
5252
 
      }
5253
 
      return *this;
5254
 
    }
5255
 
 
5256
 
    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
5257
 
                        const unsigned int normalization_type=3, const unsigned int events_type=3,
5258
 
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
5259
 
      if (!dimw || !dimh) return assign();
5260
 
      _assign(dimw,dimh,title,normalization_type,events_type,fullscreen_flag,closed_flag);
5261
 
      min = max = 0;
5262
 
      std::memset(data,0,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
5263
 
                          (cimg::X11attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*width*height);
5264
 
      return paint();
5265
 
    }
5266
 
 
5267
 
    template<typename T> CImgDisplay& assign(const CImg<T>& img, const char *title=0,
5268
 
                                             const unsigned int normalization_type=3, const unsigned int events_type=3,
5269
 
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
5270
 
      if (!img) return assign();
5271
 
      CImg<T> tmp;
5272
 
      const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
5273
 
      _assign(nimg.width,nimg.height,title,normalization_type,events_type,fullscreen_flag,closed_flag);
5274
 
      if (normalization==2) { const CImgStats st(nimg,false); min = (float)st.min; max = (float)st.max; }
5275
 
      return render(nimg).paint();
5276
 
    }
5277
 
 
5278
 
    template<typename T> CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
5279
 
                                             const unsigned int normalization_type=3, const unsigned int events_type=3,
5280
 
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
5281
 
      if (!list) return assign();
5282
 
      CImg<T> tmp;
5283
 
      const CImg<T> img = list.get_append('x','p'),
5284
 
        &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
5285
 
      _assign(nimg.width,nimg.height,title,normalization_type,events_type,fullscreen_flag,closed_flag);
5286
 
      if (normalization==2) { const CImgStats st(nimg,false); min = (float)st.min; max = (float)st.max; }
5287
 
      return render(nimg).paint();
5288
 
    }
5289
 
 
5290
 
    CImgDisplay& assign(const CImgDisplay& win) {
5291
 
      if (!win) return assign();
5292
 
      _assign(win.width,win.height,win.title,win.normalization,win.events,win.is_fullscreen,win.is_closed);
5293
 
      std::memcpy(data,win.data,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
5294
 
                                 cimg::X11attr().nb_bits==16?sizeof(unsigned short):
5295
 
                                 sizeof(unsigned int))*width*height);
5296
 
      return paint();
5297
 
    }
5298
 
 
5299
 
    template<typename T> CImgDisplay& display(const CImg<T>& img) {
5300
 
      if (is_empty()) assign(img.width,img.height);
5301
 
      return render(img).paint(false);
5302
 
    }
5303
 
 
5304
 
    CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
5305
 
      if (!nwidth || !nheight) return assign();
5306
 
      if (is_empty()) return assign(cimg::max(nwidth,0),cimg::max(nheight,0));
5307
 
      const unsigned int
5308
 
        tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
5309
 
        tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
5310
 
        dimx = cimg::min(tmpdimx?tmpdimx:1,(unsigned int)screen_dimx()),
5311
 
        dimy = cimg::min(tmpdimy?tmpdimy:1,(unsigned int)screen_dimy());
5312
 
      const bool
5313
 
        is_disp_different = (width!=dimx || height!=dimy),
5314
 
        is_win_different = (window_width!=dimx || window_height!=dimy);
5315
 
      if (is_disp_different || is_win_different) {
5316
 
        pthread_mutex_lock(cimg::X11attr().mutex);
5317
 
        XResizeWindow(cimg::X11attr().display,window,dimx,dimy);
5318
 
        window_width = dimx;
5319
 
        window_height = dimy;
5320
 
        is_resized = false;
5321
 
        if (is_disp_different) {
5322
 
          switch (cimg::X11attr().nb_bits) {
5323
 
          case 8:  { unsigned char foo = 0; _resize(foo,dimx,dimy,redraw); } break;
5324
 
          case 16: { unsigned short foo = 0; _resize(foo,dimx,dimy,redraw); } break;
5325
 
          default: { unsigned int foo = 0; _resize(foo,dimx,dimy,redraw); } break;
5326
 
          }
5327
 
          width = dimx;
5328
 
          height = dimy;
5329
 
        }
5330
 
        pthread_mutex_unlock(cimg::X11attr().mutex);
5331
 
        if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
5332
 
        if (redraw) return paint();
5333
 
      }
5334
 
      return *this;
5335
 
    }
5336
 
 
5337
 
    CImgDisplay& move(const int posx, const int posy) {
5338
 
      if (is_empty()) return *this;
5339
 
      show();
5340
 
      pthread_mutex_lock(cimg::X11attr().mutex);
5341
 
      XMoveWindow(cimg::X11attr().display,window,posx,posy);
5342
 
      is_moved = false;
5343
 
      window_x = posx;
5344
 
      window_y = posy;
5345
 
      pthread_mutex_unlock(cimg::X11attr().mutex);
5346
 
      return paint();
5347
 
    }
5348
 
 
5349
 
    CImgDisplay& set_mouse(const int posx, const int posy) {
5350
 
      if (!is_closed && posx>=0 && posy>=0) {
5351
 
        pthread_mutex_lock(cimg::X11attr().mutex);
5352
 
        XWarpPointer(cimg::X11attr().display,None,window,0,0,0,0,posx,posy);
5353
 
        is_moved = false;
5354
 
        mouse_x = posx;
5355
 
        mouse_y = posy;
5356
 
        XSync(cimg::X11attr().display, False);
5357
 
        pthread_mutex_unlock(cimg::X11attr().mutex);
5358
 
      }
5359
 
      return *this;
5360
 
    }
5361
 
 
5362
 
    CImgDisplay& hide_mouse() {
5363
 
      if (cimg::X11attr().display) {
5364
 
        pthread_mutex_lock(cimg::X11attr().mutex);
5365
 
        const char pix_data[8] = { 0 };
5366
 
        XColor col;
5367
 
        col.red = col.green = col.blue = 0;
5368
 
        Pixmap pix = XCreateBitmapFromData(cimg::X11attr().display,window,pix_data,8,8);
5369
 
        Cursor cur = XCreatePixmapCursor(cimg::X11attr().display,pix,pix,&col,&col,0,0);
5370
 
        XFreePixmap(cimg::X11attr().display,pix);
5371
 
        XDefineCursor(cimg::X11attr().display,window,cur);
5372
 
        pthread_mutex_unlock(cimg::X11attr().mutex);
5373
 
      }
5374
 
      return *this;
5375
 
    }
5376
 
 
5377
 
    CImgDisplay& show_mouse() {
5378
 
      if (cimg::X11attr().display) {
5379
 
        pthread_mutex_lock(cimg::X11attr().mutex);
5380
 
        XDefineCursor(cimg::X11attr().display,window,None);
5381
 
        pthread_mutex_unlock(cimg::X11attr().mutex);
5382
 
      }
5383
 
      return *this;
5384
 
    }
5385
 
 
5386
7836
    static void wait_all() {
5387
7837
      if (cimg::X11attr().display) {
5388
 
        pthread_mutex_lock(cimg::X11attr().mutex);
 
7838
        XLockDisplay(cimg::X11attr().display);
5389
7839
        bool flag = true;
5390
7840
        XEvent event;
5391
7841
        while (flag) {
5392
 
          for (unsigned int i=0; i<cimg::X11attr().nb_wins; ++i) {
5393
 
            cimg::X11attr().wins[i]->is_event = false;
5394
 
            const unsigned int xevent_type = (cimg::X11attr().wins[i]->events)&3;
5395
 
            const unsigned int emask =
5396
 
              ((xevent_type>=1)?ExposureMask|StructureNotifyMask:0)|
5397
 
              ((xevent_type>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)|
5398
 
              ((xevent_type>=3)?ButtonReleaseMask|KeyReleaseMask:0);
5399
 
            XSelectInput(cimg::X11attr().display,cimg::X11attr().wins[i]->window,emask);
5400
 
          }
5401
7842
          XNextEvent(cimg::X11attr().display, &event);
5402
 
          for (unsigned int i=0; i<cimg::X11attr().nb_wins; ++i)
 
7843
          for (unsigned int i = 0; i<cimg::X11attr().nb_wins; ++i)
5403
7844
            if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window) {
5404
7845
              cimg::X11attr().wins[i]->_handle_events(&event);
5405
7846
              if (cimg::X11attr().wins[i]->is_event) flag = false;
5406
7847
            }
5407
7848
        }
5408
 
        pthread_mutex_unlock(cimg::X11attr().mutex);
5409
 
      }
5410
 
    }
5411
 
 
5412
 
    CImgDisplay& show() {
5413
 
      if (is_empty()) return *this;
5414
 
      if (is_closed) {
5415
 
        pthread_mutex_lock(cimg::X11attr().mutex);
5416
 
        if (is_fullscreen) _init_fullscreen();
5417
 
        _map_window();
5418
 
        is_closed = false;
5419
 
        pthread_mutex_unlock(cimg::X11attr().mutex);
5420
 
      }
5421
 
      return paint();
5422
 
    }
5423
 
 
5424
 
    CImgDisplay& close() {
5425
 
      if (is_empty()) return *this;
5426
 
      if (!is_closed) {
5427
 
        pthread_mutex_lock(cimg::X11attr().mutex);
5428
 
        if (is_fullscreen) _desinit_fullscreen();
5429
 
        XUnmapWindow(cimg::X11attr().display,window);
5430
 
        window_x = window_y = -1;
5431
 
        is_closed = true;
5432
 
        pthread_mutex_unlock(cimg::X11attr().mutex);
5433
 
      }
5434
 
      return *this;
5435
 
    }
5436
 
 
5437
 
    CImgDisplay& set_title(const char *format,...) {
5438
 
      if (is_empty()) return *this;
5439
 
      char tmp[1024] = {0};
5440
 
      va_list ap;
5441
 
      va_start(ap, format);
5442
 
      std::vsprintf(tmp,format,ap);
5443
 
      va_end(ap);
5444
 
      if (title) delete[] title;
5445
 
      const int s = cimg::strlen(tmp)+1;
5446
 
      title = new char[s];
5447
 
      std::memcpy(title,tmp,s*sizeof(char));
5448
 
      pthread_mutex_lock(cimg::X11attr().mutex);
5449
 
      XStoreName(cimg::X11attr().display,window,tmp);
5450
 
      pthread_mutex_unlock(cimg::X11attr().mutex);
5451
 
      return *this;
5452
 
    }
5453
 
 
5454
 
    CImgDisplay& paint(const bool wait_expose=true) {
5455
 
      if (is_empty()) return *this;
5456
 
      pthread_mutex_lock(cimg::X11attr().mutex);
5457
 
      _paint(wait_expose);
5458
 
      pthread_mutex_unlock(cimg::X11attr().mutex);
5459
 
      return *this;
5460
 
    }
5461
 
 
5462
 
    template<typename T> CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
5463
 
      if (is_empty()) return *this;
5464
 
      if (!img)
5465
 
        throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
5466
 
                                    img.width,img.height,img.depth,img.dim,img.data);
5467
 
      if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
5468
 
      if (cimg::X11attr().nb_bits==8 && (img.width!=width || img.height!=height)) return render(img.get_resize(width,height,1,-100,1));
5469
 
      if (cimg::X11attr().nb_bits==8 && !flag8 && img.dim==3) return render(img.get_RGBtoLUT(true),true);
5470
 
 
5471
 
      const unsigned int xymax = img.width*img.height;
5472
 
      const T
5473
 
        *data1 = img.ptr(),
5474
 
        *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
5475
 
        *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
5476
 
      if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
5477
 
      pthread_mutex_lock(cimg::X11attr().mutex);
5478
 
 
5479
 
      if (!normalization || (normalization==3 && cimg::type<T>::id()==cimg::type<unsigned char>::id())) {
5480
 
        min = max = 0;
5481
 
        switch (cimg::X11attr().nb_bits) {
5482
 
        case 8: {
5483
 
          _set_colormap(colormap,img.dim);
5484
 
          unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
5485
 
          unsigned char *ptrd = (unsigned char*)ndata;
5486
 
          switch (img.dim) {
5487
 
          case 1: for (unsigned int xy=0; xy<xymax; ++xy) (*ptrd++) = (unsigned char)*(data1++);
5488
 
            break;
5489
 
          case 2: for (unsigned int xy=0; xy<xymax; ++xy) {
5490
 
            const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++);
5491
 
            (*ptrd++) = (R&0xf0)|(G>>4);
5492
 
          } break;
5493
 
          default: for (unsigned int xy=0; xy<xymax; ++xy) {
5494
 
            const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
5495
 
            (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
5496
 
          } break;
5497
 
          }
5498
 
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
5499
 
        } break;
5500
 
        case 16: {
5501
 
          unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
5502
 
          unsigned char *ptrd = (unsigned char*)ndata;
5503
 
          const unsigned int M = 248;
5504
 
          if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy<xymax; ++xy) {
5505
 
            const unsigned char G = (unsigned char)*(data2++)>>2;
5506
 
            *(ptrd++) = (unsigned char)*(data1++)&M | (G>>3);
5507
 
            *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
5508
 
          } else for (unsigned int xy=0; xy<xymax; ++xy) {
5509
 
            const unsigned char G = (unsigned char)*(data2++)>>2;
5510
 
            *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
5511
 
            *(ptrd++) = (unsigned char)*(data1++)&M | (G>>3);
5512
 
          }
5513
 
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
5514
 
        } break;
5515
 
        default: {
5516
 
          unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
5517
 
          unsigned char *ptrd = (unsigned char*)ndata;
5518
 
          if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy<xymax; ++xy) {
5519
 
            *(ptrd++) = 0;
5520
 
            *(ptrd++) = (unsigned char)*(data1++);
5521
 
            *(ptrd++) = (unsigned char)*(data2++);
5522
 
            *(ptrd++) = (unsigned char)*(data3++);
5523
 
          } else for (unsigned int xy=0; xy<xymax; ++xy) {
5524
 
            *(ptrd++) = (unsigned char)*(data3++);
5525
 
            *(ptrd++) = (unsigned char)*(data2++);
5526
 
            *(ptrd++) = (unsigned char)*(data1++);
5527
 
            *(ptrd++) = 0;
5528
 
          }
5529
 
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
5530
 
        } break;
5531
 
        };
5532
 
      } else {
5533
 
        if (normalization==3) {
5534
 
          if (cimg::type<T>::is_float()) { const CImgStats st(img,false); min = (float)st.min; max = (float)st.max; }
5535
 
          else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
5536
 
        } else if ((min>max) || normalization==1) { const CImgStats st(img,false); min = (float)st.min; max = (float)st.max; }
5537
 
        const float delta = max-min, mm = delta?delta:1.0f;
5538
 
        switch (cimg::X11attr().nb_bits) {
5539
 
        case 8: {
5540
 
          _set_colormap(colormap,img.dim);
5541
 
          unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
5542
 
          unsigned char *ptrd = (unsigned char*)ndata;
5543
 
          switch (img.dim) {
5544
 
          case 1: for (unsigned int xy=0; xy<xymax; ++xy) {
5545
 
            const unsigned char R = (unsigned char)(255*(*(data1++)-min)/mm);
5546
 
            *(ptrd++) = R;
5547
 
          } break;
5548
 
          case 2: for (unsigned int xy=0; xy<xymax; ++xy) {
5549
 
            const unsigned char
5550
 
              R = (unsigned char)(255*(*(data1++)-min)/mm),
5551
 
              G = (unsigned char)(255*(*(data2++)-min)/mm);
5552
 
            (*ptrd++) = (R&0xf0) | (G>>4);
5553
 
          } break;
5554
 
          default:
5555
 
            for (unsigned int xy=0; xy<xymax; ++xy) {
5556
 
              const unsigned char
5557
 
                R = (unsigned char)(255*(*(data1++)-min)/mm),
5558
 
                G = (unsigned char)(255*(*(data2++)-min)/mm),
5559
 
                B = (unsigned char)(255*(*(data3++)-min)/mm);
5560
 
              *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
5561
 
            } break;
5562
 
          }
5563
 
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
5564
 
        } break;
5565
 
        case 16: {
5566
 
          unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
5567
 
          unsigned char *ptrd = (unsigned char*)ndata;
5568
 
          const unsigned int M = 248;
5569
 
          if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy<xymax; ++xy) {
5570
 
            const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
5571
 
            *(ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm)&M | (G>>3);
5572
 
            *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
5573
 
          } else for (unsigned int xy=0; xy<xymax; ++xy) {
5574
 
            const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
5575
 
            *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
5576
 
            *(ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm)&M | (G>>3);
5577
 
          }
5578
 
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
5579
 
        } break;
5580
 
        default: {
5581
 
          unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
5582
 
          unsigned char *ptrd = (unsigned char*)ndata;
5583
 
          if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy<xymax; ++xy) {
5584
 
            (*ptrd++) = 0;
5585
 
            (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
5586
 
            (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
5587
 
            (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
5588
 
          } else for (unsigned int xy=0; xy<xymax; ++xy) {
5589
 
            (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
5590
 
            (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
5591
 
            (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
5592
 
            (*ptrd++) = 0;
5593
 
          }
5594
 
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
5595
 
        } break;
5596
 
        }
5597
 
      }
5598
 
      pthread_mutex_unlock(cimg::X11attr().mutex);
5599
 
      return *this;
5600
 
    }
5601
 
 
5602
 
    template<typename T> const CImgDisplay& snapshot(CImg<T>& img) const {
5603
 
      if (is_empty()) img.assign();
5604
 
      else {
5605
 
        img.assign(width,height,1,3);
5606
 
        const unsigned int xymax = width*height;
5607
 
        T
5608
 
          *data1 = img.ptr(0,0,0,0),
5609
 
          *data2 = img.ptr(0,0,0,1),
5610
 
          *data3 = img.ptr(0,0,0,2);
5611
 
        if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
5612
 
        switch (cimg::X11attr().nb_bits) {
5613
 
        case 8: {
5614
 
          unsigned char *ptrs = (unsigned char*)data;
5615
 
          for (unsigned int xy=0; xy<xymax; ++xy) {
5616
 
            const unsigned char val = *(ptrs++);
5617
 
            *(data1++) = val&0xe0;
5618
 
            *(data2++) = (val&0x1c)<<3;
5619
 
            *(data3++) = val<<6;
5620
 
          }
5621
 
        } break;
5622
 
        case 16: {
5623
 
          unsigned char *ptrs = (unsigned char*)data;
5624
 
          if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy<xymax; ++xy) {
5625
 
            const unsigned char val0 = *(ptrs++), val1 = *(ptrs++);
5626
 
            *(data1++) = val0&0xf8;
5627
 
            *(data2++) = (val0<<5) | ((val1&0xe0)>>5);
5628
 
            *(data3++) = val1<<3;
5629
 
          } else for (unsigned int xy=0; xy<xymax; ++xy) {
5630
 
            const unsigned short val0 = *(ptrs++), val1 = *(ptrs++);
5631
 
            *(data1++) = val1&0xf8;
5632
 
            *(data2++) = (val1<<5) | ((val0&0xe0)>>5);
5633
 
            *(data3++) = val0<<3;
5634
 
          }
5635
 
        } break;
5636
 
        default: {
5637
 
          unsigned char *ptrs = (unsigned char*)data;
5638
 
          if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy<xymax; ++xy) {
5639
 
            ++ptrs;
5640
 
            *(data1++) = *(ptrs++);
5641
 
            *(data2++) = *(ptrs++);
5642
 
            *(data3++) = *(ptrs++);
5643
 
          } else for (unsigned int xy=0; xy<xymax; ++xy) {
5644
 
            *(data3++) = *(ptrs++);
5645
 
            *(data2++) = *(ptrs++);
5646
 
            *(data1++) = *(ptrs++);
5647
 
            ++ptrs;
5648
 
          }
5649
 
        } break;
5650
 
        }
5651
 
      }
5652
 
      return *this;
5653
 
    }
5654
 
 
5655
 
    static int _assign_xshm(Display *dpy, XErrorEvent *error) {
5656
 
      dpy = 0; error = 0;
5657
 
      cimg::X11attr().shm_enabled = false;
 
7849
        XUnlockDisplay(cimg::X11attr().display);
 
7850
      }
 
7851
    }
 
7852
 
 
7853
    void _handle_events(const XEvent *const pevent) {
 
7854
      XEvent event = *pevent;
 
7855
      switch (event.type) {
 
7856
      case ClientMessage: {
 
7857
        if ((int)event.xclient.message_type==(int)wm_delete_protocol &&
 
7858
            (int)event.xclient.data.l[0]==(int)wm_delete_window) {
 
7859
          XUnmapWindow(cimg::X11attr().display,window);
 
7860
          mouse_x = mouse_y = -1;
 
7861
          if (button) { std::memmove((void*)(buttons+1),(void*)buttons,512-1); button = 0; }
 
7862
          if (key) { std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
 
7863
          if (released_key) { std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
 
7864
          is_closed = is_event = true;
 
7865
        }
 
7866
      } break;
 
7867
      case ConfigureNotify: {
 
7868
        while (XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event)) {}
 
7869
        const unsigned int
 
7870
          nw = event.xconfigure.width,
 
7871
          nh = event.xconfigure.height;
 
7872
        const int
 
7873
          nx = event.xconfigure.x,
 
7874
          ny = event.xconfigure.y;
 
7875
        if (nw && nh && (nw!=window_width || nh!=window_height)) {
 
7876
          window_width = nw;
 
7877
          window_height = nh;
 
7878
          mouse_x = mouse_y = -1;
 
7879
          XResizeWindow(cimg::X11attr().display,window,window_width,window_height);
 
7880
          is_resized = is_event = true;
 
7881
        }
 
7882
        if (nx!=window_x || ny!=window_y) {
 
7883
          window_x = nx;
 
7884
          window_y = ny;
 
7885
          is_moved = is_event = true;
 
7886
        }
 
7887
      } break;
 
7888
      case Expose: {
 
7889
        while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event)) {}
 
7890
        _paint(false);
 
7891
        if (is_fullscreen) {
 
7892
          XWindowAttributes attr;
 
7893
          XGetWindowAttributes(cimg::X11attr().display, window, &attr);
 
7894
          while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
 
7895
          XSetInputFocus(cimg::X11attr().display, window, RevertToParent, CurrentTime);
 
7896
        }
 
7897
      } break;
 
7898
      case ButtonPress: {
 
7899
        do {
 
7900
          switch (event.xbutton.button) {
 
7901
          case 1: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=1; is_event = true; break;
 
7902
          case 2: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=4; is_event = true; break;
 
7903
          case 3: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=2; is_event = true; break;
 
7904
          }
 
7905
        } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event));
 
7906
      } break;
 
7907
      case ButtonRelease: {
 
7908
        do {
 
7909
          switch (event.xbutton.button) {
 
7910
          case 1: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~1U; is_event = true; break;
 
7911
          case 2: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~4U; is_event = true; break;
 
7912
          case 3: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~2U; is_event = true; break;
 
7913
          case 4: ++wheel; is_event = true; break;
 
7914
          case 5: --wheel; is_event = true; break;
 
7915
          }
 
7916
        } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event));
 
7917
      } break;
 
7918
      case KeyPress: {
 
7919
        char tmp;
 
7920
        KeySym ksym;
 
7921
        XLookupString(&event.xkey,&tmp,1,&ksym,0);
 
7922
        update_iskey((unsigned int)ksym,true);
 
7923
        if (key) std::memmove((void*)(keys+1),(void*)keys,512-1);
 
7924
        key = (unsigned int)ksym;
 
7925
        if (released_key) { std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
 
7926
        is_event = true;
 
7927
      } break;
 
7928
      case KeyRelease: {
 
7929
        char tmp;
 
7930
        KeySym ksym;
 
7931
        XLookupString(&event.xkey,&tmp,1,&ksym,0);
 
7932
        update_iskey((unsigned int)ksym,false);
 
7933
        if (key) { std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
 
7934
        if (released_key) std::memmove((void*)(released_keys+1),(void*)released_keys,512-1);
 
7935
        released_key = (unsigned int)ksym;
 
7936
        is_event = true;
 
7937
      } break;
 
7938
      case LeaveNotify: {
 
7939
        while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event)) {}
 
7940
        mouse_x = mouse_y =-1;
 
7941
        is_event = true;
 
7942
      } break;
 
7943
      case MotionNotify: {
 
7944
        while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event)) {}
 
7945
        mouse_x = event.xmotion.x;
 
7946
        mouse_y = event.xmotion.y;
 
7947
        if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
 
7948
        is_event = true;
 
7949
      } break;
 
7950
      }
 
7951
    }
 
7952
 
 
7953
    static void* _events_thread(void *arg) {
 
7954
      arg = 0;
 
7955
      XEvent event;
 
7956
      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
 
7957
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
 
7958
      for (;;) {
 
7959
        XLockDisplay(cimg::X11attr().display);
 
7960
        bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event);
 
7961
        if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display,
 
7962
                                                      ExposureMask|StructureNotifyMask|ButtonPressMask|
 
7963
                                                      KeyPressMask|PointerMotionMask|LeaveWindowMask|ButtonReleaseMask|
 
7964
                                                      KeyReleaseMask,&event);
 
7965
        if (event_flag) {
 
7966
          for (unsigned int i=0; i<cimg::X11attr().nb_wins; ++i)
 
7967
            if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window)
 
7968
              cimg::X11attr().wins[i]->_handle_events(&event);
 
7969
        }
 
7970
        XUnlockDisplay(cimg::X11attr().display);
 
7971
        pthread_testcancel();
 
7972
        cimg::sleep(7);
 
7973
      }
5658
7974
      return 0;
5659
7975
    }
5660
7976
 
5661
 
    void _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
5662
 
                 const unsigned int normalization_type=3, const unsigned int events_type=3,
5663
 
                 const bool fullscreen_flag=false, const bool closed_flag=false) {
5664
 
 
5665
 
      // Allocate space for window title
5666
 
      const int s = cimg::strlen(ptitle)+1;
5667
 
      char *tmp_title = s?new char[s]:0;
5668
 
      if (s) std::memcpy(tmp_title,ptitle,s*sizeof(char));
5669
 
 
5670
 
      // Destroy previous display window if existing
5671
 
      if (!is_empty()) assign();
5672
 
 
5673
 
      // Open X11 display if necessary.
5674
 
      if (!cimg::X11attr().display) {
5675
 
        cimg::X11attr().nb_wins = 0;
5676
 
        cimg::X11attr().mutex = new pthread_mutex_t;
5677
 
        pthread_mutex_init(cimg::X11attr().mutex,0);
5678
 
 
5679
 
        cimg::X11attr().display = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0"));
5680
 
        if (!cimg::X11attr().display)
5681
 
          throw CImgDisplayException("CImgDisplay::_create_window() : Can't open X11 display");
5682
 
        cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display));
5683
 
        if (cimg::X11attr().nb_bits!=8 && cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24 && cimg::X11attr().nb_bits!=32)
5684
 
          throw CImgDisplayException("CImgDisplay::_create_window() : %u bits mode is not supported "
5685
 
                                     "(only 8, 16, 24 and 32 bits modes are supported)",cimg::X11attr().nb_bits);
5686
 
        cimg::X11attr().gc = new GC;
5687
 
        *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
5688
 
        Visual *visual = DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
5689
 
        XVisualInfo vtemplate;
5690
 
        vtemplate.visualid = XVisualIDFromVisual(visual);
5691
 
        int nb_visuals;
5692
 
        XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals);
5693
 
        if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11attr().blue_first = true;
5694
 
        cimg::X11attr().byte_order = ImageByteOrder(cimg::X11attr().display);
5695
 
        XFree(vinfo);
5696
 
        pthread_mutex_lock(cimg::X11attr().mutex);
5697
 
        cimg::X11attr().event_thread = new pthread_t;
5698
 
        pthread_create(cimg::X11attr().event_thread,0,_events_thread,0);
5699
 
      } else pthread_mutex_lock(cimg::X11attr().mutex);
5700
 
 
5701
 
      // Set display variables
5702
 
      width = cimg::min(dimw,(unsigned int)screen_dimx());
5703
 
      height = cimg::min(dimh,(unsigned int)screen_dimy());
5704
 
      normalization = normalization_type%4;
5705
 
      events = events_type%4;
5706
 
      is_fullscreen = fullscreen_flag;
5707
 
      title = tmp_title;
5708
 
      window_x = window_y = wheel = 0;
5709
 
      mouse_x = mouse_y = -1;
5710
 
      std::memset((void*)buttons,0,512*sizeof(unsigned int));
5711
 
      std::memset((void*)keys,0,512*sizeof(unsigned int));
5712
 
      std::memset((void*)released_keys,0,512*sizeof(unsigned int));
5713
 
      is_resized = is_moved = is_event = false;
5714
 
      is_closed = closed_flag;
5715
 
      fps_timer = fps_frames = timer = 0;
5716
 
      fps_fps = 0;
5717
 
 
5718
 
      // Create X11 window and palette (if 8bits display)
5719
 
      if (is_fullscreen) {
5720
 
        _init_fullscreen();
5721
 
        const unsigned int sx = screen_dimx(), sy = screen_dimy();
5722
 
        XSetWindowAttributes winattr;
5723
 
        winattr.override_redirect = True;
5724
 
        window = XCreateWindow(cimg::X11attr().display,
5725
 
                               RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
5726
 
                               (sx-width)/2,(sy-height)/2,
5727
 
                               width,height,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
5728
 
      } else
5729
 
        window = XCreateSimpleWindow(cimg::X11attr().display,
5730
 
                                     RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
5731
 
                                     0,0,width,height,2,0,0x0L);
5732
 
      XStoreName(cimg::X11attr().display,window,title?title:" ");
5733
 
      if (cimg::X11attr().nb_bits==8) {
5734
 
        colormap = XCreateColormap(cimg::X11attr().display,window,DefaultVisual(cimg::X11attr().display,
5735
 
                                                                                DefaultScreen(cimg::X11attr().display)),AllocAll);
5736
 
        _set_colormap(colormap,3);
5737
 
        XSetWindowColormap(cimg::X11attr().display,window,colormap);
5738
 
      }
5739
 
      window_width = width;
5740
 
      window_height = height;
5741
 
 
5742
 
      // Create XImage
5743
 
      const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
5744
 
#ifdef cimg_use_xshm
5745
 
      shminfo = 0;
5746
 
      if (XShmQueryExtension(cimg::X11attr().display)) {
5747
 
        shminfo = new XShmSegmentInfo;
5748
 
        image = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
5749
 
                                cimg::X11attr().nb_bits,ZPixmap,0,shminfo,width,height);
5750
 
        if (!image) {
5751
 
          delete shminfo;
5752
 
          shminfo = 0;
5753
 
        } else {
5754
 
          shminfo->shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777);
5755
 
          if (shminfo->shmid==-1) {
5756
 
            XDestroyImage(image);
5757
 
            delete shminfo;
5758
 
            shminfo = 0;
5759
 
          } else {
5760
 
            shminfo->shmaddr = image->data = (char*)(data = shmat(shminfo->shmid,0,0));
5761
 
            if (shminfo->shmaddr==(char*)-1) {
5762
 
              shmctl(shminfo->shmid,IPC_RMID,0);
5763
 
              XDestroyImage(image);
5764
 
              delete shminfo;
5765
 
              shminfo = 0;
5766
 
            } else {
5767
 
              shminfo->readOnly = False;
5768
 
              cimg::X11attr().shm_enabled = true;
5769
 
              XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
5770
 
              XShmAttach(cimg::X11attr().display, shminfo);
5771
 
              XSync(cimg::X11attr().display, False);
5772
 
              XSetErrorHandler(oldXErrorHandler);
5773
 
              if (!cimg::X11attr().shm_enabled) {
5774
 
                shmdt(shminfo->shmaddr);
5775
 
                shmctl(shminfo->shmid,IPC_RMID,0);
5776
 
                XDestroyImage(image);
5777
 
                delete shminfo;
5778
 
                shminfo = 0;
5779
 
              }
5780
 
            }
5781
 
          }
5782
 
        }
5783
 
      }
5784
 
      if (!shminfo)
5785
 
#endif
5786
 
        {
5787
 
          data = std::malloc(bufsize);
5788
 
          image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
5789
 
                               cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0);
5790
 
        }
5791
 
 
5792
 
      if (!is_closed) _map_window(); else { window_x = window_y = cimg::type<int>::min(); }
5793
 
 
5794
 
      if (events) {
5795
 
        wm_delete_window = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False);
5796
 
        wm_delete_protocol = XInternAtom(cimg::X11attr().display, "WM_PROTOCOLS", False);
5797
 
        XSetWMProtocols(cimg::X11attr().display, window, &wm_delete_window, 1);
5798
 
        if (is_fullscreen) XGrabKeyboard(cimg::X11attr().display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
5799
 
      }
5800
 
      cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this;
5801
 
      pthread_mutex_unlock(cimg::X11attr().mutex);
5802
 
    }
5803
 
 
5804
 
    void _map_window() {
5805
 
      XWindowAttributes attr;
5806
 
      XEvent event;
5807
 
      XSelectInput(cimg::X11attr().display,window,ExposureMask | StructureNotifyMask);
5808
 
      bool exposed = false, mapped = false;
5809
 
      XMapRaised(cimg::X11attr().display,window);
5810
 
      XSync(cimg::X11attr().display,False);
5811
 
      do {
5812
 
        XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask | ExposureMask,&event);
5813
 
        switch (event.type) {
5814
 
        case MapNotify: mapped = true; break;
5815
 
        case Expose: exposed = true; break;
5816
 
        default:  XSync(cimg::X11attr().display, False); cimg::sleep(10);
5817
 
        }
5818
 
      } while (!(exposed && mapped));
5819
 
      do {
5820
 
        XGetWindowAttributes(cimg::X11attr().display, window, &attr);
5821
 
        if (attr.map_state!=IsViewable) { XSync(cimg::X11attr().display,False); cimg::sleep(10); }
5822
 
      } while (attr.map_state != IsViewable);
5823
 
      window_x = attr.x;
5824
 
      window_y = attr.y;
5825
 
    }
5826
 
 
5827
7977
    void _set_colormap(Colormap& colormap, const unsigned int dim) {
5828
7978
      XColor palette[256];
5829
7979
      switch (dim) {
5830
 
      case 1:  // palette for greyscale images
 
7980
      case 1: { // palette for greyscale images
5831
7981
        for (unsigned int index=0; index<256; ++index) {
5832
7982
          palette[index].pixel = index;
5833
7983
          palette[index].red = palette[index].green = palette[index].blue = (unsigned short)(index<<8);
5834
7984
          palette[index].flags = DoRed | DoGreen | DoBlue;
5835
7985
        }
5836
 
        break;
5837
 
      case 2: // palette for RG images
 
7986
      } break;
 
7987
      case 2: { // palette for RG images
5838
7988
        for (unsigned int index=0, r=8; r<256; r+=16)
5839
7989
          for (unsigned int g=8; g<256; g+=16) {
5840
7990
            palette[index].pixel = index;
5842
7992
            palette[index].green = (unsigned short)(g<<8);
5843
7993
            palette[index++].flags = DoRed | DoGreen | DoBlue;
5844
7994
          }
5845
 
        break;
5846
 
      default: // palette for RGB images
 
7995
      } break;
 
7996
      default: { // palette for RGB images
5847
7997
        for (unsigned int index=0, r=16; r<256; r+=32)
5848
7998
          for (unsigned int g=16; g<256; g+=32)
5849
7999
            for (unsigned int b=32; b<256; b+=64) {
5853
8003
              palette[index].blue  = (unsigned short)(b<<8);
5854
8004
              palette[index++].flags = DoRed | DoGreen | DoBlue;
5855
8005
            }
5856
 
        break;
 
8006
      }
5857
8007
      }
5858
8008
      XStoreColors(cimg::X11attr().display,colormap,palette,256);
5859
8009
    }
5860
8010
 
 
8011
    void _map_window() {
 
8012
      XWindowAttributes attr;
 
8013
      XEvent event;
 
8014
      bool exposed = false, mapped = false;
 
8015
      XMapRaised(cimg::X11attr().display,window);
 
8016
      XSync(cimg::X11attr().display,False);
 
8017
      do {
 
8018
        XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask | ExposureMask,&event);
 
8019
        switch (event.type) {
 
8020
        case MapNotify: mapped = true; break;
 
8021
        case Expose: exposed = true; break;
 
8022
        default: XSync(cimg::X11attr().display, False); cimg::sleep(10);
 
8023
        }
 
8024
      } while (!(exposed && mapped));
 
8025
      do {
 
8026
        XGetWindowAttributes(cimg::X11attr().display, window, &attr);
 
8027
        if (attr.map_state!=IsViewable) { XSync(cimg::X11attr().display,False); cimg::sleep(10); }
 
8028
      } while (attr.map_state != IsViewable);
 
8029
      window_x = attr.x;
 
8030
      window_y = attr.y;
 
8031
    }
 
8032
 
5861
8033
    void _paint(const bool wait_expose=true) {
5862
8034
      if (!is_closed) {
5863
8035
        if (wait_expose) {
5869
8041
          event.xexpose.window = window;
5870
8042
          event.xexpose.x = 0;
5871
8043
          event.xexpose.y = 0;
5872
 
          event.xexpose.width = (int)width;
5873
 
          event.xexpose.height = (int)height;
 
8044
          event.xexpose.width = dimx();
 
8045
          event.xexpose.height = dimy();
5874
8046
          event.xexpose.count = 0;
5875
8047
          XSendEvent(cimg::X11attr().display, window, False, 0, &event);
5876
8048
        } else {
6031
8203
      }
6032
8204
    }
6033
8205
 
6034
 
    void _handle_events(const XEvent *const pevent) {
6035
 
      XEvent event=*pevent;
6036
 
      switch (event.type) {
6037
 
      case ClientMessage:
6038
 
        if ((int)event.xclient.message_type==(int)wm_delete_protocol &&
6039
 
            (int)event.xclient.data.l[0]==(int)wm_delete_window) {
6040
 
          XUnmapWindow(cimg::X11attr().display,window);
6041
 
          mouse_x = mouse_y = -1;
6042
 
          if (button) {
6043
 
            std::memmove((void*)(buttons+1),(void*)buttons,512-1);
6044
 
            button = 0;
6045
 
          }
6046
 
          if (key) {
6047
 
            std::memmove((void*)(keys+1),(void*)keys,512-1);
6048
 
            key = 0;
6049
 
          }
6050
 
          if (released_key) {
6051
 
            std::memmove((void*)(released_keys+1),(void*)released_keys,512-1);
6052
 
            released_key = 0;
6053
 
          }
6054
 
          is_closed = is_event = true;
6055
 
        }
6056
 
        break;
6057
 
     case ConfigureNotify: {
6058
 
        while (XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event));
6059
 
        const unsigned int
6060
 
          nw = event.xconfigure.width,
6061
 
          nh = event.xconfigure.height;
6062
 
        const int
6063
 
          nx = event.xconfigure.x,
6064
 
          ny = event.xconfigure.y;
6065
 
        if (nw && nh && (nw!=window_width || nh!=window_height)) {
6066
 
          window_width = nw;
6067
 
          window_height = nh;
6068
 
          mouse_x = mouse_y = -1;
6069
 
          XResizeWindow(cimg::X11attr().display,window,window_width,window_height);
6070
 
          is_resized = is_event = true;
6071
 
        }
6072
 
        if (nx!=window_x || ny!=window_y) {
6073
 
          window_x = nx;
6074
 
          window_y = ny;
6075
 
          is_moved = is_event = true;
6076
 
        }
6077
 
     } break;
6078
 
      case Expose: {
6079
 
        while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event));
6080
 
        _paint(false);
6081
 
        if (is_fullscreen) {
6082
 
          XWindowAttributes attr;
6083
 
          XGetWindowAttributes(cimg::X11attr().display, window, &attr);
6084
 
          while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
6085
 
          XSetInputFocus(cimg::X11attr().display, window, RevertToParent, CurrentTime);
6086
 
        }
6087
 
      } break;
6088
 
      case ButtonPress: {
6089
 
        do {
6090
 
          switch (event.xbutton.button) {
6091
 
          case 1: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=1; is_event = true; break;
6092
 
          case 2: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=4; is_event = true; break;
6093
 
          case 3: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=2; is_event = true; break;
6094
 
          default: break;
6095
 
          }
6096
 
        } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event));
6097
 
      } break;
6098
 
      case ButtonRelease: {
6099
 
        do {
6100
 
          switch (event.xbutton.button) {
6101
 
          case 1: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~1U; is_event = true; break;
6102
 
          case 2: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~4U; is_event = true; break;
6103
 
          case 3: std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~2U; is_event = true; break;
6104
 
          case 4: ++wheel; is_event = true; break;
6105
 
          case 5: --wheel; is_event = true; break;
6106
 
          default: break;
6107
 
          }
6108
 
        } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event));
6109
 
      } break;
6110
 
      case KeyPress: {
6111
 
        char tmp;
6112
 
        KeySym ksym;
6113
 
        XLookupString(&event.xkey,&tmp,1,&ksym,0);
6114
 
        if (key) std::memmove((void*)(keys+1),(void*)keys,512-1);
6115
 
        key = (unsigned int)ksym;
6116
 
        if (released_key) {
6117
 
          std::memmove((void*)(released_keys+1),(void*)released_keys,512-1);
6118
 
          released_key = 0;
6119
 
        }
6120
 
        is_event = true;
6121
 
      } break;
6122
 
      case KeyRelease: {
6123
 
        char tmp;
6124
 
        KeySym ksym;
6125
 
        XLookupString(&event.xkey,&tmp,1,&ksym,0);
6126
 
        if (key) {
6127
 
          std::memmove((void*)(keys+1),(void*)keys,512-1);
6128
 
          key = 0;
6129
 
        }
6130
 
        if (released_key) std::memmove((void*)(released_keys+1),(void*)released_keys,512-1);
6131
 
        released_key = (unsigned int)ksym;
6132
 
        is_event = true;
6133
 
      } break;
6134
 
      case LeaveNotify:
6135
 
        while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event));
6136
 
        mouse_x = mouse_y =-1;
6137
 
        is_event = true;
6138
 
        break;
6139
 
      case MotionNotify:
6140
 
        while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event));
6141
 
        mouse_x = event.xmotion.x;
6142
 
        mouse_y = event.xmotion.y;
6143
 
        if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
6144
 
        is_event = true;
6145
 
        break;
6146
 
      }
6147
 
    }
6148
 
 
6149
 
    static void* _events_thread(void *arg) {
6150
 
      arg = 0;
6151
 
      XEvent event;
6152
 
      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
6153
 
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
6154
 
      for (;;) {
6155
 
        pthread_mutex_lock(cimg::X11attr().mutex);
6156
 
        for (unsigned int i=0; i<cimg::X11attr().nb_wins; ++i) {
6157
 
          const unsigned int xevent_type = (cimg::X11attr().wins[i]->events)&3;
6158
 
          const unsigned int emask =
6159
 
            ((xevent_type>=1)?ExposureMask|StructureNotifyMask:0)|
6160
 
            ((xevent_type>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)|
6161
 
            ((xevent_type>=3)?ButtonReleaseMask|KeyReleaseMask:0);
6162
 
          XSelectInput(cimg::X11attr().display,cimg::X11attr().wins[i]->window,emask);
6163
 
        }
6164
 
        bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event);
6165
 
        if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display,
6166
 
                                                      ExposureMask|StructureNotifyMask|ButtonPressMask|
6167
 
                                                      KeyPressMask|PointerMotionMask|LeaveWindowMask|ButtonReleaseMask|
6168
 
                                                      KeyReleaseMask,&event);
6169
 
        if (event_flag) {
6170
 
          for (unsigned int i=0; i<cimg::X11attr().nb_wins; ++i)
6171
 
            if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window)
6172
 
              cimg::X11attr().wins[i]->_handle_events(&event);
6173
 
        }
6174
 
        pthread_mutex_unlock(cimg::X11attr().mutex);
6175
 
        pthread_testcancel();
6176
 
        cimg::sleep(7);
6177
 
      }
 
8206
    static int _assign_xshm(Display *dpy, XErrorEvent *error) {
 
8207
      dpy = 0; error = 0;
 
8208
      cimg::X11attr().shm_enabled = false;
6178
8209
      return 0;
6179
8210
    }
6180
8211
 
 
8212
    void _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
 
8213
                 const unsigned int normalization_type=3,
 
8214
                 const bool fullscreen_flag=false, const bool closed_flag=false) {
 
8215
 
 
8216
      // Allocate space for window title
 
8217
      const int s = cimg::strlen(ptitle)+1;
 
8218
      char *tmp_title = s?new char[s]:0;
 
8219
      if (s) std::memcpy(tmp_title,ptitle,s*sizeof(char));
 
8220
 
 
8221
      // Destroy previous display window if existing
 
8222
      if (!is_empty()) assign();
 
8223
 
 
8224
      // Open X11 display if necessary.
 
8225
      if (!cimg::X11attr().display) {
 
8226
        static bool xinit_threads = false;
 
8227
        if (!xinit_threads) { XInitThreads(); xinit_threads = true; }
 
8228
        cimg::X11attr().nb_wins = 0;
 
8229
        cimg::X11attr().display = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0"));
 
8230
        if (!cimg::X11attr().display)
 
8231
          throw CImgDisplayException("CImgDisplay::_create_window() : Can't open X11 display");
 
8232
        cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display));
 
8233
        if (cimg::X11attr().nb_bits!=8 && cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24 && cimg::X11attr().nb_bits!=32)
 
8234
          throw CImgDisplayException("CImgDisplay::_create_window() : %u bits mode is not supported "
 
8235
                                     "(only 8, 16, 24 and 32 bits modes are supported)",cimg::X11attr().nb_bits);
 
8236
        cimg::X11attr().gc = new GC;
 
8237
        *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
 
8238
        Visual *visual = DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
 
8239
        XVisualInfo vtemplate;
 
8240
        vtemplate.visualid = XVisualIDFromVisual(visual);
 
8241
        int nb_visuals;
 
8242
        XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals);
 
8243
        if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11attr().blue_first = true;
 
8244
        cimg::X11attr().byte_order = ImageByteOrder(cimg::X11attr().display);
 
8245
        XFree(vinfo);
 
8246
        XLockDisplay(cimg::X11attr().display);
 
8247
        cimg::X11attr().event_thread = new pthread_t;
 
8248
        pthread_create(cimg::X11attr().event_thread,0,_events_thread,0);
 
8249
      } else XLockDisplay(cimg::X11attr().display);
 
8250
 
 
8251
      // Set display variables
 
8252
      width = cimg::min(dimw,(unsigned int)screen_dimx());
 
8253
      height = cimg::min(dimh,(unsigned int)screen_dimy());
 
8254
      normalization = normalization_type<4?normalization_type:3;
 
8255
      is_fullscreen = fullscreen_flag;
 
8256
      window_x = window_y = 0;
 
8257
      is_closed = closed_flag;
 
8258
      title = tmp_title;
 
8259
      flush();
 
8260
 
 
8261
      // Create X11 window and palette (if 8bits display)
 
8262
      if (is_fullscreen) {
 
8263
        if (!is_closed) _init_fullscreen();
 
8264
        const unsigned int sx = screen_dimx(), sy = screen_dimy();
 
8265
        XSetWindowAttributes winattr;
 
8266
        winattr.override_redirect = True;
 
8267
        window = XCreateWindow(cimg::X11attr().display,
 
8268
                               RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
 
8269
                               (sx-width)/2,(sy-height)/2,
 
8270
                               width,height,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
 
8271
      } else
 
8272
        window = XCreateSimpleWindow(cimg::X11attr().display,
 
8273
                                     RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
 
8274
                                     0,0,width,height,2,0,0x0L);
 
8275
      XStoreName(cimg::X11attr().display,window,title?title:" ");
 
8276
      if (cimg::X11attr().nb_bits==8) {
 
8277
        colormap = XCreateColormap(cimg::X11attr().display,window,DefaultVisual(cimg::X11attr().display,
 
8278
                                                                                DefaultScreen(cimg::X11attr().display)),AllocAll);
 
8279
        _set_colormap(colormap,3);
 
8280
        XSetWindowColormap(cimg::X11attr().display,window,colormap);
 
8281
      }
 
8282
      window_width = width;
 
8283
      window_height = height;
 
8284
 
 
8285
      // Create XImage
 
8286
      const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
 
8287
#ifdef cimg_use_xshm
 
8288
      shminfo = 0;
 
8289
      if (XShmQueryExtension(cimg::X11attr().display)) {
 
8290
        shminfo = new XShmSegmentInfo;
 
8291
        image = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
 
8292
                                cimg::X11attr().nb_bits,ZPixmap,0,shminfo,width,height);
 
8293
        if (!image) {
 
8294
          delete shminfo;
 
8295
          shminfo = 0;
 
8296
        } else {
 
8297
          shminfo->shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777);
 
8298
          if (shminfo->shmid==-1) {
 
8299
            XDestroyImage(image);
 
8300
            delete shminfo;
 
8301
            shminfo = 0;
 
8302
          } else {
 
8303
            shminfo->shmaddr = image->data = (char*)(data = shmat(shminfo->shmid,0,0));
 
8304
            if (shminfo->shmaddr==(char*)-1) {
 
8305
              shmctl(shminfo->shmid,IPC_RMID,0);
 
8306
              XDestroyImage(image);
 
8307
              delete shminfo;
 
8308
              shminfo = 0;
 
8309
            } else {
 
8310
              shminfo->readOnly = False;
 
8311
              cimg::X11attr().shm_enabled = true;
 
8312
              XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
 
8313
              XShmAttach(cimg::X11attr().display, shminfo);
 
8314
              XSync(cimg::X11attr().display, False);
 
8315
              XSetErrorHandler(oldXErrorHandler);
 
8316
              if (!cimg::X11attr().shm_enabled) {
 
8317
                shmdt(shminfo->shmaddr);
 
8318
                shmctl(shminfo->shmid,IPC_RMID,0);
 
8319
                XDestroyImage(image);
 
8320
                delete shminfo;
 
8321
                shminfo = 0;
 
8322
              }
 
8323
            }
 
8324
          }
 
8325
        }
 
8326
      }
 
8327
      if (!shminfo)
 
8328
#endif
 
8329
        {
 
8330
          data = std::malloc(bufsize);
 
8331
          image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
 
8332
                               cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0);
 
8333
        }
 
8334
 
 
8335
      wm_delete_window = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False);
 
8336
      wm_delete_protocol = XInternAtom(cimg::X11attr().display, "WM_PROTOCOLS", False);
 
8337
      XSetWMProtocols(cimg::X11attr().display, window, &wm_delete_window, 1);
 
8338
      XSelectInput(cimg::X11attr().display,window,
 
8339
                   ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask |
 
8340
                   LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask);
 
8341
      if (is_fullscreen) XGrabKeyboard(cimg::X11attr().display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
 
8342
      cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this;
 
8343
      if (!is_closed) _map_window(); else { window_x = window_y = cimg::type<int>::min(); }
 
8344
      XUnlockDisplay(cimg::X11attr().display);
 
8345
    }
 
8346
 
 
8347
    CImgDisplay& assign() {
 
8348
      if (!is_empty()) {
 
8349
        XLockDisplay(cimg::X11attr().display);
 
8350
 
 
8351
        // Remove display window from event thread list.
 
8352
        unsigned int i;
 
8353
        for (i = 0; i<cimg::X11attr().nb_wins && cimg::X11attr().wins[i]!=this; ++i) {}
 
8354
        for (; i<cimg::X11attr().nb_wins-1; ++i) cimg::X11attr().wins[i] = cimg::X11attr().wins[i+1];
 
8355
        --cimg::X11attr().nb_wins;
 
8356
 
 
8357
        // Destroy window, image, colormap and title.
 
8358
        if (is_fullscreen && !is_closed) _desinit_fullscreen();
 
8359
        XDestroyWindow(cimg::X11attr().display,window);
 
8360
        window = 0;
 
8361
#ifdef cimg_use_xshm
 
8362
        if (shminfo) {
 
8363
          XShmDetach(cimg::X11attr().display, shminfo);
 
8364
          XDestroyImage(image);
 
8365
          shmdt(shminfo->shmaddr);
 
8366
          shmctl(shminfo->shmid,IPC_RMID,0);
 
8367
          delete shminfo;
 
8368
          shminfo = 0;
 
8369
        } else
 
8370
#endif
 
8371
          XDestroyImage(image);
 
8372
        data = 0; image = 0;
 
8373
        if (cimg::X11attr().nb_bits==8) XFreeColormap(cimg::X11attr().display,colormap);
 
8374
        colormap = 0;
 
8375
        XSync(cimg::X11attr().display, False);
 
8376
 
 
8377
        // Reset display variables
 
8378
        if (title) delete[] title;
 
8379
        width = height = normalization = window_width = window_height = 0;
 
8380
        window_x = window_y = 0;
 
8381
        is_fullscreen = false;
 
8382
        is_closed = true;
 
8383
        min = max = 0;
 
8384
        title = 0;
 
8385
        flush();
 
8386
 
 
8387
        // End event thread and close display if necessary
 
8388
        XUnlockDisplay(cimg::X11attr().display);
 
8389
 
 
8390
        /* The code below was used to close the X11 display when not used anymore,
 
8391
           unfortunately, since the latest Xorg versions, it randomely hangs, so
 
8392
           I prefer to remove it. A fix would be needed anyway.
 
8393
 
 
8394
          if (!cimg::X11attr().nb_wins) {
 
8395
          // Kill event thread
 
8396
          pthread_cancel(*cimg::X11attr().event_thread);
 
8397
          XUnlockDisplay(cimg::X11attr().display);
 
8398
          pthread_join(*cimg::X11attr().event_thread,0);
 
8399
          delete cimg::X11attr().event_thread;
 
8400
          cimg::X11attr().event_thread = 0;
 
8401
          XCloseDisplay(cimg::X11attr().display);
 
8402
          cimg::X11attr().display = 0;
 
8403
          delete cimg::X11attr().gc;
 
8404
          cimg::X11attr().gc = 0;
 
8405
          } else XUnlockDisplay(cimg::X11attr().display);
 
8406
        */
 
8407
      }
 
8408
      return *this;
 
8409
    }
 
8410
 
 
8411
    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
 
8412
                        const unsigned int normalization_type=3,
 
8413
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
 
8414
      if (!dimw || !dimh) return assign();
 
8415
      _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
 
8416
      min = max = 0;
 
8417
      std::memset(data,0,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
 
8418
                          (cimg::X11attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*width*height);
 
8419
      return paint();
 
8420
    }
 
8421
 
 
8422
    template<typename T> CImgDisplay& assign(const CImg<T>& img, const char *title=0,
 
8423
                                             const unsigned int normalization_type=3,
 
8424
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
 
8425
      if (!img) return assign();
 
8426
      CImg<T> tmp;
 
8427
      const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
 
8428
      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
 
8429
      if (normalization==2) min = (float)nimg.minmax(max);
 
8430
      return render(nimg).paint();
 
8431
    }
 
8432
 
 
8433
    template<typename T> CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
 
8434
                                             const unsigned int normalization_type=3,
 
8435
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
 
8436
      if (!list) return assign();
 
8437
      CImg<T> tmp;
 
8438
      const CImg<T> img = list.get_append('x','p'),
 
8439
        &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
 
8440
      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
 
8441
      if (normalization==2) min = (float)nimg.minmax(max);
 
8442
      return render(nimg).paint();
 
8443
    }
 
8444
 
 
8445
    CImgDisplay& assign(const CImgDisplay& win) {
 
8446
      if (!win) return assign();
 
8447
      _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
 
8448
      std::memcpy(data,win.data,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
 
8449
                                 cimg::X11attr().nb_bits==16?sizeof(unsigned short):
 
8450
                                 sizeof(unsigned int))*width*height);
 
8451
      return paint();
 
8452
    }
 
8453
 
 
8454
    CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
 
8455
      if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
 
8456
      if (is_empty()) return assign(nwidth,nheight);
 
8457
      const unsigned int
 
8458
        tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
 
8459
        tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
 
8460
        dimx = tmpdimx?tmpdimx:1,
 
8461
        dimy = tmpdimy?tmpdimy:1;
 
8462
      XLockDisplay(cimg::X11attr().display);
 
8463
      if (window_width!=dimx || window_height!=dimy) XResizeWindow(cimg::X11attr().display,window,dimx,dimy);
 
8464
      if (width!=dimx || height!=dimy) switch (cimg::X11attr().nb_bits) {
 
8465
      case 8:  { unsigned char foo = 0; _resize(foo,dimx,dimy,redraw); } break;
 
8466
      case 16: { unsigned short foo = 0; _resize(foo,dimx,dimy,redraw); } break;
 
8467
      default: { unsigned int foo = 0; _resize(foo,dimx,dimy,redraw); }
 
8468
      }
 
8469
      window_width = width = dimx; window_height = height = dimy;
 
8470
      is_resized = false;
 
8471
      XUnlockDisplay(cimg::X11attr().display);
 
8472
      if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
 
8473
      if (redraw) return paint();
 
8474
      return *this;
 
8475
    }
 
8476
 
 
8477
    CImgDisplay& toggle_fullscreen(const bool redraw=true) {
 
8478
      if (is_empty()) return *this;
 
8479
      if (redraw) {
 
8480
        const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
 
8481
        void *odata = std::malloc(bufsize);
 
8482
        std::memcpy(odata,data,bufsize);
 
8483
        assign(width,height,title,normalization,!is_fullscreen,false);
 
8484
        std::memcpy(data,odata,bufsize);
 
8485
        std::free(odata);
 
8486
        return paint(false);
 
8487
      }
 
8488
      return assign(width,height,title,normalization,!is_fullscreen,false);
 
8489
    }
 
8490
 
 
8491
    CImgDisplay& show() {
 
8492
      if (!is_empty() && is_closed) {
 
8493
        XLockDisplay(cimg::X11attr().display);
 
8494
        if (is_fullscreen) _init_fullscreen();
 
8495
        _map_window();
 
8496
        is_closed = false;
 
8497
        XUnlockDisplay(cimg::X11attr().display);
 
8498
        return paint();
 
8499
      }
 
8500
      return *this;
 
8501
    }
 
8502
 
 
8503
    CImgDisplay& close() {
 
8504
      if (!is_empty() && !is_closed) {
 
8505
        XLockDisplay(cimg::X11attr().display);
 
8506
        if (is_fullscreen) _desinit_fullscreen();
 
8507
        XUnmapWindow(cimg::X11attr().display,window);
 
8508
        window_x = window_y = -1;
 
8509
        is_closed = true;
 
8510
        XUnlockDisplay(cimg::X11attr().display);
 
8511
      }
 
8512
      return *this;
 
8513
    }
 
8514
 
 
8515
    CImgDisplay& move(const int posx, const int posy) {
 
8516
      if (is_empty()) return *this;
 
8517
      show();
 
8518
      XLockDisplay(cimg::X11attr().display);
 
8519
      XMoveWindow(cimg::X11attr().display,window,posx,posy);
 
8520
      window_x = posx; window_y = posy;
 
8521
      is_moved = false;
 
8522
      XUnlockDisplay(cimg::X11attr().display);
 
8523
      return paint();
 
8524
    }
 
8525
 
 
8526
    CImgDisplay& show_mouse() {
 
8527
      if (is_empty()) return *this;
 
8528
      XLockDisplay(cimg::X11attr().display);
 
8529
      XDefineCursor(cimg::X11attr().display,window,None);
 
8530
      XUnlockDisplay(cimg::X11attr().display);
 
8531
      return *this;
 
8532
    }
 
8533
 
 
8534
    CImgDisplay& hide_mouse() {
 
8535
      if (is_empty()) return *this;
 
8536
      XLockDisplay(cimg::X11attr().display);
 
8537
      const char pix_data[8] = { 0 };
 
8538
      XColor col;
 
8539
      col.red = col.green = col.blue = 0;
 
8540
      Pixmap pix = XCreateBitmapFromData(cimg::X11attr().display,window,pix_data,8,8);
 
8541
      Cursor cur = XCreatePixmapCursor(cimg::X11attr().display,pix,pix,&col,&col,0,0);
 
8542
      XFreePixmap(cimg::X11attr().display,pix);
 
8543
      XDefineCursor(cimg::X11attr().display,window,cur);
 
8544
      XUnlockDisplay(cimg::X11attr().display);
 
8545
      return *this;
 
8546
    }
 
8547
 
 
8548
    CImgDisplay& set_mouse(const int posx, const int posy) {
 
8549
      if (is_empty() || is_closed) return *this;
 
8550
      XLockDisplay(cimg::X11attr().display);
 
8551
      XWarpPointer(cimg::X11attr().display,None,window,0,0,0,0,posx,posy);
 
8552
      mouse_x = posx; mouse_y = posy;
 
8553
      is_moved = false;
 
8554
      XSync(cimg::X11attr().display, False);
 
8555
      XUnlockDisplay(cimg::X11attr().display);
 
8556
      return *this;
 
8557
    }
 
8558
 
 
8559
    CImgDisplay& set_title(const char *format, ...) {
 
8560
      if (is_empty()) return *this;
 
8561
      char tmp[1024] = {0};
 
8562
      va_list ap;
 
8563
      va_start(ap, format);
 
8564
      std::vsprintf(tmp,format,ap);
 
8565
      va_end(ap);
 
8566
      if (title) delete[] title;
 
8567
      const int s = cimg::strlen(tmp)+1;
 
8568
      title = new char[s];
 
8569
      std::memcpy(title,tmp,s*sizeof(char));
 
8570
      XLockDisplay(cimg::X11attr().display);
 
8571
      XStoreName(cimg::X11attr().display,window,tmp);
 
8572
      XUnlockDisplay(cimg::X11attr().display);
 
8573
      return *this;
 
8574
    }
 
8575
 
 
8576
    template<typename T> CImgDisplay& display(const CImg<T>& img) {
 
8577
      if (img.is_empty()) throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
 
8578
      if (is_empty()) assign(img.width,img.height);
 
8579
      return render(img).paint(false);
 
8580
    }
 
8581
 
 
8582
    CImgDisplay& paint(const bool wait_expose=true) {
 
8583
      if (is_empty()) return *this;
 
8584
      XLockDisplay(cimg::X11attr().display);
 
8585
      _paint(wait_expose);
 
8586
      XUnlockDisplay(cimg::X11attr().display);
 
8587
      return *this;
 
8588
    }
 
8589
 
 
8590
    template<typename T> CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
 
8591
      if (is_empty()) return *this;
 
8592
      if (!img)
 
8593
        throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
 
8594
                                    img.width,img.height,img.depth,img.dim,img.data);
 
8595
      if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
 
8596
      if (cimg::X11attr().nb_bits==8 && (img.width!=width || img.height!=height)) return render(img.get_resize(width,height,1,-100,1));
 
8597
      if (cimg::X11attr().nb_bits==8 && !flag8 && img.dim==3) return render(img.get_RGBtoLUT(true),true);
 
8598
 
 
8599
      const T
 
8600
        *data1 = img.data,
 
8601
        *data2 = (img.dim>1)?img.ptr(0,0,0,1):data1,
 
8602
        *data3 = (img.dim>2)?img.ptr(0,0,0,2):data1;
 
8603
 
 
8604
      if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
 
8605
      XLockDisplay(cimg::X11attr().display);
 
8606
 
 
8607
      if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
 
8608
        min = max = 0;
 
8609
        switch (cimg::X11attr().nb_bits) {
 
8610
        case 8: { // 256 color palette, no normalization
 
8611
          _set_colormap(colormap,img.dim);
 
8612
          unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
 
8613
          unsigned char *ptrd = (unsigned char*)ndata;
 
8614
          switch (img.dim) {
 
8615
          case 1: for (unsigned int xy = img.width*img.height; xy>0; --xy) (*ptrd++) = (unsigned char)*(data1++);
 
8616
            break;
 
8617
          case 2: for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8618
              const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++);
 
8619
              (*ptrd++) = (R&0xf0) | (G>>4);
 
8620
            } break;
 
8621
          default: for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8622
              const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
 
8623
              (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
 
8624
            }
 
8625
          }
 
8626
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
 
8627
        } break;
 
8628
        case 16: { // 16 bits colors, no normalization
 
8629
          unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
 
8630
          unsigned char *ptrd = (unsigned char*)ndata;
 
8631
          const unsigned int M = 248;
 
8632
          switch (img.dim) {
 
8633
          case 1:
 
8634
            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8635
              const unsigned char val = (unsigned char)*(data1++), G = val>>2;
 
8636
              *(ptrd++) = (val&M) | (G>>3);
 
8637
              *(ptrd++) = (G<<5) | (G>>1);
 
8638
            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8639
              const unsigned char val = (unsigned char)*(data1++), G = val>>2;
 
8640
              *(ptrd++) = (G<<5) | (G>>1);
 
8641
              *(ptrd++) = (val&M) | (G>>3);
 
8642
            }
 
8643
            break;
 
8644
          case 2:
 
8645
            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8646
              const unsigned char G = (unsigned char)*(data2++)>>2;
 
8647
              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
 
8648
              *(ptrd++) = (G<<5);
 
8649
            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8650
              const unsigned char G = (unsigned char)*(data2++)>>2;
 
8651
              *(ptrd++) = (G<<5);
 
8652
              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
 
8653
            }
 
8654
            break;
 
8655
          default:
 
8656
            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8657
              const unsigned char G = (unsigned char)*(data2++)>>2;
 
8658
              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
 
8659
              *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
 
8660
            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8661
              const unsigned char G = (unsigned char)*(data2++)>>2;
 
8662
              *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
 
8663
              *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
 
8664
            }
 
8665
          }
 
8666
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
 
8667
        } break;
 
8668
        default: { // 24 bits colors, no normalization
 
8669
          unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
 
8670
          if (sizeof(int)==4) { // 32 bits int uses optimized version
 
8671
            unsigned int *ptrd = ndata;
 
8672
            switch (img.dim) {
 
8673
            case 1:
 
8674
              if (cimg::X11attr().byte_order==cimg::endianness())
 
8675
                for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8676
                  const unsigned char val = (unsigned char)*(data1++);
 
8677
                  *(ptrd++) = (val<<16) | (val<<8) | val;
 
8678
                }
 
8679
              else
 
8680
               for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8681
                  const unsigned char val = (unsigned char)*(data1++)<<8;
 
8682
                  *(ptrd++) = (val<<16) | (val<<8) | val;
 
8683
                }
 
8684
              break;
 
8685
            case 2:
 
8686
              if (cimg::X11attr().byte_order==cimg::endianness())
 
8687
               for (unsigned int xy = img.width*img.height; xy>0; --xy)
 
8688
                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
 
8689
              else
 
8690
               for (unsigned int xy = img.width*img.height; xy>0; --xy)
 
8691
                  *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
 
8692
              break;
 
8693
            default:
 
8694
              if (cimg::X11attr().byte_order==cimg::endianness())
 
8695
               for (unsigned int xy = img.width*img.height; xy>0; --xy)
 
8696
                  *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
 
8697
              else
 
8698
               for (unsigned int xy = img.width*img.height; xy>0; --xy)
 
8699
                  *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
 
8700
            }
 
8701
          } else {
 
8702
            unsigned char *ptrd = (unsigned char*)ndata;
 
8703
            switch (img.dim) {
 
8704
            case 1:
 
8705
              if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8706
                *(ptrd++) = 0;
 
8707
                *(ptrd++) = (unsigned char)*(data1++);
 
8708
                *(ptrd++) = 0;
 
8709
                *(ptrd++) = 0;
 
8710
              } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8711
                *(ptrd++) = 0;
 
8712
                *(ptrd++) = 0;
 
8713
                *(ptrd++) = (unsigned char)*(data1++);
 
8714
                *(ptrd++) = 0;
 
8715
              }
 
8716
              break;
 
8717
            case 2:
 
8718
              if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
 
8719
              for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8720
                *(ptrd++) = 0;
 
8721
                *(ptrd++) = (unsigned char)*(data2++);
 
8722
                *(ptrd++) = (unsigned char)*(data1++);
 
8723
                *(ptrd++) = 0;
 
8724
              }
 
8725
              break;
 
8726
            default:
 
8727
              if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8728
                *(ptrd++) = 0;
 
8729
                *(ptrd++) = (unsigned char)*(data1++);
 
8730
                *(ptrd++) = (unsigned char)*(data2++);
 
8731
                *(ptrd++) = (unsigned char)*(data3++);
 
8732
              } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8733
                *(ptrd++) = (unsigned char)*(data3++);
 
8734
                *(ptrd++) = (unsigned char)*(data2++);
 
8735
                *(ptrd++) = (unsigned char)*(data1++);
 
8736
                *(ptrd++) = 0;
 
8737
              }
 
8738
            }
 
8739
          }
 
8740
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
 
8741
        }
 
8742
        };
 
8743
      } else {
 
8744
        if (normalization==3) {
 
8745
          if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
 
8746
          else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
 
8747
        } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
 
8748
        const float delta = max-min, mm = delta?delta:1.0f;
 
8749
        switch (cimg::X11attr().nb_bits) {
 
8750
        case 8: { // 256 color palette, with normalization
 
8751
          _set_colormap(colormap,img.dim);
 
8752
          unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
 
8753
          unsigned char *ptrd = (unsigned char*)ndata;
 
8754
          switch (img.dim) {
 
8755
          case 1: for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8756
            const unsigned char R = (unsigned char)(255*(*(data1++)-min)/mm);
 
8757
            *(ptrd++) = R;
 
8758
          } break;
 
8759
          case 2: for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8760
            const unsigned char
 
8761
              R = (unsigned char)(255*(*(data1++)-min)/mm),
 
8762
              G = (unsigned char)(255*(*(data2++)-min)/mm);
 
8763
            (*ptrd++) = (R&0xf0) | (G>>4);
 
8764
          } break;
 
8765
          default:
 
8766
            for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8767
              const unsigned char
 
8768
                R = (unsigned char)(255*(*(data1++)-min)/mm),
 
8769
                G = (unsigned char)(255*(*(data2++)-min)/mm),
 
8770
                B = (unsigned char)(255*(*(data3++)-min)/mm);
 
8771
              *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
 
8772
            }
 
8773
          }
 
8774
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
 
8775
        } break;
 
8776
        case 16: { // 16 bits colors, with normalization
 
8777
          unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
 
8778
          unsigned char *ptrd = (unsigned char*)ndata;
 
8779
          const unsigned int M = 248;
 
8780
          switch (img.dim) {
 
8781
          case 1:
 
8782
            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8783
              const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
 
8784
              *(ptrd++) = (val&M) | (G>>3);
 
8785
              *(ptrd++) = (G<<5) | (val>>3);
 
8786
            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8787
              const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
 
8788
              *(ptrd++) = (G<<5) | (val>>3);
 
8789
              *(ptrd++) = (val&M) | (G>>3);
 
8790
            }
 
8791
            break;
 
8792
          case 2:
 
8793
            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8794
              const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
 
8795
              *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
 
8796
              *(ptrd++) = (G<<5);
 
8797
            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8798
              const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
 
8799
              *(ptrd++) = (G<<5);
 
8800
              *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
 
8801
            }
 
8802
            break;
 
8803
          default:
 
8804
            if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8805
              const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
 
8806
              *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
 
8807
              *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
 
8808
            } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8809
              const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
 
8810
              *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
 
8811
              *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
 
8812
            }
 
8813
          }
 
8814
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
 
8815
        } break;
 
8816
        default: { // 24 bits colors, with normalization
 
8817
          unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
 
8818
          if (sizeof(int)==4) { // 32 bits int uses optimized version
 
8819
            unsigned int *ptrd = ndata;
 
8820
            switch (img.dim) {
 
8821
            case 1:
 
8822
              if (cimg::X11attr().byte_order==cimg::endianness())
 
8823
                for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8824
                  const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
 
8825
                  *(ptrd++) = (val<<16) | (val<<8) | val;
 
8826
                }
 
8827
              else
 
8828
                for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8829
                  const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
 
8830
                  *(ptrd++) = (val<<24) | (val<<16) | (val<<8);
 
8831
                }
 
8832
              break;
 
8833
            case 2:
 
8834
              if (cimg::X11attr().byte_order==cimg::endianness())
 
8835
                for (unsigned int xy = img.width*img.height; xy>0; --xy)
 
8836
                  *(ptrd++) =
 
8837
                    ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
 
8838
                    ((unsigned char)(255*(*(data2++)-min)/mm)<<8);
 
8839
              else
 
8840
                for (unsigned int xy = img.width*img.height; xy>0; --xy)
 
8841
                  *(ptrd++) =
 
8842
                    ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
 
8843
                    ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
 
8844
              break;
 
8845
            default:
 
8846
              if (cimg::X11attr().byte_order==cimg::endianness())
 
8847
                for (unsigned int xy = img.width*img.height; xy>0; --xy)
 
8848
                  *(ptrd++) =
 
8849
                    ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
 
8850
                    ((unsigned char)(255*(*(data2++)-min)/mm)<<8) |
 
8851
                    (unsigned char)(255*(*(data3++)-min)/mm);
 
8852
              else
 
8853
                for (unsigned int xy = img.width*img.height; xy>0; --xy)
 
8854
                  *(ptrd++) =
 
8855
                    ((unsigned char)(255*(*(data3++)-min)/mm)<<24) |
 
8856
                    ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
 
8857
                    ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
 
8858
            }
 
8859
          } else {
 
8860
            unsigned char *ptrd = (unsigned char*)ndata;
 
8861
            switch (img.dim) {
 
8862
            case 1:
 
8863
              if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8864
                const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
 
8865
                (*ptrd++) = 0;
 
8866
                (*ptrd++) = val;
 
8867
                (*ptrd++) = val;
 
8868
                (*ptrd++) = val;
 
8869
              } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8870
                const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
 
8871
                (*ptrd++) = val;
 
8872
                (*ptrd++) = val;
 
8873
                (*ptrd++) = val;
 
8874
                (*ptrd++) = 0;
 
8875
              }
 
8876
              break;
 
8877
            case 2:
 
8878
              if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
 
8879
              for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8880
                (*ptrd++) = 0;
 
8881
                (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
 
8882
                (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
 
8883
                (*ptrd++) = 0;
 
8884
              }
 
8885
              break;
 
8886
            default:
 
8887
              if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8888
                (*ptrd++) = 0;
 
8889
                (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
 
8890
                (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
 
8891
                (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
 
8892
              } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8893
                (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
 
8894
                (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
 
8895
                (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
 
8896
                (*ptrd++) = 0;
 
8897
              }
 
8898
            }
 
8899
          }
 
8900
          if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
 
8901
        }
 
8902
        }
 
8903
      }
 
8904
      XUnlockDisplay(cimg::X11attr().display);
 
8905
      return *this;
 
8906
    }
 
8907
 
 
8908
    template<typename T> const CImgDisplay& snapshot(CImg<T>& img) const {
 
8909
      if (is_empty()) img.assign();
 
8910
      else {
 
8911
        img.assign(width,height,1,3);
 
8912
        T
 
8913
          *data1 = img.ptr(0,0,0,0),
 
8914
          *data2 = img.ptr(0,0,0,1),
 
8915
          *data3 = img.ptr(0,0,0,2);
 
8916
        if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
 
8917
        switch (cimg::X11attr().nb_bits) {
 
8918
        case 8: {
 
8919
          unsigned char *ptrs = (unsigned char*)data;
 
8920
          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8921
            const unsigned char val = *(ptrs++);
 
8922
            *(data1++) = val&0xe0;
 
8923
            *(data2++) = (val&0x1c)<<3;
 
8924
            *(data3++) = val<<6;
 
8925
          }
 
8926
        } break;
 
8927
        case 16: {
 
8928
          unsigned char *ptrs = (unsigned char*)data;
 
8929
          if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8930
            const unsigned char val0 = *(ptrs++), val1 = *(ptrs++);
 
8931
            *(data1++) = val0&0xf8;
 
8932
            *(data2++) = (val0<<5) | ((val1&0xe0)>>5);
 
8933
            *(data3++) = val1<<3;
 
8934
          } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8935
            const unsigned short val0 = *(ptrs++), val1 = *(ptrs++);
 
8936
            *(data1++) = val1&0xf8;
 
8937
            *(data2++) = (val1<<5) | ((val0&0xe0)>>5);
 
8938
            *(data3++) = val0<<3;
 
8939
          }
 
8940
        } break;
 
8941
        default: {
 
8942
          unsigned char *ptrs = (unsigned char*)data;
 
8943
          if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8944
            ++ptrs;
 
8945
            *(data1++) = *(ptrs++);
 
8946
            *(data2++) = *(ptrs++);
 
8947
            *(data3++) = *(ptrs++);
 
8948
          } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
8949
            *(data3++) = *(ptrs++);
 
8950
            *(data2++) = *(ptrs++);
 
8951
            *(data1++) = *(ptrs++);
 
8952
            ++ptrs;
 
8953
          }
 
8954
        }
 
8955
        }
 
8956
      }
 
8957
      return *this;
 
8958
    }
 
8959
 
6181
8960
    // Windows-based display
6182
8961
    //-----------------------
6183
 
#elif cimg_display_type==2
 
8962
#elif cimg_display==2
6184
8963
    CLIENTCREATESTRUCT ccs;
6185
8964
    BITMAPINFO bmi;
6186
8965
    unsigned int *data;
6191
8970
    HANDLE thread;
6192
8971
    HANDLE created;
6193
8972
    HANDLE mutex;
 
8973
    bool mouse_tracking;
6194
8974
    bool visible_cursor;
6195
8975
 
6196
8976
    static int screen_dimx() {
6209
8989
      return mode.dmPelsHeight;
6210
8990
    }
6211
8991
 
6212
 
    CImgDisplay& assign() {
6213
 
      if (!is_empty()) {
6214
 
        DestroyWindow(window);
6215
 
        if (events) TerminateThread(thread,0);
6216
 
        if (data) delete[] data;
6217
 
        if (title) delete[] title;
6218
 
        if (is_fullscreen) _desinit_fullscreen();
6219
 
        width = height = normalization = events = 0;
6220
 
        is_fullscreen = is_resized = is_moved = is_event = false;
6221
 
        is_closed = true;
6222
 
        title = 0;
6223
 
        window_x = window_y = window_width = window_height = mouse_x = mouse_y = wheel = 0;
6224
 
        std::memset((void*)buttons,0,512*sizeof(unsigned int));
6225
 
        std::memset((void*)keys,0,512*sizeof(unsigned int));
6226
 
        std::memset((void*)released_keys,0,512*sizeof(unsigned int));
6227
 
        min = max = 0;
6228
 
      }
6229
 
      return *this;
6230
 
    }
6231
 
 
6232
 
    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
6233
 
                        const unsigned int normalization_type=3, const unsigned int events_type=3,
6234
 
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
6235
 
      if (!dimw || !dimh) return assign();
6236
 
      _assign(dimw,dimh,title,normalization_type,events_type,fullscreen_flag,closed_flag);
6237
 
      min = max = 0;
6238
 
      std::memset(data,0,sizeof(unsigned int)*width*height);
6239
 
      return paint();
6240
 
    }
6241
 
 
6242
 
    template<typename T> CImgDisplay& assign(const CImg<T>& img, const char *title=0,
6243
 
                                             const unsigned int normalization_type=3, const unsigned int events_type=3,
6244
 
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
6245
 
      if (!img) return assign();
6246
 
      CImg<T> tmp;
6247
 
      const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
6248
 
      _assign(nimg.width,nimg.height,title,normalization_type,events_type,fullscreen_flag,closed_flag);
6249
 
      if (normalization==2) { const CImgStats st(nimg,false); min = (float)st.min; max = (float)st.max; }
6250
 
      return display(nimg);
6251
 
    }
6252
 
 
6253
 
    template<typename T> CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
6254
 
                                             const unsigned int normalization_type=3, const unsigned int events_type=3,
6255
 
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
6256
 
      if (!list) return assign();
6257
 
      CImg<T> tmp;
6258
 
      const CImg<T> img = list.get_append('x','p'),
6259
 
        &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
6260
 
      _assign(nimg.width,nimg.height,title,normalization_type,events_type,fullscreen_flag,closed_flag);
6261
 
      if (normalization==2) { const CImgStats st(nimg,false); min = (float)st.min; max = (float)st.max; }
6262
 
      return display(nimg);
6263
 
    }
6264
 
 
6265
 
    CImgDisplay& assign(const CImgDisplay& win) {
6266
 
      if (!win) return assign();
6267
 
      _assign(win.width,win.height,win.title,win.normalization,win.events,win.is_fullscreen,win.is_closed);
6268
 
      std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
6269
 
      return paint();
6270
 
    }
6271
 
 
6272
 
    template<typename T> CImgDisplay& display(const CImg<T>& img) {
6273
 
      if (is_empty()) assign(img.width,img.height);
6274
 
      return render(img).paint();
6275
 
    }
6276
 
 
6277
 
    CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
6278
 
      if (!nwidth || !nheight) return assign();
6279
 
      if (is_empty()) return assign(cimg::max(nwidth,0),cimg::max(nheight,0));
6280
 
      const unsigned int
6281
 
        tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100),
6282
 
        tmpdimy=(nheight>0)?nheight:(-nheight*height/100),
6283
 
        dimx = cimg::min(tmpdimx?tmpdimx:1,(unsigned int)screen_dimx()),
6284
 
        dimy = cimg::min(tmpdimy?tmpdimy:1,(unsigned int)screen_dimy());
6285
 
      const bool
6286
 
        is_disp_different = (width!=dimx || height!=dimy),
6287
 
        is_win_different = (window_width!=dimx || window_height!=dimy);
6288
 
 
6289
 
      if (is_disp_different || is_win_different) {
6290
 
        RECT rect; rect.left = rect.top = 0; rect.right = dimx-1; rect.bottom = dimy-1;
6291
 
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
6292
 
        const int cwidth = rect.right-rect.left+1, cheight = rect.bottom-rect.top+1;
6293
 
        SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
6294
 
        window_width  = dimx;
6295
 
        window_height = dimy;
6296
 
        is_resized = false;
6297
 
        if (is_disp_different) {
6298
 
          unsigned int *ndata = new unsigned int[dimx*dimy];
6299
 
          if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
6300
 
          else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
6301
 
          delete[] data;
6302
 
          data = ndata;
6303
 
          bmi.bmiHeader.biWidth = dimx;
6304
 
          bmi.bmiHeader.biHeight = -(int)dimy;
6305
 
          width = dimx;
6306
 
          height = dimy;
6307
 
        }
6308
 
        if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
6309
 
        if (redraw) return paint();
6310
 
      }
6311
 
      return *this;
6312
 
    }
6313
 
 
6314
 
    CImgDisplay& move(const int posx, const int posy) {
6315
 
      if (is_empty()) return *this;
6316
 
      if (!is_fullscreen) {
6317
 
        RECT rect; rect.left = rect.top = 0; rect.right=window_width-1; rect.bottom=window_height-1;
6318
 
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
6319
 
        const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
6320
 
        SetWindowPos(window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
6321
 
      } else SetWindowPos(window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
6322
 
      window_x = posx;
6323
 
      window_y = posy;
6324
 
      is_moved = false;
6325
 
      return show();
6326
 
    }
6327
 
 
6328
 
    CImgDisplay& set_mouse(const int posx, const int posy) {
6329
 
      if (!is_closed && posx>=0 && posy>=0) {
6330
 
        _update_window_pos();
6331
 
        SetCursorPos(window_x+posx,window_y+posy);
6332
 
        mouse_x = posx;
6333
 
        mouse_y = posy;
6334
 
      }
6335
 
      return *this;
6336
 
    }
6337
 
 
6338
 
    CImgDisplay& hide_mouse() {
6339
 
      if (is_empty()) return *this;
6340
 
      visible_cursor = false;
6341
 
      ShowCursor(FALSE);
6342
 
      SendMessage(window,WM_SETCURSOR,0,0);
6343
 
      return *this;
6344
 
    }
6345
 
 
6346
 
    CImgDisplay& show_mouse() {
6347
 
      if (is_empty()) return *this;
6348
 
      visible_cursor = true;
6349
 
      ShowCursor(TRUE);
6350
 
      SendMessage(window,WM_SETCURSOR,0,0);
6351
 
      return *this;
6352
 
    }
6353
 
 
6354
8992
    static void wait_all() {
6355
8993
      WaitForSingleObject(cimg::Win32attr().wait_event,INFINITE);
6356
8994
    }
6357
8995
 
6358
 
    CImgDisplay& show() {
6359
 
      if (is_empty()) return *this;
6360
 
      if (is_closed) {
6361
 
        is_closed = false;
6362
 
        if (is_fullscreen) _init_fullscreen();
6363
 
        ShowWindow(window,SW_SHOW);
6364
 
        _update_window_pos();
6365
 
      }
6366
 
      return paint();
6367
 
    }
6368
 
 
6369
 
    CImgDisplay& close() {
6370
 
      if (is_empty()) return *this;
6371
 
      if (!is_closed && !is_fullscreen) {
6372
 
        if (is_fullscreen) _desinit_fullscreen();
6373
 
        ShowWindow(window,SW_HIDE);
6374
 
        is_closed = true;
6375
 
        window_x = window_y = 0;
6376
 
      }
6377
 
      return *this;
6378
 
    }
6379
 
 
6380
 
    CImgDisplay& set_title(const char *format,...) {
6381
 
      if (is_empty()) return *this;
6382
 
      char tmp[1024] = {0};
6383
 
      va_list ap;
6384
 
      va_start(ap, format);
6385
 
      std::vsprintf(tmp,format,ap);
6386
 
      va_end(ap);
6387
 
      if (title) delete[] title;
6388
 
      const int s = cimg::strlen(tmp)+1;
6389
 
      title = new char[s];
6390
 
      std::memcpy(title,tmp,s*sizeof(char));
6391
 
      SetWindowTextA(window, tmp);
6392
 
      return *this;
6393
 
    }
6394
 
 
6395
 
    CImgDisplay& paint() {
6396
 
      if (!is_closed) {
6397
 
        WaitForSingleObject(mutex,INFINITE);
6398
 
        SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
6399
 
        ReleaseMutex(mutex);
6400
 
      }
6401
 
      return *this;
6402
 
    }
6403
 
 
6404
 
    template<typename T> CImgDisplay& render(const CImg<T>& img) {
6405
 
      if (is_empty()) return *this;
6406
 
      if (!img)
6407
 
        throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
6408
 
                                    img.width,img.height,img.depth,img.dim,img.data);
6409
 
      if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
6410
 
 
6411
 
      const T
6412
 
        *data1 = img.ptr(),
6413
 
        *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
6414
 
        *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
6415
 
 
6416
 
      WaitForSingleObject(mutex,INFINITE);
6417
 
      unsigned int
6418
 
        *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
6419
 
        *ptrd = ndata;
6420
 
 
6421
 
      if (!normalization || (normalization==3 && cimg::type<T>::id()==cimg::type<unsigned char>::id())) {
6422
 
        min = max = 0;
6423
 
        for (unsigned int xy = img.width*img.height; xy>0; --xy)
6424
 
          *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
6425
 
      } else {
6426
 
        if (normalization==3) {
6427
 
          if (cimg::type<T>::is_float()) { const CImgStats st(img,false); min = (float)st.min; max = (float)st.max; }
6428
 
          else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
6429
 
        } else if ((min>max) || normalization==1) { const CImgStats st(img,false); min = (float)st.min; max = (float)st.max; }
6430
 
        const float delta = max-min, mm = delta?delta:1.0f;
6431
 
        for (unsigned int xy = img.width*img.height; xy>0; --xy) {
6432
 
          const unsigned char
6433
 
            R = (unsigned char)(255*(*(data1++)-min)/mm),
6434
 
            G = (unsigned char)(255*(*(data2++)-min)/mm),
6435
 
            B = (unsigned char)(255*(*(data3++)-min)/mm);
6436
 
          *(ptrd++) = (R<<16) | (G<<8) | (B);
6437
 
        }
6438
 
      }
6439
 
      if (ndata!=data) { _render_resize(ndata,img.width,img.height,data,width,height); delete[] ndata; }
6440
 
      ReleaseMutex(mutex);
6441
 
      return *this;
6442
 
    }
6443
 
 
6444
 
    template<typename T> const CImgDisplay& snapshot(CImg<T>& img) const {
6445
 
      if (is_empty()) img.assign();
6446
 
      else {
6447
 
        img.assign(width,height,1,3);
6448
 
        T
6449
 
          *data1 = img.ptr(0,0,0,0),
6450
 
          *data2 = img.ptr(0,0,0,1),
6451
 
          *data3 = img.ptr(0,0,0,2);
6452
 
        unsigned int *ptrs = data;
6453
 
        for (unsigned int xy = img.width*img.height; xy>0; --xy) {
6454
 
          const unsigned int val = *(ptrs++);
6455
 
          *(data1++) = (unsigned char)(val>>16);
6456
 
          *(data2++) = (unsigned char)((val>>8)&0xFF);
6457
 
          *(data3++) = (unsigned char)(val&0xFF);
6458
 
        }
6459
 
      }
6460
 
      return *this;
6461
 
    }
6462
 
 
6463
 
    CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
6464
 
                         const unsigned int normalization_type=3, const unsigned int events_type=3,
6465
 
                         const bool fullscreen_flag=false, const bool closed_flag=false) {
6466
 
 
6467
 
      // Allocate space for window title
6468
 
      const int s = cimg::strlen(ptitle)+1;
6469
 
      char *tmp_title = s?new char[s]:0;
6470
 
      if (s) std::memcpy(tmp_title,ptitle,s*sizeof(char));
6471
 
 
6472
 
      // Destroy previous window if existing
6473
 
      if (!is_empty()) assign();
6474
 
 
6475
 
      // Set display variables
6476
 
      width = cimg::min(dimw,(unsigned int)screen_dimx());
6477
 
      height = cimg::min(dimh,(unsigned int)screen_dimy());
6478
 
      normalization = normalization_type%4;
6479
 
      events = events_type%4;
6480
 
      is_fullscreen = fullscreen_flag;
6481
 
      title = tmp_title;
6482
 
      window_x = window_y = wheel = 0;
6483
 
      mouse_x = mouse_y = -1;
6484
 
      std::memset((void*)buttons,0,512*sizeof(unsigned int));
6485
 
      std::memset((void*)keys,0,512*sizeof(unsigned int));
6486
 
      std::memset((void*)released_keys,0,512*sizeof(unsigned int));
6487
 
      is_resized = is_moved = is_event = false;
6488
 
      is_closed = closed_flag;
6489
 
      fps_timer = fps_frames = timer = 0;
6490
 
      fps_fps = 0;
6491
 
      visible_cursor = true;
6492
 
 
6493
 
      if (is_fullscreen) _init_fullscreen();
6494
 
 
6495
 
      // Create event thread
6496
 
      void *arg = (void*)(new void*[2]);
6497
 
      ((void**)arg)[0]=(void*)this;
6498
 
      ((void**)arg)[1]=(void*)title;
6499
 
      if (events) {
6500
 
        unsigned long ThreadID = 0;
6501
 
        mutex     = CreateMutex(0,FALSE,0);
6502
 
        created   = CreateEvent(0,FALSE,FALSE,0);
6503
 
        thread    = CreateThread(0,0,_events_thread,arg,0,&ThreadID);
6504
 
        WaitForSingleObject(created,INFINITE);
6505
 
      } else _events_thread(arg);
6506
 
 
6507
 
      return *this;
6508
 
    }
6509
 
 
6510
8996
    static LRESULT APIENTRY _handle_events(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
6511
8997
#ifdef _WIN64
6512
8998
      CImgDisplay* disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA);
6515
9001
#endif
6516
9002
      MSG st_msg;
6517
9003
 
6518
 
      switch(msg) {
 
9004
      switch (msg) {
6519
9005
      case WM_CLOSE:
6520
9006
        disp->mouse_x = disp->mouse_y = -1;
6521
9007
        disp->window_x = disp->window_y = 0;
6527
9013
          std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
6528
9014
          disp->key = 0;
6529
9015
        }
6530
 
        if (disp->released_key) {
6531
 
          std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
6532
 
          disp->released_key = 0;
6533
 
        }
 
9016
        if (disp->released_key) { std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
6534
9017
        disp->is_closed = true;
6535
9018
        ReleaseMutex(disp->mutex);
6536
9019
        ShowWindow(disp->window,SW_HIDE);
6565
9048
      case WM_PAINT:
6566
9049
        disp->paint();
6567
9050
        break;
6568
 
      }
6569
 
      if (disp->events>=2) switch(msg) {
6570
9051
      case WM_KEYDOWN:
 
9052
        disp->update_iskey((unsigned int)wParam,true);
6571
9053
        if (disp->key) std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
6572
 
        disp->key = (int)wParam;
6573
 
        if (disp->released_key) {
6574
 
          std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
6575
 
          disp->released_key = 0;
6576
 
        }
 
9054
        disp->key = (unsigned int)wParam;
 
9055
        if (disp->released_key) { std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
6577
9056
        disp->is_event = true;
6578
9057
        SetEvent(cimg::Win32attr().wait_event);
6579
9058
        break;
6581
9060
        while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE));
6582
9061
        disp->mouse_x = LOWORD(lParam);
6583
9062
        disp->mouse_y = HIWORD(lParam);
 
9063
        if (!disp->mouse_tracking) {
 
9064
          TRACKMOUSEEVENT tme;
 
9065
          tme.cbSize = sizeof(TRACKMOUSEEVENT);
 
9066
          tme.dwFlags = TME_LEAVE;
 
9067
          tme.hwndTrack = disp->window;
 
9068
          if (TrackMouseEvent(&tme)) disp->mouse_tracking = true;
 
9069
        }
6584
9070
        if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
6585
9071
          disp->mouse_x=disp->mouse_y=-1;
6586
9072
        disp->is_event = true;
6587
9073
        SetEvent(cimg::Win32attr().wait_event);
6588
9074
      } break;
 
9075
      case WM_MOUSELEAVE: {
 
9076
        disp->mouse_x = disp->mouse_y = -1;
 
9077
        disp->mouse_tracking = false;
 
9078
      } break;
6589
9079
      case WM_LBUTTONDOWN:
6590
9080
        std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
6591
9081
        disp->button|=1U;
6608
9098
        disp->wheel+=(int)((short)HIWORD(wParam))/120;
6609
9099
        disp->is_event = true;
6610
9100
        SetEvent(cimg::Win32attr().wait_event);
6611
 
      }
6612
 
 
6613
 
      if (disp->events>=3) switch(msg) {
6614
9101
      case WM_KEYUP:
6615
 
        if (disp->key) {
6616
 
          std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
6617
 
          disp->key = 0;
6618
 
        }
 
9102
        disp->update_iskey((unsigned int)wParam,false);
 
9103
        if (disp->key) { std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
6619
9104
        if (disp->released_key) std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
6620
 
        disp->released_key = (int)wParam;
 
9105
        disp->released_key = (unsigned int)wParam;
6621
9106
        disp->is_event = true;
6622
9107
        SetEvent(cimg::Win32attr().wait_event);
6623
9108
        break;
6689
9174
      disp->hdc = GetDC(disp->window);
6690
9175
      disp->window_width = disp->width;
6691
9176
      disp->window_height = disp->height;
6692
 
      disp->mouse_x = disp->mouse_y = -1;
6693
 
      disp->wheel = 0;
6694
 
      std::memset((void*)disp->buttons,0,512*sizeof(unsigned int));
6695
 
      std::memset((void*)disp->keys,0,512*sizeof(unsigned int));
6696
 
      std::memset((void*)disp->released_keys,0,512*sizeof(unsigned int));
6697
 
      disp->is_resized = disp->is_moved = disp->is_event = false;
6698
 
      if (disp->events) {
 
9177
      disp->flush();
6699
9178
#ifdef _WIN64
6700
 
        SetWindowLongPtr(disp->window,GWLP_USERDATA,(LONG_PTR)disp);
6701
 
        SetWindowLongPtr(disp->window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
 
9179
      SetWindowLongPtr(disp->window,GWLP_USERDATA,(LONG_PTR)disp);
 
9180
      SetWindowLongPtr(disp->window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
6702
9181
#else
6703
 
        SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
6704
 
        SetWindowLong(disp->window,GWL_WNDPROC,(LONG)_handle_events);
 
9182
      SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
 
9183
      SetWindowLong(disp->window,GWL_WNDPROC,(LONG)_handle_events);
6705
9184
#endif
6706
 
        SetEvent(disp->created);
6707
 
        while( GetMessage(&msg,0,0,0) ) DispatchMessage( &msg );
6708
 
      }
 
9185
      SetEvent(disp->created);
 
9186
      while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
6709
9187
      return 0;
6710
9188
    }
6711
9189
 
 
9190
    CImgDisplay& _update_window_pos() {
 
9191
      if (!is_closed) {
 
9192
        RECT rect;
 
9193
        rect.left = rect.top = 0; rect.right = width-1; rect.bottom = height-1;
 
9194
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
 
9195
        const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
 
9196
        GetWindowRect(window,&rect);
 
9197
        window_x = rect.left + border1;
 
9198
        window_y = rect.top + border2;
 
9199
      } else window_x = window_y = -1;
 
9200
      return *this;
 
9201
    }
 
9202
 
6712
9203
    void _init_fullscreen() {
6713
9204
      background_window = 0;
6714
9205
      if (is_fullscreen && !is_closed) {
6732
9223
        const unsigned int sx = screen_dimx(), sy = screen_dimy();
6733
9224
        if (sx!=width || sy!=height) {
6734
9225
          CLIENTCREATESTRUCT background_ccs;
6735
 
          background_window = CreateWindowA("MDICLIENT"," ",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);
 
9226
          background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);
6736
9227
          SetForegroundWindow(background_window);
6737
9228
        }
6738
9229
      } else curr_mode.dmSize = 0;
6747
9238
      }
6748
9239
    }
6749
9240
 
6750
 
    CImgDisplay& _update_window_pos() {
6751
 
      if (!is_closed) {
6752
 
        RECT rect;
6753
 
        rect.left = rect.top = 0; rect.right = width-1; rect.bottom = height-1;
 
9241
    CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
 
9242
                         const unsigned int normalization_type=3,
 
9243
                         const bool fullscreen_flag=false, const bool closed_flag=false) {
 
9244
 
 
9245
      // Allocate space for window title
 
9246
      const int s = cimg::strlen(ptitle)+1;
 
9247
      char *tmp_title = s?new char[s]:0;
 
9248
      if (s) std::memcpy(tmp_title,ptitle,s*sizeof(char));
 
9249
 
 
9250
      // Destroy previous window if existing
 
9251
      if (!is_empty()) assign();
 
9252
 
 
9253
      // Set display variables
 
9254
      width = cimg::min(dimw,(unsigned int)screen_dimx());
 
9255
      height = cimg::min(dimh,(unsigned int)screen_dimy());
 
9256
      normalization = normalization_type<4?normalization_type:3;
 
9257
      is_fullscreen = fullscreen_flag;
 
9258
      window_x = window_y = 0;
 
9259
      is_closed = closed_flag;
 
9260
      visible_cursor = true;
 
9261
      mouse_tracking = false;
 
9262
      title = tmp_title;
 
9263
      flush();
 
9264
      if (is_fullscreen) _init_fullscreen();
 
9265
 
 
9266
      // Create event thread
 
9267
      void *arg = (void*)(new void*[2]);
 
9268
      ((void**)arg)[0]=(void*)this;
 
9269
      ((void**)arg)[1]=(void*)title;
 
9270
      unsigned long ThreadID = 0;
 
9271
      mutex     = CreateMutex(0,FALSE,0);
 
9272
      created   = CreateEvent(0,FALSE,FALSE,0);
 
9273
      thread    = CreateThread(0,0,_events_thread,arg,0,&ThreadID);
 
9274
      WaitForSingleObject(created,INFINITE);
 
9275
      return *this;
 
9276
    }
 
9277
 
 
9278
    CImgDisplay& assign() {
 
9279
      if (!is_empty()) {
 
9280
        DestroyWindow(window);
 
9281
        TerminateThread(thread,0);
 
9282
        if (data) delete[] data;
 
9283
        if (title) delete[] title;
 
9284
        if (is_fullscreen) _desinit_fullscreen();
 
9285
        width = height = normalization = window_width = window_height = 0;
 
9286
        window_x = window_y = 0;
 
9287
        is_fullscreen = false;
 
9288
        is_closed = true;
 
9289
        min = max = 0;
 
9290
        title = 0;
 
9291
        flush();
 
9292
      }
 
9293
      return *this;
 
9294
    }
 
9295
 
 
9296
    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
 
9297
                        const unsigned int normalization_type=3,
 
9298
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
 
9299
      if (!dimw || !dimh) return assign();
 
9300
      _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
 
9301
      min = max = 0;
 
9302
      std::memset(data,0,sizeof(unsigned int)*width*height);
 
9303
      return paint();
 
9304
    }
 
9305
 
 
9306
    template<typename T> CImgDisplay& assign(const CImg<T>& img, const char *title=0,
 
9307
                                             const unsigned int normalization_type=3,
 
9308
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
 
9309
      if (!img) return assign();
 
9310
      CImg<T> tmp;
 
9311
      const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
 
9312
      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
 
9313
      if (normalization==2) min = (float)nimg.minmax(max);
 
9314
      return display(nimg);
 
9315
    }
 
9316
 
 
9317
    template<typename T> CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
 
9318
                                             const unsigned int normalization_type=3,
 
9319
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
 
9320
      if (!list) return assign();
 
9321
      CImg<T> tmp;
 
9322
      const CImg<T> img = list.get_append('x','p'),
 
9323
        &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
 
9324
      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
 
9325
      if (normalization==2) min = (float)nimg.minmax(max);
 
9326
      return display(nimg);
 
9327
    }
 
9328
 
 
9329
    CImgDisplay& assign(const CImgDisplay& win) {
 
9330
      if (!win) return assign();
 
9331
      _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
 
9332
      std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
 
9333
      return paint();
 
9334
    }
 
9335
 
 
9336
    CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
 
9337
      if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
 
9338
      if (is_empty()) return assign(nwidth,nheight);
 
9339
      const unsigned int
 
9340
        tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100),
 
9341
        tmpdimy=(nheight>0)?nheight:(-nheight*height/100),
 
9342
        dimx = tmpdimx?tmpdimx:1,
 
9343
        dimy = tmpdimy?tmpdimy:1;
 
9344
      if (window_width!=dimx || window_height!=dimy) {
 
9345
        RECT rect; rect.left = rect.top = 0; rect.right = dimx-1; rect.bottom = dimy-1;
 
9346
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
 
9347
        const int cwidth = rect.right-rect.left+1, cheight = rect.bottom-rect.top+1;
 
9348
        SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
 
9349
      }
 
9350
      if (width!=dimx || height!=dimy) {
 
9351
        unsigned int *ndata = new unsigned int[dimx*dimy];
 
9352
        if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
 
9353
        else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
 
9354
        delete[] data;
 
9355
        data = ndata;
 
9356
        bmi.bmiHeader.biWidth = dimx;
 
9357
        bmi.bmiHeader.biHeight = -(int)dimy;
 
9358
        width = dimx;
 
9359
        height = dimy;
 
9360
      }
 
9361
      window_width  = dimx; window_height = dimy;
 
9362
      is_resized = false;
 
9363
      if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
 
9364
      if (redraw) return paint();
 
9365
      return *this;
 
9366
    }
 
9367
 
 
9368
    CImgDisplay& toggle_fullscreen(const bool redraw=true) {
 
9369
      if (is_empty()) return *this;
 
9370
      if (redraw) {
 
9371
        const unsigned int bufsize = width*height*4;
 
9372
        void *odata = std::malloc(bufsize);
 
9373
        std::memcpy(odata,data,bufsize);
 
9374
        assign(width,height,title,normalization,!is_fullscreen,false);
 
9375
        std::memcpy(data,odata,bufsize);
 
9376
        std::free(odata);
 
9377
        return paint();
 
9378
      }
 
9379
      return assign(width,height,title,normalization,!is_fullscreen,false);
 
9380
    }
 
9381
 
 
9382
    CImgDisplay& show() {
 
9383
      if (is_empty()) return *this;
 
9384
      if (is_closed) {
 
9385
        is_closed = false;
 
9386
        if (is_fullscreen) _init_fullscreen();
 
9387
        ShowWindow(window,SW_SHOW);
 
9388
        _update_window_pos();
 
9389
      }
 
9390
      return paint();
 
9391
    }
 
9392
 
 
9393
    CImgDisplay& close() {
 
9394
      if (is_empty()) return *this;
 
9395
      if (!is_closed && !is_fullscreen) {
 
9396
        if (is_fullscreen) _desinit_fullscreen();
 
9397
        ShowWindow(window,SW_HIDE);
 
9398
        is_closed = true;
 
9399
        window_x = window_y = 0;
 
9400
      }
 
9401
      return *this;
 
9402
    }
 
9403
 
 
9404
    CImgDisplay& move(const int posx, const int posy) {
 
9405
      if (is_empty()) return *this;
 
9406
      if (!is_fullscreen) {
 
9407
        RECT rect; rect.left = rect.top = 0; rect.right=window_width-1; rect.bottom=window_height-1;
6754
9408
        AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
6755
9409
        const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
6756
 
        GetWindowRect(window,&rect);
6757
 
        window_x = rect.left + border1;
6758
 
        window_y = rect.top + border2;
6759
 
      } else window_x = window_y = -1;
 
9410
        SetWindowPos(window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
 
9411
      } else SetWindowPos(window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
 
9412
      window_x = posx;
 
9413
      window_y = posy;
 
9414
      is_moved = false;
 
9415
      return show();
 
9416
    }
 
9417
 
 
9418
    CImgDisplay& show_mouse() {
 
9419
      if (is_empty()) return *this;
 
9420
      visible_cursor = true;
 
9421
      ShowCursor(TRUE);
 
9422
      SendMessage(window,WM_SETCURSOR,0,0);
 
9423
      return *this;
 
9424
    }
 
9425
 
 
9426
    CImgDisplay& hide_mouse() {
 
9427
      if (is_empty()) return *this;
 
9428
      visible_cursor = false;
 
9429
      ShowCursor(FALSE);
 
9430
      SendMessage(window,WM_SETCURSOR,0,0);
 
9431
      return *this;
 
9432
    }
 
9433
 
 
9434
    CImgDisplay& set_mouse(const int posx, const int posy) {
 
9435
      if (!is_closed && posx>=0 && posy>=0) {
 
9436
        _update_window_pos();
 
9437
        const int res = (int)SetCursorPos(window_x+posx,window_y+posy);
 
9438
        if (res) { mouse_x = posx; mouse_y = posy; }
 
9439
      }
 
9440
      return *this;
 
9441
    }
 
9442
 
 
9443
    CImgDisplay& set_title(const char *format, ...) {
 
9444
      if (is_empty()) return *this;
 
9445
      char tmp[1024] = {0};
 
9446
      va_list ap;
 
9447
      va_start(ap, format);
 
9448
      std::vsprintf(tmp,format,ap);
 
9449
      va_end(ap);
 
9450
      if (title) delete[] title;
 
9451
      const int s = cimg::strlen(tmp)+1;
 
9452
      title = new char[s];
 
9453
      std::memcpy(title,tmp,s*sizeof(char));
 
9454
      SetWindowTextA(window, tmp);
 
9455
      return *this;
 
9456
    }
 
9457
 
 
9458
    template<typename T> CImgDisplay& display(const CImg<T>& img) {
 
9459
      if (img.is_empty()) throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
 
9460
      if (is_empty()) assign(img.width,img.height);
 
9461
      return render(img).paint();
 
9462
    }
 
9463
 
 
9464
    CImgDisplay& paint() {
 
9465
      if (!is_closed) {
 
9466
        WaitForSingleObject(mutex,INFINITE);
 
9467
        SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
 
9468
        ReleaseMutex(mutex);
 
9469
      }
 
9470
      return *this;
 
9471
    }
 
9472
 
 
9473
    template<typename T> CImgDisplay& render(const CImg<T>& img) {
 
9474
      if (is_empty()) return *this;
 
9475
      if (!img)
 
9476
        throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
 
9477
                                    img.width,img.height,img.depth,img.dim,img.data);
 
9478
      if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
 
9479
 
 
9480
      const T
 
9481
        *data1 = img.data,
 
9482
        *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
 
9483
        *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
 
9484
 
 
9485
      WaitForSingleObject(mutex,INFINITE);
 
9486
      unsigned int
 
9487
        *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
 
9488
        *ptrd = ndata;
 
9489
 
 
9490
      if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
 
9491
        min = max = 0;
 
9492
        switch (img.dim) {
 
9493
        case 1: {
 
9494
          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
9495
            const unsigned char val = (unsigned char)*(data1++);
 
9496
            *(ptrd++) = (val<<16) | (val<<8) | val;
 
9497
          }} break;
 
9498
        case 2: {
 
9499
          for (unsigned int xy = img.width*img.height; xy>0; --xy)
 
9500
            *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
 
9501
        } break;
 
9502
        default: {
 
9503
          for (unsigned int xy = img.width*img.height; xy>0; --xy)
 
9504
            *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
 
9505
        }
 
9506
        }
 
9507
      } else {
 
9508
        if (normalization==3) {
 
9509
          if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
 
9510
          else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
 
9511
        } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
 
9512
        const float delta = max-min, mm = delta?delta:1.0f;
 
9513
        switch (img.dim) {
 
9514
        case 1: {
 
9515
          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
9516
            const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
 
9517
            *(ptrd++) = (val<<16) | (val<<8) | val;
 
9518
          }} break;
 
9519
        case 2: {
 
9520
          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
9521
            const unsigned char
 
9522
              R = (unsigned char)(255*(*(data1++)-min)/mm),
 
9523
              G = (unsigned char)(255*(*(data2++)-min)/mm);
 
9524
            *(ptrd++) = (R<<16) | (G<<8);
 
9525
          }} break;
 
9526
        default: {
 
9527
          for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
9528
            const unsigned char
 
9529
              R = (unsigned char)(255*(*(data1++)-min)/mm),
 
9530
              G = (unsigned char)(255*(*(data2++)-min)/mm),
 
9531
              B = (unsigned char)(255*(*(data3++)-min)/mm);
 
9532
            *(ptrd++) = (R<<16) | (G<<8) | B;
 
9533
          }}
 
9534
        }
 
9535
      }
 
9536
      if (ndata!=data) { _render_resize(ndata,img.width,img.height,data,width,height); delete[] ndata; }
 
9537
      ReleaseMutex(mutex);
 
9538
      return *this;
 
9539
    }
 
9540
 
 
9541
    template<typename T> const CImgDisplay& snapshot(CImg<T>& img) const {
 
9542
      if (is_empty()) img.assign();
 
9543
      else {
 
9544
        img.assign(width,height,1,3);
 
9545
        T
 
9546
          *data1 = img.ptr(0,0,0,0),
 
9547
          *data2 = img.ptr(0,0,0,1),
 
9548
          *data3 = img.ptr(0,0,0,2);
 
9549
        unsigned int *ptrs = data;
 
9550
         for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
9551
          const unsigned int val = *(ptrs++);
 
9552
          *(data1++) = (unsigned char)(val>>16);
 
9553
          *(data2++) = (unsigned char)((val>>8)&0xFF);
 
9554
          *(data3++) = (unsigned char)(val&0xFF);
 
9555
        }
 
9556
      }
 
9557
      return *this;
 
9558
    }
 
9559
 
 
9560
    // MacOSX - Carbon-based display
 
9561
    //-------------------------------
 
9562
    // (Code by Adrien Reboisson && Romain Blei, supervised by Jean-Marie Favreau)
 
9563
    //
 
9564
#elif cimg_display==3
 
9565
    unsigned int *data;                     // The bits of the picture
 
9566
    WindowRef carbonWindow;                 // The opaque carbon window struct associated with the display
 
9567
    MPCriticalRegionID paintCriticalRegion; // Critical section used when drawing
 
9568
    CGColorSpaceRef csr;                    // Needed for painting
 
9569
    CGDataProviderRef dataProvider;         // Needed for painting
 
9570
    CGImageRef imageRef;                    // The image
 
9571
    UInt32 lastKeyModifiers;                // Buffer storing modifiers state
 
9572
 
 
9573
    // Define the kind of the queries which can be serialized using the event thread.
 
9574
    typedef enum {
 
9575
      COM_CREATEWINDOW = 0, // Create window query
 
9576
      COM_RELEASEWINDOW,    // Release window query
 
9577
      COM_SHOWWINDOW,       // Show window query
 
9578
      COM_HIDEWINDOW,       // Hide window query
 
9579
      COM_SHOWMOUSE,        // Show mouse query
 
9580
      COM_HIDEMOUSE,        // Hide mouse query
 
9581
      COM_RESIZEWINDOW,     // Resize window query
 
9582
      COM_MOVEWINDOW,       // Move window query
 
9583
      COM_SETTITLE,         // Set window title query
 
9584
      COM_SETMOUSEPOS       // Set cursor position query
 
9585
    } CImgCarbonQueryKind;
 
9586
 
 
9587
    // The query destructor send to the event thread.
 
9588
    struct CbSerializedQuery {
 
9589
      CImgDisplay* sender;         // Query's sender
 
9590
      CImgCarbonQueryKind kind;    // The kind of the query sent to the background thread
 
9591
      short x, y;                  // X:Y values for move/resize operations
 
9592
      char *c;                     // Char values for window title
 
9593
      bool createFullScreenWindow; // Boolean value used for full-screen window creation
 
9594
      bool createClosedWindow;     // Boolean value used for closed-window creation
 
9595
      bool update;                 // Boolean value used for resize
 
9596
      bool success;                // Succes or failure of the message, used as return value
 
9597
      CbSerializedQuery(CImgDisplay *s, CImgCarbonQueryKind k):sender(s),kind(k),success(false) {};
 
9598
 
 
9599
      inline static CbSerializedQuery BuildReleaseWindowQuery(CImgDisplay* sender) {
 
9600
        return CbSerializedQuery(sender, COM_RELEASEWINDOW);
 
9601
      }
 
9602
      inline static CbSerializedQuery BuildCreateWindowQuery(CImgDisplay* sender, const bool fullscreen, const bool closed) {
 
9603
        CbSerializedQuery q(sender, COM_CREATEWINDOW);
 
9604
        q.createFullScreenWindow = fullscreen;
 
9605
        q.createClosedWindow = closed;
 
9606
        return q;
 
9607
      }
 
9608
      inline static CbSerializedQuery BuildShowWindowQuery(CImgDisplay* sender) {
 
9609
        return CbSerializedQuery(sender, COM_SHOWWINDOW);
 
9610
      }
 
9611
      inline static CbSerializedQuery BuildHideWindowQuery(CImgDisplay* sender) {
 
9612
        return CbSerializedQuery(sender, COM_HIDEWINDOW);
 
9613
      }
 
9614
      inline static CbSerializedQuery BuildShowMouseQuery(CImgDisplay* sender) {
 
9615
        return CbSerializedQuery(sender, COM_SHOWMOUSE);
 
9616
      }
 
9617
      inline static CbSerializedQuery BuildHideMouseQuery(CImgDisplay* sender) {
 
9618
        return CbSerializedQuery(sender, COM_HIDEMOUSE);
 
9619
      }
 
9620
      inline static CbSerializedQuery BuildResizeWindowQuery(CImgDisplay* sender, const int x, const int y, bool update) {
 
9621
        CbSerializedQuery q(sender, COM_RESIZEWINDOW);
 
9622
        q.x = x, q.y = y;
 
9623
        q.update = update;
 
9624
        return q;
 
9625
      }
 
9626
      inline static CbSerializedQuery BuildMoveWindowQuery(CImgDisplay* sender, const int x, const int y) {
 
9627
        CbSerializedQuery q(sender, COM_MOVEWINDOW);
 
9628
        q.x = x, q.y = y;
 
9629
        return q;
 
9630
      }
 
9631
      inline static CbSerializedQuery BuildSetWindowTitleQuery(CImgDisplay* sender, char* c) {
 
9632
        CbSerializedQuery q(sender, COM_SETTITLE);
 
9633
        q.c = c;
 
9634
        return q;
 
9635
      }
 
9636
      inline static CbSerializedQuery BuildSetWindowPosQuery(CImgDisplay* sender, const int x, const int y) {
 
9637
        CbSerializedQuery q(sender, COM_SETMOUSEPOS);
 
9638
        q.x = x, q.y = y;
 
9639
        return q;
 
9640
      }
 
9641
    };
 
9642
 
 
9643
    // Send a serialized query in a synchroneous way.
 
9644
    // @param c Application Carbon global settings.
 
9645
    // @param m The query to send.
 
9646
    // @result Success/failure of the operation returned by the event thread.
 
9647
    bool _CbSendMsg(cimg::CarbonInfo& c, CbSerializedQuery m) {
 
9648
      MPNotifyQueue(c.com_queue,&m,0,0); // Send the given message
 
9649
      MPWaitOnSemaphore(c.sync_event,kDurationForever); // Wait end of processing notification
 
9650
      return m.success;
 
9651
    }
 
9652
 
 
9653
    // Free the window attached to the current display.
 
9654
    // @param c Application Carbon global settings.
 
9655
    // @result Success/failure of the operation.
 
9656
    bool _CbFreeAttachedWindow(cimg::CarbonInfo& c) {
 
9657
      if (!_CbSendMsg(c, CbSerializedQuery::BuildReleaseWindowQuery(this))) // Ask the main thread to free the given window
 
9658
        throw CImgDisplayException("Cannot release window associated with the current display.");
 
9659
      // If a window existed, ask to release it
 
9660
      MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
 
9661
      --c.windowCount; //Decrement the window count
 
9662
      MPExitCriticalRegion(c.windowListCR); // Unlock the list
 
9663
      return c.windowCount == 0;
 
9664
    }
 
9665
 
 
9666
    // Create the window attached to the current display.
 
9667
    // @param c Application Carbon global settings.
 
9668
    // @param title The window title, if any.
 
9669
    // @param fullscreen Shoud we start in fullscreen mode ?
 
9670
    // @param create_closed If true, the window is created but not displayed.
 
9671
    // @result Success/failure of the operation.
 
9672
    void _CbCreateAttachedWindow(cimg::CarbonInfo& c, const char* title, const bool fullscreen, const bool create_closed) {
 
9673
      if (!_CbSendMsg(c,CbSerializedQuery::BuildCreateWindowQuery(this,fullscreen,create_closed))) // Ask the main thread to create the window
 
9674
        throw CImgDisplayException("Cannot create the window associated with the current display.");
 
9675
      if (title) set_title(title); // Set the title, if any
 
9676
      // Now we can register the window
 
9677
      MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
 
9678
      ++c.windowCount; //Increment the window count
 
9679
      MPExitCriticalRegion(c.windowListCR); // Unlock the list
 
9680
    }
 
9681
 
 
9682
    // Destroy graphic objects previously allocated. We free the image, the data provider, then the colorspace.
 
9683
    void _CbFinalizeGraphics() {
 
9684
      CGImageRelease (imageRef); // Release the picture
 
9685
      CGDataProviderRelease(dataProvider); // Release the DP
 
9686
      CGColorSpaceRelease(csr); // Free the cs
 
9687
    }
 
9688
 
 
9689
    // Create graphic objects associated to a display. We have to create a colormap, a data provider, and the image.
 
9690
    void _CbInitializeGraphics() {
 
9691
      csr = CGColorSpaceCreateDeviceRGB(); // Create the color space first
 
9692
      if (!csr)
 
9693
        throw CImgDisplayException("CGColorSpaceCreateDeviceRGB() failed.");
 
9694
      // Create the DP
 
9695
      dataProvider = CGDataProviderCreateWithData(0,data,height*width*sizeof(unsigned int),0);
 
9696
      if (!dataProvider)
 
9697
        throw CImgDisplayException("CGDataProviderCreateWithData() failed.");
 
9698
      // ... and finally the image.
 
9699
      if (cimg::endianness())
 
9700
        imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
 
9701
                                 kCGImageAlphaNoneSkipFirst,dataProvider,0,false,kCGRenderingIntentDefault);
 
9702
      else
 
9703
        imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
 
9704
                                 kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,dataProvider,0,false,kCGRenderingIntentDefault);
 
9705
      if (!imageRef)
 
9706
        throw CImgDisplayException("CGImageCreate() failed.");
 
9707
    }
 
9708
 
 
9709
    // Reinit graphic objects. Free them, then reallocate all.
 
9710
    // This is used when image bounds are changed or when data source get invalid.
 
9711
    void _CbReinitGraphics() {
 
9712
      MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
 
9713
      _CbFinalizeGraphics();
 
9714
      _CbInitializeGraphics();
 
9715
      MPExitCriticalRegion(paintCriticalRegion);
 
9716
    }
 
9717
 
 
9718
    // Convert a point having global coordonates into the window coordonates.
 
9719
    // We use this function to replace the deprecated GlobalToLocal QuickDraw API.
 
9720
    // @param mouseEvent The mouse event which triggered the event handler.
 
9721
    // @param window The window where the event occured.
 
9722
    // @param point The modified point struct.
 
9723
    // @result True if the point struct has been converted successfully.
 
9724
    static bool _CbToLocalPointFromMouseEvent(EventRef mouseEvent, WindowRef window, HIPoint* point) {
 
9725
      Rect bounds;
 
9726
      if (GetWindowBounds(window,kWindowStructureRgn,&bounds)==noErr) {
 
9727
        point->x -= bounds.left;
 
9728
        point->y -= bounds.top;
 
9729
        HIViewRef view = NULL;
 
9730
        if (HIViewGetViewForMouseEvent(HIViewGetRoot(window),mouseEvent,&view)==noErr)
 
9731
          return HIViewConvertPoint(point, NULL, view) == noErr;
 
9732
      }
 
9733
      return false;
 
9734
    }
 
9735
 
 
9736
    static int screen_dimx() {
 
9737
      return CGDisplayPixelsWide(kCGDirectMainDisplay);
 
9738
    }
 
9739
 
 
9740
    static int screen_dimy() {
 
9741
      return CGDisplayPixelsHigh(kCGDirectMainDisplay);
 
9742
    }
 
9743
 
 
9744
    CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
 
9745
                        const unsigned int normalization_type=3,
 
9746
                        const bool fullscreen_flag=false, const bool closed_flag=false) {
 
9747
      if (!dimw || !dimh) return assign();
 
9748
      _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
 
9749
      min = max = 0;
 
9750
      std::memset(data,0,sizeof(unsigned int)*width*height);
 
9751
      return paint();
 
9752
    }
 
9753
 
 
9754
    template<typename T> CImgDisplay& assign(const CImg<T>& img, const char *title=0,
 
9755
                                             const unsigned int normalization_type=3,
 
9756
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
 
9757
      if (!img) return assign();
 
9758
      CImg<T> tmp;
 
9759
      const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
 
9760
      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
 
9761
      if (normalization==2) min = (float)nimg.minmax(max);
 
9762
      return display(nimg);
 
9763
    }
 
9764
 
 
9765
    template<typename T> CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
 
9766
                                             const unsigned int normalization_type=3,
 
9767
                                             const bool fullscreen_flag=false, const bool closed_flag=false) {
 
9768
      if (!list) return assign();
 
9769
      CImg<T> tmp;
 
9770
      const CImg<T> img = list.get_append('x','p'),
 
9771
        &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
 
9772
      _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
 
9773
      if (normalization==2) min = (float)nimg.minmax(max);
 
9774
      return display(nimg);
 
9775
    }
 
9776
 
 
9777
    CImgDisplay& assign(const CImgDisplay &win) {
 
9778
      if (!win) return assign();
 
9779
      _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
 
9780
      std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
 
9781
      return paint();
 
9782
    }
 
9783
 
 
9784
    template<typename T> CImgDisplay& display(const CImg<T>& img) {
 
9785
      if (is_empty()) assign(img.width,img.height);
 
9786
      return render(img).paint();
 
9787
    }
 
9788
 
 
9789
    CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
 
9790
      if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
 
9791
      if (is_empty()) return assign(nwidth,nheight);
 
9792
      const unsigned int
 
9793
        tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
 
9794
        tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
 
9795
        dimx = tmpdimx?tmpdimx:1,
 
9796
        dimy = tmpdimy?tmpdimy:1;
 
9797
      cimg::CarbonInfo& c = cimg::CarbonAttr();
 
9798
 
 
9799
      if ((window_width!=dimx || window_height!=dimy) &&
 
9800
          !_CbSendMsg(c,CbSerializedQuery::BuildResizeWindowQuery(this,dimx,dimy,redraw)))
 
9801
        throw CImgDisplayException("CImgDisplay::resize() : Cannot resize the window associated to the current display.");
 
9802
 
 
9803
      if (width!=dimx || height!=dimy) {
 
9804
        unsigned int *ndata = new unsigned int[dimx*dimy];
 
9805
        if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
 
9806
        else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
 
9807
        unsigned int const* old_data = data;
 
9808
        data = ndata;
 
9809
        delete[] old_data;
 
9810
        _CbReinitGraphics();
 
9811
      }
 
9812
      window_width = width = dimx; window_height = height = dimy;
 
9813
      is_resized = false;
 
9814
      if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
 
9815
      if (redraw) return paint();
 
9816
      return *this;
 
9817
    }
 
9818
 
 
9819
    CImgDisplay& move(const int posx, const int posy) {
 
9820
      if (is_empty()) return *this;
 
9821
      if (!is_fullscreen) {
 
9822
        // If the operation succeeds, window_x and window_y are updated by the event thread
 
9823
        cimg::CarbonInfo& c = cimg::CarbonAttr();
 
9824
        // Send the query
 
9825
        if (!_CbSendMsg(c,CbSerializedQuery::BuildMoveWindowQuery(this,posx,posy)))
 
9826
          throw CImgDisplayException("CImgDisplay::move() : Cannot move the window associated to the current display.");
 
9827
      }
 
9828
      return show();
 
9829
    }
 
9830
 
 
9831
    CImgDisplay& set_mouse(const int posx, const int posy) {
 
9832
      if (!is_closed && posx>=0 && posy>=0) {
 
9833
        // If the operation succeeds, mouse_x and mouse_y are updated by the event thread
 
9834
        cimg::CarbonInfo& c = cimg::CarbonAttr();
 
9835
        // Send the query
 
9836
        if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowPosQuery(this,posx,posy)))
 
9837
          throw CImgDisplayException("CImgDisplay::set_mouse() : Cannot set the mouse position to the current display.");
 
9838
      }
 
9839
      return *this;
 
9840
    }
 
9841
 
 
9842
    CImgDisplay& hide_mouse() {
 
9843
      if (is_empty()) return *this;
 
9844
      cimg::CarbonInfo& c = cimg::CarbonAttr();
 
9845
      // Send the query
 
9846
      if (!_CbSendMsg(c,CbSerializedQuery::BuildHideMouseQuery(this)))
 
9847
        throw CImgDisplayException("CImgDisplay::hide_mouse() : Cannot hide the mouse associated to the current display.");
 
9848
      return *this;
 
9849
    }
 
9850
 
 
9851
    CImgDisplay& show_mouse() {
 
9852
      if (is_empty()) return *this;
 
9853
      cimg::CarbonInfo& c = cimg::CarbonAttr();
 
9854
      // Send the query
 
9855
      if (!_CbSendMsg(c,CbSerializedQuery::BuildShowMouseQuery(this)))
 
9856
        throw CImgDisplayException("CImgDisplay::show_mouse() : Cannot show the mouse associated to the current display.");
 
9857
      return *this;
 
9858
    }
 
9859
 
 
9860
    static void wait_all() {
 
9861
      cimg::CarbonInfo& c = cimg::CarbonAttr();
 
9862
      MPWaitOnSemaphore(c.wait_event,kDurationForever);
 
9863
    }
 
9864
 
 
9865
    CImgDisplay& show() {
 
9866
      if (is_empty()) return *this;
 
9867
      if (is_closed) {
 
9868
        cimg::CarbonInfo& c = cimg::CarbonAttr();
 
9869
        if (!_CbSendMsg(c,CbSerializedQuery::BuildShowWindowQuery(this)))
 
9870
          throw CImgDisplayException("CImgDisplay::show() : Cannot show the window associated to the current display.");
 
9871
      }
 
9872
      return paint();
 
9873
    }
 
9874
 
 
9875
    CImgDisplay& close() {
 
9876
      if (is_empty()) return *this;
 
9877
      if (!is_closed && !is_fullscreen) {
 
9878
        cimg::CarbonInfo& c = cimg::CarbonAttr();
 
9879
        // If the operation succeeds, window_x and window_y are updated on the event thread
 
9880
        if (!_CbSendMsg(c,CbSerializedQuery::BuildHideWindowQuery(this)))
 
9881
          throw CImgDisplayException("CImgDisplay::close() : Cannot hide the window associated to the current display.");
 
9882
      }
 
9883
      return *this;
 
9884
    }
 
9885
 
 
9886
    CImgDisplay& set_title(const char *format, ...) {
 
9887
      if (is_empty()) return *this;
 
9888
      char tmp[1024] = {0};
 
9889
      va_list ap;
 
9890
      va_start(ap, format);
 
9891
      std::vsprintf(tmp,format,ap);
 
9892
      va_end(ap);
 
9893
      if (title) delete[] title;
 
9894
      const int s = cimg::strlen(tmp)+1;
 
9895
      title = new char[s];
 
9896
      std::memcpy(title,tmp,s*sizeof(char));
 
9897
      cimg::CarbonInfo& c = cimg::CarbonAttr();
 
9898
      if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowTitleQuery(this,tmp)))
 
9899
        throw CImgDisplayException("CImgDisplay::set_title() : Cannot set the window title associated to the current display.");
 
9900
      return *this;
 
9901
    }
 
9902
 
 
9903
    CImgDisplay& paint() {
 
9904
      if (!is_closed) {
 
9905
        MPEnterCriticalRegion(paintCriticalRegion,kDurationForever);
 
9906
        CGrafPtr portPtr = GetWindowPort(carbonWindow);
 
9907
        CGContextRef currentContext = 0;
 
9908
        QDBeginCGContext(portPtr,&currentContext);
 
9909
        CGContextSetRGBFillColor(currentContext,255,255,255,255);
 
9910
        CGContextFillRect(currentContext,CGRectMake(0,0,window_width,window_height));
 
9911
        CGContextDrawImage(currentContext,CGRectMake(0,int(window_height-height)<0?0:window_height-height,width,height),imageRef);
 
9912
        CGContextFlush(currentContext);
 
9913
        QDEndCGContext(portPtr, &currentContext);
 
9914
        MPExitCriticalRegion(paintCriticalRegion);
 
9915
      }
 
9916
      return *this;
 
9917
    }
 
9918
 
 
9919
    template<typename T> CImgDisplay& render(const CImg<T>& img) {
 
9920
      if (is_empty()) return *this;
 
9921
      if (!img)
 
9922
        throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
 
9923
                                    img.width,img.height,img.depth,img.dim,img.data);
 
9924
      if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
 
9925
      const T
 
9926
        *data1 = img.data,
 
9927
        *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
 
9928
        *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
 
9929
      MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
 
9930
      unsigned int
 
9931
        *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
 
9932
        *ptrd = ndata;
 
9933
      if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
 
9934
        min = max = 0;
 
9935
        for (unsigned int xy = img.width*img.height; xy>0; --xy)
 
9936
          *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
 
9937
      } else {
 
9938
        if (normalization==3) {
 
9939
          if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
 
9940
          else {
 
9941
            min = (float)cimg::type<T>::min();
 
9942
            max = (float)cimg::type<T>::max();
 
9943
          }
 
9944
        } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
 
9945
        const float delta = max-min, mm = delta?delta:1.0f;
 
9946
        for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
9947
          const unsigned char
 
9948
            R = (unsigned char)(255*(*(data1++)-min)/mm),
 
9949
            G = (unsigned char)(255*(*(data2++)-min)/mm),
 
9950
            B = (unsigned char)(255*(*(data3++)-min)/mm);
 
9951
          *(ptrd++) = (R<<16) | (G<<8) | (B);
 
9952
        }
 
9953
      }
 
9954
      if (ndata!=data) {
 
9955
        _render_resize(ndata,img.width,img.height,data,width,height);
 
9956
        delete[] ndata;
 
9957
      }
 
9958
      MPExitCriticalRegion(paintCriticalRegion);
 
9959
      return *this;
 
9960
    }
 
9961
 
 
9962
    template<typename T> const CImgDisplay& snapshot(CImg<T>& img) const {
 
9963
      if (is_empty()) img.assign();
 
9964
      else {
 
9965
        img.assign(width,height,1,3);
 
9966
        T
 
9967
          *data1 = img.ptr(0,0,0,0),
 
9968
          *data2 = img.ptr(0,0,0,1),
 
9969
          *data3 = img.ptr(0,0,0,2);
 
9970
        unsigned int *ptrs = data;
 
9971
        for (unsigned int xy = img.width*img.height; xy>0; --xy) {
 
9972
          const unsigned int val = *(ptrs++);
 
9973
          *(data1++) = (unsigned char)(val>>16);
 
9974
          *(data2++) = (unsigned char)((val>>8)&0xFF);
 
9975
          *(data3++) = (unsigned char)(val&0xFF);
 
9976
        }
 
9977
      }
 
9978
      return *this;
 
9979
    }
 
9980
 
 
9981
    CImgDisplay& toggle_fullscreen(const bool redraw=true) {
 
9982
      if (is_empty()) return *this;
 
9983
      if (redraw) {
 
9984
        const unsigned int bufsize = width*height*4;
 
9985
        void *odata = std::malloc(bufsize);
 
9986
        std::memcpy(odata,data,bufsize);
 
9987
        assign(width,height,title,normalization,!is_fullscreen,false);
 
9988
        std::memcpy(data,odata,bufsize);
 
9989
        std::free(odata);
 
9990
        return paint();
 
9991
      }
 
9992
      return assign(width,height,title,normalization,!is_fullscreen,false);
 
9993
    }
 
9994
 
 
9995
    static OSStatus CarbonEventHandler(EventHandlerCallRef myHandler, EventRef theEvent, void* userData) {
 
9996
      OSStatus result = eventNotHandledErr;
 
9997
      CImgDisplay* disp = (CImgDisplay*) userData;
 
9998
      (void)myHandler; // Avoid "unused parameter"
 
9999
      cimg::CarbonInfo& c = cimg::CarbonAttr();
 
10000
      // Gets the associated display
 
10001
      if (disp) {
 
10002
        // Window events are always handled
 
10003
        if (GetEventClass(theEvent)==kEventClassWindow) switch (GetEventKind (theEvent)) {
 
10004
        case kEventWindowClose:
 
10005
          disp->mouse_x = disp->mouse_y = -1;
 
10006
          disp->window_x = disp->window_y = 0;
 
10007
          if (disp->button) {
 
10008
            std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
 
10009
            disp->button = 0;
 
10010
          }
 
10011
          if (disp->key) {
 
10012
            std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
 
10013
            disp->key = 0;
 
10014
          }
 
10015
          if (disp->released_key) { std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
 
10016
          disp->is_closed = true;
 
10017
          HideWindow(disp->carbonWindow);
 
10018
          disp->is_event = true;
 
10019
          MPSignalSemaphore(c.wait_event);
 
10020
          result = noErr;
 
10021
          break;
 
10022
          // There is a lot of case where we have to redraw our window
 
10023
        case kEventWindowBoundsChanging:
 
10024
        case kEventWindowResizeStarted:
 
10025
        case kEventWindowCollapsed: //Not sure it's really needed :-)
 
10026
          break;
 
10027
        case kEventWindowZoomed:
 
10028
        case kEventWindowExpanded:
 
10029
        case kEventWindowResizeCompleted: {
 
10030
          MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
 
10031
          // Now we retrieve the new size of the window
 
10032
          Rect newContentRect;
 
10033
          GetWindowBounds(disp->carbonWindow,kWindowContentRgn,&newContentRect);
 
10034
          const unsigned int
 
10035
            nw = (unsigned int)(newContentRect.right - newContentRect.left),
 
10036
            nh = (unsigned int)(newContentRect.bottom - newContentRect.top);
 
10037
 
 
10038
          // Then we update CImg internal settings
 
10039
          if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
 
10040
            disp->window_width  = nw;
 
10041
            disp->window_height = nh;
 
10042
            disp->mouse_x = disp->mouse_y = -1;
 
10043
            disp->is_resized = true;
 
10044
          }
 
10045
          disp->is_event = true;
 
10046
          MPExitCriticalRegion(disp->paintCriticalRegion);
 
10047
          disp->paint(); // Coords changed, must update the screen
 
10048
          MPSignalSemaphore(c.wait_event);
 
10049
          result = noErr;
 
10050
        } break;
 
10051
        case kEventWindowDragStarted:
 
10052
        case kEventWindowDragCompleted: {
 
10053
          MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
 
10054
          // Now we retrieve the new size of the window
 
10055
          Rect newContentRect ;
 
10056
          GetWindowBounds(disp->carbonWindow,kWindowStructureRgn,&newContentRect);
 
10057
          const int nx = (int)(newContentRect.left), ny = (int)(newContentRect.top);
 
10058
          // Then we update CImg internal settings
 
10059
          if (nx!=disp->window_x || ny!=disp->window_y) {
 
10060
            disp->window_x = nx;
 
10061
            disp->window_y = ny;
 
10062
            disp->is_moved = true;
 
10063
          }
 
10064
          disp->is_event = true;
 
10065
          MPExitCriticalRegion(disp->paintCriticalRegion);
 
10066
          disp->paint(); // Coords changed, must update the screen
 
10067
          MPSignalSemaphore(c.wait_event);
 
10068
          result = noErr;
 
10069
        } break;
 
10070
          case kEventWindowPaint:
 
10071
          disp->paint();
 
10072
          break;
 
10073
          }
 
10074
 
 
10075
        switch (GetEventClass(theEvent)) {
 
10076
        case kEventClassKeyboard: {
 
10077
          if (GetEventKind(theEvent)==kEventRawKeyModifiersChanged) {
 
10078
            // Apple has special keys named "notifiers", we have to convert this (exotic ?) key handling into the regular CImg processing.
 
10079
            UInt32 newModifiers;
 
10080
            if (GetEventParameter(theEvent,kEventParamKeyModifiers,typeUInt32,0,sizeof(UInt32),0,&newModifiers)==noErr) {
 
10081
              int newKeyCode = -1;
 
10082
              UInt32 changed = disp->lastKeyModifiers^newModifiers;
 
10083
              // Find what changed here
 
10084
              if ((changed & rightShiftKey)!=0) newKeyCode = cimg::keySHIFTRIGHT;
 
10085
              if ((changed & shiftKey)!=0) newKeyCode = cimg::keySHIFTLEFT;
 
10086
 
 
10087
              // On the Mac, the "option" key = the ALT key
 
10088
              if ((changed & (optionKey | rightOptionKey))!=0) newKeyCode = cimg::keyALTGR;
 
10089
              if ((changed & controlKey)!=0) newKeyCode = cimg::keyCTRLLEFT;
 
10090
              if ((changed & rightControlKey)!=0) newKeyCode = cimg::keyCTRLRIGHT;
 
10091
              if ((changed & cmdKey)!=0) newKeyCode = cimg::keyAPPLEFT;
 
10092
              if ((changed & alphaLock)!=0) newKeyCode = cimg::keyCAPSLOCK;
 
10093
              if (newKeyCode != -1) { // Simulate keystroke
 
10094
                if (disp->key) std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
 
10095
                disp->key = (int)newKeyCode;
 
10096
              }
 
10097
              disp->lastKeyModifiers = newModifiers; // Save current state
 
10098
            }
 
10099
            disp->is_event = true;
 
10100
            MPSignalSemaphore(c.wait_event);
 
10101
          }
 
10102
          if (GetEventKind(theEvent)==kEventRawKeyDown || GetEventKind(theEvent)==kEventRawKeyRepeat) {
 
10103
            char keyCode;
 
10104
            if (GetEventParameter(theEvent,kEventParamKeyMacCharCodes,typeChar,0,sizeof(keyCode),0,&keyCode)==noErr) {
 
10105
              disp->update_iskey((unsigned int)keyCode,true);
 
10106
              if (disp->key) std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
 
10107
              disp->key = (unsigned int)keyCode;
 
10108
              if (disp->released_key) { std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
 
10109
            }
 
10110
            disp->is_event = true;
 
10111
            MPSignalSemaphore(c.wait_event);
 
10112
          }
 
10113
        } break;
 
10114
 
 
10115
        case kEventClassMouse:
 
10116
          switch (GetEventKind(theEvent)) {
 
10117
          case kEventMouseDragged:
 
10118
            //  When you push the main button on the Apple mouse while moving it, you got NO kEventMouseMoved msg,
 
10119
            //  but a kEventMouseDragged one. So we merge them here.
 
10120
          case kEventMouseMoved:
 
10121
            HIPoint point;
 
10122
            if (GetEventParameter(theEvent,kEventParamMouseLocation,typeHIPoint,0,sizeof(point),0,&point)==noErr) {
 
10123
              if (_CbToLocalPointFromMouseEvent(theEvent,disp->carbonWindow,&point)) {
 
10124
                disp->mouse_x = (int)point.x;
 
10125
                disp->mouse_y = (int)point.y;
 
10126
                if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
 
10127
                  disp->mouse_x = disp->mouse_y = -1;
 
10128
              } else disp->mouse_x = disp->mouse_y = -1;
 
10129
            }
 
10130
            disp->is_event = true;
 
10131
            MPSignalSemaphore(c.wait_event);
 
10132
            break;
 
10133
          case kEventMouseDown:
 
10134
            UInt16 btn;
 
10135
            if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
 
10136
              std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
 
10137
              if (btn==kEventMouseButtonPrimary) disp->button|=1U;
 
10138
              // For those who don't have a multi-mouse button (as me), I think it's better to allow the user
 
10139
              // to emulate a right click by using the Control key
 
10140
              if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
 
10141
                cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Down]");
 
10142
              if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button|=2U;
 
10143
              if (btn==kEventMouseButtonTertiary) disp->button|=4U;
 
10144
            }
 
10145
            disp->is_event = true;
 
10146
            MPSignalSemaphore(c.wait_event);
 
10147
            break;
 
10148
          case kEventMouseWheelMoved:
 
10149
            EventMouseWheelAxis wheelax;
 
10150
            SInt32 delta;
 
10151
            if (GetEventParameter(theEvent,kEventParamMouseWheelAxis,typeMouseWheelAxis,0,sizeof(wheelax),0,&wheelax)==noErr)
 
10152
              if (wheelax==kEventMouseWheelAxisY) {
 
10153
                if (GetEventParameter(theEvent,kEventParamMouseWheelDelta,typeLongInteger,0,sizeof(delta),0,&delta)==noErr)
 
10154
                  if (delta>0) disp->wheel+=delta/120; //FIXME: why 120 ?
 
10155
                disp->is_event = true;
 
10156
                MPSignalSemaphore(c.wait_event);
 
10157
              }
 
10158
            break;
 
10159
          }
 
10160
        }
 
10161
 
 
10162
        switch (GetEventClass(theEvent)) {
 
10163
        case kEventClassKeyboard:
 
10164
          if (GetEventKind(theEvent)==kEventRawKeyUp) {
 
10165
            UInt32 keyCode;
 
10166
            if (GetEventParameter(theEvent,kEventParamKeyCode,typeUInt32,0,sizeof(keyCode),0,&keyCode)==noErr) {
 
10167
              disp->update_iskey((unsigned int)keyCode,false);
 
10168
              if (disp->key) { std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
 
10169
              if (disp->released_key) std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
 
10170
              disp->released_key = (int)keyCode;
 
10171
            }
 
10172
            disp->is_event = true;
 
10173
            MPSignalSemaphore(c.wait_event);
 
10174
          }
 
10175
          break;
 
10176
 
 
10177
        case kEventClassMouse:
 
10178
          switch (GetEventKind(theEvent)) {
 
10179
          case kEventMouseUp:
 
10180
            UInt16 btn;
 
10181
            if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
 
10182
              std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
 
10183
              if (btn==kEventMouseButtonPrimary) disp->button&=~1U;
 
10184
              // See note in kEventMouseDown handler.
 
10185
              if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
 
10186
                cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Up]");
 
10187
              if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button&=~2U;
 
10188
              if (btn==kEventMouseButtonTertiary) disp->button&=~2U;
 
10189
            }
 
10190
            disp->is_event = true;
 
10191
            MPSignalSemaphore(c.wait_event);
 
10192
            break;
 
10193
          }
 
10194
        }
 
10195
      }
 
10196
      return (result);
 
10197
    }
 
10198
 
 
10199
    static void* _events_thread(void* args) {
 
10200
      (void)args;      // Make the compiler happy
 
10201
      cimg::CarbonInfo& c = cimg::CarbonAttr();
 
10202
      pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
 
10203
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
 
10204
      MPSignalSemaphore(c.sync_event);  // Notify the caller that all goes fine
 
10205
      EventRef theEvent;
 
10206
      EventTargetRef theTarget;
 
10207
      OSStatus err;
 
10208
      CbSerializedQuery* query;
 
10209
      theTarget = GetEventDispatcherTarget();
 
10210
 
 
10211
      // Enter in the main loop
 
10212
      while (true) {
 
10213
        pthread_testcancel(); /* Check if cancelation happens */
 
10214
        err = ReceiveNextEvent(0,0,kDurationImmediate,true,&theEvent); // Fetch new events
 
10215
        if (err==noErr) { // Received a carbon event, so process it !
 
10216
          SendEventToEventTarget (theEvent, theTarget);
 
10217
          ReleaseEvent(theEvent);
 
10218
        } else if (err == eventLoopTimedOutErr) { // There is no event to process, so check if there is new messages to process
 
10219
          OSStatus r =MPWaitOnQueue(c.com_queue,(void**)&query,0,0,10*kDurationMillisecond);
 
10220
          if (r!=noErr) continue; //nothing in the queue or an error.., bye
 
10221
          // If we're here, we've something to do now.
 
10222
          if (query) {
 
10223
            switch (query->kind) {
 
10224
            case COM_SETMOUSEPOS: { // change the cursor position
 
10225
              query->success = CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,CGPointMake(query->sender->window_x+query->x,query->sender->window_y+query->y))
 
10226
                == kCGErrorSuccess;
 
10227
              if (query->success) {
 
10228
                query->sender->mouse_x = query->x;
 
10229
                query->sender->mouse_y = query->y;
 
10230
              } else cimg::warn("CImgDisplay::_events_thread() : CGDisplayMoveCursorToPoint failed.");
 
10231
            } break;
 
10232
            case COM_SETTITLE: { // change the title bar caption
 
10233
              CFStringRef windowTitle = CFStringCreateWithCString(0,query->c,kCFStringEncodingMacRoman);
 
10234
              query->success = SetWindowTitleWithCFString(query->sender->carbonWindow,windowTitle)==noErr;
 
10235
              if (!query->success) cimg::warn("CImgDisplay::_events_thread() : SetWindowTitleWithCFString failed.");
 
10236
              CFRelease(windowTitle);
 
10237
            } break;
 
10238
            case COM_RESIZEWINDOW: { // Resize a window
 
10239
              SizeWindow(query->sender->carbonWindow,query->x,query->y,query->update);
 
10240
              // If the window has been resized successfully, update display informations
 
10241
              query->sender->window_width = query->x;
 
10242
              query->sender->window_height = query->y;
 
10243
              query->success = true;
 
10244
            } break;
 
10245
            case COM_MOVEWINDOW: { // Move a window
 
10246
              MoveWindow(query->sender->carbonWindow,query->x,query->y,false);
 
10247
              query->sender->window_x = query->x;
 
10248
              query->sender->window_y = query->y;
 
10249
              query->sender->is_moved = false;
 
10250
              query->success = true;
 
10251
            } break;
 
10252
            case COM_SHOWMOUSE: { // Show the mouse
 
10253
              query->success = CGDisplayShowCursor(kCGDirectMainDisplay)==noErr;
 
10254
              if (!query->success) cimg::warn("CImgDisplay::_events_thread() : CGDisplayShowCursor failed.");
 
10255
            } break;
 
10256
            case COM_HIDEMOUSE: { // Hide the mouse
 
10257
              query->success = CGDisplayHideCursor(kCGDirectMainDisplay)==noErr;
 
10258
              if (!query->success) cimg::warn("CImgDisplay::_events_thread() : CGDisplayHideCursor failed.");
 
10259
            } break;
 
10260
            case COM_SHOWWINDOW: { // We've to show a window
 
10261
              ShowWindow(query->sender->carbonWindow);
 
10262
              query->success = true;
 
10263
              query->sender->is_closed = false;
 
10264
            } break;
 
10265
            case COM_HIDEWINDOW: { // We've to show a window
 
10266
              HideWindow(query->sender->carbonWindow);
 
10267
              query->sender->is_closed = true;
 
10268
              query->sender->window_x = query->sender->window_y = 0;
 
10269
              query->success = true;
 
10270
            } break;
 
10271
            case COM_RELEASEWINDOW: { // We have to release a given window handle
 
10272
              query->success = true;
 
10273
              CFRelease(query->sender->carbonWindow);
 
10274
            } break;
 
10275
            case COM_CREATEWINDOW: { // We have to create a window
 
10276
              query->success = true;
 
10277
              WindowAttributes  windowAttrs;
 
10278
              Rect              contentRect;
 
10279
              if (query->createFullScreenWindow) {
 
10280
                // To simulate a "true" full screen, we remove menus and close boxes
 
10281
                windowAttrs = (1L << 9); //Why ? kWindowNoTitleBarAttribute seems to be not defined on 10.3
 
10282
                // Define a full screen bound rect
 
10283
                SetRect(&contentRect,0,0,CGDisplayPixelsWide(kCGDirectMainDisplay),CGDisplayPixelsHigh(kCGDirectMainDisplay));
 
10284
              } else { // Set the window size
 
10285
                SetRect(&contentRect,0,0,query->sender->width,query->sender->height); // Window will be centered with RepositionWindow.
 
10286
                // Use default attributes
 
10287
                windowAttrs = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute | kWindowLiveResizeAttribute;
 
10288
              }
 
10289
              // Update window position
 
10290
              if (query->createClosedWindow) query->sender->window_x = query->sender->window_y = 0;
 
10291
              else {
 
10292
                query->sender->window_x = contentRect.left;
 
10293
                query->sender->window_y = contentRect.top;
 
10294
              }
 
10295
              // Update window flags
 
10296
              query->sender->window_width = query->sender->width;
 
10297
              query->sender->window_height = query->sender->height;
 
10298
              query->sender->flush();
 
10299
              // Create the window
 
10300
              if (CreateNewWindow(kDocumentWindowClass,windowAttrs,&contentRect,&query->sender->carbonWindow)!=noErr) {
 
10301
                query->success = false;
 
10302
                cimg::warn("CImgDisplay::_events_thread() : CreateNewWindow() failed.");
 
10303
              }
 
10304
              // Send it to the foreground
 
10305
              if (RepositionWindow(query->sender->carbonWindow,0,kWindowCenterOnMainScreen)!=noErr) query->success = false;
 
10306
              // Show it, if needed
 
10307
              if (!query->createClosedWindow) ShowWindow(query->sender->carbonWindow);
 
10308
 
 
10309
              // Associate a valid event handler
 
10310
              EventTypeSpec eventList[] = {
 
10311
                { kEventClassWindow, kEventWindowClose },
 
10312
                { kEventClassWindow, kEventWindowResizeStarted },
 
10313
                { kEventClassWindow, kEventWindowResizeCompleted },
 
10314
                { kEventClassWindow, kEventWindowDragStarted},
 
10315
                { kEventClassWindow, kEventWindowDragCompleted },
 
10316
                { kEventClassWindow, kEventWindowPaint },
 
10317
                { kEventClassWindow, kEventWindowBoundsChanging },
 
10318
                { kEventClassWindow, kEventWindowCollapsed },
 
10319
                { kEventClassWindow, kEventWindowExpanded },
 
10320
                { kEventClassWindow, kEventWindowZoomed },
 
10321
                { kEventClassKeyboard, kEventRawKeyDown },
 
10322
                { kEventClassKeyboard, kEventRawKeyUp },
 
10323
                { kEventClassKeyboard, kEventRawKeyRepeat },
 
10324
                { kEventClassKeyboard, kEventRawKeyModifiersChanged },
 
10325
                { kEventClassMouse, kEventMouseMoved },
 
10326
                { kEventClassMouse, kEventMouseDown },
 
10327
                { kEventClassMouse, kEventMouseUp },
 
10328
                { kEventClassMouse, kEventMouseDragged }
 
10329
              };
 
10330
 
 
10331
              // Set up the handler
 
10332
              if (InstallWindowEventHandler(query->sender->carbonWindow,NewEventHandlerUPP(CarbonEventHandler),GetEventTypeCount(eventList),
 
10333
                                            eventList,(void*)query->sender,0)!=noErr) {
 
10334
                query->success = false;
 
10335
                cimg::warn("CImgDisplay::_events_thread() : InstallWindowEventHandler failed.");
 
10336
              }
 
10337
 
 
10338
              // Paint
 
10339
              query->sender->paint();
 
10340
            } break;
 
10341
            default:
 
10342
              cimg::warn("CImgDisplay::_events_thread() : Received unknow code %d.",query->kind);
 
10343
            }
 
10344
            // Signal that the message has been processed
 
10345
            MPSignalSemaphore(c.sync_event);
 
10346
          }
 
10347
        }
 
10348
      }
 
10349
      // If we are here, the application is now finished
 
10350
      pthread_exit(0);
 
10351
    }
 
10352
 
 
10353
    CImgDisplay& assign() {
 
10354
      if (!is_empty()) {
 
10355
        cimg::CarbonInfo& c = cimg::CarbonAttr();
 
10356
        // Destroy the window associated to the display
 
10357
        _CbFreeAttachedWindow(c);
 
10358
        // Don't destroy the background thread here.
 
10359
        // If you check whether _CbFreeAttachedWindow() returned true,
 
10360
        //   - saying that there were no window left on screen - and
 
10361
        //   you destroy the background thread here, ReceiveNextEvent won't
 
10362
        //   work anymore if you create a new window after. So the
 
10363
        //  background thread must be killed (pthread_cancel() + pthread_join())
 
10364
        //   only on the application shutdown.
 
10365
 
 
10366
        // Finalize graphics
 
10367
        _CbFinalizeGraphics();
 
10368
 
 
10369
        // Do some cleanup
 
10370
        if (data) delete[] data;
 
10371
        if (title) delete[] title;
 
10372
        width = height = normalization = window_width = window_height = 0;
 
10373
        window_x = window_y = 0;
 
10374
        is_fullscreen = false;
 
10375
        is_closed = true;
 
10376
        min = max = 0;
 
10377
        title = 0;
 
10378
        flush();
 
10379
        if (MPDeleteCriticalRegion(paintCriticalRegion)!=noErr)
 
10380
          throw CImgDisplayException("CImgDisplay()::assign() : MPDeleteCriticalRegion failed.");
 
10381
      }
 
10382
      return *this;
 
10383
    }
 
10384
 
 
10385
    CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
 
10386
                         const unsigned int normalization_type=3,
 
10387
                         const bool fullscreen_flag=false, const bool closed_flag=false) {
 
10388
      cimg::CarbonInfo& c = cimg::CarbonAttr();
 
10389
 
 
10390
      // Allocate space for window title
 
10391
      const int s = cimg::strlen(ptitle)+1;
 
10392
      char *tmp_title = s?new char[s]:0;
 
10393
      if (s) std::memcpy(tmp_title,ptitle,s*sizeof(char));
 
10394
 
 
10395
      // Destroy previous window if existing
 
10396
      if (!is_empty()) assign();
 
10397
 
 
10398
      // Set display variables
 
10399
      width = cimg::min(dimw,(unsigned int)screen_dimx());
 
10400
      height = cimg::min(dimh,(unsigned int)screen_dimy());
 
10401
      normalization = normalization_type<4?normalization_type:3;
 
10402
      is_fullscreen = fullscreen_flag;
 
10403
      is_closed = closed_flag;
 
10404
      lastKeyModifiers = 0;
 
10405
      title = tmp_title;
 
10406
      flush();
 
10407
 
 
10408
      // Create the paint CR
 
10409
      if (MPCreateCriticalRegion(&paintCriticalRegion) != noErr)
 
10410
        throw CImgDisplayException("CImgDisplay::_assign() : MPCreateCriticalRegion() failed.");
 
10411
 
 
10412
      // Create the thread if it's not already created
 
10413
      if (c.event_thread==0) {
 
10414
        // Background thread does not exists, so create it !
 
10415
        if (pthread_create(&c.event_thread,0,_events_thread,0)!=0)
 
10416
          throw CImgDisplayException("CImgDisplay::_assign() : pthread_create() failed.");
 
10417
        // Wait for thread initialization
 
10418
        MPWaitOnSemaphore(c.sync_event, kDurationForever);
 
10419
      }
 
10420
 
 
10421
      // Init disp. graphics
 
10422
      data = new unsigned int[width*height];
 
10423
      _CbInitializeGraphics();
 
10424
 
 
10425
      // Now ask the thread to create the window
 
10426
      _CbCreateAttachedWindow(c,ptitle,fullscreen_flag,closed_flag);
6760
10427
      return *this;
6761
10428
    }
6762
10429
 
6783
10450
 
6784
10451
     \par Image representation
6785
10452
 
6786
 
     A %CImg image is defined as an instance of the container \ref CImg<T>, which contains a regular grid of pixels,
 
10453
     A %CImg image is defined as an instance of the container \ref CImg<\c T>, which contains a regular grid of pixels,
6787
10454
     each pixel value being of type \c T. The image grid can have up to 4 dimensions : width, height, depth
6788
10455
     and number of channels.
6789
10456
     Usually, the three first dimensions are used to describe spatial coordinates <tt>(x,y,z)</tt>, while the number of channels
6790
10457
     is rather used as a vector-valued dimension (it may describe the R,G,B color channels for instance).
6791
 
     If you need a fifth dimension, you can use image lists \ref CImgList<T> rather than simple images \ref CImg<T>.
 
10458
     If you need a fifth dimension, you can use image lists \ref CImgList<\c T> rather than simple images \ref CImg<\c T>.
6792
10459
 
6793
 
     Thus, the \ref CImg<T> class is able to represent volumetric images of vector-valued pixels,
 
10460
     Thus, the \ref CImg<\c T> class is able to represent volumetric images of vector-valued pixels,
6794
10461
     as well as images with less dimensions (1D scalar signal, 2D color images, ...).
6795
 
     Most member functions of the class CImg<T> are designed to handle this maximum case of (3+1) dimensions.
 
10462
     Most member functions of the class CImg<\c T> are designed to handle this maximum case of (3+1) dimensions.
6796
10463
 
6797
10464
     Concerning the pixel value type \c T :
6798
10465
     fully supported template types are the basic C++ types : <tt>unsigned char, char, short, unsigned int, int,
6805
10472
 
6806
10473
     \par Image structure
6807
10474
 
6808
 
     The \ref CImg<\c T> structure contains \a five fields :
 
10475
     The \ref CImg<\c T> structure contains \a six fields :
6809
10476
     - \ref width defines the number of \a columns of the image (size along the X-axis).
6810
10477
     - \ref height defines the number of \a rows of the image (size along the Y-axis).
6811
10478
     - \ref depth defines the number of \a slices of the image (size along the Z-axis).
6812
10479
     - \ref dim defines the number of \a channels of the image (size along the V-axis).
6813
10480
     - \ref data defines a \a pointer to the \a pixel \a data (of type \c T).
 
10481
     - \ref is_shared is a boolean that tells if the memory buffer \ref data is shared with
 
10482
       another image.
6814
10483
 
6815
10484
     You can access these fields publicly although it is recommended to use the dedicated functions
6816
10485
     dimx(), dimy(), dimz(), dimv() and ptr() to do so.
6845
10514
         - <tt>CImg<unsigned char> img("image.jpg");</tt> reads a JPEG color image from the file "image.jpg".
6846
10515
         - <tt>CImg<float> img("analyze.hdr");</tt> reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr".
6847
10516
         - \b Note : You need to install <a href="http://www.imagemagick.org">ImageMagick</a>
6848
 
         to be able to read common compressed image formats (JPG,PNG,...) (See \ref cimg_files_io).
 
10517
         to be able to read common compressed image formats (JPG,PNG, ...) (See \ref cimg_files_io).
6849
10518
 
6850
10519
     - Construct images from C-style arrays :
6851
10520
         - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer
6859
10528
 
6860
10529
     \par Most useful functions
6861
10530
 
6862
 
     The \ref CImg<T> class contains a lot of functions that operates on images.
 
10531
     The \ref CImg<\c T> class contains a lot of functions that operates on images.
6863
10532
     Some of the most useful are :
6864
10533
 
6865
10534
     - operator()(), operator[]() : allows to access or write pixel values.
6866
10535
     - display() : displays the image in a new window.
6867
 
 
6868
 
     \sa CImgList, CImgStats, CImgDisplay, CImgException.
6869
 
 
6870
10536
  **/
6871
10537
  template<typename T> struct CImg {
6872
10538
 
6938
10604
    //! Get value type
6939
10605
    typedef T value_type;
6940
10606
 
 
10607
    // Define common T-dependant types.
 
10608
    typedef typename cimg::superset<T,unsigned char>::type Tuchar;
 
10609
    typedef typename cimg::superset<T,int>::type Tint;
 
10610
    typedef typename cimg::superset<T,float>::type Tfloat;
 
10611
    typedef typename cimg::superset<T,float>::type Tdouble;
 
10612
 
6941
10613
    //@}
6942
10614
    //---------------------------
6943
10615
    //
6947
10619
#ifdef cimg_plugin
6948
10620
#include cimg_plugin
6949
10621
#endif
 
10622
#ifdef cimg_plugin1
 
10623
#include cimg_plugin1
 
10624
#endif
 
10625
#ifdef cimg_plugin2
 
10626
#include cimg_plugin2
 
10627
#endif
 
10628
#ifdef cimg_plugin3
 
10629
#include cimg_plugin3
 
10630
#endif
 
10631
#ifdef cimg_plugin4
 
10632
#include cimg_plugin4
 
10633
#endif
 
10634
#ifdef cimg_plugin5
 
10635
#include cimg_plugin5
 
10636
#endif
 
10637
#ifdef cimg_plugin6
 
10638
#include cimg_plugin6
 
10639
#endif
 
10640
#ifdef cimg_plugin7
 
10641
#include cimg_plugin7
 
10642
#endif
 
10643
#ifdef cimg_plugin8
 
10644
#include cimg_plugin8
 
10645
#endif
 
10646
#ifndef cimg_plugin_greycstoration
 
10647
#define cimg_plugin_greycstoration_count
 
10648
#endif
 
10649
#ifndef cimg_plugin_greycstoration_lock
 
10650
#define cimg_plugin_greycstoration_lock
 
10651
#endif
 
10652
#ifndef cimg_plugin_greycstoration_unlock
 
10653
#define cimg_plugin_greycstoration_unlock
 
10654
#endif
 
10655
 
6950
10656
    //@}
6951
10657
 
6952
10658
    //--------------------------------------
6955
10661
    //@{
6956
10662
    //--------------------------------------
6957
10663
 
 
10664
    //! Destructor.
 
10665
    /**
 
10666
       The destructor destroys the instance image.
 
10667
       \remark
 
10668
       - Destructing an empty or shared image does nothing.
 
10669
       - Otherwise, all memory used to store the pixel data of the instance image is freed.
 
10670
       - When destroying a non-shared image, be sure that every shared instances of the same image are
 
10671
       also destroyed to avoid further access to desallocated memory buffers.
 
10672
    **/
 
10673
    ~CImg() {
 
10674
      if (data && !is_shared) delete[] data;
 
10675
    }
 
10676
 
6958
10677
    //! Default constructor.
6959
10678
    /**
6960
10679
       The default constructor creates an empty instance image.
6962
10681
       - An empty image does not contain any data and has all of its dimensions \ref width, \ref height, \ref depth, \ref dim
6963
10682
       set to 0 as well as its pointer to the pixel buffer \ref data.
6964
10683
       - An empty image is non-shared.
6965
 
       \see ~CImg(), assign(), is_empty().
6966
10684
    **/
6967
10685
    CImg():
6968
10686
      width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {}
6969
10687
 
6970
 
    //! Destructor.
6971
 
    /**
6972
 
       The destructor destroys the instance image.
6973
 
       \remark
6974
 
       - Destructing an empty or shared image does nothing.
6975
 
       - Otherwise, all memory used to store the pixel data of the instance image is freed.
6976
 
       - When destroying a non-shared image, be sure that every shared instances of the same image are
6977
 
       also destroyed to avoid further access to desallocated memory buffers.
6978
 
       \see CImg(), assign(), is_empty().
6979
 
    **/
6980
 
    ~CImg() {
6981
 
      if (data && !is_shared) delete[] data;
6982
 
    }
6983
 
 
6984
 
    //! In-place version of the default constructor.
6985
 
    /**
6986
 
       This function replaces the instance image by an empty image.
6987
 
       \remark
6988
 
       - Memory used by the previous content of the instance image is freed if necessary.
6989
 
       - If the instance image was initially shared, it is replaced by a (non-shared) empty image.
6990
 
       - This function is useful to free memory used by an image that is not of use, but which
6991
 
       has been created in the current code scope (i.e. not destroyed yet).
6992
 
       \see ~CImg(), assign(), is_empty().
6993
 
    **/
6994
 
    CImg& assign() {
6995
 
      if (data && !is_shared) delete[] data;
6996
 
      width = height = depth = dim = 0; is_shared = false; data = 0;
6997
 
      return *this;
6998
 
    }
6999
 
 
7000
 
    //! In-place version of the default constructor.
7001
 
    /**
7002
 
       This function is strictly equivalent to \ref assign() and has been
7003
 
       introduced for having a STL-compliant function name.
7004
 
       \see assign().
7005
 
    **/
7006
 
    CImg& clear() {
7007
 
      return assign();
7008
 
    }
7009
 
 
7010
 
    //! Default copy constructor.
 
10688
    //! Constructs a new image with given size (\p dx,\p dy,\p dz,\p dv).
 
10689
    /**
 
10690
       This constructors create an instance image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T.
 
10691
       \param dx Desired size along the X-axis, i.e. the \ref width of the image.
 
10692
       \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
 
10693
       \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
 
10694
       \param dv Desired size along the V-axis, i.e. the number of image channels \ref dim.
 
10695
       \remark
 
10696
       - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the created image is empty
 
10697
       and all has its dimensions set to 0. No memory for pixel data is then allocated.
 
10698
       - This constructor creates only non-shared images.
 
10699
       - Image pixels allocated by this constructor are \b not \b initialized.
 
10700
       Use the constructor CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
 
10701
       to get an image of desired size with pixels set to a particular value.
 
10702
    **/
 
10703
    explicit CImg(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1):
 
10704
      is_shared(false) {
 
10705
      const unsigned long siz = dx*dy*dz*dv;
 
10706
      if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; }
 
10707
      else { width = height = depth = dim = 0; data = 0; }
 
10708
    }
 
10709
 
 
10710
    //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with pixel having a default value \p val.
 
10711
    /**
 
10712
       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
 
10713
       values of the created instance image to \p val.
 
10714
       \param dx Desired size along the X-axis, i.e. the \ref width of the image.
 
10715
       \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
 
10716
       \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
 
10717
       \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
 
10718
       \param val Default value for image pixels.
 
10719
       \remark
 
10720
       - This constructor has the same properties as CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
 
10721
    **/
 
10722
    CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val):
 
10723
      is_shared(false) {
 
10724
      const unsigned long siz = dx*dy*dz*dv;
 
10725
      if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(val); }
 
10726
      else { width = height = depth = dim = 0; data = 0; }
 
10727
    }
 
10728
 
 
10729
    //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (int version).
 
10730
    CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 
10731
         const int val0, const int val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 
10732
#define _CImg_stdarg(img,a0,a1,N,t) { \
 
10733
        unsigned int _siz = (unsigned int)N; \
 
10734
        if (_siz--) { \
 
10735
          va_list ap; \
 
10736
          va_start(ap,a1); \
 
10737
          T *ptrd = (img).data; \
 
10738
          *(ptrd++) = (T)a0; \
 
10739
          if (_siz--) { \
 
10740
            *(ptrd++) = (T)a1; \
 
10741
            for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \
 
10742
          } \
 
10743
          va_end(ap); \
 
10744
        }}
 
10745
      assign(dx,dy,dz,dv);
 
10746
      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
 
10747
    }
 
10748
 
 
10749
    //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (double version).
 
10750
    CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 
10751
         const double val0, const double val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 
10752
      assign(dx,dy,dz,dv);
 
10753
      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
 
10754
    }
 
10755
 
 
10756
    //! Construct an image with given size and with specified values given in a string.
 
10757
    CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 
10758
         const char *const values, const bool repeat_pattern):is_shared(false) {
 
10759
      const unsigned long siz = dx*dy*dz*dv;
 
10760
      if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(values,repeat_pattern); }
 
10761
      else { width = height = depth = dim = 0; data = 0; }
 
10762
    }
 
10763
 
 
10764
    //! Construct an image from a raw memory buffer.
 
10765
    /**
 
10766
       This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dv) and fill its pixel buffer by
 
10767
       copying data values from the input raw pixel buffer \p data_buffer.
 
10768
    **/
 
10769
    template<typename t> CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 
10770
                              const unsigned int dz=1, const unsigned int dv=1, const bool shared=false):is_shared(false) {
 
10771
      if (shared) throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a (%s*) buffer "
 
10772
                                              "(different pixel types).",pixel_type(),CImg<t>::pixel_type());
 
10773
      const unsigned long siz = dx*dy*dz*dv;
 
10774
      if (data_buffer && siz) {
 
10775
        width = dx; height = dy; depth = dz; dim = dv; data = new T[siz];
 
10776
        const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 
10777
      } else { width = height = depth = dim = 0; data = 0; }
 
10778
    }
 
10779
 
 
10780
#ifndef cimg_use_visualcpp6
 
10781
    CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 
10782
         const unsigned int dz=1, const unsigned int dv=1, const bool shared=false) {
 
10783
#else
 
10784
    CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
 
10785
         const unsigned int dz, const unsigned int dv, const bool shared) {
 
10786
#endif
 
10787
      const unsigned long siz = dx*dy*dz*dv;
 
10788
      if (data_buffer && siz) {
 
10789
        width = dx; height = dy; depth = dz; dim = dv; is_shared = shared;
 
10790
        if (is_shared) data = const_cast<T*>(data_buffer);
 
10791
        else { data = new T[siz]; std::memcpy(data,data_buffer,siz*sizeof(T)); }
 
10792
      } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
 
10793
    }
 
10794
 
 
10795
   //! Default copy constructor.
7011
10796
    /**
7012
10797
       The default copy constructor creates a new instance image having same dimensions
7013
10798
       (\ref width, \ref height, \ref depth, \ref dim) and same pixel values as the input image \p img.
7024
10809
       - Copying an image having a different template type \p t != \p T performs a crude static cast conversion of each pixel value from
7025
10810
       type \p t to type \p T.
7026
10811
       - Copying an image having the same template type \p t == \p T is significantly faster.
7027
 
       \see assign(const CImg< t >&), CImg(const CImg< t >&, const bool).
7028
10812
    **/
7029
10813
    template<typename t> CImg(const CImg<t>& img):is_shared(false) {
7030
10814
      const unsigned int siz = img.size();
7031
10815
      if (img.data && siz) {
7032
10816
        width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
7033
 
        const t *ptrs = img.data+siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 
10817
        const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
7034
10818
      } else { width = height = depth = dim = 0; data = 0; }
7035
10819
    }
7036
10820
 
7037
 
    CImg(const CImg& img) {
 
10821
    CImg(const CImg<T>& img) {
7038
10822
      const unsigned int siz = img.size();
7039
10823
      if (img.data && siz) {
7040
10824
        width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = img.is_shared;
7043
10827
      } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
7044
10828
    }
7045
10829
 
7046
 
    //! In-place version of the default copy constructor.
7047
 
    /**
7048
 
       This function assigns a copy of the input image \p img to the current instance image.
7049
 
       \param img The input image to copy.
7050
 
       \remark
7051
 
       - If the instance image is not shared, the content of the input image \p img is copied into a new buffer
7052
 
       becoming the new pixel buffer of the instance image, while the old pixel buffer is freed if necessary.
7053
 
       - If the instance image is shared, the content of the input image \p img is copied into the current (shared) pixel buffer
7054
 
       of the instance image, modifying then the image referenced by the shared instance image. The instance image still remains shared.
7055
 
       \see CImg(const CImg< t >&), operator=(const CImg< t >&).
7056
 
    **/
7057
 
    template<typename t> CImg& assign(const CImg<t>& img) {
7058
 
      return assign(img.data,img.width,img.height,img.depth,img.dim);
7059
 
    }
7060
 
 
7061
 
    //! Advanced copy constructor.
 
10830
   //! Advanced copy constructor.
7062
10831
    /**
7063
10832
       The advanced copy constructor - as the default constructor CImg(const CImg< t >&) - creates a new instance image having same dimensions
7064
10833
       \ref width, \ref height, \ref depth, \ref dim and same pixel values as the input image \p img.
7071
10840
       - If a non-shared copy of the input image \p img is created, a new memory buffer is allocated for pixel data.
7072
10841
       - If a shared copy of the input image \p img is created, no extra memory is allocated and the pixel buffer of the instance
7073
10842
       image is the same as the one used by the input image \p img.
7074
 
       \see CImg(const CImg<t>&), assign(const CImg<t>&, const bool).
7075
10843
    **/
7076
10844
    template<typename t> CImg(const CImg<t>& img, const bool shared):is_shared(false) {
7077
 
      if (shared) throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared copy from a CImg<%s> image "
 
10845
      if (shared) throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a CImg<%s> instance "
7078
10846
                                              "(different pixel types).",pixel_type(),CImg<t>::pixel_type());
7079
10847
      const unsigned int siz = img.size();
7080
10848
      if (img.data && siz) {
7081
10849
        width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
7082
 
        const t *ptrs = img.data+siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 
10850
        const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
7083
10851
      } else { width = height = depth = dim = 0; data = 0; }
7084
10852
    }
7085
10853
 
7086
 
    CImg(const CImg& img, const bool shared) {
 
10854
    CImg(const CImg<T>& img, const bool shared) {
7087
10855
      const unsigned int siz = img.size();
7088
10856
      if (img.data && siz) {
7089
10857
        width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = shared;
7092
10860
      } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
7093
10861
    }
7094
10862
 
7095
 
    //! In-place version of the advanced constructor.
7096
 
    /**
7097
 
       This function - as the simpler function assign(const CImg< t >&) - assigns a copy of the input image \p img to the
7098
 
       current instance image. But it also decides if the copy is shared (if the input parameter \p shared is set to \true) or non-shared
7099
 
       (if the input parameter \p shared is set to false).
7100
 
       \param img The input image to copy.
7101
 
       \param shared Boolean flag that decides if the copy is shared or non-shared.
7102
 
       \remark
7103
 
       - 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.
7104
 
       - If a non-shared copy of the input image \p img is assigned, a new memory buffer is allocated for pixel data.
7105
 
       - If a shared copy of the input image \p img is assigned, no extra memory is allocated and the pixel buffer of the instance
7106
 
       image is the same as the one used by the input image \p img.
7107
 
       \see CImg(const CImg<t>&, const bool), assign(const CImg< t >&).
7108
 
    **/
7109
 
    template<typename t> CImg& assign(const CImg<t>& img, const bool shared) {
7110
 
      return assign(img.data,img.width,img.height,img.depth,img.dim,shared);
7111
 
    }
7112
 
 
7113
 
    //! Constructs a new image with given size (\p dx,\p dy,\p dz,\p dv).
7114
 
    /**
7115
 
       This constructors create an instance image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T.
7116
 
       \param dx Desired size along the X-axis, i.e. the \ref width of the image.
7117
 
       \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
7118
 
       \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
7119
 
       \param dv Desired size along the V-axis, i.e. the number of image channels \ref dim.
7120
 
       \remark
7121
 
       - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the created image is empty
7122
 
       and all has its dimensions set to 0. No memory for pixel data is then allocated.
7123
 
       - This constructor creates only non-shared images.
7124
 
       - Image pixels allocated by this constructor are \b not \b initialized.
7125
 
       Use the constructor CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T&)
7126
 
       to get an image of desired size with pixels set to a particular value.
7127
 
       \see assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int),
7128
 
       CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T&).
7129
 
    **/
7130
 
    explicit CImg(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1):
7131
 
      is_shared(false) {
7132
 
      const unsigned int siz = dx*dy*dz*dv;
7133
 
      if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; }
7134
 
      else { width = height = depth = dim = 0; data = 0; }
 
10863
    //! Construct an image using dimensions of another image
 
10864
    template<typename t> CImg(const CImg<t>& img, const char *const dimensions):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 
10865
      assign(img,dimensions);
 
10866
    }
 
10867
 
 
10868
    //! Construct an image using dimensions of another image, and fill it with a default value
 
10869
    template<typename t> CImg(const CImg<t>& img, const char *const dimensions, const T val):
 
10870
      width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 
10871
      assign(img,dimensions).fill(val);
 
10872
    }
 
10873
 
 
10874
   //! Construct an image from an image file.
 
10875
    /**
 
10876
       This constructor creates an instance image by reading it from a file.
 
10877
       \param filename Filename of the image file.
 
10878
       \remark
 
10879
       - The image format is deduced from the filename only by looking for the filename extension i.e. without
 
10880
       analyzing the file itself.
 
10881
       - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
 
10882
       More informations on this topic can be found in cimg_files_io.
 
10883
       - If the filename is not found, a CImgIOException is thrown by this constructor.
 
10884
    **/
 
10885
    CImg(const char *const filename):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 
10886
      assign(filename);
 
10887
    }
 
10888
 
 
10889
    //! Construct an image from the content of a CImgDisplay instance.
 
10890
    CImg(const CImgDisplay &disp):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
 
10891
      disp.snapshot(*this);
 
10892
    }
 
10893
 
 
10894
    //! In-place version of the default constructor/destructor.
 
10895
    /**
 
10896
       This function replaces the instance image by an empty image.
 
10897
       \remark
 
10898
       - Memory used by the previous content of the instance image is freed if necessary.
 
10899
       - If the instance image was initially shared, it is replaced by a (non-shared) empty image.
 
10900
       - This function is useful to free memory used by an image that is not of use, but which
 
10901
       has been created in the current code scope (i.e. not destroyed yet).
 
10902
    **/
 
10903
    CImg<T>& assign() {
 
10904
      if (data && !is_shared) delete[] data;
 
10905
      width = height = depth = dim = 0; is_shared = false; data = 0;
 
10906
      return *this;
 
10907
    }
 
10908
 
 
10909
    //! In-place version of the default constructor.
 
10910
    /**
 
10911
       This function is strictly equivalent to \ref assign() and has been
 
10912
       introduced for having a STL-compliant function name.
 
10913
    **/
 
10914
    CImg<T>& clear() {
 
10915
      return assign();
7135
10916
    }
7136
10917
 
7137
10918
    //! In-place version of the previous constructor.
7147
10928
       - If the instance image is shared, this constructor actually does nothing more than verifying
7148
10929
       that new and old image dimensions fit.
7149
10930
       - Image pixels allocated by this function are \b not \b initialized.
7150
 
       Use the function assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T&)
 
10931
       Use the function assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
7151
10932
       to assign an image of desired size with pixels set to a particular value.
7152
 
       \see CImg(), assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
7153
10933
    **/
7154
 
    CImg& assign(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1) {
7155
 
      const unsigned long siz = dx*dy*dz*dv, curr_siz = size();
7156
 
      if (is_shared) {
7157
 
        if (siz!=curr_siz)
7158
 
          throw CImgArgumentException("CImg<%s>::assign() : Cannot assign image (%u,%u,%u,%u) to shared instance image (%u,%u,%u,%u,%p).",
7159
 
                                      pixel_type(),dx,dy,dz,dv,width,height,depth,dim,data);
7160
 
      } else {
7161
 
        if (siz) {
7162
 
          if (siz!=curr_siz) { if (data) delete[] data; data = new T[siz]; }
7163
 
          width = dx; height = dy; depth = dz; dim = dv;
7164
 
        } else {
7165
 
          if (data) delete[] data;
7166
 
          width = height = depth = dim = 0; data = 0;
7167
 
        }
 
10934
    CImg<T>& assign(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1) {
 
10935
      const unsigned long siz = dx*dy*dz*dv;
 
10936
      if (!siz) return assign();
 
10937
      const unsigned long curr_siz = size();
 
10938
      if (siz!=curr_siz) {
 
10939
        if (is_shared) throw CImgArgumentException("CImg<%s>::assign() : Cannot assign image (%u,%u,%u,%u) to shared instance image (%u,%u,%u,%u,%p).",
 
10940
                                                   pixel_type(),dx,dy,dz,dv,width,height,depth,dim,data);
 
10941
        else { if (data) delete[] data; data = new T[siz]; }
7168
10942
      }
 
10943
      width = dx; height = dy; depth = dz; dim = dv;
7169
10944
      return *this;
7170
10945
    }
7171
10946
 
7172
 
    //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with pixel having a default value \p val.
7173
 
    /**
7174
 
       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
7175
 
       values of the created instance image to \p val.
7176
 
       \param dx Desired size along the X-axis, i.e. the \ref width of the image.
7177
 
       \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
7178
 
       \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
7179
 
       \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
7180
 
       \param val Default value for image pixels.
7181
 
       \remark
7182
 
       - This constructor has the same properties as CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
7183
 
       \see CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
7184
 
    **/
7185
 
    CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T& val):
7186
 
      is_shared(false) {
7187
 
      const unsigned int siz = dx*dy*dz*dv;
7188
 
      if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(val); }
7189
 
      else { width = height = depth = dim = 0; data = 0; }
7190
 
    }
7191
 
 
7192
10947
    //! In-place version of the previous constructor.
7193
10948
    /**
7194
10949
       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
7200
10955
       \param val Default value for image pixels.
7201
10956
       \remark
7202
10957
       - This function has the same properties as assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
7203
 
       \see assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
7204
10958
    **/
7205
 
    CImg& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T& val) {
 
10959
    CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val) {
7206
10960
      return assign(dx,dy,dz,dv).fill(val);
7207
10961
    }
7208
10962
 
7209
 
    //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (int version).
7210
 
    CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
7211
 
         const int val0, const int val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
7212
 
      assign(dx,dy,dz,dv);
7213
 
      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
7214
 
    }
7215
 
 
7216
 
    //! In-place version of the previous constructor.
7217
 
    CImg& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
7218
 
                 const int val0, const int val1, ...) {
7219
 
      assign(dx,dy,dz,dv);
7220
 
      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
7221
 
      return *this;
7222
 
    }
7223
 
 
7224
 
    //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (double version).
7225
 
    CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
7226
 
         const double val0, const double val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
7227
 
      assign(dx,dy,dz,dv);
7228
 
      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
7229
 
    }
7230
 
 
7231
 
    //! In-place version of the previous constructor.
7232
 
    CImg& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
7233
 
                 const double val0, const double val1, ...) {
7234
 
      assign(dx,dy,dz,dv);
7235
 
      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
7236
 
      return *this;
7237
 
    }
7238
 
 
7239
 
    //! Construct an image from an image file.
7240
 
    /**
7241
 
       This constructor creates an instance image by reading it from a file.
7242
 
       \param filename Filename of the image file.
7243
 
       \remark
7244
 
       - The image format is deduced from the filename only by looking for the filename extension i.e. without
7245
 
       analyzing the file itself.
7246
 
       - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
7247
 
       More informations on this topic can be found in cimg_files_io.
7248
 
       - If the filename is not found, a CImgIOException is thrown by this constructor.
7249
 
       \see assign(const char *const), load(const char *const)
7250
 
    **/
7251
 
    CImg(const char *const filename):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
7252
 
      assign(filename);
 
10963
    //! In-place version of the previous constructor.
 
10964
    CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 
10965
                    const int val0, const int val1, ...) {
 
10966
      assign(dx,dy,dz,dv);
 
10967
      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
 
10968
      return *this;
 
10969
    }
 
10970
 
 
10971
    //! In-place version of the previous constructor.
 
10972
    CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
 
10973
                    const double val0, const double val1, ...) {
 
10974
      assign(dx,dy,dz,dv);
 
10975
      _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
 
10976
      return *this;
 
10977
    }
 
10978
 
 
10979
    //! In-place version of the previous constructor.
 
10980
    template<typename t> CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 
10981
                                         const unsigned int dz=1, const unsigned int dv=1) {
 
10982
      const unsigned long siz = dx*dy*dz*dv;
 
10983
      if (!data_buffer || !siz) return assign();
 
10984
      assign(dx,dy,dz,dv);
 
10985
      const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
 
10986
      return *this;
 
10987
    }
 
10988
 
 
10989
#ifndef cimg_use_visualcpp6
 
10990
    CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
 
10991
                    const unsigned int dz=1, const unsigned int dv=1) {
 
10992
#else
 
10993
    CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
 
10994
                    const unsigned int dz, const unsigned int dv) {
 
10995
#endif
 
10996
      const unsigned long siz = dx*dy*dz*dv;
 
10997
      if (!data_buffer || !siz) return assign();
 
10998
      const unsigned long curr_siz = size();
 
10999
      if (data_buffer==data && siz==curr_siz) return assign(dx,dy,dz,dv);
 
11000
      if (is_shared || data_buffer+siz<data || data_buffer>=data+size()) {
 
11001
        assign(dx,dy,dz,dv);
 
11002
        if (is_shared) std::memmove(data,data_buffer,siz*sizeof(T));
 
11003
        else std::memcpy(data,data_buffer,siz*sizeof(T));
 
11004
      } else {
 
11005
        T *new_data = new T[siz];
 
11006
        std::memcpy(new_data,data_buffer,siz*sizeof(T));
 
11007
        delete[] data; data = new_data; width = dx; height = dy; depth = dz; dim = dv;
 
11008
      }
 
11009
      return *this;
 
11010
    }
 
11011
 
 
11012
    //! In-place version of the previous constructor, allowing to force the shared state of the instance image.
 
11013
    template<typename t> CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy,
 
11014
                                         const unsigned int dz, const unsigned int dv, const bool shared) {
 
11015
      if (shared) throw CImgArgumentException("CImg<%s>::assign() : Cannot assign buffer (%s*) to shared instance image (%u,%u,%u,%u,%p)"
 
11016
                                              "(different pixel types).",pixel_type(),CImg<t>::pixel_type(),width,height,depth,dim,data);
 
11017
      return assign(data_buffer,dx,dy,dz,dv);
 
11018
    }
 
11019
 
 
11020
    CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
 
11021
                    const unsigned int dz, const unsigned int dv, const bool shared) {
 
11022
      const unsigned long siz = dx*dy*dz*dv;
 
11023
      if (!data_buffer || !siz) return assign();
 
11024
      if (!shared) { if (is_shared) assign(); assign(data_buffer,dx,dy,dz,dv); }
 
11025
      else {
 
11026
        if (!is_shared) {
 
11027
          if (data_buffer+siz<data || data_buffer>=data+size()) assign();
 
11028
          else cimg::warn("CImg<%s>::assign() : Shared instance image has overlapping memory !",pixel_type());
 
11029
        }
 
11030
        width = dx; height = dy; depth = dz; dim = dv; is_shared = true;
 
11031
        data = const_cast<T*>(data_buffer);
 
11032
      }
 
11033
      return *this;
 
11034
    }
 
11035
 
 
11036
    //! In-place version of the default copy constructor.
 
11037
    /**
 
11038
       This function assigns a copy of the input image \p img to the current instance image.
 
11039
       \param img The input image to copy.
 
11040
       \remark
 
11041
       - If the instance image is not shared, the content of the input image \p img is copied into a new buffer
 
11042
       becoming the new pixel buffer of the instance image, while the old pixel buffer is freed if necessary.
 
11043
       - If the instance image is shared, the content of the input image \p img is copied into the current (shared) pixel buffer
 
11044
       of the instance image, modifying then the image referenced by the shared instance image. The instance image still remains shared.
 
11045
    **/
 
11046
    template<typename t> CImg<T>& assign(const CImg<t>& img) {
 
11047
      return assign(img.data,img.width,img.height,img.depth,img.dim);
 
11048
    }
 
11049
 
 
11050
    //! In-place version of the advanced constructor.
 
11051
    /**
 
11052
       This function - as the simpler function assign(const CImg< t >&) - assigns a copy of the input image \p img to the
 
11053
       current instance image. But it also decides if the copy is shared (if the input parameter \p shared is set to \c true)
 
11054
       or non-shared (if the input parameter \p shared is set to \c false).
 
11055
       \param img The input image to copy.
 
11056
       \param shared Boolean flag that decides if the copy is shared or non-shared.
 
11057
       \remark
 
11058
       - 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.
 
11059
       - If a non-shared copy of the input image \p img is assigned, a new memory buffer is allocated for pixel data.
 
11060
       - If a shared copy of the input image \p img is assigned, no extra memory is allocated and the pixel buffer of the instance
 
11061
       image is the same as the one used by the input image \p img.
 
11062
    **/
 
11063
    template<typename t> CImg<T>& assign(const CImg<t>& img, const bool shared) {
 
11064
      return assign(img.data,img.width,img.height,img.depth,img.dim,shared);
 
11065
    }
 
11066
 
 
11067
    //! In-place version of the previous constructor.
 
11068
    template<typename t> CImg<T>& assign(const CImg<t>& img, const char *const dimensions) {
 
11069
      if (dimensions) {
 
11070
        unsigned int siz[4] = { 0,1,1,1 };
 
11071
        const char *s = dimensions;
 
11072
        char tmp[256] = { 0 }, c = 0;
 
11073
        int val = 0;
 
11074
        for (unsigned int k=0; k<4; ++k) {
 
11075
          const int err = std::sscanf(s,"%[-0-9]%c",tmp,&c);
 
11076
          if (err>=1) {
 
11077
            const int err = std::sscanf(s,"%d",&val);
 
11078
            if (err==1) {
 
11079
              int val2 = val<0?-val:(c=='%'?val:-1);
 
11080
              if (val2>=0) {
 
11081
                val = (int)((k==0?img.width:(k==1?img.height:(k==2?img.depth:img.dim)))*val2/100);
 
11082
                if (c!='%' && !val) val = 1;
 
11083
              }
 
11084
              siz[k] = val;
 
11085
            }
 
11086
            s+=cimg::strlen(tmp);
 
11087
            if (c=='%') ++s;
 
11088
          }
 
11089
          if (!err) {
 
11090
            if (!cimg::strncasecmp(s,"x",1)) { ++s; siz[k] = img.width; }
 
11091
            else if (!cimg::strncasecmp(s,"y",1)) { ++s; siz[k] = img.height; }
 
11092
            else if (!cimg::strncasecmp(s,"z",1)) { ++s; siz[k] = img.depth; }
 
11093
            else if (!cimg::strncasecmp(s,"v",1)) { ++s; siz[k] = img.dim; }
 
11094
            else if (!cimg::strncasecmp(s,"dx",2)) { s+=2; siz[k] = img.width; }
 
11095
            else if (!cimg::strncasecmp(s,"dy",2)) { s+=2; siz[k] = img.height; }
 
11096
            else if (!cimg::strncasecmp(s,"dz",2)) { s+=2; siz[k] = img.depth; }
 
11097
            else if (!cimg::strncasecmp(s,"dv",2)) { s+=2; siz[k] = img.dim; }
 
11098
            else if (!cimg::strncasecmp(s,"dimx",4)) { s+=4; siz[k] = img.width; }
 
11099
            else if (!cimg::strncasecmp(s,"dimy",4)) { s+=4; siz[k] = img.height; }
 
11100
            else if (!cimg::strncasecmp(s,"dimz",4)) { s+=4; siz[k] = img.depth; }
 
11101
            else if (!cimg::strncasecmp(s,"dimv",4)) { s+=4; siz[k] = img.dim; }
 
11102
            else if (!cimg::strncasecmp(s,"width",5)) { s+=5; siz[k] = img.width; }
 
11103
            else if (!cimg::strncasecmp(s,"height",6)) { s+=6; siz[k] = img.height; }
 
11104
            else if (!cimg::strncasecmp(s,"depth",5)) { s+=5; siz[k] = img.depth; }
 
11105
            else if (!cimg::strncasecmp(s,"dim",3)) { s+=3; siz[k] = img.dim; }
 
11106
            else { ++s; --k; }
 
11107
          }
 
11108
        }
 
11109
        return assign(siz[0],siz[1],siz[2],siz[3]);
 
11110
      }
 
11111
      return assign();
 
11112
    }
 
11113
 
 
11114
    //! In-place version of the previous constructor.
 
11115
    template<typename t> CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T val) {
 
11116
      return assign(img,dimensions).fill(val);
7253
11117
    }
7254
11118
 
7255
11119
    //! In-place version of the previous constructor.
7262
11126
       More informations on this topic can be found in cimg_files_io.
7263
11127
       - If the filename is not found, a CImgIOException is thrown by this constructor.
7264
11128
    **/
7265
 
    CImg& assign(const char *const filename) {
 
11129
    CImg<T>& assign(const char *const filename) {
7266
11130
      return load(filename);
7267
11131
    }
7268
11132
 
7269
 
    //! Construct an image from raw memory buffer.
 
11133
    //! In-place version of the previous constructor.
 
11134
    CImg<T>& assign(const CImgDisplay &disp) {
 
11135
      disp.snapshot(*this);
 
11136
      return *this;
 
11137
    }
 
11138
 
 
11139
    //! Transfer the content of the instance image into another one in a way that memory copies are avoided if possible.
7270
11140
    /**
7271
 
       This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dv) and fill its pixel buffer by
7272
 
       copying data values from the input raw pixel buffer \p data_buffer.
 
11141
       The instance image is always empty after a call to this function.
7273
11142
    **/
7274
 
    template<typename t> CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
7275
 
                              const unsigned int dz=1, const unsigned int dv=1, const bool shared=false):is_shared(false) {
7276
 
      if (shared) throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared copy from a (%s*) buffer "
7277
 
                                              "(different pixel types).",pixel_type(),CImg<t>::pixel_type());
7278
 
      const unsigned int siz = dx*dy*dz*dv;
7279
 
      if (data_buffer && siz) {
7280
 
        width = dx; height = dy; depth = dz; dim = dv; data = new T[siz];
7281
 
        const t *ptrs = data_buffer+siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
7282
 
      } else { width = height = depth = dim = 0; data = 0; }
7283
 
    }
7284
 
 
7285
 
#ifdef cimg_use_visualcpp6
7286
 
    CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
7287
 
         const unsigned int dz, const unsigned int dv, const bool shared) {
7288
 
#else
7289
 
    CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
7290
 
         const unsigned int dz=1, const unsigned int dv=1, const bool shared=false) {
7291
 
#endif
7292
 
      const unsigned int siz = dx*dy*dz*dv;
7293
 
      if (data_buffer && siz) {
7294
 
        width = dx; height = dy; depth = dz; dim = dv; is_shared = shared;
7295
 
        if (is_shared) data = const_cast<T*>(data_buffer);
7296
 
        else { data = new T[siz]; std::memcpy(data,data_buffer,siz*sizeof(T)); }
7297
 
      } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
7298
 
    }
7299
 
 
7300
 
    //! In-place version of the previous constructor.
7301
 
#ifdef cimg_use_visualcpp6
7302
 
    template<typename t> CImg& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy,
7303
 
                                      const unsigned int dz, const unsigned int dv) {
7304
 
#else
7305
 
    template<typename t> CImg& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
7306
 
                                      const unsigned int dz=1, const unsigned int dv=1) {
7307
 
#endif
7308
 
      assign(dx,dy,dz,dv);
7309
 
      const unsigned int siz = dx*dy*dz*dv;
7310
 
      if (data_buffer && siz) { const t *ptrs = data_buffer+siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs); }
7311
 
      else { width = height = depth = dim = 0; is_shared = false; data = 0; }
7312
 
      return *this;
7313
 
    }
7314
 
 
7315
 
    CImg& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
7316
 
                 const unsigned int dz=1, const unsigned int dv=1) {
7317
 
      assign(dx,dy,dz,dv);
7318
 
      const unsigned int siz = dx*dy*dz*dv;
7319
 
      if (data_buffer && siz) std::memcpy(data,data_buffer,siz*sizeof(T));
7320
 
      else { width = height = depth = dim = 0; is_shared = false; data = 0; }
7321
 
      return *this;
7322
 
    }
7323
 
 
7324
 
    //! In-place version of the previous constructor, allowing to force the shared state of the instance image.
7325
 
    template<typename t> CImg& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy,
7326
 
                                      const unsigned int dz, const unsigned int dv, const bool shared) {
7327
 
      if (shared) throw CImgArgumentException("CImg<%s>::assign() : Cannot define a shared copy from a CImg<%s> image "
7328
 
                                              "(different pixel types).",pixel_type(),CImg<t>::pixel_type());
7329
 
      if (data && !is_shared) delete[] data;
7330
 
      is_shared = false;
7331
 
      const unsigned int siz = dx*dy*dz*dv;
7332
 
      if (data_buffer && siz) {
7333
 
        width = dx; height = dy; depth = dz; dim = dv; data = new T[siz];
7334
 
        const t *ptrs = data_buffer+siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
7335
 
      } else { width = height = depth = dim = 0; data = 0; }
7336
 
      return *this;
7337
 
    }
7338
 
 
7339
 
    CImg& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
7340
 
                 const unsigned int dz, const unsigned int dv, const bool shared) {
7341
 
      if (data && !is_shared) delete[] data;
7342
 
      const unsigned int siz = dx*dy*dz*dv;
7343
 
      if (data_buffer && siz) {
7344
 
        width = dx; height = dy; depth = dz; dim = dv; is_shared = shared;
7345
 
        if (is_shared) data = const_cast<T*>(data_buffer);
7346
 
        else { data = new T[siz]; std::memcpy(data,data_buffer,siz*sizeof(T)); }
7347
 
      } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
7348
 
      return *this;
7349
 
    }
7350
 
 
7351
 
    //! Construct an image from the content of a CImgDisplay instance.
7352
 
    CImg(const CImgDisplay &disp):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
7353
 
      disp.snapshot(*this);
7354
 
    }
7355
 
 
7356
 
    //! In-place version of the previous constructor.
7357
 
    CImg& assign(const CImgDisplay &disp) {
7358
 
      disp.snapshot(*this);
7359
 
      return *this;
7360
 
    }
7361
 
 
7362
 
    // INNER ROUTINE : Swap fields of an image (use it carefully!)
7363
 
    // If one of the image is shared, its content is replaced by the non-shared image (which remains unchanged).
7364
 
    CImg& swap(CImg& img) {
7365
 
      if (img.is_shared==is_shared) {
7366
 
        cimg::swap(width,img.width);
7367
 
        cimg::swap(height,img.height);
7368
 
        cimg::swap(depth,img.depth);
7369
 
        cimg::swap(dim,img.dim);
7370
 
        cimg::swap(data,img.data);
7371
 
      } else {
7372
 
        if (img.is_shared) img.assign(*this);
7373
 
        else assign(img);
7374
 
      }
 
11143
    template<typename t> CImg<t>& transfer_to(CImg<t>& img) {
 
11144
      img.assign(*this);
 
11145
      assign();
 
11146
      return img;
 
11147
    }
 
11148
 
 
11149
    CImg<T>& transfer_to(CImg<T>& img) {
 
11150
      if (is_shared || img.is_shared) { img.assign(*this); assign(); } else { img.assign(); swap(img); }
 
11151
      return img;
 
11152
    }
 
11153
 
 
11154
    //! Swap all fields of two images. Use with care !
 
11155
    CImg<T>& swap(CImg<T>& img) {
 
11156
      cimg::swap(width,img.width);
 
11157
      cimg::swap(height,img.height);
 
11158
      cimg::swap(depth,img.depth);
 
11159
      cimg::swap(dim,img.dim);
 
11160
      cimg::swap(data,img.data);
 
11161
      cimg::swap(is_shared,img.is_shared);
7375
11162
      return img;
7376
11163
    }
7377
11164
 
7389
11176
       - If the template parameter T does not correspond to a registered type, the string <tt>"unknown"</tt> is returned.
7390
11177
    **/
7391
11178
    static const char* pixel_type() {
7392
 
      return cimg::type<T>::id();
 
11179
      return cimg::type<T>::string();
7393
11180
    }
7394
11181
 
7395
11182
    //! Return the total number of pixel values in an image.
7401
11188
       CImg<> img(100,100,1,3);
7402
11189
       if (img.size()==100*100*3) std::fprintf(stderr,"This statement is true");
7403
11190
       \endcode
7404
 
       \sa dimx(), dimy(), dimz(), dimv()
7405
11191
    **/
7406
11192
    unsigned long size() const {
7407
11193
      return width*height*depth*dim;
7408
11194
    }
7409
11195
 
7410
11196
    //! Return the number of columns of the instance image (size along the X-axis, i.e image width).
7411
 
    /**
7412
 
       \sa width, dimy(), dimz(), dimv(), size().
7413
 
    **/
7414
11197
    int dimx() const {
7415
11198
      return (int)width;
7416
11199
    }
7417
11200
 
7418
11201
    //! Return the number of rows of the instance image (size along the Y-axis, i.e image height).
7419
 
    /**
7420
 
       \sa height, dimx(), dimz(), dimv(), size().
7421
 
    **/
7422
11202
    int dimy() const {
7423
11203
      return (int)height;
7424
11204
    }
7425
11205
 
7426
11206
    //! Return the number of slices of the instance image (size along the Z-axis).
7427
 
    /**
7428
 
       \sa depth, dimx(), dimy(), dimv(), size().
7429
 
    **/
7430
11207
    int dimz() const {
7431
11208
      return (int)depth;
7432
11209
    }
7433
11210
 
7434
11211
    //! Return the number of vector channels of the instance image (size along the V-axis).
7435
 
    /**
7436
 
       \sa dim, dimx(), dimy(), dimz(), size().
7437
 
    **/
7438
11212
    int dimv() const {
7439
11213
      return (int)dim;
7440
11214
    }
7479
11253
      return (is_sameX(disp) && is_sameY(disp));
7480
11254
    }
7481
11255
 
 
11256
    //! Return \c true if images have same width and same depth.
 
11257
    template<typename t> bool is_sameXZ(const CImg<t>& img) const {
 
11258
      return (is_sameX(img) && is_sameZ(img));
 
11259
    }
 
11260
 
 
11261
    //! Return \c true if images have same width and same number of channels.
 
11262
    template<typename t> bool is_sameXV(const CImg<t>& img) const {
 
11263
      return (is_sameX(img) && is_sameV(img));
 
11264
    }
 
11265
 
 
11266
    //! Return \c true if images have same height and same depth.
 
11267
    template<typename t> bool is_sameYZ(const CImg<t>& img) const {
 
11268
      return (is_sameY(img) && is_sameZ(img));
 
11269
    }
 
11270
 
 
11271
    //! Return \c true if images have same height and same number of channels.
 
11272
    template<typename t> bool is_sameYV(const CImg<t>& img) const {
 
11273
      return (is_sameY(img) && is_sameV(img));
 
11274
    }
 
11275
 
 
11276
    //! Return \c true if images have same depth and same number of channels.
 
11277
    template<typename t> bool is_sameZV(const CImg<t>& img) const {
 
11278
      return (is_sameZ(img) && is_sameV(img));
 
11279
    }
 
11280
 
7482
11281
    //! Return \c true if images have same width, same height and same depth.
7483
11282
    template<typename t> bool is_sameXYZ(const CImg<t>& img) const {
7484
11283
      return (is_sameXY(img) && is_sameZ(img));
7485
11284
    }
7486
11285
 
 
11286
    //! Return \c true if images have same width, same height and same number of channels.
 
11287
    template<typename t> bool is_sameXYV(const CImg<t>& img) const {
 
11288
      return (is_sameXY(img) && is_sameZ(img));
 
11289
    }
 
11290
 
 
11291
    //! Return \c true if images have same width, same depth and same number of channels.
 
11292
    template<typename t> bool is_sameXZV(const CImg<t>& img) const {
 
11293
      return (is_sameXY(img) && is_sameZ(img));
 
11294
    }
 
11295
 
 
11296
    //! Return \c true if images have same heigth, same depth and same number of channels.
 
11297
    template<typename t> bool is_sameYZV(const CImg<t>& img) const {
 
11298
      return (is_sameXY(img) && is_sameZ(img));
 
11299
    }
 
11300
 
7487
11301
    //! Return \c true if images \c (*this) and \c img have same width, same height, same depth and same number of channels.
7488
11302
    template<typename t> bool is_sameXYZV(const CImg<t>& img) const {
7489
11303
      return (is_sameXYZ(img) && is_sameV(img));
7490
11304
    }
7491
11305
 
7492
 
    //! Return \c true if pixel (x,y,z,v) is inside the image boundaries.
7493
 
    bool contains(const int x, const int y=0, const int z=0, const int v=0) const {
7494
 
      return data && x>=0 && x<(int)width && y>=0 && y<(int)height && z>=0 && z<(int)depth && v>=0 && v<(int)dim;
 
11306
    //! Return \c true if pixel (x,y,z,v) is inside image boundaries.
 
11307
    bool containsXYZV(const int x, const int y=0, const int z=0, const int v=0) const {
 
11308
      if (is_empty()) return false;
 
11309
      return  x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz() && v>=0 && v<dimv();
 
11310
    }
 
11311
 
 
11312
    //! Return \c true if specified pixel is inside image boundaries. If true, returns pixel coordinates in (x,y,z,v).
 
11313
    template<typename t> bool contains(const T& pixel, t& x, t& y, t& z, t& v) const {
 
11314
      const unsigned long wh = width*height, whz = wh*depth, siz = whz*dim;
 
11315
      const T *const ppixel = &pixel;
 
11316
      if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
 
11317
      unsigned long off = (unsigned long)(ppixel - data);
 
11318
      const unsigned long nv = off/whz;
 
11319
      off%=whz;
 
11320
      const unsigned long nz = off/wh;
 
11321
      off%=wh;
 
11322
      const unsigned long ny = off/width, nx = off%width;
 
11323
      x = (t)nx; y = (t)ny; z = (t)nz; v = (t)nv;
 
11324
      return true;
 
11325
    }
 
11326
 
 
11327
    //! Return \c true if specified pixel is inside image boundaries. If true, returns pixel coordinates in (x,y,z).
 
11328
    template<typename t> bool contains(const T& pixel, t& x, t& y, t& z) const {
 
11329
      t v;
 
11330
      return contains(pixel,x,y,z,v);
 
11331
    }
 
11332
 
 
11333
    //! Return \c true if specified pixel is inside image boundaries. If true, returns pixel coordinates in (x,y).
 
11334
    template<typename t> bool contains(const T& pixel, t& x, t& y) const {
 
11335
      t z,v;
 
11336
      return contains(pixel,x,y,z,v);
 
11337
    }
 
11338
 
 
11339
    //! Return \c true if specified pixel is inside image boundaries. If true, returns pixel coordinates in (x).
 
11340
    template<typename t> bool contains(const T& pixel, t& x) const {
 
11341
      t y,z,v;
 
11342
      return contains(pixel,x,y,z,v);
 
11343
    }
 
11344
 
 
11345
    //! Return \c true if pixel is inside the image boundaries.
 
11346
    bool contains(const T& pixel) const {
 
11347
      unsigned int x,y,z,v;
 
11348
      return contains(pixel,x,y,z,v);
 
11349
    }
 
11350
 
 
11351
    //! Return \c true if the memory buffers of the two images overlaps.
 
11352
    /**
 
11353
       May happen when using shared images.
 
11354
    **/
 
11355
    template<typename t> bool is_overlapping(const CImg<t>& img) const {
 
11356
      const unsigned long csiz = size(), isiz = img.size();
 
11357
      return !((void*)(data+csiz)<=(void*)img.data || (void*)data>=(void*)(img.data+isiz));
7495
11358
    }
7496
11359
 
7497
11360
    //! Return \c true if current image is empty.
7499
11362
      return !(data && width && height && depth && dim);
7500
11363
    }
7501
11364
 
7502
 
    //! Image to boolean conversion
 
11365
    //! Return \p true if image is not empty.
7503
11366
    operator bool() const {
7504
11367
      return !is_empty();
7505
11368
    }
7519
11382
       long off = img.offset(10,10,0,2);       // Get the offset of the blue value of the pixel located at (10,10).
7520
11383
       float val = img[off];                   // Get the blue value of the pixel.
7521
11384
       \endcode
7522
 
       \sa ptr(), operator()(), operator[](), cimg_storage.
7523
11385
    **/
7524
 
    long offset(const int x=0, const int y=0, const int z=0, const int v=0) const {
7525
 
      return x + y*width + z*width*height + v*width*height*depth;
 
11386
    long offset(const int x, const int y, const int z, const int v) const {
 
11387
      return (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
 
11388
    }
 
11389
 
 
11390
    long offset(const int x, const int y, const int z) const {
 
11391
      return (long)x + (long)y*width + (long)z*width*height;
 
11392
    }
 
11393
 
 
11394
    long offset(const int x, const int y) const {
 
11395
      return (long)x + (long)y*width;
 
11396
    }
 
11397
 
 
11398
    long offset(const int x) const {
 
11399
      return (long)x;
7526
11400
    }
7527
11401
 
7528
11402
    //! Return a pointer to the pixel value located at (\p x,\p y,\p z,\p v).
7533
11407
       \param v V-coordinate of the pixel.
7534
11408
 
7535
11409
       - When called without parameters, ptr() returns a pointer to the begining of the pixel buffer.
7536
 
       - If the macro \c cimg_debug == 3, boundary checking is performed and warning messages may appear if
 
11410
       - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear if
7537
11411
       given coordinates are outside the image range (but function performances decrease).
7538
11412
 
7539
11413
       \par example:
7542
11416
       float *ptr = ptr(10,10);          // Get a pointer to the pixel located at (10,10).
7543
11417
       float val = *ptr;                 // Get the pixel value.
7544
11418
       \endcode
7545
 
       \sa data, offset(), operator()(), operator[](), cimg_storage, cimg_environment.
7546
11419
    **/
7547
 
    T* ptr(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
7548
 
      const long off = offset(x,y,z,v);
7549
 
#if cimg_debug>=3
7550
 
      if (off<0 || off>=(long)size()) {
7551
 
        cimg::warn("CImg<%s>::ptr() : Asked for a pointer at coordinates (%u,%u,%u,%u) (offset=%u), "
7552
 
                   "outside image range (%u,%u,%u,%u) (size=%u)",
7553
 
                   pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
7554
 
        return data;
7555
 
      }
7556
 
#endif
7557
 
      return data+off;
7558
 
    }
7559
 
 
7560
 
    const T* ptr(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
7561
 
      const long off = offset(x,y,z,v);
7562
 
#if cimg_debug>=3
7563
 
      if (off<0 || off>=(long)size()) {
7564
 
        cimg::warn("CImg<%s>::ptr() : Trying to get a pointer at (%u,%u,%u,%u) (offset=%u) which is"
7565
 
                   "outside the data of the image (%u,%u,%u,%u) (size=%u)",
7566
 
                   pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
7567
 
        return data;
7568
 
      }
7569
 
#endif
7570
 
      return data+off;
 
11420
#if cimg_debug>=3
 
11421
    T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
 
11422
      const long off = offset(x,y,z,v);
 
11423
      if (off<0 || off>=(long)size()) {
 
11424
        cimg::warn("CImg<%s>::ptr() : Asked for a pointer at coordinates (%u,%u,%u,%u) (offset=%ld), "
 
11425
                   "outside image range (%u,%u,%u,%u) (size=%lu)",
 
11426
                   pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
 
11427
        return data;
 
11428
      }
 
11429
      return data + off;
 
11430
    }
 
11431
 
 
11432
    const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
 
11433
      return const_cast<CImg<T>*>(this)->ptr(x,y,z,v);
 
11434
    }
 
11435
#else
 
11436
    T* ptr(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int v) {
 
11437
      return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
 
11438
    }
 
11439
 
 
11440
    const T* ptr(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int v) const {
 
11441
      return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
 
11442
    }
 
11443
 
 
11444
    T* ptr(const unsigned int x, const unsigned int y, const unsigned int z) {
 
11445
      return data + (long)x + (long)y*width + (long)z*width*height;
 
11446
    }
 
11447
 
 
11448
    const T* ptr(const unsigned int x, const unsigned int y, const unsigned int z) const {
 
11449
      return data + (long)x + (long)y*width + (long)z*width*height;
 
11450
    }
 
11451
 
 
11452
    T* ptr(const unsigned int x, const unsigned int y) {
 
11453
      return data + (long)x + (long)y*width;
 
11454
    }
 
11455
 
 
11456
    const T* ptr(const unsigned int x, const unsigned int y) const {
 
11457
      return data + (long)x + (long)y*width;
 
11458
    }
 
11459
 
 
11460
    T* ptr(const unsigned int x) {
 
11461
      return data + (long)x;
 
11462
    }
 
11463
 
 
11464
    const T* ptr(const unsigned int x) const {
 
11465
      return data + (long)x;
 
11466
    }
 
11467
#endif
 
11468
    T* ptr() {
 
11469
      return data;
 
11470
    }
 
11471
 
 
11472
    const T* ptr() const {
 
11473
      return data;
7571
11474
    }
7572
11475
 
7573
11476
    //! Return an iterator to the first image pixel
7596
11499
       \param v V-coordinate of the pixel.
7597
11500
 
7598
11501
       - If one image dimension is equal to 1, it can be omitted in the coordinate list (see example below).
7599
 
       - If the macro \c cimg_debug == 3, boundary checking is performed and warning messages may appear
 
11502
       - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
7600
11503
       (but function performances decrease).
7601
11504
 
7602
11505
       \par example:
7608
11511
       const float avg = (valR + valG + valB)/3;             // Compute average pixel value.
7609
11512
       img(10,10,0) = img(10,10,1) = img(10,10,2) = avg;     // Replace the pixel (10,10) by the average grey value.
7610
11513
       \endcode
7611
 
 
7612
 
       \sa operator[](), ptr(), offset(), cimg_storage, cimg_environment.
7613
11514
    **/
 
11515
#if cimg_debug>=3
7614
11516
    T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
7615
11517
      const long off = offset(x,y,z,v);
7616
 
#if cimg_debug>=3
7617
11518
      if (!data || off>=(long)size()) {
7618
 
        cimg::warn("CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%u) "
7619
 
                   "outside the image range (%u,%u,%u,%u) (size=%u)",
 
11519
        cimg::warn("CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%ld) "
 
11520
                   "outside the image range (%u,%u,%u,%u) (size=%lu)",
7620
11521
                   pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
7621
11522
        return *data;
7622
11523
      }
7623
 
#endif
7624
 
      return data[off];
 
11524
      else return data[off];
7625
11525
    }
7626
11526
 
7627
11527
    const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
7628
 
      const long off = offset(x,y,z,v);
7629
 
#if cimg_debug>=3
7630
 
      if (!data || off>=(long)size()) {
7631
 
        cimg::warn("CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%u) "
7632
 
                   "outside the image range (%u,%u,%u,%u) (size=%u)",
7633
 
                   pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
7634
 
        return *data;
7635
 
      }
 
11528
      return const_cast<CImg<T>*>(this)->operator()(x,y,z,v);
 
11529
    }
 
11530
#else
 
11531
    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int v) {
 
11532
      return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
 
11533
    }
 
11534
 
 
11535
    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int v) const {
 
11536
      return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
 
11537
    }
 
11538
 
 
11539
    T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) {
 
11540
      return data[(long)x + (long)y*width + (long)z*width*height];
 
11541
    }
 
11542
 
 
11543
    const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) const {
 
11544
      return data[(long)x + (long)y*width + (long)z*width*height];
 
11545
    }
 
11546
 
 
11547
    T& operator()(const unsigned int x, const unsigned int y) {
 
11548
      return data[(long)x + (long)y*width];
 
11549
    }
 
11550
 
 
11551
    const T& operator()(const unsigned int x, const unsigned int y) const {
 
11552
      return data[(long)x + (long)y*width];
 
11553
    }
 
11554
 
 
11555
    T& operator()(const unsigned int x) {
 
11556
      return data[(long)x];
 
11557
    }
 
11558
 
 
11559
    const T& operator()(const unsigned int x) const {
 
11560
      return data[(long)x];
 
11561
    }
7636
11562
#endif
7637
 
      return data[off];
7638
 
    }
7639
 
 
7640
 
    //! Return pixel value at a given position. Equivalent to operator().
7641
 
    T& at(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
7642
 
      const long off = offset(x,y,z,v);
7643
 
      if (!data || off>=(long)size())
7644
 
        throw CImgArgumentException("CImg<%s>::at() : Pixel access requested at (%u,%u,%u,%u) (offset=%u) "
7645
 
                                    "outside the image range (%u,%u,%u,%u) (size=%u)",
7646
 
                                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
7647
 
      return data[off];
7648
 
    }
7649
 
 
7650
 
    const T& at(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
7651
 
      const long off = offset(x,y,z,v);
7652
 
      if (!data || off>=(long)size())
7653
 
        throw CImgArgumentException("CImg<%s>::at() : Pixel access requested at (%u,%u,%u,%u) (offset=%u) "
7654
 
                                    "outside the image range (%u,%u,%u,%u) (size=%u)",
7655
 
                                    pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
7656
 
      return data[off];
7657
 
    }
7658
11563
 
7659
11564
    //! Fast access to pixel value for reading or writing, using an offset to the image pixel.
7660
11565
    /**
7661
11566
       \param off Offset of the pixel according to the begining of the pixel buffer, given by ptr().
7662
11567
 
7663
 
       - If the macro \c cimg_debug==3, boundary checking is performed and warning messages may appear
 
11568
       - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
7664
11569
       (but function performances decrease).
7665
11570
       - As pixel values are aligned in memory, this operator can sometime useful to access values easier than
7666
11571
       with operator()() (see example below).
7671
11576
       const float val1 = vec(0,4);  // Get the fifth element using operator()().
7672
11577
       const float val2 = vec[4];    // Get the fifth element using operator[]. Here, val2==val1.
7673
11578
       \endcode
7674
 
 
7675
 
       \sa operator()(), ptr(), offset(), cimg_storage, cimg_environment.
7676
11579
    **/
7677
 
    T& operator[](const unsigned long off) {
7678
 
      return operator()(off);
7679
 
    }
7680
 
 
7681
 
    const T& operator[](const unsigned long off) const {
7682
 
      return operator()(off);
7683
 
    }
 
11580
#if cimg_debug>=3
 
11581
    T& operator[](const unsigned long off) {
 
11582
      if (!data || off>=size()) {
 
11583
        cimg::warn("CImg<%s>::operator[] : Pixel access requested at offset=%lu "
 
11584
                   "outside the image range (%u,%u,%u,%u) (size=%lu)",
 
11585
                   pixel_type(),off,width,height,depth,dim,size());
 
11586
        return *data;
 
11587
      }
 
11588
      else return data[off];
 
11589
    }
 
11590
 
 
11591
    const T& operator[](const unsigned long off) const {
 
11592
      return const_cast<CImg<T>*>(this)->operator[](off);
 
11593
    }
 
11594
#else
 
11595
    T& operator[](const unsigned long off) {
 
11596
      return data[off];
 
11597
    }
 
11598
 
 
11599
    const T& operator[](const unsigned long off) const {
 
11600
      return data[off];
 
11601
    }
 
11602
#endif
7684
11603
 
7685
11604
    //! Return a reference to the last image value
7686
11605
    T& back() {
7700
11619
      return *data;
7701
11620
    }
7702
11621
 
7703
 
    //! Read a pixel value with Dirichlet or Neumann boundary conditions.
7704
 
    /**
7705
 
       \param x X-coordinate of the pixel.
7706
 
       \param y Y-coordinate of the pixel.
7707
 
       \param z Z-coordinate of the pixel.
7708
 
       \param v V-coordinate of the pixel.
7709
 
       \param out_val Desired value if pixel coordinates are outside the image range (optional parameter).
7710
 
 
7711
 
       - This function allows to read pixel values with boundary checking on all coordinates.
7712
 
       - If given coordinates are outside the image range and the parameter out_val is specified, the value \c out_val is returned.
7713
 
       - If given coordinates are outside the image range and the parameter out_val is not specified, the closest pixel value
7714
 
       is returned.
7715
 
 
7716
 
       \par example:
7717
 
       \code
7718
 
       CImg<float> img(100,100,1,1,128);                     // Define a 100x100 images with all pixel values equal to 128.
7719
 
       const float val1 = img.pix4d(10,10,0,0,0);  // Equivalent to val1=img(10,10) (but slower).
7720
 
       const float val2 = img.pix4d(-4,5,0,0,0);   // Return 0, since coordinates are outside the image range.
7721
 
       const float val3 = img.pix4d(10,10,5,0,64); // Return 64, since coordinates are outside the image range.
7722
 
       \endcode
7723
 
 
7724
 
       \sa operator()(), linear_pix4d(), cubic_pix2d().
7725
 
    **/
7726
 
    T pix4d(const int x, const int y, const int z, const int v, const T& out_val) const {
 
11622
    //! Read a pixel value with Dirichlet boundary conditions.
 
11623
    T at(const int x, const int y, const int z, const int v, const T out_val) const {
 
11624
      return at4(x,y,z,v,out_val);
 
11625
    }
 
11626
 
 
11627
    //! Read a pixel value with Neumann boundary conditions.
 
11628
    T& at(const int x, const int y=0, const int z=0, const int v=0) {
 
11629
      return at4(x,y,z,v);
 
11630
    }
 
11631
 
 
11632
    const T& at(const int x, const int y=0, const int z=0, const int v=0) const {
 
11633
      return at4(x,y,z,v);
 
11634
    }
 
11635
 
 
11636
    //! Read a pixel value with Dirichlet boundary conditions.
 
11637
    T at4(const int x, const int y, const int z, const int v, const T out_val) const {
7727
11638
      return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v);
7728
11639
    }
7729
11640
 
7730
 
    T pix4d(const int x, const int y, const int z, const int v) const {
7731
 
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
7732
 
                     z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
7733
 
    }
7734
 
 
7735
 
    //! Read a pixel value with Dirichlet or Neumann boundary conditions for the three first coordinates (\c x,\c y,\c z).
7736
 
    T pix3d(const int x, const int y, const int z, const int v, const T& out_val) const {
 
11641
    //! Read a pixel value with Neumann boundary conditions.
 
11642
    T& at4(const int x, const int y=0, const int z=0, const int v=0) {
 
11643
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
 
11644
                     z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
 
11645
    }
 
11646
 
 
11647
    const T& at4(const int x, const int y=0, const int z=0, const int v=0) const {
 
11648
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
 
11649
                     z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
 
11650
    }
 
11651
 
 
11652
    //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c x,\c y,\c z).
 
11653
    T at3(const int x, const int y, const int z, const int v, const T out_val) const {
7737
11654
      return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v);
7738
11655
    }
7739
11656
 
7740
 
    const T& pix3d(const int x, const int y, const int z, const int v=0) const {
7741
 
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
7742
 
                     z<0?0:(z>=dimz()?dimz()-1:z),v);
7743
 
    }
7744
 
 
7745
 
    //! Read a pixel value with Dirichlet or Neumann boundary conditions for the two first coordinates (\c x,\c y).
7746
 
    T pix2d(const int x, const int y, const int z, const int v, const T& out_val) const {
 
11657
    //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c x,\c y,\c z).
 
11658
    T& at3(const int x, const int y, const int z, const int v=0) {
 
11659
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
 
11660
                     z<0?0:(z>=dimz()?dimz()-1:z),v);
 
11661
    }
 
11662
 
 
11663
    const T& at3(const int x, const int y, const int z, const int v=0) const {
 
11664
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
 
11665
                     z<0?0:(z>=dimz()?dimz()-1:z),v);
 
11666
    }
 
11667
 
 
11668
    //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c x,\c y).
 
11669
    T at2(const int x, const int y, const int z, const int v, const T out_val) const {
7747
11670
      return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v);
7748
11671
    }
7749
11672
 
7750
 
    const T& pix2d(const int x, const int y, const int z=0, const int v=0) const {
7751
 
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
7752
 
    }
7753
 
 
7754
 
    //! Read a pixel value with Dirichlet or Neumann boundary conditions for the first coordinate \c x.
7755
 
    T pix1d(const int x, const int y, const int z, const int v, const T& out_val) const {
 
11673
    //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c x,\c y).
 
11674
    T& at2(const int x, const int y, const int z=0, const int v=0) {
 
11675
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
 
11676
    }
 
11677
 
 
11678
    const T& at2(const int x, const int y, const int z=0, const int v=0) const {
 
11679
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
 
11680
    }
 
11681
 
 
11682
    //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c x).
 
11683
    T at1(const int x, const int y, const int z, const int v, const T out_val) const {
7756
11684
      return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v);
7757
11685
    }
7758
11686
 
7759
 
    const T& pix1d(const int x, const int y=0, const int z=0, const int v=0) const {
7760
 
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
7761
 
    }
7762
 
 
7763
 
    //! Read a pixel value using linear interpolation.
7764
 
    /**
7765
 
       \param ffx X-coordinate of the pixel (float-valued).
7766
 
       \param ffy Y-coordinate of the pixel (float-valued).
7767
 
       \param ffz Z-coordinate of the pixel (float-valued).
7768
 
       \param ffv V-coordinate of the pixel (float-valued).
7769
 
       \param out_val Out-of-border pixel value
7770
 
 
7771
 
       - This function allows to read pixel values with boundary checking on all coordinates.
7772
 
       - If given coordinates are outside the image range, the value of the nearest pixel inside the image is returned
7773
 
       (Neumann boundary conditions).
7774
 
       - If given coordinates are float-valued, a linear interpolation is performed in order to compute the returned value.
7775
 
 
7776
 
       \par example:
7777
 
       \code
7778
 
       CImg<float> img(2,2);     // Define a greyscale 2x2 image.
7779
 
       img(0,0) = 0;             // Fill image with specified pixel values.
7780
 
       img(1,0) = 1;
7781
 
       img(0,1) = 2;
7782
 
       img(1,1) = 3;
7783
 
       const double val = img.linear_pix4d(0.5,0.5);  // Return val=1.5, which is the average intensity of the four pixels values.
7784
 
       \endcode
7785
 
 
7786
 
       \sa operator()(), linear_pix3d(), linear_pix2d(), linear_pix1d(), cubic_pix2d().
7787
 
    **/
7788
 
    typename cimg::largest<T,float>::type linear_pix4d(const float fx, const float fy, const float fz, const float fv,
7789
 
                                                       const T& out_val) const {
7790
 
      const int x = (int)fx-(fx>=0?0:1), y = (int)fy-(fy>=0?0:1), z = (int)fz-(fz>=0?0:1), v = (int)fv-(fv>=0?0:1),
7791
 
        nx = x+1, ny = y+1, nz = z+1, nv = v+1;
7792
 
      const float dx = fx-x, dy = fy-y, dz = fz-z, dv = fv-v;
7793
 
      const T
7794
 
        Icccc = pix4d(x,y,z,v,out_val),    Inccc = pix4d(nx,y,z,v,out_val),
7795
 
        Icncc = pix4d(x,ny,z,v,out_val),   Inncc = pix4d(nx,ny,z,v,out_val),
7796
 
        Iccnc = pix4d(x,y,nz,v,out_val),   Incnc = pix4d(nx,y,nz,v,out_val),
7797
 
        Icnnc = pix4d(x,ny,nz,v,out_val),  Innnc = pix4d(nx,ny,nz,v,out_val),
7798
 
        Icccn = pix4d(x,y,z,nv,out_val),   Inccn = pix4d(nx,y,z,nv,out_val),
7799
 
        Icncn = pix4d(x,ny,z,nv,out_val),  Inncn = pix4d(nx,ny,z,nv,out_val),
7800
 
        Iccnn = pix4d(x,y,nz,nv,out_val),  Incnn = pix4d(nx,y,nz,nv,out_val),
7801
 
        Icnnn = pix4d(x,ny,nz,nv,out_val), Innnn = pix4d(nx,ny,nz,nv,out_val);
7802
 
      return Icccc +
7803
 
        dx*(Inccc-Icccc +
7804
 
            dy*(Icccc+Inncc-Icncc-Inccc +
7805
 
                dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
7806
 
                    dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
7807
 
                dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
7808
 
            dz*(Icccc+Incnc-Iccnc-Inccc +
7809
 
                dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
7810
 
            dv*(Icccc+Inccn-Inccc-Icccn)) +
7811
 
        dy*(Icncc-Icccc +
7812
 
            dz*(Icccc+Icnnc-Iccnc-Icncc +
7813
 
                dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
7814
 
            dv*(Icccc+Icncn-Icncc-Icccn)) +
7815
 
        dz*(Iccnc-Icccc +
7816
 
            dv*(Icccc+Iccnn-Iccnc-Icccn)) +
7817
 
        dv*(Icccn-Icccc);
7818
 
    }
7819
 
 
7820
 
    typename cimg::largest<T,float>::type linear_pix4d(const float ffx, const float ffy=0, const float ffz=0, const float ffv=0) const {
7821
 
      const float
7822
 
        fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy),
7823
 
        fz = ffz<0?0:(ffz>depth-1?depth-1:ffz), fv = ffv<0?0:(ffv>dim-1?dim-1:ffv);
7824
 
      const unsigned int x = (unsigned int)fx, y = (unsigned int)fy,  z = (unsigned int)fz, v = (unsigned int)fv;
7825
 
      const float dx = fx-x, dy = fy-y, dz = fz-z, dv = fv-v;
7826
 
      const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y,  nz = dz>0?z+1:z, nv = dv>0?v+1:v;
7827
 
      const T
7828
 
        &Icccc = (*this)(x,y,z,v),   &Inccc = (*this)(nx,y,z,v),   &Icncc = (*this)(x,ny,z,v),   &Inncc = (*this)(nx,ny,z,v),
7829
 
        &Iccnc = (*this)(x,y,nz,v),  &Incnc = (*this)(nx,y,nz,v),  &Icnnc = (*this)(x,ny,nz,v),  &Innnc = (*this)(nx,ny,nz,v),
7830
 
        &Icccn = (*this)(x,y,z,nv),  &Inccn = (*this)(nx,y,z,nv),  &Icncn = (*this)(x,ny,z,nv),  &Inncn = (*this)(nx,ny,z,nv),
7831
 
        &Iccnn = (*this)(x,y,nz,nv), &Incnn = (*this)(nx,y,nz,nv), &Icnnn = (*this)(x,ny,nz,nv), &Innnn = (*this)(nx,ny,nz,nv);
7832
 
      return Icccc +
7833
 
        dx*(Inccc-Icccc +
7834
 
            dy*(Icccc+Inncc-Icncc-Inccc +
7835
 
                dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
7836
 
                    dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
7837
 
                dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
7838
 
            dz*(Icccc+Incnc-Iccnc-Inccc +
7839
 
                dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
7840
 
            dv*(Icccc+Inccn-Inccc-Icccn)) +
7841
 
        dy*(Icncc-Icccc +
7842
 
            dz*(Icccc+Icnnc-Iccnc-Icncc +
7843
 
                dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
7844
 
            dv*(Icccc+Icncn-Icncc-Icccn)) +
7845
 
        dz*(Iccnc-Icccc +
7846
 
            dv*(Icccc+Iccnn-Iccnc-Icccn)) +
7847
 
        dv*(Icccn-Icccc);
7848
 
    }
7849
 
 
7850
 
    //! Read a pixel value using linear interpolation for the three first coordinates (\c cx,\c cy,\c cz).
7851
 
    /**
7852
 
       - Same as linear_pix4d(), except that linear interpolation and boundary checking is performed only on the three first coordinates.
7853
 
 
7854
 
       \sa operator()(), linear_pix4d(), linear_pix2d(), linear_pix1d(), linear_pix3d(), cubic_pix2d().
7855
 
    **/
7856
 
    typename cimg::largest<T,float>::type linear_pix3d(const float fx, const float fy, const float fz, const int v,
7857
 
                                                       const T& out_val) const {
7858
 
      const int x = (int)fx-(fx>=0?0:1), y = (int)fy-(fy>=0?0:1), z = (int)fz-(fz>=0?0:1), nx = x+1, ny = y+1, nz = z+1;
7859
 
      const float dx = fx-x, dy = fy-y, dz = fz-z;
7860
 
      const T
7861
 
        Iccc = pix3d(x,y,z,v,out_val),  Incc = pix3d(nx,y,z,v,out_val),  Icnc = pix3d(x,ny,z,v,out_val),  Innc = pix3d(nx,ny,z,v,out_val),
7862
 
        Iccn = pix3d(x,y,nz,v,out_val), Incn = pix3d(nx,y,nz,v,out_val), Icnn = pix3d(x,ny,nz,v,out_val), Innn = pix3d(nx,ny,nz,v,out_val);
7863
 
      return Iccc +
7864
 
        dx*(Incc-Iccc +
7865
 
            dy*(Iccc+Innc-Icnc-Incc +
7866
 
                dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
7867
 
            dz*(Iccc+Incn-Iccn-Incc)) +
7868
 
        dy*(Icnc-Iccc +
7869
 
            dz*(Iccc+Icnn-Iccn-Icnc)) +
7870
 
        dz*(Iccn-Iccc);
7871
 
    }
7872
 
 
7873
 
    typename cimg::largest<T,float>::type linear_pix3d(const float ffx, const float ffy=0, const float ffz=0, const int v=0) const {
7874
 
      const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy), fz = ffz<0?0:(ffz>depth-1?depth-1:ffz);
7875
 
      const unsigned int x = (unsigned int)fx, y = (unsigned int)fy, z = (unsigned int)fz;
7876
 
      const float dx = fx-x, dy = fy-y, dz = fz-z;
7877
 
      const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y, nz = dz>0?z+1:z;
7878
 
      const T
7879
 
        &Iccc = (*this)(x,y,z,v),  &Incc = (*this)(nx,y,z,v),  &Icnc = (*this)(x,ny,z,v),  &Innc = (*this)(nx,ny,z,v),
7880
 
        &Iccn = (*this)(x,y,nz,v), &Incn = (*this)(nx,y,nz,v), &Icnn = (*this)(x,ny,nz,v), &Innn = (*this)(nx,ny,nz,v);
7881
 
      return Iccc +
7882
 
        dx*(Incc-Iccc +
7883
 
            dy*(Iccc+Innc-Icnc-Incc +
7884
 
                dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
7885
 
            dz*(Iccc+Incn-Iccn-Incc)) +
7886
 
        dy*(Icnc-Iccc +
7887
 
            dz*(Iccc+Icnn-Iccn-Icnc)) +
7888
 
        dz*(Iccn-Iccc);
7889
 
    }
7890
 
 
7891
 
    //! Read a pixel value using linear interpolation for the two first coordinates (\c cx,\c cy).
7892
 
    /**
7893
 
       - Same as linear_pix4d(), except that linear interpolation and boundary checking is performed only on the two first coordinates.
7894
 
 
7895
 
       \sa operator()(), linear_pix4d(), linear_pix3d(), linear_pix1d(), linear_pix2d(), cubic_pix2d().
7896
 
    **/
7897
 
    typename cimg::largest<T,float>::type linear_pix2d(const float fx, const float fy, const int z, const int v,
7898
 
                                                       const T& out_val) const {
7899
 
      const int x = (int)fx-(fx>0?0:1), y = (int)fy-(fy>0?0:1), nx = x+1, ny = y+1;
7900
 
      const float dx = fx-x, dy = fy-y;
7901
 
      const T
7902
 
        Icc = pix2d(x,y,z,v,out_val),  Inc = pix2d(nx,y,z,v,out_val),
7903
 
        Icn = pix2d(x,ny,z,v,out_val), Inn = pix2d(nx,ny,z,v,out_val);
7904
 
      return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
7905
 
    }
7906
 
 
7907
 
    typename cimg::largest<T,float>::type linear_pix2d(const float ffx, const float ffy=0, const int z=0, const int v=0) const {
7908
 
      const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy);
7909
 
      const unsigned int x = (unsigned int)fx, y = (unsigned int)fy;
7910
 
      const float dx = fx-x, dy = fy-y;
7911
 
      const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y;
7912
 
      const T &Icc = (*this)(x,y,z,v), &Inc = (*this)(nx,y,z,v), &Icn = (*this)(x,ny,z,v), &Inn = (*this)(nx,ny,z,v);
7913
 
      return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
7914
 
    }
7915
 
 
7916
 
    //! Read a pixel value using linear interpolation for the first coordinate \c cx.
7917
 
    /**
7918
 
       - Same as linear_pix4d(), except that linear interpolation and boundary checking is performed only on the first coordinate.
7919
 
 
7920
 
       \sa operator()(), linear_pix4d(), linear_pix3d(), linear_pix2d(), linear_pix1d(), cubic_pix1d().
7921
 
    **/
7922
 
    typename cimg::largest<T,float>::type linear_pix1d(const float fx, const int y, const int z, const int v,
7923
 
                                                       const T& out_val) const {
7924
 
      const int x = (int)fx-(fx>0?0:1), nx = x+1;
7925
 
      const float dx = fx-x;
7926
 
      const T Ic = pix1d(x,y,z,v,out_val), In = pix2d(nx,y,z,v,out_val);
7927
 
      return Ic + dx*(In-Ic);
7928
 
    }
7929
 
 
7930
 
    typename cimg::largest<T,float>::type linear_pix1d(const float ffx, const int y=0, const int z=0, const int v=0) const {
7931
 
      const float fx = ffx<0?0:(ffx>width-1?width-1:ffx);
7932
 
      const unsigned int x = (unsigned int)fx;
7933
 
      const float dx = fx-x;
7934
 
      const unsigned int nx = dx>0?x+1:x;
7935
 
      const T &Ic = (*this)(x,y,z,v), &In = (*this)(nx,y,z,v);
7936
 
      return Ic + dx*(In-Ic);
7937
 
    }
7938
 
 
7939
 
    // This function is used as a subroutine for cubic interpolation
7940
 
    static float _cubic_R(const float x) {
7941
 
      const float xp2 = x+2, xp1 = x+1, xm1 = x-1,
7942
 
        nxp2 = xp2>0?xp2:0, nxp1 = xp1>0?xp1:0, nx = x>0?x:0, nxm1 = xm1>0?xm1:0;
7943
 
      return (nxp2*nxp2*nxp2 - 4*nxp1*nxp1*nxp1 + 6*nx*nx*nx - 4*nxm1*nxm1*nxm1)/6.0f;
7944
 
    }
7945
 
 
7946
 
    //! Read a pixel value using cubic interpolation for the first coordinate \c cx.
7947
 
    /**
7948
 
       - Same as cubic_pix2d(), except that cubic interpolation and boundary checking is performed only on the first coordinate.
7949
 
 
7950
 
       \sa operator()(), cubic_pix2d(), linear_pix1d().
7951
 
    **/
7952
 
    typename cimg::largest<T,float>::type cubic_pix1d(const float fx, const int y, const int z, const int v,
7953
 
                                                      const T& out_val) const {
7954
 
      const int x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = nx+1;
7955
 
      const float dx = fx-x;
7956
 
      const T a = pix2d(px,y,z,v,out_val), b = pix2d(x,y,z,v,out_val), c = pix2d(nx,y,z,v,out_val), d = pix2d(ax,y,z,v,out_val);
7957
 
      const float Rxp = _cubic_R(-1-dx), Rxc = _cubic_R(dx), Rxn = _cubic_R(1-dx), Rxa = _cubic_R(2-dx);
7958
 
      return Rxp*a + Rxc*b + Rxn*c + Rxa*d;
7959
 
    }
7960
 
 
7961
 
    typename cimg::largest<T,float>::type cubic_pix1d(const float pfx, const int y=0, const int z=0, const int v=0) const {
7962
 
      const float fx = pfx<0?0:(pfx>width-1?width-1:pfx);
7963
 
      const unsigned int x = (unsigned int)fx, px = (int)x-1>=0?x-1:0, nx = x+1<width?x+1:width-1, ax = nx+1<width?nx+1:width-1;
7964
 
      const float dx = fx-x;
7965
 
      const T& a = (*this)(px,y,z,v), b = (*this)(x,y,z,v), c = (*this)(nx,y,z,v), d = (*this)(ax,y,z,v);
7966
 
      const float Rxp = _cubic_R(-1-dx), Rxc = _cubic_R(dx), Rxn = _cubic_R(1-dx), Rxa = _cubic_R(2-dx);
7967
 
      return Rxp*a + Rxc*b + Rxn*c + Rxa*d;
7968
 
    }
7969
 
 
7970
 
    //! Read a pixel value using bicubic interpolation.
7971
 
    /**
7972
 
       \param pfx X-coordinate of the pixel (float-valued).
7973
 
       \param pfy Y-coordinate of the pixel (float-valued).
7974
 
       \param z   Z-coordinate of the pixel.
7975
 
       \param v   V-coordinate of the pixel.
7976
 
 
7977
 
       - This function allows to read pixel values with boundary checking on the two first coordinates.
7978
 
       - If given coordinates are outside the image range, the value of the nearest pixel inside the image is returned
7979
 
       (Neumann boundary conditions).
7980
 
       - If given coordinates are float-valued, a cubic interpolation is performed in order to compute the returned value.
7981
 
 
7982
 
       \sa operator()(), cubic_pix1d(), linear_pix2d().
7983
 
    **/
7984
 
    typename cimg::largest<T,float>::type cubic_pix2d(const float fx, const float fy, const int z, const int v,
7985
 
                                                      const T& out_val) const {
7986
 
      const int
7987
 
        x = (int)fx-(fx>=0?0:1), y = (int)fy-(fy>=0?0:1),
7988
 
        px = x-1, nx = x+1, ax = nx+1, py = y-1, ny = y+1, ay = ny+1;
7989
 
      const float dx = fx-x, dy = fy-y;
7990
 
      const T
7991
 
        a = pix2d(px,py,z,v,out_val), b = pix2d(x,py,z,v,out_val), c = pix2d(nx,py,z,v,out_val), d = pix2d(ax,py,z,v,out_val),
7992
 
        e = pix2d(px, y,z,v,out_val), f = pix2d(x, y,z,v,out_val), g = pix2d(nx, y,z,v,out_val), h = pix2d(ax, y,z,v,out_val),
7993
 
        i = pix2d(px,ny,z,v,out_val), j = pix2d(x,ny,z,v,out_val), k = pix2d(nx,ny,z,v,out_val), l = pix2d(ax,ny,z,v,out_val),
7994
 
        m = pix2d(px,ay,z,v,out_val), n = pix2d(x,ay,z,v,out_val), o = pix2d(nx,ay,z,v,out_val), p = pix2d(ax,ay,z,v,out_val);
7995
 
      const float
7996
 
        Rxp = _cubic_R(-1-dx), Rxc = _cubic_R(dx), Rxn = _cubic_R(1-dx), Rxa = _cubic_R(2-dx),
7997
 
        Ryp = _cubic_R(dy+1),  Ryc = _cubic_R(dy), Ryn = _cubic_R(dy-1), Rya = _cubic_R(dy-2);
7998
 
      return
7999
 
        Rxp*Ryp*a + Rxc*Ryp*b + Rxn*Ryp*c + Rxa*Ryp*d +
8000
 
        Rxp*Ryc*e + Rxc*Ryc*f + Rxn*Ryc*g + Rxa*Ryc*h +
8001
 
        Rxp*Ryn*i + Rxc*Ryn*j + Rxn*Ryn*k + Rxa*Ryn*l +
8002
 
        Rxp*Rya*m + Rxc*Rya*n + Rxn*Rya*o + Rxa*Rya*p;
8003
 
    }
8004
 
 
8005
 
    typename cimg::largest<T,float>::type cubic_pix2d(const float pfx, const float pfy=0, const int z=0, const int v=0) const {
8006
 
      const float fx = pfx<0?0:(pfx>width-1?width-1:pfx), fy = pfy<0?0:(pfy>height-1?height-1:pfy);
8007
 
      const unsigned int
8008
 
        x = (unsigned int)fx,  px = (int)x-1>=0?x-1:0, nx = x+1<width?x+1:width-1, ax = nx+1<width?nx+1:width-1,
8009
 
        y = (unsigned int)fy,  py = (int)y-1>=0?y-1:0, ny = y+1<height?y+1:height-1, ay = ny+1<height?ny+1:height-1;
8010
 
      const float dx = fx-x, dy = fy-y;
8011
 
      const T&
8012
 
        a = (*this)(px,py,z,v), b = (*this)(x,py,z,v), c = (*this)(nx,py,z,v), d = (*this)(ax,py,z,v),
8013
 
        e = (*this)(px, y,z,v), f = (*this)(x, y,z,v), g = (*this)(nx, y,z,v), h = (*this)(ax, y,z,v),
8014
 
        i = (*this)(px,ny,z,v), j = (*this)(x,ny,z,v), k = (*this)(nx,ny,z,v), l = (*this)(ax,ny,z,v),
8015
 
        m = (*this)(px,ay,z,v), n = (*this)(x,ay,z,v), o = (*this)(nx,ay,z,v), p = (*this)(ax,ay,z,v);
8016
 
      const float
8017
 
        Rxp = _cubic_R(-1-dx), Rxc = _cubic_R(dx), Rxn = _cubic_R(1-dx), Rxa = _cubic_R(2-dx),
8018
 
        Ryp = _cubic_R(dy+1),  Ryc = _cubic_R(dy), Ryn = _cubic_R(dy-1), Rya = _cubic_R(dy-2);
8019
 
      return
8020
 
        Rxp*Ryp*a + Rxc*Ryp*b + Rxn*Ryp*c + Rxa*Ryp*d +
8021
 
        Rxp*Ryc*e + Rxc*Ryc*f + Rxn*Ryc*g + Rxa*Ryc*h +
8022
 
        Rxp*Ryn*i + Rxc*Ryn*j + Rxn*Ryn*k + Rxa*Ryn*l +
8023
 
        Rxp*Rya*m + Rxc*Rya*n + Rxn*Rya*o + Rxa*Rya*p;
 
11687
    //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c x).
 
11688
    T& at1(const int x, const int y=0, const int z=0, const int v=0) {
 
11689
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
 
11690
    }
 
11691
 
 
11692
    const T& at1(const int x, const int y=0, const int z=0, const int v=0) const {
 
11693
      return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
 
11694
    }
 
11695
 
 
11696
    //! Read a pixel value using linear interpolation and Dirichlet boundary conditions.
 
11697
    Tfloat linear_at(const float fx, const float fy, const float fz, const float fv, const T out_val) const {
 
11698
      return linear_at(fx,fy,fz,fv,out_val);
 
11699
    }
 
11700
 
 
11701
    //! Read a pixel value using linear interpolation and Neumann boundary conditions.
 
11702
    Tfloat linear_at(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
 
11703
      return linear_at(fx,fy,fz,fv);
 
11704
    }
 
11705
 
 
11706
    //! Read a pixel value using linear interpolation and Dirichlet boundary conditions.
 
11707
    Tfloat linear_at4(const float fx, const float fy, const float fz, const float fv, const T out_val) const {
 
11708
      const int
 
11709
        x = (int)fx-(fx>=0?0:1), nx = x+1,
 
11710
        y = (int)fy-(fy>=0?0:1), ny = y+1,
 
11711
        z = (int)fz-(fz>=0?0:1), nz = z+1,
 
11712
        v = (int)fv-(fv>=0?0:1), nv = v+1;
 
11713
      const float
 
11714
        dx = fx-x,
 
11715
        dy = fy-y,
 
11716
        dz = fz-z,
 
11717
        dv = fv-v;
 
11718
      const Tfloat
 
11719
        Icccc = (Tfloat)at(x,y,z,v,out_val), Inccc = (Tfloat)at(nx,y,z,v,out_val),
 
11720
        Icncc = (Tfloat)at(x,ny,z,v,out_val), Inncc = (Tfloat)at(nx,ny,z,v,out_val),
 
11721
        Iccnc = (Tfloat)at(x,y,nz,v,out_val), Incnc = (Tfloat)at(nx,y,nz,v,out_val),
 
11722
        Icnnc = (Tfloat)at(x,ny,nz,v,out_val), Innnc = (Tfloat)at(nx,ny,nz,v,out_val),
 
11723
        Icccn = (Tfloat)at(x,y,z,nv,out_val), Inccn = (Tfloat)at(nx,y,z,nv,out_val),
 
11724
        Icncn = (Tfloat)at(x,ny,z,nv,out_val), Inncn = (Tfloat)at(nx,ny,z,nv,out_val),
 
11725
        Iccnn = (Tfloat)at(x,y,nz,nv,out_val), Incnn = (Tfloat)at(nx,y,nz,nv,out_val),
 
11726
        Icnnn = (Tfloat)at(x,ny,nz,nv,out_val), Innnn = (Tfloat)at(nx,ny,nz,nv,out_val);
 
11727
      return Icccc +
 
11728
        dx*(Inccc-Icccc +
 
11729
            dy*(Icccc+Inncc-Icncc-Inccc +
 
11730
                dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
 
11731
                    dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
 
11732
                dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
 
11733
            dz*(Icccc+Incnc-Iccnc-Inccc +
 
11734
                dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
 
11735
            dv*(Icccc+Inccn-Inccc-Icccn)) +
 
11736
        dy*(Icncc-Icccc +
 
11737
            dz*(Icccc+Icnnc-Iccnc-Icncc +
 
11738
                dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
 
11739
            dv*(Icccc+Icncn-Icncc-Icccn)) +
 
11740
        dz*(Iccnc-Icccc +
 
11741
            dv*(Icccc+Iccnn-Iccnc-Icccn)) +
 
11742
        dv*(Icccn-Icccc);
 
11743
    }
 
11744
 
 
11745
    //! Read a pixel value using linear interpolation and Neumann boundary conditions.
 
11746
    Tfloat linear_at4(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
 
11747
      const float
 
11748
        nfx = fx<0?0:(fx>width-1?width-1:fx),
 
11749
        nfy = fy<0?0:(fy>height-1?height-1:fy),
 
11750
        nfz = fz<0?0:(fz>depth-1?depth-1:fz),
 
11751
        nfv = fv<0?0:(fv>dim-1?dim-1:fv);
 
11752
      const unsigned int
 
11753
        x = (unsigned int)nfx,
 
11754
        y = (unsigned int)nfy,
 
11755
        z = (unsigned int)nfz,
 
11756
        v = (unsigned int)nfv;
 
11757
      const float
 
11758
        dx = nfx-x,
 
11759
        dy = nfy-y,
 
11760
        dz = nfz-z,
 
11761
        dv = nfv-v;
 
11762
      const unsigned int
 
11763
        nx = dx>0?x+1:x,
 
11764
        ny = dy>0?y+1:y,
 
11765
        nz = dz>0?z+1:z,
 
11766
        nv = dv>0?v+1:v;
 
11767
      const Tfloat
 
11768
        Icccc = (Tfloat)(*this)(x,y,z,v), Inccc = (Tfloat)(*this)(nx,y,z,v),
 
11769
        Icncc = (Tfloat)(*this)(x,ny,z,v), Inncc = (Tfloat)(*this)(nx,ny,z,v),
 
11770
        Iccnc = (Tfloat)(*this)(x,y,nz,v), Incnc = (Tfloat)(*this)(nx,y,nz,v),
 
11771
        Icnnc = (Tfloat)(*this)(x,ny,nz,v), Innnc = (Tfloat)(*this)(nx,ny,nz,v),
 
11772
        Icccn = (Tfloat)(*this)(x,y,z,nv), Inccn = (Tfloat)(*this)(nx,y,z,nv),
 
11773
        Icncn = (Tfloat)(*this)(x,ny,z,nv), Inncn = (Tfloat)(*this)(nx,ny,z,nv),
 
11774
        Iccnn = (Tfloat)(*this)(x,y,nz,nv), Incnn = (Tfloat)(*this)(nx,y,nz,nv),
 
11775
        Icnnn = (Tfloat)(*this)(x,ny,nz,nv), Innnn = (Tfloat)(*this)(nx,ny,nz,nv);
 
11776
      return Icccc +
 
11777
        dx*(Inccc-Icccc +
 
11778
            dy*(Icccc+Inncc-Icncc-Inccc +
 
11779
                dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
 
11780
                    dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
 
11781
                dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
 
11782
            dz*(Icccc+Incnc-Iccnc-Inccc +
 
11783
                dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
 
11784
            dv*(Icccc+Inccn-Inccc-Icccn)) +
 
11785
        dy*(Icncc-Icccc +
 
11786
            dz*(Icccc+Icnnc-Iccnc-Icncc +
 
11787
                dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
 
11788
            dv*(Icccc+Icncn-Icncc-Icccn)) +
 
11789
        dz*(Iccnc-Icccc +
 
11790
            dv*(Icccc+Iccnn-Iccnc-Icccn)) +
 
11791
        dv*(Icccn-Icccc);
 
11792
    }
 
11793
 
 
11794
    //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first three coordinates).
 
11795
    Tfloat linear_at3(const float fx, const float fy, const float fz, const int v, const T out_val) const {
 
11796
      const int
 
11797
        x = (int)fx-(fx>=0?0:1), nx = x+1,
 
11798
        y = (int)fy-(fy>=0?0:1), ny = y+1,
 
11799
        z = (int)fz-(fz>=0?0:1), nz = z+1;
 
11800
      const float
 
11801
        dx = fx-x,
 
11802
        dy = fy-y,
 
11803
        dz = fz-z;
 
11804
      const Tfloat
 
11805
        Iccc = (Tfloat)at3(x,y,z,v,out_val), Incc = (Tfloat)at3(nx,y,z,v,out_val),
 
11806
        Icnc = (Tfloat)at3(x,ny,z,v,out_val), Innc = (Tfloat)at3(nx,ny,z,v,out_val),
 
11807
        Iccn = (Tfloat)at3(x,y,nz,v,out_val), Incn = (Tfloat)at3(nx,y,nz,v,out_val),
 
11808
        Icnn = (Tfloat)at3(x,ny,nz,v,out_val), Innn = (Tfloat)at3(nx,ny,nz,v,out_val);
 
11809
      return Iccc +
 
11810
        dx*(Incc-Iccc +
 
11811
            dy*(Iccc+Innc-Icnc-Incc +
 
11812
                dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
 
11813
            dz*(Iccc+Incn-Iccn-Incc)) +
 
11814
        dy*(Icnc-Iccc +
 
11815
            dz*(Iccc+Icnn-Iccn-Icnc)) +
 
11816
        dz*(Iccn-Iccc);
 
11817
    }
 
11818
 
 
11819
    //! Read a pixel value using linear interpolation and Neumann boundary conditions (first three coordinates).
 
11820
    Tfloat linear_at3(const float fx, const float fy=0, const float fz=0, const int v=0) const {
 
11821
      const float
 
11822
        nfx = fx<0?0:(fx>width-1?width-1:fx),
 
11823
        nfy = fy<0?0:(fy>height-1?height-1:fy),
 
11824
        nfz = fz<0?0:(fz>depth-1?depth-1:fz);
 
11825
      const unsigned int
 
11826
        x = (unsigned int)nfx,
 
11827
        y = (unsigned int)nfy,
 
11828
        z = (unsigned int)nfz;
 
11829
      const float
 
11830
        dx = nfx-x,
 
11831
        dy = nfy-y,
 
11832
        dz = nfz-z;
 
11833
      const unsigned int
 
11834
        nx = dx>0?x+1:x,
 
11835
        ny = dy>0?y+1:y,
 
11836
        nz = dz>0?z+1:z;
 
11837
      const Tfloat
 
11838
        Iccc = (Tfloat)(*this)(x,y,z,v), Incc = (Tfloat)(*this)(nx,y,z,v),
 
11839
        Icnc = (Tfloat)(*this)(x,ny,z,v), Innc = (Tfloat)(*this)(nx,ny,z,v),
 
11840
        Iccn = (Tfloat)(*this)(x,y,nz,v), Incn = (Tfloat)(*this)(nx,y,nz,v),
 
11841
        Icnn = (Tfloat)(*this)(x,ny,nz,v), Innn = (Tfloat)(*this)(nx,ny,nz,v);
 
11842
      return Iccc +
 
11843
        dx*(Incc-Iccc +
 
11844
            dy*(Iccc+Innc-Icnc-Incc +
 
11845
                dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
 
11846
            dz*(Iccc+Incn-Iccn-Incc)) +
 
11847
        dy*(Icnc-Iccc +
 
11848
            dz*(Iccc+Icnn-Iccn-Icnc)) +
 
11849
        dz*(Iccn-Iccc);
 
11850
    }
 
11851
 
 
11852
    //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first two coordinates).
 
11853
    Tfloat linear_at2(const float fx, const float fy, const int z, const int v, const T out_val) const {
 
11854
      const int
 
11855
        x = (int)fx-(fx>=0?0:1), nx = x+1,
 
11856
        y = (int)fy-(fy>=0?0:1), ny = y+1;
 
11857
      const float
 
11858
        dx = fx-x,
 
11859
        dy = fy-y;
 
11860
      const Tfloat
 
11861
        Icc = (Tfloat)at2(x,y,z,v,out_val),  Inc = (Tfloat)at2(nx,y,z,v,out_val),
 
11862
        Icn = (Tfloat)at2(x,ny,z,v,out_val), Inn = (Tfloat)at2(nx,ny,z,v,out_val);
 
11863
      return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
 
11864
    }
 
11865
 
 
11866
    //! Read a pixel value using linear interpolation and Neumann boundary conditions (first two coordinates).
 
11867
    Tfloat linear_at2(const float fx, const float fy, const int z=0, const int v=0) const {
 
11868
      const float
 
11869
        nfx = fx<0?0:(fx>width-1?width-1:fx),
 
11870
        nfy = fy<0?0:(fy>height-1?height-1:fy);
 
11871
      const unsigned int
 
11872
        x = (unsigned int)nfx,
 
11873
        y = (unsigned int)nfy;
 
11874
      const float
 
11875
        dx = nfx-x,
 
11876
        dy = nfy-y;
 
11877
      const unsigned int
 
11878
        nx = dx>0?x+1:x,
 
11879
        ny = dy>0?y+1:y;
 
11880
      const Tfloat
 
11881
        Icc = (Tfloat)(*this)(x,y,z,v),  Inc = (Tfloat)(*this)(nx,y,z,v),
 
11882
        Icn = (Tfloat)(*this)(x,ny,z,v), Inn = (Tfloat)(*this)(nx,ny,z,v);
 
11883
      return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
 
11884
    }
 
11885
 
 
11886
    //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first coordinate).
 
11887
    Tfloat linear_at1(const float fx, const int y, const int z, const int v, const T out_val) const {
 
11888
      const int
 
11889
        x = (int)fx-(fx>=0?0:1), nx = x+1;
 
11890
      const float
 
11891
        dx = fx-x;
 
11892
      const Tfloat
 
11893
        Ic = (Tfloat)at1(x,y,z,v,out_val), In = (Tfloat)at2(nx,y,z,v,out_val);
 
11894
      return Ic + dx*(In-Ic);
 
11895
    }
 
11896
 
 
11897
    //! Read a pixel value using linear interpolation and Neumann boundary conditions (first coordinate).
 
11898
    Tfloat linear_at1(const float fx, const int y=0, const int z=0, const int v=0) const {
 
11899
      const float
 
11900
        nfx = fx<0?0:(fx>width-1?width-1:fx);
 
11901
      const unsigned int
 
11902
        x = (unsigned int)nfx;
 
11903
      const float
 
11904
        dx = nfx-x;
 
11905
      const unsigned int
 
11906
        nx = dx>0?x+1:x;
 
11907
      const Tfloat
 
11908
        Ic = (Tfloat)(*this)(x,y,z,v), In = (Tfloat)(*this)(nx,y,z,v);
 
11909
      return Ic + dx*(In-Ic);
 
11910
    }
 
11911
 
 
11912
    //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions.
 
11913
    Tfloat cubic_at(const float fx, const float fy, const int z, const int v, const T out_val) const {
 
11914
      return cubic_at2(fx,fy,z,v,out_val);
 
11915
    }
 
11916
 
 
11917
    //! Read a pixel value using cubic interpolation and Neumann boundary conditions.
 
11918
    Tfloat cubic_at(const float fx, const float fy, const int z=0, const int v=0) const {
 
11919
      return cubic_at2(fx,fy,z,v);
 
11920
    }
 
11921
 
 
11922
    //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions.
 
11923
    Tfloat cubic_at2(const float fx, const float fy, const int z, const int v, const T out_val) const {
 
11924
      const int
 
11925
        x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2,
 
11926
        y = (int)fy-(fy>=0?0:1), py = y-1, ny = y+1, ay = y+2;
 
11927
      const float
 
11928
        dx = fx-x, dx2 = dx*dx, dx3 = dx2*dx,
 
11929
        dy = fy-y;
 
11930
      const Tfloat
 
11931
        Ipp = (Tfloat)at2(px,py,z,v,out_val), Icp = (Tfloat)at2(x,py,z,v,out_val),
 
11932
        Inp = (Tfloat)at2(nx,py,z,v,out_val), Iap = (Tfloat)at2(ax,py,z,v,out_val),
 
11933
        Ipc = (Tfloat)at2(px,y,z,v,out_val),  Icc = (Tfloat)at2(x,y,z,v,out_val),
 
11934
        Inc = (Tfloat)at2(nx,y,z,v,out_val),  Iac = (Tfloat)at2(ax,y,z,v,out_val),
 
11935
        Ipn = (Tfloat)at2(px,ny,z,v,out_val), Icn = (Tfloat)at2(x,ny,z,v,out_val),
 
11936
        Inn = (Tfloat)at2(nx,ny,z,v,out_val), Ian = (Tfloat)at2(ax,ny,z,v,out_val),
 
11937
        Ipa = (Tfloat)at2(px,ay,z,v,out_val), Ica = (Tfloat)at2(x,ay,z,v,out_val),
 
11938
        Ina = (Tfloat)at2(nx,ay,z,v,out_val), Iaa = (Tfloat)at2(ax,ay,z,v,out_val),
 
11939
        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)),
 
11940
        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)),
 
11941
        u0p = Icp - Ipp,
 
11942
        u1p = Iap - Inp,
 
11943
        ap = 2*(Icp-Inp) + u0p + u1p,
 
11944
        bp = 3*(Inp-Icp) - 2*u0p - u1p,
 
11945
        u0c = Icc - Ipc,
 
11946
        u1c = Iac - Inc,
 
11947
        ac = 2*(Icc-Inc) + u0c + u1c,
 
11948
        bc = 3*(Inc-Icc) - 2*u0c - u1c,
 
11949
        u0n = Icn - Ipn,
 
11950
        u1n = Ian - Inn,
 
11951
        an = 2*(Icn-Inn) + u0n + u1n,
 
11952
        bn = 3*(Inn-Icn) - 2*u0n - u1n,
 
11953
        u0a = Ica - Ipa,
 
11954
        u1a = Iaa - Ina,
 
11955
        aa = 2*(Ica-Ina) + u0a + u1a,
 
11956
        ba = 3*(Ina-Ica) - 2*u0a - u1a,
 
11957
        valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
 
11958
        valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
 
11959
        valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
 
11960
        vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
 
11961
        u0 = valc - valp,
 
11962
        u1 = vala - valn,
 
11963
        a = 2*(valc-valn) + u0 + u1,
 
11964
        b = 3*(valn-valc) - 2*u0 - u1,
 
11965
        val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
 
11966
      return val<valm?valm:(val>valM?valM:val);
 
11967
    }
 
11968
 
 
11969
    //! Read a pixel value using cubic interpolation and Neumann boundary conditions.
 
11970
    Tfloat cubic_at2(const float fx, const float fy, const int z=0, const int v=0) const {
 
11971
      const float
 
11972
        nfx = fx<0?0:(fx>width-1?width-1:fx),
 
11973
        nfy = fy<0?0:(fy>height-1?height-1:fy);
 
11974
      const int
 
11975
        x = (int)nfx,
 
11976
        y = (int)nfy;
 
11977
      const float
 
11978
        dx = nfx-x, dx2 = dx*dx, dx3 = dx2*dx,
 
11979
        dy = nfy-y;
 
11980
      const int
 
11981
        px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2,
 
11982
        py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=dimy()?dimy()-1:y+2;
 
11983
      const Tfloat
 
11984
        Ipp = (Tfloat)(*this)(px,py,z,v), Icp = (Tfloat)(*this)(x,py,z,v),
 
11985
        Inp = (Tfloat)(*this)(nx,py,z,v), Iap = (Tfloat)(*this)(ax,py,z,v),
 
11986
        Ipc = (Tfloat)(*this)(px,y,z,v),  Icc = (Tfloat)(*this)(x,y,z,v),
 
11987
        Inc = (Tfloat)(*this)(nx,y,z,v),  Iac = (Tfloat)(*this)(ax,y,z,v),
 
11988
        Ipn = (Tfloat)(*this)(px,ny,z,v), Icn = (Tfloat)(*this)(x,ny,z,v),
 
11989
        Inn = (Tfloat)(*this)(nx,ny,z,v), Ian = (Tfloat)(*this)(ax,ny,z,v),
 
11990
        Ipa = (Tfloat)(*this)(px,ay,z,v), Ica = (Tfloat)(*this)(x,ay,z,v),
 
11991
        Ina = (Tfloat)(*this)(nx,ay,z,v), Iaa = (Tfloat)(*this)(ax,ay,z,v),
 
11992
        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)),
 
11993
        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)),
 
11994
        u0p = Icp - Ipp,
 
11995
        u1p = Iap - Inp,
 
11996
        ap = 2*(Icp-Inp) + u0p + u1p,
 
11997
        bp = 3*(Inp-Icp) - 2*u0p - u1p,
 
11998
        u0c = Icc - Ipc,
 
11999
        u1c = Iac - Inc,
 
12000
        ac = 2*(Icc-Inc) + u0c + u1c,
 
12001
        bc = 3*(Inc-Icc) - 2*u0c - u1c,
 
12002
        u0n = Icn - Ipn,
 
12003
        u1n = Ian - Inn,
 
12004
        an = 2*(Icn-Inn) + u0n + u1n,
 
12005
        bn = 3*(Inn-Icn) - 2*u0n - u1n,
 
12006
        u0a = Ica - Ipa,
 
12007
        u1a = Iaa - Ina,
 
12008
        aa = 2*(Ica-Ina) + u0a + u1a,
 
12009
        ba = 3*(Ina-Ica) - 2*u0a - u1a,
 
12010
        valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
 
12011
        valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
 
12012
        valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
 
12013
        vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
 
12014
        u0 = valc - valp,
 
12015
        u1 = vala - valn,
 
12016
        a = 2*(valc-valn) + u0 + u1,
 
12017
        b = 3*(valn-valc) - 2*u0 - u1,
 
12018
        val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
 
12019
      return val<valm?valm:(val>valM?valM:val);
 
12020
    }
 
12021
 
 
12022
    //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions (first coordinates).
 
12023
    Tfloat cubic_at1(const float fx, const int y, const int z, const int v, const T out_val) const {
 
12024
      const int
 
12025
        x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2;
 
12026
      const float
 
12027
        dx = fx-x;
 
12028
      const Tfloat
 
12029
        Ip = (Tfloat)at1(px,y,z,v,out_val), Ic = (Tfloat)at1(x,y,z,v,out_val),
 
12030
        In = (Tfloat)at1(nx,y,z,v,out_val), Ia = (Tfloat)at1(ax,y,z,v,out_val),
 
12031
        valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
 
12032
        u0 = Ic - Ip,
 
12033
        u1 = Ia - In,
 
12034
        a = 2*(Ic-In) + u0 + u1,
 
12035
        b = 3*(In-Ic) - 2*u0 - u1,
 
12036
        val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
 
12037
      return val<valm?valm:(val>valM?valM:val);
 
12038
    }
 
12039
 
 
12040
    //! Read a pixel value using cubic interpolation and Neumann boundary conditions (first coordinates).
 
12041
    Tfloat cubic_at1(const float fx, const int y=0, const int z=0, const int v=0) const {
 
12042
      const float
 
12043
        nfx = fx<0?0:(fx>width-1?width-1:fx);
 
12044
      const int
 
12045
        x = (int)nfx;
 
12046
      const float
 
12047
        dx = nfx-x;
 
12048
      const int
 
12049
        px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2;
 
12050
      const Tfloat
 
12051
        Ip = (Tfloat)(*this)(px,y,z,v), Ic = (Tfloat)(*this)(x,y,z,v),
 
12052
        In = (Tfloat)(*this)(nx,y,z,v), Ia = (Tfloat)(*this)(ax,y,z,v),
 
12053
        valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
 
12054
        u0 = Ic - Ip,
 
12055
        u1 = Ia - In,
 
12056
        a = 2*(Ic-In) + u0 + u1,
 
12057
        b = 3*(In-Ic) - 2*u0 - u1,
 
12058
        val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
 
12059
      return val<valm?valm:(val>valM?valM:val);
 
12060
    }
 
12061
 
 
12062
    //! Return a reference to the maximum pixel value of the instance image
 
12063
    const T& max() const {
 
12064
      if (is_empty()) throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",pixel_type());
 
12065
      const T *ptrmax = data;
 
12066
      T max_value = *ptrmax;
 
12067
      cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 
12068
      return *ptrmax;
 
12069
    }
 
12070
 
 
12071
    //! Return a reference to the maximum pixel value of the instance image
 
12072
    T& max() {
 
12073
      if (is_empty()) throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",pixel_type());
 
12074
      T *ptrmax = data;
 
12075
      T max_value = *ptrmax;
 
12076
      cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 
12077
      return *ptrmax;
 
12078
    }
 
12079
 
 
12080
    //! Return a reference to the minimum pixel value of the instance image
 
12081
    const T& min() const {
 
12082
      if (is_empty()) throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",pixel_type());
 
12083
      const T *ptrmin = data;
 
12084
      T min_value = *ptrmin;
 
12085
      cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 
12086
      return *ptrmin;
 
12087
    }
 
12088
 
 
12089
    //! Return a reference to the minimum pixel value of the instance image
 
12090
    T& min() {
 
12091
      if (is_empty()) throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",pixel_type());
 
12092
      T *ptrmin = data;
 
12093
      T min_value = *ptrmin;
 
12094
      cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 
12095
      return *ptrmin;
 
12096
    }
 
12097
 
 
12098
    //! Return a reference to the minimum pixel value and return also the maximum pixel value.
 
12099
    template<typename t> const T& minmax(t& max_val) const {
 
12100
      if (is_empty()) throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",pixel_type());
 
12101
      const T *ptrmin = data;
 
12102
      T min_value = *ptrmin, max_value = min_value;
 
12103
      cimg_for(*this,ptr,T) {
 
12104
        const T val = *ptr;
 
12105
        if (val<min_value) { min_value = val; ptrmin = ptr; }
 
12106
        if (val>max_value) max_value = val;
 
12107
      }
 
12108
      max_val = (t)max_value;
 
12109
      return *ptrmin;
 
12110
    }
 
12111
 
 
12112
    //! Return a reference to the minimum pixel value and return also the maximum pixel value.
 
12113
    template<typename t> T& minmax(t& max_val) {
 
12114
      if (is_empty()) throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",pixel_type());
 
12115
      T *ptrmin = data;
 
12116
      T min_value = *ptrmin, max_value = min_value;
 
12117
      cimg_for(*this,ptr,T) {
 
12118
        const T val = *ptr;
 
12119
        if (val<min_value) { min_value = val; ptrmin = ptr; }
 
12120
        if (val>max_value) max_value = val;
 
12121
      }
 
12122
      max_val = (t)max_value;
 
12123
      return *ptrmin;
 
12124
    }
 
12125
 
 
12126
    //! Return a reference to the maximum pixel value and return also the minimum pixel value.
 
12127
    template<typename t> const T& maxmin(t& min_val) const {
 
12128
      if (is_empty()) throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",pixel_type());
 
12129
      const T *ptrmax = data;
 
12130
      T max_value = *ptrmax, min_value = max_value;
 
12131
      cimg_for(*this,ptr,T) {
 
12132
        const T val = *ptr;
 
12133
        if (val>max_value) { max_value = val; ptrmax = ptr; }
 
12134
        if (val<min_value) min_value = val;
 
12135
      }
 
12136
      min_val = (t)min_value;
 
12137
      return *ptrmax;
 
12138
    }
 
12139
 
 
12140
    //! Return a reference to the maximum pixel value and return also the minimum pixel value.
 
12141
    template<typename t> T& maxmin(t& min_val) {
 
12142
      if (is_empty()) throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",pixel_type());
 
12143
      T *ptrmax = data;
 
12144
      T max_value = *ptrmax, min_value = max_value;
 
12145
      cimg_for(*this,ptr,T) {
 
12146
        const T val = *ptr;
 
12147
        if (val>max_value) { max_value = val; ptrmax = ptr; }
 
12148
        if (val<min_value) min_value = val;
 
12149
      }
 
12150
      min_val = (t)min_value;
 
12151
      return *ptrmax;
 
12152
    }
 
12153
 
 
12154
    //! Return the mean pixel value of the instance image.
 
12155
    double mean() const {
 
12156
      if (is_empty()) throw CImgInstanceException("CImg<%s>::mean() : Instance image is empty.",pixel_type());
 
12157
      double val = 0;
 
12158
      cimg_for(*this,ptr,T) val+=(double)*ptr;
 
12159
      return val/size();
 
12160
    }
 
12161
 
 
12162
    //! Return the variance and the mean of the image.
 
12163
    template<typename t> double variancemean(const unsigned int variance_method, t& mean) const {
 
12164
      if (is_empty())
 
12165
        throw CImgInstanceException("CImg<%s>::variance() : Instance image is empty.",pixel_type());
 
12166
      double variance = 0, average = 0;
 
12167
      const unsigned int siz = size();
 
12168
      switch (variance_method) {
 
12169
      case 3: { // Least trimmed of Squares
 
12170
        CImg<double> buf(*this);
 
12171
        const unsigned int siz2 = siz>>1;
 
12172
        { cimg_for(buf,ptrs,double) { const double val = *ptrs; (*ptrs)*=val; average+=val; }}
 
12173
        buf.sort();
 
12174
        double a = 0;
 
12175
        const double *ptrs = buf.ptr();
 
12176
        for (unsigned int j=0; j<siz2; ++j) a+=(*ptrs++);
 
12177
        const double sig = 2.6477*std::sqrt(a/siz2);
 
12178
        variance = sig*sig;
 
12179
      } break;
 
12180
      case 2: { // Least Median of Squares (MAD)
 
12181
        CImg<double> buf(*this);
 
12182
        buf.sort();
 
12183
        const unsigned int siz2 = siz>>1;
 
12184
        const double med_i = buf[siz2];
 
12185
        cimg_for(buf,ptrs,double) { const double val = *ptrs; *ptrs = cimg::abs(val-med_i); average+=val; }
 
12186
        buf.sort();
 
12187
        const double sig = 1.4828*buf[siz2];
 
12188
        variance = sig*sig;
 
12189
      } break;
 
12190
      case 1: { // Least mean square (robust definition)
 
12191
        double S = 0, S2 = 0;
 
12192
        cimg_for(*this,ptr,T) { const double val = (double)*ptr; S+=val;  S2+=val*val; }
 
12193
        variance = siz>1?(S2 - S*S/siz)/(siz-1):0;
 
12194
        average = S;
 
12195
      } break;
 
12196
      case 0:{ // Least mean square (standard definition)
 
12197
        double S = 0, S2 = 0;
 
12198
        cimg_for(*this,ptr,T) { const double val = (double)*ptr; S+=val;  S2+=val*val; }
 
12199
        variance = (S2 - S*S/siz)/siz;
 
12200
        average = S;
 
12201
      } break;
 
12202
      default:
 
12203
        throw CImgArgumentException("CImg<%s>::variancemean() : Incorrect parameter 'variance_method = %d' (correct values are 0,1,2 or 3).",
 
12204
                                    pixel_type(),variance_method);
 
12205
      }
 
12206
      mean = (t)(average/siz);
 
12207
      return variance;
 
12208
    }
 
12209
 
 
12210
    //! Return the variance and the mean of the image.
 
12211
    double variance(const unsigned int variance_method=0) const {
 
12212
      double foo;
 
12213
      return variancemean(variance_method,foo);
 
12214
    }
 
12215
 
 
12216
    //! Compute the MSE (Mean-Squared Error) between two images.
 
12217
    template<typename t> double MSE(const CImg<t>& img) const {
 
12218
      if (img.size()!=size())
 
12219
        throw CImgArgumentException("CImg<%s>::MSE() : Instance image (%u,%u,%u,%u) and given image (%u,%u,%u,%u) have different dimensions.",
 
12220
                                    pixel_type(),width,height,depth,dim,img.width,img.height,img.depth,img.dim);
 
12221
 
 
12222
      double vMSE = 0;
 
12223
      const t* ptr2 = img.end();
 
12224
      cimg_for(*this,ptr1,T) {
 
12225
        const double diff = (double)*ptr1 - (double)*(--ptr2);
 
12226
        vMSE += diff*diff;
 
12227
      }
 
12228
      vMSE/=img.size();
 
12229
      return vMSE;
 
12230
    }
 
12231
 
 
12232
    //! Compute the PSNR between two images.
 
12233
    template<typename t> double PSNR(const CImg<t>& img, const double valmax=255.0) const {
 
12234
      const double vMSE = std::sqrt(MSE(img));
 
12235
      return (vMSE!=0)?(20*std::log10(valmax/vMSE)):(cimg::type<double>::max());
 
12236
    }
 
12237
 
 
12238
    //! Return the trace of the current matrix.
 
12239
    double trace() const {
 
12240
      if (is_empty())
 
12241
        throw CImgInstanceException("CImg<%s>::trace() : Instance matrix (%u,%u,%u,%u,%p) is empty.",
 
12242
                                    pixel_type(),width,height,depth,dim,data);
 
12243
      double res = 0;
 
12244
      cimg_forX(*this,k) res+=(*this)(k,k);
 
12245
      return res;
 
12246
    }
 
12247
 
 
12248
    //! Return the median of the image.
 
12249
    T median() const {
 
12250
      const unsigned int s = size();
 
12251
      const T res = kth_smallest(s>>1);
 
12252
      return (s%2)?res:((res+kth_smallest((s>>1)-1))/2);
 
12253
    }
 
12254
 
 
12255
    //! Return the dot product of the current vector/matrix with the vector/matrix \p img.
 
12256
    template<typename t> double dot(const CImg<t>& img) const {
 
12257
      if (is_empty())
 
12258
        throw CImgInstanceException("CImg<%s>::dot() : Instance object (%u,%u,%u,%u,%p) is empty.",
 
12259
                                    pixel_type(),width,height,depth,dim,data);
 
12260
      if (!img)
 
12261
        throw CImgArgumentException("CImg<%s>::trace() : Specified argument (%u,%u,%u,%u,%p) is empty.",
 
12262
                                    pixel_type(),img.width,img.height,img.depth,img.dim,img.data);
 
12263
      const unsigned long nb = cimg::min(size(),img.size());
 
12264
      double res = 0;
 
12265
      for (unsigned long off=0; off<nb; ++off) res+=(double)data[off]*(double)img[off];
 
12266
      return res;
 
12267
    }
 
12268
 
 
12269
    //! Return the determinant of the current matrix.
 
12270
    double det() const {
 
12271
      if (is_empty() || width!=height || depth!=1 || dim!=1)
 
12272
        throw CImgInstanceException("CImg<%s>::det() : Instance matrix (%u,%u,%u,%u,%p) is not square or is empty.",
 
12273
                                    pixel_type(),width,height,depth,dim,data);
 
12274
      switch (width) {
 
12275
      case 1: return (*this)(0,0);
 
12276
      case 2: return (*this)(0,0)*(*this)(1,1)-(*this)(0,1)*(*this)(1,0);
 
12277
      case 3: {
 
12278
        const double
 
12279
          a = data[0], d = data[1], g = data[2],
 
12280
          b = data[3], e = data[4], h = data[5],
 
12281
          c = data[6], f = data[7], i = data[8];
 
12282
        return i*a*e-a*h*f-i*b*d+b*g*f+c*d*h-c*g*e;
 
12283
      }
 
12284
      default: {
 
12285
        CImg<Tfloat> lu(*this);
 
12286
        CImg<unsigned int> indx;
 
12287
        bool d;
 
12288
        lu._LU(indx,d);
 
12289
        double res = d?1.0:-1.0;
 
12290
        cimg_forX(lu,i) res*=lu(i,i);
 
12291
        return res;
 
12292
      }
 
12293
      }
 
12294
      return 0;
 
12295
    }
 
12296
 
 
12297
    //! Return the norm of the current vector/matrix. \p ntype = norm type (0=L2, 1=L1, -1=Linf).
 
12298
    double norm(const int norm_type=2) const {
 
12299
      if (is_empty())
 
12300
        throw CImgInstanceException("CImg<%s>::norm() : Instance object (%u,%u,%u,%u,%p) is empty.",
 
12301
                                    pixel_type(),width,height,depth,dim,data);
 
12302
      double res = 0;
 
12303
      switch (norm_type) {
 
12304
      case -1: {
 
12305
        cimg_foroff(*this,off) {
 
12306
          const double tmp = cimg::abs((double)data[off]);
 
12307
          if (tmp>res) res = tmp;
 
12308
        }
 
12309
        return res;
 
12310
      } break;
 
12311
      case 1: {
 
12312
        cimg_foroff(*this,off) res+=cimg::abs((double)data[off]);
 
12313
        return res;
 
12314
      } break;
 
12315
      case 2: return std::sqrt(dot(*this)); break;
 
12316
      default:
 
12317
        throw CImgArgumentException("CImg<%s>::norm() : Incorrect parameter 'norm_type=%d' (correct values are -1,1 or 2).",
 
12318
                                    pixel_type(),norm_type);
 
12319
      }
 
12320
      return 0;
 
12321
    }
 
12322
 
 
12323
    //! Return the sum of all the pixel values in an image.
 
12324
    double sum() const {
 
12325
      if (is_empty())
 
12326
        throw CImgInstanceException("CImg<%s>::sum() : Instance object (%u,%u,%u,%u,%p) is empty.",
 
12327
                                    pixel_type(),width,height,depth,dim,data);
 
12328
      double res = 0;
 
12329
      cimg_for(*this,ptr,T) res+=*ptr;
 
12330
      return res;
 
12331
    }
 
12332
 
 
12333
    //! Return the kth smallest element of the image.
 
12334
    // (Adapted from the numerical recipies for CImg)
 
12335
    const T kth_smallest(const unsigned int k) const {
 
12336
      if (is_empty())
 
12337
        throw CImgInstanceException("CImg<%s>::kth_smallest() : Instance image (%u,%u,%u,%u,%p) is empty.",
 
12338
                                    pixel_type(),width,height,depth,dim,data);
 
12339
      CImg<T> arr(*this);
 
12340
      unsigned long l = 0, ir = size()-1;
 
12341
      for (;;) {
 
12342
        if (ir<=l+1) {
 
12343
          if (ir==l+1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
 
12344
          return arr[k];
 
12345
        } else {
 
12346
          const unsigned long mid = (l+ir)>>1;
 
12347
          cimg::swap(arr[mid],arr[l+1]);
 
12348
          if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);
 
12349
          if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]);
 
12350
          if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]);
 
12351
          unsigned long i = l+1, j = ir;
 
12352
          const T pivot = arr[l+1];
 
12353
          for (;;) {
 
12354
            do ++i; while (arr[i]<pivot);
 
12355
            do --j; while (arr[j]>pivot);
 
12356
            if (j<i) break;
 
12357
            cimg::swap(arr[i],arr[j]);
 
12358
          }
 
12359
          arr[l+1] = arr[j];
 
12360
          arr[j] = pivot;
 
12361
          if (j>=k) ir=j-1;
 
12362
          if (j<=k) l=i;
 
12363
        }
 
12364
      }
 
12365
      return 0;
8024
12366
    }
8025
12367
 
8026
12368
    //! Display informations about the image on the standard error output.
8027
12369
    /**
8028
12370
       \param title Name for the considered image (optional).
8029
 
       \param print_flag Level of informations to be printed.
8030
 
 
8031
 
       - The possible values for \c print_flag are :
8032
 
           - -1 : print nothing
8033
 
           - 0  : print only informations about image size and pixel buffer.
8034
 
           - 1  : print also statistics on the image pixels.
8035
 
           - 2  : print also the content of the pixel buffer, in a matlab-style.
8036
 
 
8037
 
       \par example:
8038
 
       \code
8039
 
       CImg<float> img("foo.jpg");      // Load image from a JPEG file.
8040
 
       img.print("Image : foo.jpg",1);  // Print image informations and statistics.
8041
 
       \endcode
8042
 
 
8043
 
       \sa CImgStats
 
12371
       \param display_stats Compute and display image statistics (optional).
8044
12372
    **/
8045
 
    const CImg& print(const char *title=0, const int print_flag=1) const {
8046
 
      if (print_flag>=0) {
8047
 
        std::fprintf(stderr,"%-8s(this=%p): { size=(%u,%u,%u,%u), data=(%s*)%p (%s)",
8048
 
                     title?title:"CImg",(void*)this,
8049
 
                     width,height,depth,dim,pixel_type(),(void*)data,
8050
 
                     is_shared?"shared":"not shared");
8051
 
        if (is_empty()) { std::fprintf(stderr,", [Undefined pixel data] }\n"); return *this; }
8052
 
        if (print_flag>=1) {
8053
 
          const CImgStats st(*this);
8054
 
          std::fprintf(stderr,", min=%g, mean=%g [var=%g], max=%g, pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d)",
8055
 
                       st.min,st.mean,st.variance,st.max,st.xmin,st.ymin,st.zmin,st.vmin,st.xmax,st.ymax,st.zmax,st.vmax);
8056
 
        }
8057
 
        if (print_flag>=2 || size()<=16) {
8058
 
          std::fprintf(stderr," }\n%s = [ ",title?title:"data");
8059
 
          cimg_forXYZV(*this,x,y,z,k)
8060
 
            std::fprintf(stderr,"%g%s",(double)(*this)(x,y,z,k),
8061
 
                         ((x+1)*(y+1)*(z+1)*(k+1)==(int)size()?" ]\n":(((x+1)%width==0)?" ; ":" ")));
8062
 
        } else std::fprintf(stderr," }\n");
8063
 
      }
8064
 
        return *this;
8065
 
    }
8066
 
 
8067
 
    //! Display informations about the image on the standard output.
8068
 
    const CImg& print(const int print_flag) const {
8069
 
      return print(0,print_flag);
 
12373
    const CImg<T>& print(const char *title=0, const bool display_stats=true) const {
 
12374
      int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0;
 
12375
      typedef typename cimg::last<T,double>::type cdouble;
 
12376
      static CImg<cdouble> st;
 
12377
      if (!is_empty() && display_stats) {
 
12378
        st = get_stats();
 
12379
        contains(data[(unsigned int)st(4)],xm,ym,zm,vm);
 
12380
        contains(data[(unsigned int)st(5)],xM,yM,zM,vM);
 
12381
      }
 
12382
      const unsigned long siz = size(), msiz = siz*sizeof(T), siz1 = siz-1;
 
12383
      const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2), width1 = width-1;
 
12384
      char ntitle[64] = { 0 };
 
12385
      if (!title) std::sprintf(ntitle,"CImg<%s>",pixel_type());
 
12386
      std::fprintf(stderr,"%s: this = %p, size = (%u,%u,%u,%u) [%lu %s], data = (%s*)%p (%s) = [ ",
 
12387
                   title?title:ntitle,(void*)this,width,height,depth,dim,
 
12388
                   mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
 
12389
                   mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
 
12390
                   pixel_type(),(void*)data,is_shared?"shared":"not shared");
 
12391
      if (!is_empty()) cimg_foroff(*this,off) {
 
12392
        std::fprintf(stderr,cimg::type<T>::format(),cimg::type<T>::format(data[off]));
 
12393
        if (off!=siz1) std::fprintf(stderr,"%s",off%width==width1?" ; ":" ");
 
12394
        if (off==7 && siz>16) { off = siz1-8; if (off!=7) std::fprintf(stderr,"... "); }
 
12395
      }
 
12396
      if (!is_empty() && display_stats)
 
12397
        std::fprintf(stderr," ], min = %g, max = %g, mean = %g, std = %g, coords(min) = (%u,%u,%u,%u), coords(max) = (%u,%u,%u,%u).\n",
 
12398
                     st[0],st[1],st[2],std::sqrt(st[3]),xm,ym,zm,vm,xM,yM,zM,vM);
 
12399
      else std::fprintf(stderr,"%s].\n",is_empty()?"":" ");
 
12400
      return *this;
8070
12401
    }
8071
12402
 
8072
12403
    //@}
8082
12413
       \param img The input image to copy.
8083
12414
       \remark
8084
12415
       - This operator is strictly equivalent to the function assign(const CImg< t >&) and has exactly the same properties.
8085
 
       \see assign(const CImg< t >&).
8086
12416
    **/
8087
12417
    template<typename t> CImg<T>& operator=(const CImg<t>& img) {
8088
12418
      return assign(img);
8089
12419
    }
8090
12420
 
8091
 
    CImg& operator=(const CImg& img) {
 
12421
    CImg<T>& operator=(const CImg<T>& img) {
8092
12422
      return assign(img);
8093
12423
    }
8094
12424
 
8106
12436
       matrice = tab;                                                   // Fill the image by the values in tab.
8107
12437
       \endcode
8108
12438
    **/
8109
 
    CImg& operator=(const T *buf) {
8110
 
      if (buf) std::memcpy(data,buf,size()*sizeof(T));
8111
 
      else assign();
8112
 
      return *this;
 
12439
    CImg<T>& operator=(const T *buf) {
 
12440
      return assign(buf,width,height,depth,dim);
8113
12441
    }
8114
12442
 
8115
12443
    //! Assign a value to each image pixel of the instance image.
8116
 
    CImg& operator=(const T& val) {
 
12444
    CImg<T>& operator=(const T val) {
8117
12445
      return fill(val);
8118
12446
    }
8119
12447
 
8122
12450
       \remark
8123
12451
       - This operator can be used to get a non-shared copy of an image.
8124
12452
    **/
8125
 
    CImg operator+() const {
 
12453
    CImg<T> operator+() const {
8126
12454
      return CImg<T>(*this,false);
8127
12455
    }
8128
12456
 
8129
12457
    //! Operator+=;
8130
12458
#ifdef cimg_use_visualcpp6
8131
 
    CImg& operator+=(const T& val) {
 
12459
    CImg<T>& operator+=(const T val) {
8132
12460
#else
8133
 
    template<typename t> CImg& operator+=(const t& val) {
 
12461
    template<typename t> CImg<T>& operator+=(const t val) {
8134
12462
#endif
8135
12463
      cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)+val);
8136
12464
      return *this;
8137
12465
    }
8138
12466
 
8139
12467
    //! Operator+=
8140
 
    template<typename t> CImg& operator+=(const CImg<t>& img) {
 
12468
    template<typename t> CImg<T>& operator+=(const CImg<t>& img) {
 
12469
      if (is_overlapping(img)) return *this+=+img;
8141
12470
      const unsigned int smin = cimg::min(size(),img.size());
8142
 
      t *ptrs = img.data+smin;
8143
 
      for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs))));
 
12471
      t *ptrs = img.data + smin;
 
12472
      for (T *ptrd = data + smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs)))) {}
8144
12473
      return *this;
8145
12474
    }
8146
12475
 
8147
 
    //! Operator++;
8148
 
    CImg& operator++() {
 
12476
    //! Operator++ (prefix)
 
12477
    CImg<T>& operator++() {
8149
12478
      cimg_for(*this,ptr,T) ++(*ptr);
8150
12479
      return *this;
8151
12480
    }
8152
12481
 
 
12482
    //! Operator++ (postfix)
 
12483
    CImg<T> operator++(int) {
 
12484
      CImg<T> copy(*this,false);
 
12485
      ++*this;
 
12486
      return copy;
 
12487
    }
 
12488
 
8153
12489
    //! Operator-.
8154
 
    CImg operator-() const {
 
12490
    CImg<T> operator-() const {
8155
12491
      return CImg<T>(width,height,depth,dim,0)-=*this;
8156
12492
    }
8157
12493
 
8158
12494
    //! Operator-=.
8159
12495
#ifdef cimg_use_visualcpp6
8160
 
    CImg& operator-=(const T& val) {
 
12496
    CImg<T>& operator-=(const T val) {
8161
12497
#else
8162
 
    template<typename t> CImg& operator-=(const t& val) {
 
12498
    template<typename t> CImg<T>& operator-=(const t val) {
8163
12499
#endif
8164
12500
      cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)-val);
8165
12501
      return *this;
8166
12502
    }
8167
12503
 
8168
12504
    //! Operator-=.
8169
 
    template<typename t> CImg& operator-=(const CImg<t>& img) {
 
12505
    template<typename t> CImg<T>& operator-=(const CImg<t>& img) {
 
12506
      if (is_overlapping(img)) return *this-=+img;
8170
12507
      const unsigned int smin = cimg::min(size(),img.size());
8171
12508
      t *ptrs = img.data+smin;
8172
 
      for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd) = (T)((*ptrd)-(*(--ptrs))));
 
12509
      for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd) = (T)((*ptrd)-(*(--ptrs)))) {}
8173
12510
      return *this;
8174
12511
    }
8175
12512
 
8176
 
    //! Operator--.
8177
 
    CImg& operator--() {
 
12513
    //! Operator-- (prefix).
 
12514
    CImg<T>& operator--() {
8178
12515
      cimg_for(*this,ptr,T) *ptr = *ptr-(T)1;
8179
12516
      return *this;
8180
12517
    }
8181
12518
 
 
12519
    //! Operator-- (postfix).
 
12520
    CImg<T> operator--(int) {
 
12521
      CImg<T> copy(*this,false);
 
12522
      --*this;
 
12523
      return copy;
 
12524
    }
 
12525
 
8182
12526
    //! Operator*=.
8183
12527
#ifdef cimg_use_visualcpp6
8184
 
    CImg& operator*=(const double val) {
 
12528
    CImg<T>& operator*=(const double val) {
8185
12529
#else
8186
 
    template<typename t> CImg& operator*=(const t& val) {
 
12530
    template<typename t> CImg<T>& operator*=(const t val) {
8187
12531
#endif
8188
12532
      cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)*val);
8189
12533
      return *this;
8190
12534
    }
8191
12535
 
8192
12536
    //! Operator*=.
8193
 
    template<typename t> CImg& operator*=(const CImg<t>& img) {
8194
 
      return ((*this)*img).swap(*this);
 
12537
    template<typename t> CImg<T>& operator*=(const CImg<t>& img) {
 
12538
      return ((*this)*img).transfer_to(*this);
8195
12539
    }
8196
12540
 
8197
12541
    //! Operator/=.
8198
12542
#ifdef cimg_use_visualcpp6
8199
 
    CImg& operator/=(const double val) {
 
12543
    CImg<T>& operator/=(const double val) {
8200
12544
#else
8201
 
    template<typename t> CImg& operator/=(const t& val) {
 
12545
    template<typename t> CImg<T>& operator/=(const t val) {
8202
12546
#endif
8203
12547
      cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)/val);
8204
12548
      return *this;
8205
12549
    }
8206
12550
 
8207
12551
    //! Operator/=.
8208
 
    template<typename t> CImg& operator/=(const CImg<t>& img) {
8209
 
      return assign(*this*img.get_inverse());
8210
 
    }
8211
 
 
8212
 
    //! Modulo.
8213
 
    CImg operator%(const CImg& img) const {
8214
 
      return (+*this)%=img;
8215
 
    }
8216
 
 
8217
 
    //! Modulo.
8218
 
    CImg operator%(const T& val) const {
 
12552
    template<typename t> CImg<T>& operator/=(const CImg<t>& img) {
 
12553
      return assign(*this*img.get_invert());
 
12554
    }
 
12555
 
 
12556
    //! Modulo.
 
12557
    template<typename t> CImg<typename cimg::superset<T,t>::type> operator%(const CImg<t>& img) const {
 
12558
      typedef typename cimg::superset<T,t>::type Tt;
 
12559
      return CImg<Tt>(*this,false)%=img;
 
12560
    }
 
12561
 
 
12562
    //! Modulo.
 
12563
    CImg<T> operator%(const T val) const {
8219
12564
      return (+*this)%=val;
8220
12565
    }
8221
12566
 
8222
12567
    //! In-place modulo.
8223
 
    CImg& operator%=(const T& val) {
 
12568
    CImg<T>& operator%=(const T val) {
8224
12569
      cimg_for(*this,ptr,T) (*ptr) = (T)cimg::mod(*ptr,val);
8225
12570
      return *this;
8226
12571
    }
8227
12572
 
8228
12573
    //! In-place modulo.
8229
 
    CImg& operator%=(const CImg& img) {
 
12574
    template<typename t> CImg<T>& operator%=(const CImg<t>& img) {
 
12575
      if (is_overlapping(img)) return *this%=+img;
 
12576
      typedef typename cimg::superset<T,t>::type Tt;
8230
12577
      const unsigned int smin = cimg::min(size(),img.size());
8231
 
      for (T *ptrs = img.data + smin, *ptrd = data + smin; ptrd>data; ) {
 
12578
      const t *ptrs = img.data + smin;
 
12579
      for (T *ptrd = data + smin; ptrd>data; ) {
8232
12580
        T& val = *(--ptrd);
8233
 
        val = (T)cimg::mod(val,*(--ptrs));
 
12581
        val = (T)cimg::mod((Tt)val,(Tt)*(--ptrs));
8234
12582
      }
8235
12583
      return *this;
8236
12584
    }
8237
12585
 
8238
12586
    //! Bitwise AND.
8239
 
    CImg operator&(const CImg& img) const {
8240
 
      return (+*this)&=img;
 
12587
    template<typename t> CImg<typename cimg::superset<T,t>::type> operator&(const CImg<t>& img) const {
 
12588
      typedef typename cimg::superset<T,t>::type Tt;
 
12589
      return CImg<Tt>(*this,false)&=img;
8241
12590
    }
8242
12591
 
8243
12592
    //! Bitwise AND.
8244
 
    CImg operator&(const T& val) const {
 
12593
    CImg<T> operator&(const T val) const {
8245
12594
      return (+*this)&=val;
8246
12595
    }
8247
12596
 
8248
12597
    //! In-place bitwise AND.
8249
 
    CImg& operator&=(const CImg& img) {
 
12598
    template<typename t> CImg<T>& operator&=(const CImg<t>& img) {
 
12599
      if (is_overlapping(img)) return *this&=+img;
8250
12600
      const unsigned int smin = cimg::min(size(),img.size());
8251
 
      for (T *ptrs=img.data+smin, *ptrd = data+smin; ptrd>data; ) {
 
12601
      const t *ptrs = img.data + smin;
 
12602
      for (T *ptrd = data + smin; ptrd>data; ) {
8252
12603
        T& val = *(--ptrd);
8253
 
        val = (T)((long)val & (long)*(--ptrs));
 
12604
        val = (T)((unsigned long)val & (unsigned long)*(--ptrs));
8254
12605
      }
8255
12606
      return *this;
8256
12607
    }
8257
12608
 
8258
12609
    //! In-place bitwise AND.
8259
 
    CImg& operator&=(const T& val) {
8260
 
      cimg_for(*this,ptr,T) *ptr = (T)((long)*ptr & (long)val);
 
12610
    CImg<T>& operator&=(const T val) {
 
12611
      cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr & (unsigned long)val);
8261
12612
      return *this;
8262
12613
    }
8263
12614
 
8264
12615
    //! Bitwise OR.
8265
 
    CImg operator|(const CImg& img) const {
8266
 
      return (+*this)|=img;
 
12616
    template<typename t> CImg<typename cimg::superset<T,t>::type> operator|(const CImg<t>& img) const {
 
12617
      typedef typename cimg::superset<T,t>::type Tt;
 
12618
      return CImg<Tt>(*this,false)|=img;
8267
12619
    }
8268
12620
 
8269
12621
    //! Bitwise OR.
8270
 
    CImg operator|(const T& val) const {
 
12622
    CImg<T> operator|(const T val) const {
8271
12623
      return (+*this)|=val;
8272
12624
    }
8273
12625
 
8274
12626
    //! In-place bitwise OR.
8275
 
    CImg& operator|=(const CImg& img) {
 
12627
    template<typename t> CImg<T>& operator|=(const CImg<t>& img) {
 
12628
      if (is_overlapping(img)) return *this|=+img;
8276
12629
      const unsigned int smin = cimg::min(size(),img.size());
8277
 
      for (T *ptrs=img.data+smin, *ptrd = data+smin; ptrd>data; ) {
 
12630
      const t *ptrs = img.data + smin;
 
12631
      for (T *ptrd = data + smin; ptrd>data; ) {
8278
12632
        T& val = *(--ptrd);
8279
 
        val = (T)((long)val | (long)*(--ptrs));
 
12633
        val = (T)((unsigned long)val | (unsigned long)*(--ptrs));
8280
12634
      }
8281
12635
      return *this;
8282
12636
    }
8283
12637
 
8284
12638
    //! In-place bitwise OR.
8285
 
    CImg& operator|=(const T& val) {
8286
 
      cimg_for(*this,ptr,T) *ptr = (T)((long)*ptr | (long)val);
 
12639
    CImg<T>& operator|=(const T val) {
 
12640
      cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr | (unsigned long)val);
8287
12641
      return *this;
8288
12642
    }
8289
12643
 
8290
12644
    //! Bitwise XOR.
8291
 
    CImg operator^(const CImg& img) const {
8292
 
      return (+*this)^=img;
 
12645
    template<typename t> CImg<typename cimg::superset<T,t>::type> operator^(const CImg<t>& img) const {
 
12646
      typedef typename cimg::superset<T,t>::type Tt;
 
12647
      return CImg<Tt>(*this,false)^=img;
8293
12648
    }
8294
12649
 
8295
12650
    //! Bitwise XOR.
8296
 
    CImg operator^(const T& val) const {
 
12651
    CImg<T> operator^(const T val) const {
8297
12652
      return (+*this)^=val;
8298
12653
    }
8299
12654
 
8300
12655
    //! In-place bitwise XOR.
8301
 
    CImg& operator^=(const CImg& img) {
 
12656
    template<typename t> CImg<T>& operator^=(const CImg<t>& img) {
 
12657
      if (is_overlapping(img)) return *this^=+img;
8302
12658
      const unsigned int smin = cimg::min(size(),img.size());
8303
 
      for (T *ptrs=img.data+smin, *ptrd = data+smin; ptrd>data; ) {
 
12659
      const t *ptrs = img.data + smin;
 
12660
      for (T *ptrd = data+smin; ptrd>data; ) {
8304
12661
        T& val = *(--ptrd);
8305
 
        val =(T)((long)val ^ (long)*(--ptrs));
 
12662
        val =(T)((unsigned long)val ^ (unsigned long)*(--ptrs));
8306
12663
      }
8307
12664
      return *this;
8308
12665
    }
8309
12666
 
8310
12667
    //! In-place bitwise XOR.
8311
 
    CImg& operator^=(const T& val) {
8312
 
      cimg_for(*this,ptr,T) *ptr = (T)((long)*ptr ^ (long)val);
 
12668
    CImg<T>& operator^=(const T val) {
 
12669
      cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr ^ (unsigned long)val);
8313
12670
      return *this;
8314
12671
    }
8315
12672
 
8316
12673
    //! Bitwise NOT.
8317
 
    CImg operator~() const {
 
12674
    CImg<T> operator~() const {
8318
12675
      CImg<T> res(width,height,depth,dim);
8319
12676
      const T *ptrs = end();
8320
 
      cimg_for(res,ptrd,T) *ptrd = (T)~(long)*(--ptrs);
 
12677
      cimg_for(res,ptrd,T) *ptrd = (T)~(unsigned long)*(--ptrs);
8321
12678
      return res;
8322
12679
    }
8323
12680
 
8324
 
    //! Bitwise shift
8325
 
    CImg& operator<<=(const int n) {
 
12681
    //! Bitwise left shift.
 
12682
    CImg<T>& operator<<=(const int n) {
8326
12683
      cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)<<n);
8327
12684
      return *this;
8328
12685
    }
8329
12686
 
8330
 
    //! Bitwise shift
8331
 
    CImg operator<<(const int n) const {
 
12687
    //! Bitwise left shift.
 
12688
    CImg<T> operator<<(const int n) const {
8332
12689
      return (+*this)<<=n;
8333
12690
    }
8334
12691
 
8335
 
    //! Bitwise shift
8336
 
    CImg& operator>>=(const int n) {
 
12692
    //! Bitwise right shift.
 
12693
    CImg<T>& operator>>=(const int n) {
8337
12694
      cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)>>n);
8338
12695
      return *this;
8339
12696
    }
8340
12697
 
8341
 
    //! Bitwise shift
8342
 
    CImg operator>>(const int n) const {
 
12698
    //! Bitwise right shift.
 
12699
    CImg<T> operator>>(const int n) const {
8343
12700
      return (+*this)>>=n;
8344
12701
    }
8345
12702
 
8348
12705
      const unsigned int siz = size();
8349
12706
      bool vequal = true;
8350
12707
      if (siz!=img.size()) return false;
8351
 
      t *ptrs=img.data+siz;
8352
 
      for (T *ptrd=data+siz; vequal && ptrd>data; vequal=vequal&&((*(--ptrd))==(*(--ptrs))));
 
12708
      t *ptrs = img.data + siz;
 
12709
      for (T *ptrd = data + siz; vequal && ptrd>data; vequal = vequal && ((*(--ptrd))==(*(--ptrs)))) {}
8353
12710
      return vequal;
8354
12711
    }
8355
12712
 
8358
12715
      return !((*this)==img);
8359
12716
    }
8360
12717
 
8361
 
    //! Return a list of two images { *this, img }
8362
 
    template<typename t> CImgList<typename cimg::largest<T,t>::type> operator<<(const CImg<t>& img) const {
8363
 
      typedef typename cimg::largest<T,t>::type restype;
8364
 
      return CImgList<restype>(*this,img);
 
12718
    //! Return a list of two images { *this, img }.
 
12719
    template<typename t> CImgList<typename cimg::superset<T,t>::type> operator<<(const CImg<t>& img) const {
 
12720
      typedef typename cimg::superset<T,t>::type Tt;
 
12721
      return CImgList<Tt>(*this,img);
8365
12722
    }
8366
12723
 
8367
12724
    //! Return a copy of \p list, where image *this has been inserted at first position.
8368
 
    template<typename t> CImgList<typename cimg::largest<T,t>::type> operator<<(const CImgList<t>& list) const {
8369
 
      typedef typename cimg::largest<T,t>::type restype;
8370
 
      return CImgList<restype>(list).insert(*this,0);
 
12725
    template<typename t> CImgList<typename cimg::superset<T,t>::type> operator<<(const CImgList<t>& list) const {
 
12726
      typedef typename cimg::superset<T,t>::type Tt;
 
12727
      return CImgList<Tt>(list).insert(*this,0);
8371
12728
    }
8372
12729
 
8373
 
    //! Return a list of two images { *this, img }
8374
 
    template<typename t> CImgList<typename cimg::largest<T,t>::type> operator>>(const CImg<t>& img) const {
 
12730
    //! Return a list of two images { *this, img }.
 
12731
    template<typename t> CImgList<typename cimg::superset<T,t>::type> operator>>(const CImg<t>& img) const {
8375
12732
      return (*this)<<img;
8376
12733
    }
8377
12734
 
8378
 
    //! Insert an image into the begining of an image list
 
12735
    //! Insert an image into the begining of an image list.
8379
12736
    template<typename t> CImgList<t>& operator>>(const CImgList<t>& list) const {
8380
12737
      return list.insert(*this,0);
8381
12738
    }
8382
12739
 
8383
 
    //! Display an image into a CImgDisplay
8384
 
    const CImg& operator>>(CImgDisplay& disp) const {
 
12740
    //! Display an image into a CImgDisplay.
 
12741
    const CImg<T>& operator>>(CImgDisplay& disp) const {
8385
12742
      return display(disp);
8386
12743
    }
8387
12744
 
8388
12745
    //@}
8389
12746
    //---------------------------------------
8390
12747
    //
8391
 
    //! \name Usual Mathematics
 
12748
    //! \name Usual Mathematics Functions
8392
12749
    //@{
8393
12750
    //---------------------------------------
8394
12751
 
8395
 
    //! Apply a R->R function on all image value.
8396
 
    template<typename t> CImg& apply(t& func) {
 
12752
    //! Apply a R->R function on all pixel values.
 
12753
    template<typename t> CImg<T> get_apply(t& func) const {
 
12754
      return (+*this).apply(func);
 
12755
    }
 
12756
 
 
12757
    //! Apply a R->R function on all pixel values (in-place).
 
12758
    template<typename t> CImg<T>& apply(t& func) {
8397
12759
      cimg_for(*this,ptr,T) *ptr = func(*ptr);
8398
12760
      return *this;
8399
12761
    }
8400
12762
 
8401
 
    //! Return an image where each pixel value is equal to func(x).
8402
 
    template<typename t> CImg get_apply(t& func) const {
8403
 
      return (+*this).apply(func);
 
12763
    //! Pointwise multiplication between two images.
 
12764
    template<typename t> CImg<typename cimg::superset<T,t>::type> get_mul(const CImg<t>& img) const {
 
12765
      typedef typename cimg::superset<T,t>::type Tt;
 
12766
      return CImg<Tt>(*this,false).mul(img);
8404
12767
    }
8405
12768
 
8406
 
    //! In-place pointwise multiplication between \c *this and \c img.
8407
 
    /**
8408
 
       This is the in-place version of get_mul().
8409
 
       \sa get_mul().
8410
 
    **/
8411
 
    template<typename t> CImg& mul(const CImg<t>& img) {
 
12769
    //! Pointwise multiplication between two images (in-place).
 
12770
    template<typename t> CImg<T>& mul(const CImg<t>& img) {
 
12771
      if (is_overlapping(img)) return mul(+img);
8412
12772
      t *ptrs = img.data;
8413
12773
      T *ptrf = data + cimg::min(size(),img.size());
8414
12774
      for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd*(*(ptrs++)));
8415
12775
      return *this;
8416
12776
    }
8417
12777
 
8418
 
    //! Pointwise multiplication between \c *this and \c img.
8419
 
    /**
8420
 
       \param img Argument of the multiplication.
8421
 
       - if \c *this and \c img have different size, the multiplication is applied on the maximum possible range.
8422
 
       \sa get_div(),mul(),div()
8423
 
    **/
8424
 
    template<typename t> CImg<typename cimg::largest<T,t>::type> get_mul(const CImg<t>& img) const {
8425
 
      typedef typename cimg::largest<T,t>::type restype;
8426
 
      return CImg<restype>(*this,false).mul(img);
 
12778
    //! Pointwise division between two images.
 
12779
    template<typename t> CImg<typename cimg::superset<T,t>::type> get_div(const CImg<t>& img) const {
 
12780
      typedef typename cimg::superset<T,t>::type Tt;
 
12781
      return CImg<Tt>(*this,false).div(img);
8427
12782
    }
8428
12783
 
8429
 
    //! Replace the image by the pointwise division between \p *this and \p img.
8430
 
    /**
8431
 
       This is the in-place version of get_div().
8432
 
       \see get_div().
8433
 
    **/
8434
 
    template<typename t> CImg& div(const CImg<t>& img) {
 
12784
    //! Pointwise division between two images (in-place).
 
12785
    template<typename t> CImg<T>& div(const CImg<t>& img) {
 
12786
      if (is_overlapping(img)) return div(+img);
8435
12787
      t *ptrs = img.data;
8436
12788
      T *ptrf = data + cimg::min(size(),img.size());
8437
12789
      for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd/(*(ptrs++)));
8438
12790
      return *this;
8439
12791
    }
8440
12792
 
8441
 
    //! Return an image from a pointwise division between \p *this and \p img.
8442
 
    /**
8443
 
       \param img = argument of the division.
8444
 
       \note if \c *this and \c img have different size, the division is applied
8445
 
       only on possible values.
8446
 
       \see get_mul(),mul(),div()
8447
 
    **/
8448
 
    template<typename t> CImg<typename cimg::largest<T,t>::type> get_div(const CImg<t>& img) const {
8449
 
      typedef typename cimg::largest<T,t>::type restype;
8450
 
      return CImg<restype>(*this,false).div(img);
 
12793
    //! Pointwise max operator between two images.
 
12794
    template<typename t> CImg<typename cimg::superset<T,t>::type> get_max(const CImg<t>& img) const {
 
12795
      typedef typename cimg::superset<T,t>::type Tt;
 
12796
      return CImg<Tt>(*this,false).max(img);
8451
12797
    }
8452
12798
 
8453
 
    //! Replace the image by the pointwise max operator between \p *this and \p img
8454
 
    /**
8455
 
       This is the in-place version of get_max().
8456
 
       \see get_max().
8457
 
    **/
8458
 
    template<typename t> CImg& max(const CImg<t>& img) {
 
12799
    //! Pointwise max operator between two images (in-place).
 
12800
    template<typename t> CImg<T>& max(const CImg<t>& img) {
 
12801
      if (is_overlapping(img)) return max(+img);
8459
12802
      t *ptrs = img.data;
8460
12803
      T *ptrf = data + cimg::min(size(),img.size());
8461
12804
      for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::max((T)*(ptrs++),*ptrd);
8462
12805
      return *this;
8463
12806
    }
8464
12807
 
8465
 
    //! Return the image corresponding to the max value for each pixel.
8466
 
    /**
8467
 
       \param img = second argument of the max operator (the first one is *this).
8468
 
       \see max(), min(), get_min()
8469
 
    **/
8470
 
    template<typename t> CImg<typename cimg::largest<T,t>::type> get_max(const CImg<t>& img) const {
8471
 
      typedef typename cimg::largest<T,t>::type restype;
8472
 
      return CImg<restype>(*this,false).max(img);
 
12808
    //! Pointwise max operator between an image and a value.
 
12809
    CImg<T> get_max(const T val) const {
 
12810
      return (+*this).max(val);
8473
12811
    }
8474
12812
 
8475
 
    //! Replace the image by the pointwise max operator between \p *this and \p val
8476
 
    /**
8477
 
       This is the in-place version of get_max().
8478
 
       \see get_max().
8479
 
    **/
8480
 
    CImg& max(const T& val) {
 
12813
    //! Pointwise max operator between an image and a value (in-place).
 
12814
    CImg<T>& max(const T val) {
8481
12815
      cimg_for(*this,ptr,T) (*ptr) = cimg::max(*ptr,val);
8482
12816
      return *this;
8483
12817
    }
8484
12818
 
8485
 
    //! Return the image corresponding to the max value for each pixel.
8486
 
    /**
8487
 
       \param val = second argument of the max operator (the first one is *this).
8488
 
       \see max(), min(), get_min()
8489
 
    **/
8490
 
    CImg get_max(const T& val) const {
8491
 
      return (+*this).max(val);
 
12819
    //! Pointwise min operator between two images.
 
12820
    template<typename t> CImg<typename cimg::superset<T,t>::type> get_min(const CImg<t>& img) const {
 
12821
      typedef typename cimg::superset<T,t>::type Tt;
 
12822
      return CImg<Tt>(*this,false).min(img);
8492
12823
    }
8493
12824
 
8494
 
    //! Replace the image by the pointwise min operator between \p *this and \p img
8495
 
    /**
8496
 
       This is the in-place version of get_min().
8497
 
       \see get_min().
8498
 
    **/
8499
 
    template<typename t> CImg& min(const CImg<t>& img) {
 
12825
    //! Pointwise min operator between two images (in-place).
 
12826
    template<typename t> CImg<T>& min(const CImg<t>& img) {
 
12827
      if (is_overlapping(img)) return min(+img);
8500
12828
      t *ptrs = img.data;
8501
12829
      T *ptrf = data + cimg::min(size(),img.size());
8502
12830
      for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::min((T)*(ptrs++),*ptrd);
8503
12831
      return *this;
8504
12832
    }
8505
 
    //! Return the image corresponding to the min value for each pixel.
8506
 
    /**
8507
 
       \param img = second argument of the min operator (the first one is *this).
8508
 
       \see min(), max(), get_max()
8509
 
    **/
8510
 
    template<typename t> CImg<typename cimg::largest<T,t>::type> get_min(const CImg<t>& img) const {
8511
 
      typedef typename cimg::largest<T,t>::type restype;
8512
 
      return CImg<restype>(*this,false).min(img);
 
12833
 
 
12834
    //! Pointwise min operator between an image and a value.
 
12835
    CImg<T> get_min(const T val) const {
 
12836
      return (+*this).min(val);
8513
12837
    }
8514
12838
 
8515
 
    //! Replace the image by the pointwise min operator between \p *this and \p val
8516
 
    /**
8517
 
       This is the in-place version of get_min().
8518
 
       \see get_min().
8519
 
    **/
8520
 
    CImg& min(const T& val) {
 
12839
    //! Pointwise min operator between an image and a value (in-place).
 
12840
    CImg<T>& min(const T val) {
8521
12841
      cimg_for(*this,ptr,T) (*ptr) = cimg::min(*ptr,val);
8522
12842
      return *this;
8523
12843
    }
8524
12844
 
8525
 
    //! Return the image corresponding to the min value for each pixel.
8526
 
    /**
8527
 
       \param val = second argument of the min operator (the first one is *this).
8528
 
       \see min(), max(), get_max()
8529
 
    **/
8530
 
    CImg get_min(const T& val) const {
8531
 
      return (+*this).min(val);
8532
 
    }
8533
 
 
8534
 
    //! Replace each image pixel by its square root.
8535
 
    /**
8536
 
       \see get_sqrt()
8537
 
    **/
8538
 
    CImg& sqrt() {
 
12845
    //! Compute a statistics vector (min,max,mean,variance,offmin,offmax).
 
12846
    CImg<Tdouble> get_stats() const {
 
12847
      return CImg<Tdouble>(*this,false).stats();
 
12848
    }
 
12849
 
 
12850
    //! Compute a statistics vector (min,max,mean,variance,offmin,offmax) (in-place).
 
12851
    CImg<T>& stats() {
 
12852
      if (is_empty())
 
12853
        throw CImgInstanceException("CImg<%s>::stats() : Instance image is empty.",pixel_type());
 
12854
      const unsigned long siz = size();
 
12855
      const T *const odata = data;
 
12856
      const T *pm = odata, *pM = odata;
 
12857
      double S = 0, S2 = 0;
 
12858
      T m = *pm, M = m;
 
12859
      cimg_for(*this,ptr,T) {
 
12860
        const T val = *ptr;
 
12861
        const double fval = (double)val;
 
12862
        if (val<m) { m = val; pm = ptr; }
 
12863
        if (val>M) { M = val; pM = ptr; }
 
12864
        S+=fval;
 
12865
        S2+=fval*fval;
 
12866
      }
 
12867
      return assign(1,6).fill((T)m,(T)M,(T)(S/siz),(T)((S2-S*S/siz)/siz),(T)(pm-odata),(T)(pM-odata));
 
12868
    }
 
12869
 
 
12870
    //! Compute the square of each pixel value.
 
12871
    CImg<Tfloat> get_sqr() const {
 
12872
      return CImg<Tfloat>(*this,false).sqr();
 
12873
    }
 
12874
 
 
12875
    //! Compute the square of each pixel value (in-place).
 
12876
    CImg<T>& sqr() {
 
12877
      cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)(val*val); };
 
12878
      return *this;
 
12879
    }
 
12880
 
 
12881
    //! Compute the square root of each pixel value.
 
12882
    CImg<Tfloat> get_sqrt() const {
 
12883
      return CImg<Tfloat>(*this,false).sqrt();
 
12884
    }
 
12885
 
 
12886
    //! Compute the square root of each pixel value (in-place).
 
12887
    CImg<T>& sqrt() {
8539
12888
      cimg_for(*this,ptr,T) (*ptr) = (T)std::sqrt((double)(*ptr));
8540
12889
      return *this;
8541
12890
    }
8542
12891
 
8543
 
    //! Return the image of the square root of the pixel values.
8544
 
    /**
8545
 
       \see sqrt()
8546
 
    **/
8547
 
    CImg<typename cimg::largest<T,float>::type> get_sqrt() const {
8548
 
      typedef typename cimg::largest<T,float>::type restype;
8549
 
      return CImg<restype>(*this,false).sqrt();
 
12892
    //! Compute the exponential of each pixel value.
 
12893
    CImg<Tfloat> get_exp() const {
 
12894
      return CImg<Tfloat>(*this,false).exp();
8550
12895
    }
8551
12896
 
8552
 
    //! Replace each image pixel by its exponential.
8553
 
    CImg& exp() {
 
12897
    //! Compute the exponential of each pixel value (in-place).
 
12898
    CImg<T>& exp() {
8554
12899
      cimg_for(*this,ptr,T) (*ptr) = (T)std::exp((double)(*ptr));
8555
12900
      return *this;
8556
12901
    }
8557
12902
 
8558
 
    //! Return the image of the exponential of the pixel values.
8559
 
    CImg<typename cimg::largest<T,float>::type> get_exp() const {
8560
 
      typedef typename cimg::largest<T,float>::type restype;
8561
 
      return CImg<restype>(*this,false).exp();
 
12903
    //! Compute the log of each each pixel value.
 
12904
    CImg<Tfloat> get_log() const {
 
12905
      return CImg<Tfloat>(*this,false).log();
8562
12906
    }
8563
12907
 
8564
 
    //! Replace each image pixel by its log.
8565
 
    /**
8566
 
       \see get_log(), log10(), get_log10()
8567
 
    **/
8568
 
    CImg& log() {
 
12908
    //! Compute the log of each each pixel value (in-place).
 
12909
    CImg<T>& log() {
8569
12910
      cimg_for(*this,ptr,T) (*ptr) = (T)std::log((double)(*ptr));
8570
12911
      return *this;
8571
12912
    }
8572
12913
 
8573
 
    //! Return the image of the log of the pixel values.
8574
 
    /**
8575
 
       \see log(), log10(), get_log10()
8576
 
    **/
8577
 
    CImg<typename cimg::largest<T,float>::type> get_log() const {
8578
 
      typedef typename cimg::largest<T,float>::type restype;
8579
 
      return CImg<restype>(*this,false).log();
 
12914
    //! Compute the log10 of each each pixel value.
 
12915
    CImg<Tfloat> get_log10() const {
 
12916
      return CImg<Tfloat>(*this,false).log10();
8580
12917
    }
8581
12918
 
8582
 
    //! Replace each image pixel by its log10.
8583
 
    /**
8584
 
       \see get_log10(), log(), get_log()
8585
 
    **/
8586
 
    CImg& log10() {
 
12919
    //! Compute the log10 of each each pixel value (in-place).
 
12920
    CImg<T>& log10() {
8587
12921
      cimg_for(*this,ptr,T) (*ptr) = (T)std::log10((double)(*ptr));
8588
12922
      return *this;
8589
12923
    }
8590
12924
 
8591
 
    //! Return the image of the log10 of the pixel values.
8592
 
    /**
8593
 
       \see log10(), log(), get_log()
8594
 
    **/
8595
 
    CImg<typename cimg::largest<T,float>::type> get_log10() const {
8596
 
      typedef typename cimg::largest<T,float>::type restype;
8597
 
      return CImg<restype>(*this,false).log10();
 
12925
    //! Compute the power by p of each pixel value.
 
12926
    CImg<Tfloat> get_pow(const double p) const {
 
12927
      return CImg<Tfloat>(*this,false).pow(p);
8598
12928
    }
8599
12929
 
8600
 
    //! Replace each image pixel by its power by \p p.
8601
 
    /**
8602
 
       \param p = power
8603
 
       \see get_pow(), sqrt(), get_sqrt()
8604
 
    **/
8605
 
    CImg& pow(const double p) {
 
12930
    //! Compute the power by p of each pixel value (in-place).
 
12931
    CImg<T>& pow(const double p) {
8606
12932
      if (p==0) return fill(1);
8607
 
      if (p==0.5) { cimg_for(*this,ptr,T) { const T& val = *ptr; *ptr = (T)std::sqrt((double)val); } return *this; }
 
12933
      if (p==0.5) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)std::sqrt((double)val); } return *this; }
8608
12934
      if (p==1) return *this;
8609
 
      if (p==2) { cimg_for(*this,ptr,T) { const T& val = *ptr; *ptr = val*val; } return *this; }
8610
 
      if (p==3) { cimg_for(*this,ptr,T) { const T& val = *ptr; *ptr = val*val*val; } return *this; }
8611
 
      if (p==4) { cimg_for(*this,ptr,T) { const T& val = *ptr; *ptr = val*val*val*val; } return *this; }
 
12935
      if (p==2) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val; } return *this; }
 
12936
      if (p==3) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val; } return *this; }
 
12937
      if (p==4) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val*val; } return *this; }
8612
12938
      cimg_for(*this,ptr,T) (*ptr) = (T)std::pow((double)(*ptr),p);
8613
12939
      return *this;
8614
12940
    }
8615
12941
 
8616
 
    //! Return the image of the square root of the pixel values.
8617
 
    /**
8618
 
       \param p = power
8619
 
       \see pow(), sqrt(), get_sqrt()
8620
 
    **/
8621
 
    CImg<typename cimg::largest<T,float>::type> get_pow(const double p) const {
8622
 
      typedef typename cimg::largest<T,float>::type restype;
8623
 
      return CImg<restype>(*this,false).pow(p);
 
12942
    //! Compute the power of each pixel value.
 
12943
    template<typename t> CImg<Tfloat> get_pow(const CImg<t>& img) const {
 
12944
      return CImg<Tfloat>(*this,false).pow(img);
8624
12945
    }
8625
12946
 
8626
 
    //! Return each image pixel (*this)(x,y,z,k) by its power by \p img(x,y,z,k)
8627
 
    /**
8628
 
       In-place version
8629
 
    **/
8630
 
    template<typename t> CImg& pow(const CImg<t>& img) {
 
12947
    //! Compute the power of each pixel value (in-place).
 
12948
    template<typename t> CImg<T>& pow(const CImg<t>& img) {
 
12949
      if (is_overlapping(img)) return pow(+img);
8631
12950
      t *ptrs = img.data;
8632
12951
      T *ptrf = data + cimg::min(size(),img.size());
8633
12952
      for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)std::pow((double)*ptrd,(double)(*(ptrs++)));
8634
12953
      return *this;
8635
12954
    }
8636
12955
 
8637
 
    //! Return each image pixel (*this)(x,y,z,k) by its power by \p img(x,y,z,k)
8638
 
    template<typename t> CImg<typename cimg::largest<T,float>::type> get_pow(const CImg<t>& img) const {
8639
 
      typedef typename cimg::largest<T,float>::type restype;
8640
 
      return CImg<restype>(*this,false).pow(img);
 
12956
    //! Compute the absolute value of each pixel value.
 
12957
    CImg<Tfloat> get_abs() const {
 
12958
      return CImg<Tfloat>(*this,false).abs();
8641
12959
    }
8642
12960
 
8643
 
    //! Replace each pixel value by its absolute value.
8644
 
    /**
8645
 
       \see get_abs()
8646
 
    **/
8647
 
    CImg& abs() {
 
12961
    //! Compute the absolute value of each pixel value (in-place).
 
12962
    CImg<T>& abs() {
8648
12963
      cimg_for(*this,ptr,T) (*ptr) = cimg::abs(*ptr);
8649
12964
      return *this;
8650
12965
    }
8651
12966
 
8652
 
    //! Return the image of the absolute value of the pixel values.
8653
 
    /**
8654
 
       \see abs()
8655
 
    **/
8656
 
    CImg<typename cimg::largest<T,float>::type> get_abs() const {
8657
 
      typedef typename cimg::largest<T,float>::type restype;
8658
 
      return CImg<restype>(*this,false).abs();
 
12967
    //! Compute the cosinus of each pixel value.
 
12968
    CImg<Tfloat> get_cos() const {
 
12969
      return CImg<Tfloat>(*this,false).cos();
8659
12970
    }
8660
12971
 
8661
 
    //! Replace each image pixel by its cosinus.
8662
 
    /**
8663
 
       \see get_cos(), sin(), get_sin(), tan(), get_tan()
8664
 
    **/
8665
 
    CImg& cos() {
 
12972
    //! Compute the cosinus of each pixel value (in-place).
 
12973
    CImg<T>& cos() {
8666
12974
      cimg_for(*this,ptr,T) (*ptr) = (T)std::cos((double)(*ptr));
8667
12975
      return *this;
8668
12976
    }
8669
12977
 
8670
 
    //! Return the image of the cosinus of the pixel values.
8671
 
    /**
8672
 
       \see cos(), sin(), get_sin(), tan(), get_tan()
8673
 
    **/
8674
 
    CImg<typename cimg::largest<T,float>::type> get_cos() const {
8675
 
      typedef typename cimg::largest<T,float>::type restype;
8676
 
      return CImg<restype>(*this,false).cos();
 
12978
    //! Compute the sinus of each pixel value.
 
12979
    CImg<Tfloat> get_sin() const {
 
12980
      return CImg<Tfloat>(*this,false).sin();
8677
12981
    }
8678
12982
 
8679
 
    //! Replace each image pixel by its sinus.
8680
 
    /**
8681
 
       \see get_sin(), cos(), get_cos(), tan(), get_tan()
8682
 
    **/
8683
 
    CImg& sin() {
 
12983
    //! Compute the sinus of each pixel value (in-place).
 
12984
    CImg<T>& sin() {
8684
12985
      cimg_for(*this,ptr,T) (*ptr) = (T)std::sin((double)(*ptr));
8685
12986
      return *this;
8686
12987
    }
8687
12988
 
8688
 
    //! Return the image of the sinus of the pixel values.
8689
 
    /**
8690
 
       \see sin(), cos(), get_cos(), tan(), get_tan()
8691
 
    **/
8692
 
    CImg<typename cimg::largest<T,float>::type> get_sin() const {
8693
 
      typedef typename cimg::largest<T,float>::type restype;
8694
 
      return CImg<restype>(*this,false).sin();
 
12989
    //! Compute the tangent of each pixel.
 
12990
    CImg<Tfloat> get_tan() const {
 
12991
      return CImg<Tfloat>(*this,false).tan();
8695
12992
    }
8696
12993
 
8697
 
    //! Replace each image pixel by its tangent.
8698
 
    /**
8699
 
       \see get_tan(), cos(), get_cos(), sin(), get_sin()
8700
 
    **/
8701
 
    CImg& tan() {
 
12994
    //! Compute the tangent of each pixel (in-place).
 
12995
    CImg<T>& tan() {
8702
12996
      cimg_for(*this,ptr,T) (*ptr) = (T)std::tan((double)(*ptr));
8703
12997
      return *this;
8704
12998
    }
8705
12999
 
8706
 
    //! Return the image of the tangent of the pixel values.
8707
 
    /**
8708
 
       \see tan(), cos(), get_cos(), sin(), get_sin()
8709
 
    **/
8710
 
    CImg<typename cimg::largest<T,float>::type> get_tan() const {
8711
 
      typedef typename cimg::largest<T,float>::type restype;
8712
 
      return CImg<restype>(*this,false).tan();
 
13000
    //! Compute the arc-cosine of each pixel value.
 
13001
    CImg<Tfloat> get_acos() const {
 
13002
      return CImg<Tfloat>(*this,false).acos();
8713
13003
    }
8714
13004
 
8715
 
    //! Replace each image pixel by its arc-cosinus.
8716
 
    CImg& acos() {
 
13005
    //! Compute the arc-cosine of each pixel value (in-place).
 
13006
    CImg<T>& acos() {
8717
13007
      cimg_for(*this,ptr,T) (*ptr) = (T)std::acos((double)(*ptr));
8718
13008
      return *this;
8719
13009
    }
8720
13010
 
8721
 
    //! Return the image of the arc-cosinus of the pixel values.
8722
 
    CImg<typename cimg::largest<T,float>::type> get_acos() const {
8723
 
      typedef typename cimg::largest<T,float>::type restype;
8724
 
      return CImg<restype>(*this,false).acos();
 
13011
    //! Compute the arc-sinus of each pixel value.
 
13012
    CImg<Tfloat> get_asin() const {
 
13013
      return CImg<Tfloat>(*this,false).asin();
8725
13014
    }
8726
13015
 
8727
 
    //! Replace each image pixel by its arc-sinus.
8728
 
    CImg& asin() {
 
13016
    //! Compute the arc-sinus of each pixel value (in-place).
 
13017
    CImg<T>& asin() {
8729
13018
      cimg_for(*this,ptr,T) (*ptr) = (T)std::asin((double)(*ptr));
8730
13019
      return *this;
8731
13020
    }
8732
13021
 
8733
 
    //! Return the image of the arc-sinus of the pixel values.
8734
 
    CImg<typename cimg::largest<T,float>::type> get_asin() const {
8735
 
      typedef typename cimg::largest<T,float>::type restype;
8736
 
      return CImg<restype>(*this,false).asin();
 
13022
    //! Compute the arc-tangent of each pixel.
 
13023
    CImg<Tfloat> get_atan() const {
 
13024
      return CImg<Tfloat>(*this,false).atan();
8737
13025
    }
8738
13026
 
8739
 
    //! Replace each image pixel by its arc-tangent.
8740
 
    CImg& atan() {
 
13027
    //! Compute the arc-tangent of each pixel (in-place).
 
13028
    CImg<T>& atan() {
8741
13029
      cimg_for(*this,ptr,T) (*ptr) = (T)std::atan((double)(*ptr));
8742
13030
      return *this;
8743
13031
    }
8744
13032
 
8745
 
    //! Return the image of the arc-tangent of the pixel values.
8746
 
    CImg<typename cimg::largest<T,float>::type> get_atan() const {
8747
 
      typedef typename cimg::largest<T,float>::type restype;
8748
 
      return CImg<restype>(*this,false).atan();
8749
 
    }
8750
 
 
8751
 
    //! Round image values
 
13033
    //! Compute image with rounded pixel values.
8752
13034
    /**
8753
 
       \param round_type : 0 (nearest), 1 (forward), 2 (backward).
 
13035
       \param x Rounding precision.
 
13036
       \param round_type Roundin type, can be 0 (nearest), 1 (forward), 2 (backward).
8754
13037
    **/
8755
 
    CImg& round(const float x, const unsigned int round_type=0) {
 
13038
    CImg<T> get_round(const float x, const unsigned int round_type=0) const {
 
13039
      return (+*this).round(x,round_type);
 
13040
    }
 
13041
 
 
13042
    //! Compute image with rounded pixel values (in-place).
 
13043
    CImg<T>& round(const float x, const unsigned int round_type=0) {
8756
13044
      cimg_for(*this,ptr,T) (*ptr) = (T)cimg::round(*ptr,x,round_type);
8757
13045
      return *this;
8758
13046
    }
8759
13047
 
8760
 
    //! Return the image of rounded values
8761
 
    CImg get_round(const float x, const unsigned int round_type=0) const {
8762
 
      return (+*this).round(x,round_type);
8763
 
    }
8764
 
 
8765
 
    //! Return the MSE (Mean-Squared Error) between two images.
8766
 
    template<typename t> double MSE(const CImg<t>& img) const {
8767
 
      if (img.size()!=size())
8768
 
        throw CImgArgumentException("CImg<%s>::MSE() : Instance image (%u,%u,%u,%u) and given image (%u,%u,%u,%u) have different dimensions.",
8769
 
                                    pixel_type(),width,height,depth,dim,img.width,img.height,img.depth,img.dim);
8770
 
 
8771
 
      double vMSE = 0;
8772
 
      const t* ptr2 = img.end();
8773
 
      cimg_for(*this,ptr1,T) {
8774
 
        const double diff = (double)*ptr1 - (double)*(--ptr2);
8775
 
        vMSE += diff*diff;
8776
 
      }
8777
 
      vMSE/=img.size();
8778
 
      return vMSE;
8779
 
    }
8780
 
 
8781
 
    //! Return the PSNR between two images.
8782
 
    template<typename t> double PSNR(const CImg<t>& img, const double valmax=255.0) const {
8783
 
      const double vMSE = std::sqrt(MSE(img));
8784
 
      return (vMSE!=0)?(20*std::log10(valmax/vMSE)):(cimg::type<double>::max());
 
13048
    //! Compute an image filled with random values between specified range.
 
13049
    CImg<T> get_rand(const T val_min, const T val_max) const {
 
13050
      return (+*this).rand(val_min,val_max);
 
13051
    }
 
13052
 
 
13053
    //! Return an image filled with random values between specified range (in-place).
 
13054
    CImg<T>& rand(const T val_min, const T val_max) {
 
13055
      const float delta = (float)val_max - (float)val_min;
 
13056
      cimg_for(*this,ptr,T) *ptr = (T)(val_min + cimg::rand()*delta);
 
13057
      return *this;
8785
13058
    }
8786
13059
 
8787
13060
    //@}
8795
13068
    /**
8796
13069
       \param val = fill value
8797
13070
       \note All pixel values of the instance image will be initialized by \p val.
8798
 
       \see operator=().
8799
13071
    **/
8800
 
    CImg& fill(const T& val) {
 
13072
    CImg<T> get_fill(const T val) const {
 
13073
      return CImg<T>(width,height,depth,dim).fill(val);
 
13074
    }
 
13075
 
 
13076
    //! Fill an image by a value \p val (in-place).
 
13077
    CImg<T>& fill(const T val) {
8801
13078
      if (!is_empty()) {
8802
 
        if (val!=0 && sizeof(T)!=1) cimg_for(*this,ptr,T) *ptr = val;
 
13079
        if (val && sizeof(T)!=1) cimg_for(*this,ptr,T) *ptr = val;
8803
13080
        else std::memset(data,(int)val,size()*sizeof(T));
8804
13081
      }
8805
13082
      return *this;
8806
13083
    }
8807
13084
 
8808
 
    CImg get_fill(const T& val) const {
8809
 
      return (+*this).fill(val);
8810
 
    }
8811
 
 
8812
13085
    //! Fill sequentially all pixel values with values \a val0 and \a val1 respectively.
8813
 
    CImg& fill(const T& val0, const T& val1) {
 
13086
    CImg<T> get_fill(const T val0, const T val1) const {
 
13087
      return CImg<T>(width,height,depth,dim).fill(val0,val1);
 
13088
    }
 
13089
 
 
13090
    //! Fill sequentially all pixel values with values \a val0 and \a val1 respectively (in-place).
 
13091
    CImg<T>& fill(const T val0, const T val1) {
8814
13092
      if (!is_empty()) {
8815
13093
        T *ptr, *ptr_end = end()-1;
8816
13094
        for (ptr=data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; }
8819
13097
      return *this;
8820
13098
    }
8821
13099
 
8822
 
    CImg get_fill(const T& val0, const T& val1) const {
8823
 
      return (+*this).fill(val0,val1);
8824
 
    }
8825
 
 
8826
13100
    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2.
8827
 
    CImg& fill(const T& val0, const T& val1, const T& val2) {
 
13101
    CImg<T> get_fill(const T val0, const T val1, const T val2) const {
 
13102
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2);
 
13103
    }
 
13104
 
 
13105
    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 (in-place).
 
13106
    CImg<T>& fill(const T val0, const T val1, const T val2) {
8828
13107
      if (!is_empty()) {
8829
13108
        T *ptr, *ptr_end = end()-2;
8830
13109
        for (ptr=data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; }
8837
13116
      return *this;
8838
13117
    }
8839
13118
 
8840
 
    CImg get_fill(const T& val0, const T& val1, const T& val2) const {
8841
 
      return (+*this).fill(val0,val1,val2);
8842
 
    }
8843
 
 
8844
13119
    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3.
8845
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3) {
 
13120
    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3) const {
 
13121
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3);
 
13122
    }
 
13123
 
 
13124
    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 (in-place).
 
13125
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3) {
8846
13126
      if (!is_empty()) {
8847
13127
        T *ptr, *ptr_end = end()-3;
8848
13128
        for (ptr=data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; }
8856
13136
      return *this;
8857
13137
    }
8858
13138
 
8859
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3) const {
8860
 
      return (+*this).fill(val0,val1,val2,val3);
8861
 
    }
8862
 
 
8863
13139
    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4.
8864
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4) {
 
13140
    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4) const {
 
13141
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4);
 
13142
    }
 
13143
 
 
13144
    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 (in-place).
 
13145
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4) {
8865
13146
      if (!is_empty()) {
8866
13147
        T *ptr, *ptr_end = end()-4;
8867
13148
        for (ptr=data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; }
8876
13157
      return *this;
8877
13158
    }
8878
13159
 
8879
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4) const {
8880
 
      return (+*this).fill(val0,val1,val2,val3,val4);
 
13160
    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5.
 
13161
    CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) const {
 
13162
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5);
8881
13163
    }
8882
13164
 
8883
 
    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5
8884
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) {
 
13165
    //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5 (in-place).
 
13166
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) {
8885
13167
      if (!is_empty()) {
8886
13168
        T *ptr, *ptr_end = end()-5;
8887
13169
        for (ptr=data; ptr<ptr_end; ) {
8899
13181
      return *this;
8900
13182
    }
8901
13183
 
8902
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) const {
8903
 
      return (+*this).fill(val0,val1,val2,val3,val4,val5);
8904
 
    }
8905
 
 
8906
13184
    //! Fill sequentially pixel values.
8907
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6) {
 
13185
    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 {
 
13186
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6);
 
13187
    }
 
13188
 
 
13189
    //! Fill sequentially pixel values (in-place).
 
13190
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) {
8908
13191
      if (!is_empty()) {
8909
13192
        T *ptr, *ptr_end = end()-6;
8910
13193
        for (ptr=data; ptr<ptr_end; ) {
8923
13206
      return *this;
8924
13207
    }
8925
13208
 
8926
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6) const {
8927
 
      return (+*this).fill(val0,val1,val2,val3,val4,val5,val6);
8928
 
    }
8929
 
 
8930
13209
    //! Fill sequentially pixel values.
8931
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
8932
 
               const T& val7) {
 
13210
    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,
 
13211
                     const T val7) const {
 
13212
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7);
 
13213
    }
 
13214
 
 
13215
    //! Fill sequentially pixel values (in-place).
 
13216
    CImg<T>& 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) {
8933
13218
      if (!is_empty()) {
8934
13219
        T *ptr, *ptr_end = end()-7;
8935
13220
        for (ptr=data; ptr<ptr_end; ) {
8950
13235
      return *this;
8951
13236
    }
8952
13237
 
8953
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
8954
 
                  const T& val7) const {
8955
 
      return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7);
8956
 
    }
8957
 
 
8958
13238
    //! Fill sequentially pixel values.
8959
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
8960
 
               const T& val7, const T& val8) {
 
13239
    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,
 
13240
                     const T val7, const T val8) const {
 
13241
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);
 
13242
    }
 
13243
 
 
13244
    //! Fill sequentially pixel values (in-place).
 
13245
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 
13246
                  const T val7, const T val8) {
8961
13247
      if (!is_empty()) {
8962
13248
        T *ptr, *ptr_end = end()-8;
8963
13249
        for (ptr=data; ptr<ptr_end; ) {
8980
13266
      return *this;
8981
13267
    }
8982
13268
 
8983
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
8984
 
                  const T& val7, const T& val8) const {
8985
 
      return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);
8986
 
    }
8987
 
 
8988
13269
    //! Fill sequentially pixel values.
8989
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
8990
 
               const T& val7, const T& val8, const T& val9) {
 
13270
    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,
 
13271
                     const T val7, const T val8, const T val9) const {
 
13272
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);
 
13273
    }
 
13274
 
 
13275
    //! Fill sequentially pixel values (in-place).
 
13276
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 
13277
                  const T val7, const T val8, const T val9) {
8991
13278
      if (!is_empty()) {
8992
13279
        T *ptr, *ptr_end = end()-9;
8993
13280
        for (ptr=data; ptr<ptr_end; ) {
9010
13297
      return *this;
9011
13298
    }
9012
13299
 
9013
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9014
 
                  const T& val7, const T& val8, const T& val9) const {
9015
 
      return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);
9016
 
    }
9017
 
 
9018
13300
    //! Fill sequentially pixel values.
9019
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9020
 
               const T& val7, const T& val8, const T& val9, const T& val10) {
 
13301
    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,
 
13302
                     const T val7, const T val8, const T val9, const T val10) const {
 
13303
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10);
 
13304
    }
 
13305
 
 
13306
    //! Fill sequentially pixel values (in-place).
 
13307
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 
13308
                  const T val7, const T val8, const T val9, const T val10) {
9021
13309
      if (!is_empty()) {
9022
13310
        T *ptr, *ptr_end = end()-10;
9023
13311
        for (ptr=data; ptr<ptr_end; ) {
9042
13330
      return *this;
9043
13331
    }
9044
13332
 
9045
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9046
 
                  const T& val7, const T& val8, const T& val9, const T& val10) const {
9047
 
      return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10);
9048
 
    }
9049
 
 
9050
13333
    //! Fill sequentially pixel values.
9051
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9052
 
               const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) {
 
13334
    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,
 
13335
                     const T val7, const T val8, const T val9, const T val10, const T val11) const {
 
13336
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11);
 
13337
    }
 
13338
 
 
13339
    //! Fill sequentially pixel values (in-place).
 
13340
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 
13341
                  const T val7, const T val8, const T val9, const T val10, const T val11) {
9053
13342
      if (!is_empty()) {
9054
13343
        T *ptr, *ptr_end = end()-11;
9055
13344
        for (ptr=data; ptr<ptr_end; ) {
9074
13363
      return *this;
9075
13364
    }
9076
13365
 
9077
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9078
 
                  const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) const {
9079
 
      return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11);
9080
 
    }
9081
 
 
9082
13366
    //! Fill sequentially pixel values.
9083
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9084
 
               const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12) {
 
13367
    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,
 
13368
                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) const {
 
13369
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12);
 
13370
    }
 
13371
 
 
13372
    //! Fill sequentially pixel values (in-place).
 
13373
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 
13374
                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) {
9085
13375
      if (!is_empty()) {
9086
13376
        T *ptr, *ptr_end = end()-12;
9087
13377
        for (ptr=data; ptr<ptr_end; ) {
9108
13398
      return *this;
9109
13399
    }
9110
13400
 
9111
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9112
 
                  const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12) const {
9113
 
      return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12);
9114
 
    }
9115
 
 
9116
13401
    //! Fill sequentially pixel values.
9117
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9118
 
               const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12,
9119
 
               const T& val13) {
 
13402
    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,
 
13403
                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 
13404
                     const T val13) const {
 
13405
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13);
 
13406
    }
 
13407
 
 
13408
    //! Fill sequentially pixel values (in-place).
 
13409
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 
13410
                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 
13411
                  const T val13) {
9120
13412
      if (!is_empty()) {
9121
13413
        T *ptr, *ptr_end = end()-13;
9122
13414
        for (ptr=data; ptr<ptr_end; ) {
9144
13436
      return *this;
9145
13437
    }
9146
13438
 
9147
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9148
 
                  const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12,
9149
 
                  const T& val13) const {
9150
 
      return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13);
9151
 
    }
9152
 
 
9153
13439
    //! Fill sequentially pixel values.
9154
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9155
 
               const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12,
9156
 
               const T& val13, const T& val14) {
 
13440
    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,
 
13441
                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 
13442
                     const T val13, const T val14) const {
 
13443
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14);
 
13444
    }
 
13445
 
 
13446
    //! Fill sequentially pixel values (in-place).
 
13447
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 
13448
                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 
13449
                  const T val13, const T val14) {
9157
13450
      if (!is_empty()) {
9158
13451
        T *ptr, *ptr_end = end()-14;
9159
13452
        for (ptr=data; ptr<ptr_end; ) {
9182
13475
      return *this;
9183
13476
    }
9184
13477
 
9185
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9186
 
                  const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12,
9187
 
                  const T& val13, const T& val14) const {
9188
 
      return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14);
9189
 
    }
9190
 
 
9191
13478
    //! Fill sequentially pixel values.
9192
 
    CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9193
 
               const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12,
9194
 
               const T& val13, const T& val14, const T& val15) {
 
13479
    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,
 
13480
                     const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 
13481
                     const T val13, const T val14, const T val15) const {
 
13482
      return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14,val15);
 
13483
    }
 
13484
 
 
13485
    //! Fill sequentially pixel values (in-place).
 
13486
    CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
 
13487
                  const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
 
13488
                  const T val13, const T val14, const T val15) {
9195
13489
      if (!is_empty()) {
9196
13490
        T *ptr, *ptr_end = end()-15;
9197
13491
        for (ptr=data; ptr<ptr_end; ) {
9221
13515
      return *this;
9222
13516
    }
9223
13517
 
9224
 
    CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, const T& val6,
9225
 
                  const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, const T& val12,
9226
 
                  const T& val13, const T& val14, const T& val15) const {
9227
 
      return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14,val15);
9228
 
    }
9229
 
 
9230
 
    template<int N, typename t> CImg& _fill(const t& val0, va_list &ap) {
 
13518
    //! Fill sequentially pixel values.
 
13519
    template<int N> CImg<T> get_fill(const int val0, ...) const {
 
13520
      CImg<T> res(*this,false);
 
13521
      va_list ap;
 
13522
      va_start(ap,val0);
 
13523
      res._fill<N,int>(val0,ap);
 
13524
      va_end(ap);
 
13525
      return res;
 
13526
    }
 
13527
 
 
13528
    //! Fill sequentially pixel values (in-place).
 
13529
    template<int N> CImg<T>& fill(const int val0, ...) {
 
13530
      va_list ap;
 
13531
      va_start(ap,val0);
 
13532
      _fill<N,int>(val0,ap);
 
13533
      va_end(ap);
 
13534
      return *this;
 
13535
    }
 
13536
 
 
13537
    //! Fill sequentially pixel values.
 
13538
    template<int N> CImg<T> get_fill(const double val0, ...) const {
 
13539
      CImg<T> res(*this,false);
 
13540
      va_list ap;
 
13541
      va_start(ap,val0);
 
13542
      res._fill<N,double>(val0,ap);
 
13543
      va_end(ap);
 
13544
      return res;
 
13545
    }
 
13546
 
 
13547
    //! Fill sequentially pixel values (in-place).
 
13548
    template<int N> CImg<T>& fill(const double val0, ...) {
 
13549
      va_list ap;
 
13550
      va_start(ap,val0);
 
13551
      _fill<N,double>(val0,ap);
 
13552
      va_end(ap);
 
13553
      return *this;
 
13554
    }
 
13555
 
 
13556
    template<int N, typename t> CImg<T>& _fill(const t val0, va_list &ap) {
9231
13557
      if (N>0 && !is_empty()) {
9232
13558
        CImg<T> vals(N);
9233
13559
        T *ptrs = vals.data;
9243
13569
      return *this;
9244
13570
    }
9245
13571
 
9246
 
    template<int N> CImg& fill(const int& val0, ...) {
9247
 
      va_list ap;
9248
 
      va_start(ap,val0);
9249
 
      _fill<N,int>(val0,ap);
9250
 
      va_end(ap);
9251
 
      return *this;
9252
 
    }
9253
 
 
9254
 
    template<int N> CImg& fill(const double& val0, ...) {
9255
 
      va_list ap;
9256
 
      va_start(ap,val0);
9257
 
      _fill<N,double>(val0,ap);
9258
 
      va_end(ap);
9259
 
      return *this;
9260
 
    }
9261
 
 
9262
 
    template<int N> CImg get_fill(const int& val0, ...) const {
9263
 
      CImg res(*this,false);
9264
 
      va_list ap;
9265
 
      va_start(ap,val0);
9266
 
      res._fill<N,int>(val0,ap);
9267
 
      va_end(ap);
9268
 
      return res;
9269
 
    }
9270
 
 
9271
 
    template<int N> CImg get_fill(const double& val0, ...) const {
9272
 
      CImg res(*this,false);
9273
 
      va_list ap;
9274
 
      va_start(ap,val0);
9275
 
      res._fill<N,double>(val0,ap);
9276
 
      va_end(ap);
9277
 
      return res;
 
13572
    //! Fill image values according to the values found in the specified string.
 
13573
    CImg<T> get_fill(const char *const values, const bool repeat_pattern) const {
 
13574
      return CImg<T>(width,height,depth,dim).fill(values,repeat_pattern);
 
13575
    }
 
13576
 
 
13577
    //! Fill image values according to the values found in the specified string (in-place).
 
13578
    CImg<T>& fill(const char *const values, const bool repeat_pattern) {
 
13579
      T *ptrd = data, *ptr_end = data + size();
 
13580
      const char *nvalues = values;
 
13581
      char tmp[64] = { 0 },  cval[64] = { 0 };
 
13582
      double val = 0;
 
13583
      unsigned int nb = 0;
 
13584
      while (std::sscanf(nvalues,"%63[ \n\t0-9e.+-]%63[^0-9.+-]",cval,tmp)>0
 
13585
             && std::sscanf(cval,"%lf",&val)>0) {
 
13586
        nvalues += cimg::strlen(tmp) + cimg::strlen(cval);
 
13587
        *(ptrd++) = (T)val;
 
13588
        ++nb;
 
13589
      }
 
13590
      if (repeat_pattern && nb) for (T *ptrs = data; ptrd<ptr_end; ++ptrs) *(ptrd++) = *ptrs;
 
13591
      return *this;
 
13592
    }
 
13593
 
 
13594
    //! Fill image values along the V-axis at the specified pixel position (x,y,z) (int version)
 
13595
    CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) {
 
13596
 
 
13597
#define _cimg_fillv(x,y,z,a0,t) if (x<width && y<height && z<depth) { \
 
13598
    va_list ap; va_start(ap,a0); \
 
13599
    const unsigned int whz = width*height*depth; \
 
13600
    T *ptrd = ptr(x,y,z,0); *ptrd = (T)a0; \
 
13601
    for (unsigned int k=1; k<dim; ++k) { ptrd+=whz; *ptrd = (T)va_arg(ap,t); } \
 
13602
    va_end(ap); }
 
13603
      _cimg_fillv(x,y,z,a0,int);
 
13604
      return *this;
 
13605
    }
 
13606
 
 
13607
    //! Fill image values along the V-axis at the specified pixel position (x,y,z) (double version)
 
13608
    CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) {
 
13609
      _cimg_fillv(x,y,z,a0,double);
 
13610
      return *this;
 
13611
    }
 
13612
 
 
13613
    //! Fill image values along the ZV-axes at the specified pixel position (x,y) (int version)
 
13614
    CImg<T>& fillZV(const unsigned int x, const unsigned int y, const int a0, ...) {
 
13615
 
 
13616
#define _cimg_fillzv(x,y,a0,t) if (x<width && y<height) { \
 
13617
    va_list ap; va_start(ap,a0); \
 
13618
    const unsigned int wh = width*height, zd = depth*dim; \
 
13619
    T *ptrd = ptr(x,y,0,0); *ptrd = (T)a0; \
 
13620
    for (unsigned int k=1; k<zd; ++k) { ptrd+=wh; *ptrd = (T)va_arg(ap,t); } \
 
13621
    va_end(ap); }
 
13622
      _cimg_fillzv(x,y,a0,int);
 
13623
      return *this;
 
13624
    }
 
13625
 
 
13626
    //! Fill image values along the ZV-axes at the specified pixel position (x,y) (double version)
 
13627
    CImg<T>& fillZV(const unsigned int x, const unsigned int y, const double a0, ...) {
 
13628
      _cimg_fillzv(x,y,a0,double);
 
13629
      return *this;
 
13630
    }
 
13631
 
 
13632
    //! Fill image values along the YZV-axes at the specified pixel position x (int version)
 
13633
    CImg<T>& fillYZV(const unsigned int x, const int a0, ...) {
 
13634
#define _cimg_fillyzv(x,a0,t) if (x<width) { \
 
13635
    va_list ap; va_start(ap,a0); \
 
13636
    const unsigned int hzd = height*depth*dim; \
 
13637
    T *ptrd = ptr(x,0,0,0); *ptrd = (T)a0; \
 
13638
    for (unsigned int k=1; k<hzd; ++k) { ptrd+=width; *ptrd = (T)va_arg(ap,t); } \
 
13639
    va_end(ap); \
 
13640
}
 
13641
      _cimg_fillyzv(x,a0,int);
 
13642
      return *this;
 
13643
    }
 
13644
 
 
13645
    //! Fill image values along the YZV-axes at the specified pixel position x (double version)
 
13646
    CImg<T>& fillYZV(const unsigned int x, const double a0, ...) {
 
13647
      _cimg_fillyzv(x,a0,double);
 
13648
      return *this;
9278
13649
    }
9279
13650
 
9280
13651
    //! Linear normalization of the pixel values between \a a and \a b.
9281
 
    /**
9282
 
       \param a = minimum pixel value after normalization.
9283
 
       \param b = maximum pixel value after normalization.
9284
 
       \see get_normalize(), cut(), get_cut().
9285
 
    **/
9286
 
    CImg& normalize(const T& a, const T& b) {
9287
 
      if (!is_empty()) {
9288
 
        const CImgStats st(*this,false);
9289
 
        if (st.min==st.max) return fill(0);
9290
 
        if (st.min!=a || st.max!=b) cimg_for(*this,ptr,T) *ptr = (T)((*ptr-st.min)/(st.max-st.min)*(b-a)+a);
9291
 
      }
9292
 
      return *this;
9293
 
    }
9294
 
 
9295
 
    //! Return the image of normalized values.
9296
 
    /**
9297
 
       \param a = minimum pixel value after normalization.
9298
 
       \param b = maximum pixel value after normalization.
9299
 
       \see normalize(), cut(), get_cut().
9300
 
    **/
9301
 
    CImg get_normalize(const T& a, const T& b) const {
 
13652
    CImg<T> get_normalize(const T a, const T b) const {
9302
13653
      return (+*this).normalize(a,b);
9303
13654
    }
9304
13655
 
 
13656
    //! Linear normalization of the pixel values between \a a and \a b (in-place).
 
13657
    CImg<T>& normalize(const T a, const T b) {
 
13658
      if (!is_empty()) {
 
13659
        T m, M = maxmin(m);
 
13660
        const Tfloat fm = (Tfloat)m, fM = (Tfloat)M;
 
13661
        if (m==M) return fill(0);
 
13662
        if (m!=a || M!=b) cimg_for(*this,ptr,T) *ptr = (T)((*ptr-fm)/(fM-fm)*(b-a)+a);
 
13663
      }
 
13664
      return *this;
 
13665
    }
 
13666
 
9305
13667
    //! Cut pixel values between \a a and \a b.
9306
 
    /**
9307
 
       \param a = minimum pixel value after cut.
9308
 
       \param b = maximum pixel value after cut.
9309
 
       \see get_cut(), normalize(), get_normalize().
9310
 
    **/
9311
 
    CImg& cut(const T& a, const T& b) {
 
13668
    CImg<T> get_cut(const T a, const T b) const {
 
13669
      return (+*this).cut(a,b);
 
13670
    }
 
13671
 
 
13672
    //! Cut pixel values between \a a and \a b (in-place).
 
13673
    CImg<T>& cut(const T a, const T b) {
9312
13674
      if (!is_empty())
9313
13675
        cimg_for(*this,ptr,T) *ptr = (*ptr<a)?a:((*ptr>b)?b:*ptr);
9314
13676
      return *this;
9315
13677
    }
9316
13678
 
9317
 
    //! Return the image of cutted values.
9318
 
    /**
9319
 
       \param a = minimum pixel value after cut.
9320
 
       \param b = maximum pixel value after cut.
9321
 
       \see cut(), normalize(), get_normalize().
9322
 
    **/
9323
 
    CImg get_cut(const T& a, const T& b) const {
9324
 
      return (+*this).cut(a,b);
9325
 
    }
9326
 
 
9327
13679
    //! Quantize pixel values into \n levels.
9328
 
    /**
9329
 
       \param n = number of quantification levels
9330
 
       \see get_quantize().
9331
 
    **/
9332
 
    CImg& quantize(const unsigned int n=256) {
 
13680
    CImg<T> get_quantize(const unsigned int n=256, const bool keep_range=true) const {
 
13681
      return (+*this).quantize(n,keep_range);
 
13682
    }
 
13683
 
 
13684
    //! Quantize pixel values into \n levels (in-place).
 
13685
    CImg<T>& quantize(const unsigned int n=256, const bool keep_range=true) {
9333
13686
      if (!is_empty()) {
9334
13687
        if (!n) throw CImgArgumentException("CImg<%s>::quantize() : Cannot quantize image to 0 values.",
9335
13688
                                            pixel_type());
9336
 
        const CImgStats st(*this,false);
9337
 
        const double range = st.max-st.min;
9338
 
        if (range>0) cimg_for(*this,ptr,T) {
9339
 
          const unsigned int val = (unsigned int)((*ptr-st.min)*n/range);
9340
 
          *ptr = (T)(st.min + cimg::min(val,n-1)*range);
 
13689
        Tfloat m, M = (Tfloat)maxmin(m), range = M - m;
 
13690
        if (range>0) {
 
13691
          if (keep_range) cimg_for(*this,ptr,T) {
 
13692
            const unsigned int val = (unsigned int)((*ptr-m)*n/range);
 
13693
            *ptr = (T)(m + cimg::min(val,n-1)*range/n);
 
13694
          } else cimg_for(*this,ptr,T) {
 
13695
            const unsigned int val = (unsigned int)((*ptr-m)*n/range);
 
13696
            *ptr = (T)cimg::min(val,n-1);
 
13697
          }
9341
13698
        }
9342
13699
      }
9343
13700
      return *this;
9344
13701
    }
9345
13702
 
9346
 
    //! Return a quantified image, with \n levels.
9347
 
    /**
9348
 
       \param n = number of quantification levels
9349
 
       \see quantize().
9350
 
    **/
9351
 
    CImg get_quantize(const unsigned int n=256) const {
9352
 
      return (+*this).quantize(n);
9353
 
    }
9354
 
 
9355
13703
    //! Threshold the image.
9356
 
    /**
9357
 
       \param thres = threshold
9358
 
       \see get_threshold().
9359
 
    **/
9360
 
    CImg& threshold(const T& thres) {
9361
 
      if (!is_empty()) cimg_for(*this,ptr,T) *ptr = *ptr<=thres?(T)0:(T)1;
 
13704
    CImg<typename cimg::last<T,bool>::type> get_threshold(const T thres, const bool strict=false) const {
 
13705
      return (+*this).threshold(thres,strict);
 
13706
    }
 
13707
 
 
13708
    //! Threshold the image (in-place).
 
13709
    CImg<T>& threshold(const T thres, const bool strict=false) {
 
13710
      if (!is_empty()) {
 
13711
        if (strict) cimg_for(*this,ptr,T) *ptr = *ptr>thres?(T)1:(T)0;
 
13712
        else cimg_for(*this,ptr,T) *ptr = *ptr>=thres?(T)1:(T)0;
 
13713
      }
9362
13714
      return *this;
9363
13715
    }
9364
13716
 
9365
 
    //! Return a thresholded image.
9366
 
    /**
9367
 
       \param thres = threshold.
9368
 
       \see threshold().
9369
 
    **/
9370
 
    CImg get_threshold(const T& thres) const {
9371
 
      return (+*this).threshold(thres);
9372
 
    }
9373
 
 
9374
 
    //! Return a rotated image.
 
13717
    //! Rotate an image.
9375
13718
    /**
9376
13719
       \param angle = rotation angle (in degrees).
9377
13720
       \param cond = rotation type. can be :
9379
13722
       - 1 = repeat image at borders
9380
13723
       - 2 = zero-value at borders and linear interpolation
9381
13724
       \note Returned image will probably have a different size than the instance image *this.
9382
 
       \see rotate()
9383
13725
    **/
9384
 
    CImg get_rotate(const float angle, const unsigned int cond=3) const {
 
13726
    CImg<T> get_rotate(const float angle, const unsigned int cond=3) const {
9385
13727
      if (is_empty()) return CImg<T>();
9386
 
      CImg dest;
9387
 
      const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0),
 
13728
      CImg<T> dest;
 
13729
      const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::valuePI)/180.0),
9388
13730
        ca=(float)std::cos(rad), sa=(float)std::sin(rad);
9389
13731
      if (cond!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
9390
13732
        const int wm1 = dimx()-1, hm1 = dimy()-1;
9416
13758
        case 0: {
9417
13759
          cimg_forXY(dest,x,y)
9418
13760
            cimg_forZV(*this,z,v)
9419
 
            dest(x,y,z,v) = pix2d((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v,0);
 
13761
            dest(x,y,z,v) = at2((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v,0);
9420
13762
        } break;
9421
13763
        case 1: {
9422
13764
          cimg_forXY(dest,x,y)
9423
13765
            cimg_forZV(*this,z,v)
9424
 
            dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)width),
9425
 
                                    cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),(int)height),z,v);
 
13766
            dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),dimx()),
 
13767
                                    cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),dimy()),z,v);
9426
13768
        } break;
9427
13769
        case 2: {
9428
13770
          cimg_forXY(dest,x,y) {
9429
13771
            const float X = w2 + (x-dw2)*ca + (y-dh2)*sa, Y = h2 - (x-dw2)*sa + (y-dh2)*ca;
9430
 
            cimg_forZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v,0);
 
13772
            cimg_forZV(*this,z,v) dest(x,y,z,v) = (T)linear_at2(X,Y,z,v,0);
9431
13773
          }
9432
13774
        } break;
9433
 
        default: {
 
13775
        case 3: {
9434
13776
          cimg_forXY(dest,x,y) {
9435
13777
            const float X = w2 + (x-dw2)*ca + (y-dh2)*sa, Y = h2 - (x-dw2)*sa + (y-dh2)*ca;
9436
 
            cimg_forZV(*this,z,v) dest(x,y,z,v) = (T)cubic_pix2d(X,Y,z,v,0);
 
13778
            cimg_forZV(*this,z,v) dest(x,y,z,v) = (T)cubic_at2(X,Y,z,v,0);
9437
13779
          }
9438
13780
        } break;
 
13781
        default:
 
13782
          throw CImgArgumentException("CImg<%s>::get_rotate() : Incorrect parameter 'cond=%d' (correct values are 0,1,2 or 3).",
 
13783
                                      pixel_type());
9439
13784
        }
9440
13785
      }
9441
13786
      return dest;
9442
13787
    }
9443
13788
 
9444
 
    //! Rotate the image
9445
 
    /**
9446
 
       \param angle = rotation angle (in degrees).
9447
 
       \param cond = rotation type. can be :
9448
 
       - 0 = zero-value at borders
9449
 
       - 1 = repeat image at borders
9450
 
       - 2 = zero-value at borders and linear interpolation
9451
 
       \see get_rotate()
9452
 
    **/
9453
 
    CImg& rotate(const float angle, const unsigned int cond=3) { return get_rotate(angle,cond).swap(*this); }
 
13789
    //! Rotate an image (in-place version).
 
13790
    CImg<T>& rotate(const float angle, const unsigned int cond=3) {
 
13791
      return get_rotate(angle,cond).transfer_to(*this);
 
13792
    }
9454
13793
 
9455
 
    //! Return a rotated image around the point (\c cx,\c cy).
 
13794
    //! Rotate an image around a center point (\c cx,\c cy).
9456
13795
    /**
9457
13796
       \param angle = rotation angle (in degrees).
9458
13797
       \param cx = X-coordinate of the rotation center.
9462
13801
       - 0 = zero-value at borders
9463
13802
       - 1 = repeat image at borders
9464
13803
       - 2 = zero-value at borders and linear interpolation
9465
 
       \see rotate()
9466
13804
    **/
9467
 
    CImg get_rotate(const float angle, const float cx, const float cy, const float zoom=1, const unsigned int cond=3) const {
 
13805
    CImg<T> get_rotate(const float angle, const float cx, const float cy, const float zoom=1, const unsigned int cond=3) const {
9468
13806
      if (is_empty()) return CImg<T>();
9469
 
      CImg dest(width,height,depth,dim);
9470
 
      const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0),
 
13807
      CImg<T> dest(width,height,depth,dim);
 
13808
      const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::valuePI)/180.0),
9471
13809
        ca=(float)std::cos(rad)/zoom, sa=(float)std::sin(rad)/zoom;
9472
13810
      if (cond!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
9473
13811
        const int iangle = (int)nangle/90;
9503
13841
        case 0: {
9504
13842
          cimg_forXY(dest,x,y)
9505
13843
            cimg_forZV(*this,z,v)
9506
 
            dest(x,y,z,v) = pix2d((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v,0);
 
13844
            dest(x,y,z,v) = at2((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v,0);
9507
13845
        } break;
9508
13846
        case 1: {
9509
13847
          cimg_forXY(dest,x,y)
9510
13848
            cimg_forZV(*this,z,v)
9511
 
            dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)width),
9512
 
                                    cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),(int)height),z,v);
 
13849
            dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),dimx()),
 
13850
                                    cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),dimy()),z,v);
9513
13851
        } break;
9514
13852
        case 2: {
9515
13853
          cimg_forXY(dest,x,y) {
9516
13854
            const float X = cx + (x-cx)*ca + (y-cy)*sa, Y = cy - (x-cx)*sa + (y-cy)*ca;
9517
 
            cimg_forZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v,0);
 
13855
            cimg_forZV(*this,z,v) dest(x,y,z,v) = (T)linear_at2(X,Y,z,v,0);
9518
13856
          }
9519
13857
        } break;
9520
 
        default: {
 
13858
        case 3: {
9521
13859
          cimg_forXY(dest,x,y) {
9522
13860
            const float X = cx + (x-cx)*ca + (y-cy)*sa, Y = cy - (x-cx)*sa + (y-cy)*ca;
9523
 
            cimg_forZV(*this,z,v) dest(x,y,z,v) = (T)cubic_pix2d(X,Y,z,v,0);
 
13861
            cimg_forZV(*this,z,v) dest(x,y,z,v) = (T)cubic_at2(X,Y,z,v,0);
9524
13862
          }
9525
13863
        } break;
 
13864
        default:
 
13865
          throw CImgArgumentException("CImg<%s>::get_rotate() : Incorrect parameter 'cond=%d' (correct values are 0,1,2 or 3).",
 
13866
                                      pixel_type());
9526
13867
        }
9527
13868
      return dest;
9528
13869
    }
9529
13870
 
9530
 
    //! Rotate the image around the point (\c cx,\c cy).
9531
 
    /**
9532
 
       \param angle = rotation angle (in degrees).
9533
 
       \param cx = X-coordinate of the rotation center.
9534
 
       \param cy = Y-coordinate of the rotation center.
9535
 
       \param zoom = zoom.
9536
 
       \param cond = rotation type. can be :
9537
 
       - 0 = zero-value at borders
9538
 
       - 1 = repeat image at borders
9539
 
       - 2 = zero-value at borders and linear interpolation
9540
 
       \note Rotation does not change the image size. If you want to get an image with a new size, use get_rotate() instead.
9541
 
       \see get_rotate()
9542
 
    **/
9543
 
    CImg& rotate(const float angle, const float cx, const float cy, const float zoom=1, const unsigned int cond=3) {
9544
 
      return get_rotate(angle,cx,cy,zoom,cond).swap(*this);
 
13871
    //! Rotate an image around a center point (\c cx,\c cy) (in-place).
 
13872
    CImg<T>& rotate(const float angle, const float cx, const float cy, const float zoom=1, const unsigned int cond=3) {
 
13873
      return get_rotate(angle,cx,cy,zoom,cond).transfer_to(*this);
9545
13874
    }
9546
13875
 
9547
 
    //! Return a resized image.
 
13876
    //! Resize an image.
9548
13877
    /**
9549
 
       \param pdx = Number of columns (new size along the X-axis).
9550
 
       \param pdy = Number of rows (new size along the Y-axis).
9551
 
       \param pdz = Number of slices (new size along the Z-axis).
9552
 
       \param pdv = Number of vector-channels (new size along the V-axis).
9553
 
       \param interp = Resizing type :
 
13878
       \param pdx Number of columns (new size along the X-axis).
 
13879
       \param pdy Number of rows (new size along the Y-axis).
 
13880
       \param pdz Number of slices (new size along the Z-axis).
 
13881
       \param pdv Number of vector-channels (new size along the V-axis).
 
13882
       \param interpolation_type Method of interpolation :
9554
13883
       - -1 = no interpolation : raw memory resizing.
9555
 
       - 0 = no interpolation : additional space is filled with 0.
 
13884
       - 0 = no interpolation : additional space is filled according to \p border_condition.
9556
13885
       - 1 = bloc interpolation (nearest point).
9557
 
       - 2 = mosaic : image is repeated if necessary.
 
13886
       - 2 = moving average interpolation.
9558
13887
       - 3 = linear interpolation.
9559
13888
       - 4 = grid interpolation.
9560
13889
       - 5 = bi-cubic interpolation.
 
13890
       \param border_condition Border condition type.
 
13891
       \param center Set centering type (only if \p interpolation_type=0).
9561
13892
       \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
9562
13893
    **/
9563
 
    CImg get_resize(const int pdx=-100, const int pdy=-100, const int pdz=-100, const int pdv=-100,
9564
 
                    const int interp=1, const int border_condition=-1) const {
 
13894
    CImg<T> get_resize(const int pdx=-100, const int pdy=-100, const int pdz=-100, const int pdv=-100,
 
13895
                       const int interpolation_type=1, const int border_condition=-1, const bool center=false) const {
9565
13896
      if (!pdx || !pdy || !pdz || !pdv) return CImg<T>();
9566
13897
      const unsigned int
9567
13898
        tdx = pdx<0?-pdx*width/100:pdx,
9572
13903
        dy = tdy?tdy:1,
9573
13904
        dz = tdz?tdz:1,
9574
13905
        dv = tdv?tdv:1;
9575
 
      if (width==dx && height==dy && depth==dz && dim==dv) return *this;
 
13906
      if (width==dx && height==dy && depth==dz && dim==dv) return +*this;
9576
13907
      if (is_empty()) return CImg<T>(dx,dy,dz,dv,0);
9577
13908
 
9578
 
      CImg res;
 
13909
      CImg<T> res;
9579
13910
 
9580
 
      switch (interp) {
 
13911
      switch (interpolation_type) {
9581
13912
      case -1: // Raw resizing
9582
13913
        std::memcpy(res.assign(dx,dy,dz,dv,0).data,data,sizeof(T)*cimg::min(size(),(long unsigned int)dx*dy*dz*dv));
9583
13914
        break;
9584
13915
 
9585
 
      case 0:  // Zero filling
9586
 
        res.assign(dx,dy,dz,dv,0).draw_image(*this,0,0,0,0);
9587
 
        break;
 
13916
      case 0:  { // No interpolation
 
13917
        const unsigned int bx = width-1, by = height-1, bz = depth-1, bv = dim-1;
 
13918
        res.assign(dx,dy,dz,dv);
 
13919
        switch (border_condition) {
 
13920
        case 1: {
 
13921
          if (center) {
 
13922
            const int
 
13923
              x0 = (res.dimx()-dimx())/2,
 
13924
              y0 = (res.dimy()-dimy())/2,
 
13925
              z0 = (res.dimz()-dimz())/2,
 
13926
              v0 = (res.dimv()-dimv())/2,
 
13927
              x1 = x0 + (int)bx,
 
13928
              y1 = y0 + (int)by,
 
13929
              z1 = z0 + (int)bz,
 
13930
              v1 = v0 + (int)bv;
 
13931
            res.draw_image(*this,x0,y0,z0,v0);
 
13932
            cimg_for_outXYZV(res,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) res(x,y,z,v) = at(x-x0,y-y0,z-z0,v-v0);
 
13933
          } else {
 
13934
            res.draw_image(*this,0,0,0,0);
 
13935
            cimg_for_outXYZV(res,0,0,0,0,bx,by,bz,bv,x,y,z,v) res(x,y,z,v) = at(x,y,z,v);
 
13936
          }
 
13937
          } break;
 
13938
        case 2 : {
 
13939
          const int
 
13940
            x0 = (res.dimx()-dimx())/2,
 
13941
            y0 = (res.dimy()-dimy())/2,
 
13942
            z0 = (res.dimz()-dimz())/2,
 
13943
            v0 = (res.dimv()-dimv())/2,
 
13944
            nx0 = x0>0?x0-(1+x0/width)*width:x0,
 
13945
            ny0 = y0>0?y0-(1+y0/height)*height:y0,
 
13946
            nz0 = z0>0?z0-(1+z0/depth)*depth:z0,
 
13947
            nv0 = v0>0?v0-(1+v0/dim)*dim:v0;
 
13948
          for (int k=nv0; k<(int)dv; k+=dimv())
 
13949
            for (int z=nz0; z<(int)dz; z+=dimz())
 
13950
              for (int y=ny0; y<(int)dy; y+=dimy())
 
13951
                for (int x=nx0; x<(int)dx; x+=dimx()) res.draw_image(*this,x,y,z,k);
 
13952
          } break;
 
13953
        default: {
 
13954
          res.fill(0);
 
13955
          if (center) res.draw_image(*this,(res.dimx()-dimx())/2,(res.dimy()-dimy())/2,(res.dimz()-dimz())/2,(res.dimv()-dimv())/2);
 
13956
          else res.draw_image(*this,0,0,0,0);
 
13957
        }
 
13958
        }
 
13959
      } break;
9588
13960
 
9589
13961
      case 1: { // Nearest-neighbor interpolation
9590
13962
        res.assign(dx,dy,dz,dv);
9600
13972
        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;
9601
13973
        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;
9602
13974
        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;
9603
 
        T *ptrd = res.ptr();
9604
 
        const T* ptrv = ptr();
 
13975
        T *ptrd = res.data;
 
13976
        const T* ptrv = data;
9605
13977
        poffv = offv;
9606
13978
        for (unsigned int k=0; k<dv; ) {
9607
13979
          const T *ptrz = ptrv;
9615
13987
              cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poffx++); }
9616
13988
              ++y;
9617
13989
              unsigned int dy = *(poffy++);
9618
 
              for (;!dy && y<dy; std::memcpy(ptrd, ptrd-dx, sizeof(T)*dx), ++y, ptrd+=dx, dy=*(poffy++));
 
13990
              for (;!dy && y<dy; std::memcpy(ptrd, ptrd-dx, sizeof(T)*dx), ++y, ptrd+=dx, dy=*(poffy++)) {}
9619
13991
              ptry+=dy;
9620
13992
            }
9621
13993
            ++z;
9622
13994
            unsigned int dz = *(poffz++);
9623
 
            for (;!dz && z<dz; std::memcpy(ptrd, ptrd-rwh, sizeof(T)*rwh), ++z, ptrd+=rwh, dz=*(poffz++));
 
13995
            for (;!dz && z<dz; std::memcpy(ptrd, ptrd-rwh, sizeof(T)*rwh), ++z, ptrd+=rwh, dz=*(poffz++)) {}
9624
13996
            ptrz+=dz;
9625
13997
          }
9626
13998
          ++k;
9627
13999
          unsigned int dv = *(poffv++);
9628
 
          for (;!dv && k<dv; std::memcpy(ptrd, ptrd-rwhd, sizeof(T)*rwhd), ++k, ptrd+=rwhd, dv=*(poffv++));
 
14000
          for (;!dv && k<dv; std::memcpy(ptrd, ptrd-rwhd, sizeof(T)*rwhd), ++k, ptrd+=rwhd, dv=*(poffv++)) {}
9629
14001
          ptrv+=dv;
9630
14002
        }
9631
14003
        delete[] offx; delete[] offy; delete[] offz; delete[] offv;
9632
14004
      } break;
9633
14005
 
9634
 
      case 2: { // Mosaic filling
9635
 
        res.assign(dx,dy,dz,dv);
9636
 
        for (unsigned int k=0; k<dv; k+=dim)
9637
 
          for (unsigned int z=0; z<dz; z+=depth)
9638
 
            for (unsigned int y=0; y<dy; y+=height)
9639
 
              for (unsigned int x=0; x<dx; x+=width) res.draw_image(*this,x,y,z,k);
 
14006
      case 2: { // Moving average
 
14007
        bool instance_first = true;
 
14008
        if (dx!=width) {
 
14009
          CImg<Tfloat> tmp(dx,height,depth,dim,0);
 
14010
          for (unsigned int a=width*dx, b=width, c=dx, s=0, t=0; a; ) {
 
14011
            const unsigned int d = cimg::min(b,c);
 
14012
            a-=d; b-=d; c-=d;
 
14013
            cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d;
 
14014
            if (!b) { cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)/=width; ++t; b = width; }
 
14015
            if (!c) { ++s; c = dx; }
 
14016
          }
 
14017
          tmp.transfer_to(res);
 
14018
          instance_first = false;
 
14019
        }
 
14020
        if (dy!=height) {
 
14021
          CImg<Tfloat> tmp(dx,dy,depth,dim,0);
 
14022
          for (unsigned int a=height*dy, b=height, c=dy, s=0, t=0; a; ) {
 
14023
            const unsigned int d = cimg::min(b,c);
 
14024
            a-=d; b-=d; c-=d;
 
14025
            if (instance_first) cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d;
 
14026
            else cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d;
 
14027
            if (!b) { cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)/=height; ++t; b = height; }
 
14028
            if (!c) { ++s; c = dy; }
 
14029
          }
 
14030
          tmp.transfer_to(res);
 
14031
          instance_first = false;
 
14032
        }
 
14033
        if (dz!=depth) {
 
14034
          CImg<Tfloat> tmp(dx,dy,dz,dim,0);
 
14035
          for (unsigned int a=depth*dz, b=depth, c=dz, s=0, t=0; a; ) {
 
14036
            const unsigned int d = cimg::min(b,c);
 
14037
            a-=d; b-=d; c-=d;
 
14038
            if (instance_first) cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d;
 
14039
            else cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d;
 
14040
            if (!b) { cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)/=depth; ++t; b = depth; }
 
14041
            if (!c) { ++s; c = dz; }
 
14042
          }
 
14043
          tmp.transfer_to(res);
 
14044
          instance_first = false;
 
14045
        }
 
14046
        if (dv!=dim) {
 
14047
          CImg<Tfloat> tmp(dx,dy,dz,dv,0);
 
14048
          for (unsigned int a=dim*dv, b=dim, c=dv, s=0, t=0; a; ) {
 
14049
            const unsigned int d = cimg::min(b,c);
 
14050
            a-=d; b-=d; c-=d;
 
14051
            if (instance_first) cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d;
 
14052
            else cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d;
 
14053
            if (!b) { cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)/=dim; ++t; b = dim; }
 
14054
            if (!c) { ++s; c = dv; }
 
14055
          }
 
14056
          tmp.transfer_to(res);
 
14057
          instance_first = false;
 
14058
        }
9640
14059
      } break;
9641
14060
 
9642
14061
      case 3: { // Linear interpolation
9649
14068
 
9650
14069
        unsigned int *const off = new unsigned int[dimmax], *poff;
9651
14070
        float *const foff = new float[dimmax], *pfoff, old, curr;
9652
 
        CImg resx, resy, resz, resv;
 
14071
        CImg<T> resx, resy, resz, resv;
9653
14072
        T *ptrd;
9654
14073
 
9655
14074
        if (dx!=width) {
9658
14077
            resx.assign(dx,height,depth,dim);
9659
14078
            curr = old = 0; poff = off; pfoff = foff;
9660
14079
            cimg_forX(resx,x) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sx; *(poff++) = (unsigned int)curr-(unsigned int)old; }
9661
 
            ptrd = resx.ptr();
9662
 
            const T *ptrs0 = ptr();
 
14080
            ptrd = resx.data;
 
14081
            const T *ptrs0 = data;
9663
14082
            cimg_forYZV(resx,y,z,k) {
9664
14083
              poff = off; pfoff = foff;
9665
14084
              const T *ptrs = ptrs0, *const ptrsmax = ptrs0 + (width-1);
9758
14177
          sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
9759
14178
          sv = (border_condition<0 && dv>dim   )?(dv>1?(dim-1.0f)/(dv-1)   :0):(float)dim/dv;
9760
14179
        res.assign(dx,dy,dz,dv);
 
14180
        T *ptrd = res.ptr();
9761
14181
        float cx, cy, cz, ck = 0;
9762
14182
        cimg_forV(res,k) { cz = 0;
9763
14183
        cimg_forZ(res,z) { cy = 0;
9764
14184
        cimg_forY(res,y) { cx = 0;
9765
 
        cimg_forX(res,x) { res(x,y,z,k) = (T)(border_condition?cubic_pix2d(cx,cy,(int)cz,(int)ck):cubic_pix2d(cx,cy,(int)cz,(int)ck,0));
9766
 
        cx+=sx;
 
14185
        cimg_forX(res,x) {
 
14186
          *(ptrd++) = (T)(border_condition?cubic_at2(cx,cy,(int)cz,(int)ck):cubic_at2(cx,cy,(int)cz,(int)ck,0));
 
14187
          cx+=sx;
9767
14188
        } cy+=sy;
9768
14189
        } cz+=sz;
9769
14190
        } ck+=sv;
9771
14192
      } break;
9772
14193
 
9773
14194
      default: // Invalid interpolation method
9774
 
        throw CImgArgumentException("CImg<%s>::resize() : Invalid interpolation method (%d) specified.",
9775
 
                                    pixel_type(),interp);
 
14195
        throw CImgArgumentException("CImg<%s>::resize() : Incorrect parameter 'interpolation_type=%d' (correct values are  -1,0,1,2,3,4 or 5).",
 
14196
                                    pixel_type(),interpolation_type);
9776
14197
      }
9777
 
 
9778
14198
      return res;
9779
14199
    }
9780
14200
 
9781
 
    //! Return a resized image.
9782
 
    /**
9783
 
       \param src = Image giving the geometry of the resize.
9784
 
       \param interp = Resizing type :
9785
 
       - 1 = raw memory
9786
 
       - 0 = no interpolation : additional space is filled with 0.
9787
 
       - 1 = bloc interpolation (nearest point).
9788
 
       - 2 = mosaic : image is repeated if necessary.
9789
 
       - 3 = linear interpolation.
9790
 
       - 4 = grid interpolation.
9791
 
       - 5 = bi-cubic interpolation.
9792
 
       \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
9793
 
    **/
9794
 
    template<typename t> CImg get_resize(const CImg<t>& src, const int interp=1, const int border_condition=-1) const {
9795
 
      return get_resize(src.width,src.height,src.depth,src.dim,interp,border_condition);
9796
 
    }
9797
 
 
9798
 
    //! Return a resized image.
9799
 
    /**
9800
 
       \param disp = Display giving the geometry of the resize.
9801
 
       \param interp = Resizing type :
9802
 
       - 0 = no interpolation : additional space is filled with 0.
9803
 
       - 1 = bloc interpolation (nearest point).
9804
 
       - 2 = mosaic : image is repeated if necessary.
9805
 
       - 3 = linear interpolation.
9806
 
       - 4 = grid interpolation.
9807
 
       - 5 = bi-cubic interpolation.
9808
 
       \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
9809
 
    **/
9810
 
    CImg get_resize(const CImgDisplay& disp, const int interp=1, const int border_condition=-1) const {
9811
 
      return get_resize(disp.width,disp.height,depth,dim,interp,border_condition);
9812
 
    }
9813
 
 
9814
 
    //! Resize the image.
9815
 
    /**
9816
 
       \param pdx = Number of columns (new size along the X-axis).
9817
 
       \param pdy = Number of rows (new size along the Y-axis).
9818
 
       \param pdz = Number of slices (new size along the Z-axis).
9819
 
       \param pdv = Number of vector-channels (new size along the V-axis).
9820
 
       \param interp = Resizing type :
9821
 
       - 0 = no interpolation : additional space is filled with 0.
9822
 
       - 1 = bloc interpolation (nearest point).
9823
 
       - 2 = mosaic : image is repeated if necessary.
9824
 
       - 3 = linear interpolation.
9825
 
       - 4 = grid interpolation.
9826
 
       - 5 = bi-cubic interpolation.
9827
 
       \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
9828
 
    **/
9829
 
    CImg& resize(const int pdx=-100, const int pdy=-100, const int pdz=-100, const int pdv=-100,
9830
 
                 const int interp=1, const int border_condition=-1) {
 
14201
    //! Resize an image (in-place).
 
14202
    CImg<T>& resize(const int pdx=-100, const int pdy=-100, const int pdz=-100, const int pdv=-100,
 
14203
                    const int interpolation_type=1, const int border_condition=-1, const bool center=false) {
9831
14204
      if (!pdx || !pdy || !pdz || !pdv) return assign();
9832
14205
      const unsigned int
9833
14206
        dx = pdx<0?-pdx*width/100:pdx,
9835
14208
        dz = pdz<0?-pdz*depth/100:pdz,
9836
14209
        dv = pdv<0?-pdv*dim/100:pdv;
9837
14210
      if (width==dx && height==dy && depth==dz && dim==dv) return *this;
9838
 
      if (interp==-1 && dx*dy*dz*dv==size()) {
 
14211
      if (interpolation_type==-1 && dx*dy*dz*dv==size()) {
9839
14212
        width = dx; height = dy; depth = dz; dim = dv;
9840
14213
        return *this;
9841
14214
      }
9842
 
      return get_resize(dx,dy,dz,dv,interp,border_condition).swap(*this);
 
14215
      return get_resize(dx,dy,dz,dv,interpolation_type,border_condition,center).transfer_to(*this);
9843
14216
    }
9844
14217
 
9845
 
    //! Resize the image.
 
14218
    //! Resize an image.
9846
14219
    /**
9847
 
       \param src = Image giving the geometry of the resize.
9848
 
       \param interp = Resizing type :
 
14220
       \param src  Image giving the geometry of the resize.
 
14221
       \param interpolation_type  Interpolation method :
 
14222
       - 1 = raw memory
9849
14223
       - 0 = no interpolation : additional space is filled with 0.
9850
14224
       - 1 = bloc interpolation (nearest point).
9851
14225
       - 2 = mosaic : image is repeated if necessary.
9852
14226
       - 3 = linear interpolation.
9853
14227
       - 4 = grid interpolation.
9854
14228
       - 5 = bi-cubic interpolation.
 
14229
       \param border_condition Border condition type.
9855
14230
       \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
9856
14231
    **/
9857
 
    template<typename t> CImg& resize(const CImg<t>& src, const int interp=1, const int border_condition=-1) {
9858
 
      return resize(src.width,src.height,src.depth,src.dim,interp,border_condition);
9859
 
    }
9860
 
 
9861
 
    //! Resize the image
 
14232
    template<typename t> CImg<T> get_resize(const CImg<t>& src, const int interpolation_type=1,
 
14233
                                            const int border_condition=-1, const bool center=false) const {
 
14234
      return get_resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
 
14235
    }
 
14236
 
 
14237
    //! Resize an image (in-place).
 
14238
    template<typename t> CImg<T>& resize(const CImg<t>& src, const int interpolation_type=1,
 
14239
                                         const int border_condition=-1, const bool center=false) {
 
14240
      return resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
 
14241
    }
 
14242
 
 
14243
    //! Resize an image.
9862
14244
    /**
9863
14245
       \param disp = Display giving the geometry of the resize.
9864
 
       \param interp = Resizing type :
 
14246
       \param interpolation_type = Resizing type :
9865
14247
       - 0 = no interpolation : additional space is filled with 0.
9866
14248
       - 1 = bloc interpolation (nearest point).
9867
14249
       - 2 = mosaic : image is repeated if necessary.
9868
14250
       - 3 = linear interpolation.
9869
14251
       - 4 = grid interpolation.
9870
14252
       - 5 = bi-cubic interpolation.
 
14253
       - 6 = moving average (best quality for photographs)
 
14254
       \param border_condition Border condition type.
9871
14255
       \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
9872
14256
    **/
9873
 
    CImg& resize(const CImgDisplay& disp, const int interp=1, const int border_condition=-1) {
9874
 
      return resize(disp.width,disp.height,depth,dim,interp,border_condition);
 
14257
    CImg<T> get_resize(const CImgDisplay& disp, const int interpolation_type=1,
 
14258
                       const int border_condition=-1, const bool center=false) const {
 
14259
      return get_resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
 
14260
    }
 
14261
 
 
14262
    //! Resize an image (in-place).
 
14263
    CImg<T>& resize(const CImgDisplay& disp, const int interpolation_type=1,
 
14264
                    const int border_condition=-1, const bool center=false) {
 
14265
      return resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
 
14266
    }
 
14267
 
 
14268
    //! Half-resize an image, using a special optimized filter.
 
14269
    CImg<T> get_resize_halfXY() const {
 
14270
      if (is_empty()) return CImg<T>();
 
14271
      const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f,
 
14272
                              0.1231940459f,  0.1935127547f, 0.1231940459f,
 
14273
                              0.07842776544f, 0.1231940459f, 0.07842776544f };
 
14274
      Tfloat I[9] = { 0 };
 
14275
      CImg<T> dest(width/2,height/2,depth,dim);
 
14276
      cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I)
 
14277
        if (x%2 && y%2) dest(x/2,y/2,z,k) = (T)
 
14278
                          (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
 
14279
                           I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
 
14280
                           I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
 
14281
      return dest;
 
14282
    }
 
14283
 
 
14284
    //! Half-resize an image, using a special optimized filter (in-place).
 
14285
    CImg<T>& resize_halfXY() {
 
14286
      return get_resize_halfXY().transfer_to(*this);
 
14287
    }
 
14288
 
 
14289
    //! Upscale an image by a factor 2x.
 
14290
    /**
 
14291
       Use anisotropic upscaling algorithm described at
 
14292
       http://scale2x.sourceforge.net/algorithm.html
 
14293
    **/
 
14294
    CImg<T> get_resize_doubleXY() const {
 
14295
 
 
14296
#define _cimg_gs2x_for3(bound,i) \
 
14297
 for (int i = 0, _p1##i = 0, \
 
14298
      _n1##i = 1>=(bound)?(int)(bound)-1:1; \
 
14299
      _n1##i<(int)(bound) || i==--_n1##i; \
 
14300
      _p1##i = i++, ++_n1##i, ptrd1+=(res).width, ptrd2+=(res).width)
 
14301
 
 
14302
#define _cimg_gs2x_for3x3(img,x,y,z,v,I) \
 
14303
  _cimg_gs2x_for3((img).height,y) for (int x = 0, \
 
14304
   _p1##x = 0, \
 
14305
   _n1##x = (int)( \
 
14306
   (I[1] = (img)(0,_p1##y,z,v)), \
 
14307
   (I[3] = I[4] = (img)(0,y,z,v)), \
 
14308
   (I[7] = (img)(0,_n1##y,z,v)),        \
 
14309
   1>=(img).width?(int)((img).width)-1:1); \
 
14310
   (_n1##x<(int)((img).width) && ( \
 
14311
   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
 
14312
   (I[5] = (img)(_n1##x,y,z,v)), \
 
14313
   (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
 
14314
   x==--_n1##x; \
 
14315
   I[1] = I[2], \
 
14316
   I[3] = I[4], I[4] = I[5], \
 
14317
   I[7] = I[8], \
 
14318
   _p1##x = x++, ++_n1##x)
 
14319
 
 
14320
      if (is_empty()) return *this;
 
14321
      CImg<T> res(2*width,2*height,depth,dim);
 
14322
      CImg_3x3(I,T);
 
14323
      cimg_forZV(*this,z,k) {
 
14324
        T
 
14325
          *ptrd1 = res.ptr(0,0,0,k),
 
14326
          *ptrd2 = ptrd1 + res.width;
 
14327
        _cimg_gs2x_for3x3(*this,x,y,0,k,I) {
 
14328
          if (Icp!=Icn && Ipc!=Inc) {
 
14329
            *(ptrd1++) = Ipc==Icp?Ipc:Icc;
 
14330
            *(ptrd1++) = Icp==Inc?Inc:Icc;
 
14331
            *(ptrd2++) = Ipc==Icn?Ipc:Icc;
 
14332
            *(ptrd2++) = Icn==Inc?Inc:Icc;
 
14333
          } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; }
 
14334
        }
 
14335
      }
 
14336
      return res;
 
14337
    }
 
14338
 
 
14339
    //! Upscale an image by a factor 2x (in-place).
 
14340
    CImg<T>& resize_doubleXY() {
 
14341
      return get_resize_doubleXY().transfer_to(*this);
 
14342
    }
 
14343
 
 
14344
    //! Upscale an image by a factor 3x.
 
14345
    /**
 
14346
       Use anisotropic upscaling algorithm described at
 
14347
       http://scale2x.sourceforge.net/algorithm.html
 
14348
    **/
 
14349
    CImg<T> get_resize_tripleXY() const {
 
14350
 
 
14351
#define _cimg_gs3x_for3(bound,i) \
 
14352
 for (int i = 0, _p1##i = 0, \
 
14353
      _n1##i = 1>=(bound)?(int)(bound)-1:1; \
 
14354
      _n1##i<(int)(bound) || i==--_n1##i; \
 
14355
      _p1##i = i++, ++_n1##i, ptrd1+=2*(res).width, ptrd2+=2*(res).width, ptrd3+=2*(res).width)
 
14356
 
 
14357
#define _cimg_gs3x_for3x3(img,x,y,z,v,I) \
 
14358
  _cimg_gs3x_for3((img).height,y) for (int x = 0, \
 
14359
   _p1##x = 0, \
 
14360
   _n1##x = (int)( \
 
14361
   (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
 
14362
   (I[3] = I[4] = (img)(0,y,z,v)), \
 
14363
   (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
 
14364
   1>=(img).width?(int)((img).width)-1:1); \
 
14365
   (_n1##x<(int)((img).width) && ( \
 
14366
   (I[2] = (img)(_n1##x,_p1##y,z,v)), \
 
14367
   (I[5] = (img)(_n1##x,y,z,v)), \
 
14368
   (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
 
14369
   x==--_n1##x; \
 
14370
   I[0] = I[1], I[1] = I[2], \
 
14371
   I[3] = I[4], I[4] = I[5], \
 
14372
   I[6] = I[7], I[7] = I[8], \
 
14373
   _p1##x = x++, ++_n1##x)
 
14374
 
 
14375
      if (is_empty()) return *this;
 
14376
      CImg<T> res(3*width,3*height,depth,dim);
 
14377
      CImg_3x3(I,T);
 
14378
      cimg_forZV(*this,z,k) {
 
14379
        T
 
14380
          *ptrd1 = res.ptr(0,0,0,k),
 
14381
          *ptrd2 = ptrd1 + res.width,
 
14382
          *ptrd3 = ptrd2 + res.width;
 
14383
        _cimg_gs3x_for3x3(*this,x,y,0,k,I) {
 
14384
          if (Icp != Icn && Ipc != Inc) {
 
14385
            *(ptrd1++) = Ipc==Icp?Ipc:Icc;
 
14386
            *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc;
 
14387
            *(ptrd1++) = Icp==Inc?Inc:Icc;
 
14388
            *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc;
 
14389
            *(ptrd2++) = Icc;
 
14390
            *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc;
 
14391
            *(ptrd3++) = Ipc==Icn?Ipc:Icc;
 
14392
            *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc;
 
14393
            *(ptrd3++) = Icn==Inc?Inc:Icc;
 
14394
          } else {
 
14395
            *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc;
 
14396
            *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc;
 
14397
            *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc;
 
14398
          }
 
14399
        }
 
14400
      }
 
14401
      return res;
 
14402
    }
 
14403
 
 
14404
    //! Upscale an image by a factor 3x (in-place).
 
14405
    CImg<T>& resize_tripleXY() {
 
14406
      return get_resize_tripleXY().transfer_to(*this);
 
14407
    }
 
14408
 
 
14409
    // Permute axes order (internal).
 
14410
    template<typename t> CImg<t> get_permute_axes(const char *permut, const t&) const {
 
14411
      if (is_empty() || !permut) return CImg<t>(*this,false);
 
14412
      CImg<t> res;
 
14413
      const T* ptrs = data;
 
14414
      if (!cimg::strncasecmp(permut,"xyzv",4)) return (+*this);
 
14415
      if (!cimg::strncasecmp(permut,"xyvz",4)) {
 
14416
        res.assign(width,height,dim,depth);
 
14417
        cimg_forXYZV(*this,x,y,z,v) res(x,y,v,z) = (t)*(ptrs++);
 
14418
      }
 
14419
      if (!cimg::strncasecmp(permut,"xzyv",4)) {
 
14420
        res.assign(width,depth,height,dim);
 
14421
        cimg_forXYZV(*this,x,y,z,v) res(x,z,y,v) = (t)*(ptrs++);
 
14422
      }
 
14423
      if (!cimg::strncasecmp(permut,"xzvy",4)) {
 
14424
        res.assign(width,depth,dim,height);
 
14425
        cimg_forXYZV(*this,x,y,z,v) res(x,z,v,y) = (t)*(ptrs++);
 
14426
      }
 
14427
      if (!cimg::strncasecmp(permut,"xvyz",4)) {
 
14428
        res.assign(width,dim,height,depth);
 
14429
        cimg_forXYZV(*this,x,y,z,v) res(x,v,y,z) = (t)*(ptrs++);
 
14430
      }
 
14431
      if (!cimg::strncasecmp(permut,"xvzy",4)) {
 
14432
        res.assign(width,dim,depth,height);
 
14433
        cimg_forXYZV(*this,x,y,z,v) res(x,v,z,y) = (t)*(ptrs++);
 
14434
      }
 
14435
      if (!cimg::strncasecmp(permut,"yxzv",4)) {
 
14436
        res.assign(height,width,depth,dim);
 
14437
        cimg_forXYZV(*this,x,y,z,v) res(y,x,z,v) = (t)*(ptrs++);
 
14438
      }
 
14439
      if (!cimg::strncasecmp(permut,"yxvz",4)) {
 
14440
        res.assign(height,width,dim,depth);
 
14441
        cimg_forXYZV(*this,x,y,z,v) res(y,x,v,z) = (t)*(ptrs++);
 
14442
      }
 
14443
      if (!cimg::strncasecmp(permut,"yzxv",4)) {
 
14444
        res.assign(height,depth,width,dim);
 
14445
        cimg_forXYZV(*this,x,y,z,v) res(y,z,x,v) = (t)*(ptrs++);
 
14446
      }
 
14447
      if (!cimg::strncasecmp(permut,"yzvx",4)) {
 
14448
        res.assign(height,depth,dim,width);
 
14449
        switch (width) {
 
14450
        case 1: {
 
14451
          t *ptrR = res.ptr(0,0,0,0);
 
14452
          for (unsigned long siz = height*depth*dim+1; siz; --siz) {
 
14453
            *(ptrR++) = (t)*(ptrs++);
 
14454
          }
 
14455
        } break;
 
14456
        case 2: {
 
14457
          t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1);
 
14458
          for (unsigned long siz = height*depth*dim+1; siz; --siz) {
 
14459
            *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++);
 
14460
          }
 
14461
        } break;
 
14462
        case 3: { // Optimization for the classical conversion from interleaved RGB to planar RGB
 
14463
          t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1), *ptrB = res.ptr(0,0,0,2);
 
14464
          for (unsigned long siz = height*depth*dim+1; siz; --siz) {
 
14465
            *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++);
 
14466
          }
 
14467
        } break;
 
14468
        case 4: { // Optimization for the classical conversion from interleaved RGBA to planar RGBA
 
14469
          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);
 
14470
          for (unsigned long siz = height*depth*dim+1; siz; --siz) {
 
14471
            *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++); *(ptrA++) = (t)*(ptrs++);
 
14472
          }
 
14473
        } break;
 
14474
        default: {
 
14475
          cimg_forXYZV(*this,x,y,z,v) res(y,z,v,x) = *(ptrs++); return res;
 
14476
        }
 
14477
        }
 
14478
      }
 
14479
      if (!cimg::strncasecmp(permut,"yvxz",4)) {
 
14480
        res.assign(height,dim,width,depth);
 
14481
        cimg_forXYZV(*this,x,y,z,v) res(y,v,x,z) = (t)*(ptrs++);
 
14482
      }
 
14483
      if (!cimg::strncasecmp(permut,"yvzx",4)) {
 
14484
        res.assign(height,dim,depth,width);
 
14485
        cimg_forXYZV(*this,x,y,z,v) res(y,v,z,x) = (t)*(ptrs++);
 
14486
      }
 
14487
      if (!cimg::strncasecmp(permut,"zxyv",4)) {
 
14488
        res.assign(depth,width,height,dim);
 
14489
        cimg_forXYZV(*this,x,y,z,v) res(z,x,y,v) = (t)*(ptrs++);
 
14490
      }
 
14491
      if (!cimg::strncasecmp(permut,"zxvy",4)) {
 
14492
        res.assign(depth,width,dim,height);
 
14493
        cimg_forXYZV(*this,x,y,z,v) res(z,x,v,y) = (t)*(ptrs++);
 
14494
      }
 
14495
      if (!cimg::strncasecmp(permut,"zyxv",4)) {
 
14496
        res.assign(depth,height,width,dim);
 
14497
        cimg_forXYZV(*this,x,y,z,v) res(z,y,x,v) = (t)*(ptrs++);
 
14498
      }
 
14499
      if (!cimg::strncasecmp(permut,"zyvx",4)) {
 
14500
        res.assign(depth,height,dim,width);
 
14501
        cimg_forXYZV(*this,x,y,z,v) res(z,y,v,x) = (t)*(ptrs++);
 
14502
      }
 
14503
      if (!cimg::strncasecmp(permut,"zvxy",4)) {
 
14504
        res.assign(depth,dim,width,height);
 
14505
        cimg_forXYZV(*this,x,y,z,v) res(z,v,x,y) = (t)*(ptrs++);
 
14506
      }
 
14507
      if (!cimg::strncasecmp(permut,"zvyx",4)) {
 
14508
        res.assign(depth,dim,height,width);
 
14509
        cimg_forXYZV(*this,x,y,z,v) res(z,v,y,x) = (t)*(ptrs++);
 
14510
      }
 
14511
      if (!cimg::strncasecmp(permut,"vxyz",4)) {
 
14512
        res.assign(dim,width,height,depth);
 
14513
        switch (dim) {
 
14514
        case 1: {
 
14515
          const T *ptrR = ptr(0,0,0,0);
 
14516
          t *ptrd = res.ptr();
 
14517
          for (unsigned long siz = width*height*depth+1; siz; --siz) {
 
14518
            *(ptrd++) = (t)*(ptrR++);
 
14519
          }
 
14520
        } break;
 
14521
        case 2: {
 
14522
          const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1);
 
14523
          t *ptrd = res.ptr();
 
14524
          for (unsigned long siz = width*height*depth+1; siz; --siz) {
 
14525
            *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++);
 
14526
          }
 
14527
        } break;
 
14528
        case 3: { // Optimization for the classical conversion from planar RGB to interleaved RGB
 
14529
          const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1), *ptrB = ptr(0,0,0,2);
 
14530
          t *ptrd = res.ptr();
 
14531
          for (unsigned long siz = width*height*depth+1; siz; --siz) {
 
14532
            *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++);
 
14533
          }
 
14534
        } break;
 
14535
        case 4: { // Optimization for the classical conversion from planar RGBA to interleaved RGBA
 
14536
          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);
 
14537
          t *ptrd = res.ptr();
 
14538
          for (unsigned long siz = width*height*depth+1; siz; --siz) {
 
14539
            *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++); *(ptrd++) = (t)*(ptrA++);
 
14540
          }
 
14541
        } break;
 
14542
        default: {
 
14543
          cimg_forXYZV(*this,x,y,z,v) res(v,x,y,z) = (t)*(ptrs++);
 
14544
        }
 
14545
        }
 
14546
      }
 
14547
      if (!cimg::strncasecmp(permut,"vxzy",4)) {
 
14548
        res.assign(dim,width,depth,height);
 
14549
        cimg_forXYZV(*this,x,y,z,v) res(v,x,z,y) = (t)*(ptrs++);
 
14550
      }
 
14551
      if (!cimg::strncasecmp(permut,"vyxz",4)) {
 
14552
        res.assign(dim,height,width,depth);
 
14553
        cimg_forXYZV(*this,x,y,z,v) res(v,y,x,z) = (t)*(ptrs++);
 
14554
      }
 
14555
      if (!cimg::strncasecmp(permut,"vyzx",4)) {
 
14556
        res.assign(dim,height,depth,width);
 
14557
        cimg_forXYZV(*this,x,y,z,v) res(v,y,z,x) = (t)*(ptrs++);
 
14558
      }
 
14559
      if (!cimg::strncasecmp(permut,"vzxy",4)) {
 
14560
        res.assign(dim,depth,width,height);
 
14561
        cimg_forXYZV(*this,x,y,z,v) res(v,z,x,y) = (t)*(ptrs++);
 
14562
      }
 
14563
      if (!cimg::strncasecmp(permut,"vzyx",4)) {
 
14564
        res.assign(dim,depth,height,width);
 
14565
        cimg_forXYZV(*this,x,y,z,v) res(v,z,y,x) = (t)*(ptrs++);
 
14566
      }
 
14567
      if (!res) throw CImgArgumentException("CImg<%s>::permute_axes() : Invalid input permutation '%s'.",pixel_type(),permut);
 
14568
      return res;
9875
14569
    }
9876
14570
 
9877
14571
    //! Permute axes order.
9878
14572
    /**
9879
14573
       This function permutes image axes.
9880
14574
       \param permut = String describing the permutation (4 characters).
9881
 
 
9882
 
    **/
9883
 
    CImg get_permute_axes(const char *permut="vxyz") const {
9884
 
      if (is_empty() || !permut) return (+*this);
9885
 
      CImg<T> res;
9886
 
      const T* ptr = data;
9887
 
      if (!cimg::strncasecmp(permut,"xyzv",4)) return (+*this);
9888
 
      if (!cimg::strncasecmp(permut,"xyvz",4)) { res.assign(width,height,dim,depth); cimg_forXYZV(*this,x,y,z,v) res(x,y,v,z) = *(ptr++); return res; }
9889
 
      if (!cimg::strncasecmp(permut,"xzyv",4)) { res.assign(width,depth,height,dim); cimg_forXYZV(*this,x,y,z,v) res(x,z,y,v) = *(ptr++); return res; }
9890
 
      if (!cimg::strncasecmp(permut,"xzvy",4)) { res.assign(width,depth,dim,height); cimg_forXYZV(*this,x,y,z,v) res(x,z,v,y) = *(ptr++); return res; }
9891
 
      if (!cimg::strncasecmp(permut,"xvyz",4)) { res.assign(width,dim,height,depth); cimg_forXYZV(*this,x,y,z,v) res(x,v,y,z) = *(ptr++); return res; }
9892
 
      if (!cimg::strncasecmp(permut,"xvzy",4)) { res.assign(width,dim,depth,height); cimg_forXYZV(*this,x,y,z,v) res(x,v,z,y) = *(ptr++); return res; }
9893
 
      if (!cimg::strncasecmp(permut,"yxzv",4)) { res.assign(height,width,depth,dim); cimg_forXYZV(*this,x,y,z,v) res(y,x,z,v) = *(ptr++); return res; }
9894
 
      if (!cimg::strncasecmp(permut,"yxvz",4)) { res.assign(height,width,dim,depth); cimg_forXYZV(*this,x,y,z,v) res(y,x,v,z) = *(ptr++); return res; }
9895
 
      if (!cimg::strncasecmp(permut,"yzxv",4)) { res.assign(height,depth,width,dim); cimg_forXYZV(*this,x,y,z,v) res(y,z,x,v) = *(ptr++); return res; }
9896
 
      if (!cimg::strncasecmp(permut,"yzvx",4)) { res.assign(height,depth,dim,width); cimg_forXYZV(*this,x,y,z,v) res(y,z,v,x) = *(ptr++); return res; }
9897
 
      if (!cimg::strncasecmp(permut,"yvxz",4)) { res.assign(height,dim,width,depth); cimg_forXYZV(*this,x,y,z,v) res(y,v,x,z) = *(ptr++); return res; }
9898
 
      if (!cimg::strncasecmp(permut,"yvzx",4)) { res.assign(height,dim,depth,width); cimg_forXYZV(*this,x,y,z,v) res(y,v,z,x) = *(ptr++); return res; }
9899
 
      if (!cimg::strncasecmp(permut,"zxyv",4)) { res.assign(depth,width,height,dim); cimg_forXYZV(*this,x,y,z,v) res(z,x,y,v) = *(ptr++); return res; }
9900
 
      if (!cimg::strncasecmp(permut,"zxvy",4)) { res.assign(depth,width,dim,height); cimg_forXYZV(*this,x,y,z,v) res(z,x,v,y) = *(ptr++); return res; }
9901
 
      if (!cimg::strncasecmp(permut,"zyxv",4)) { res.assign(depth,height,width,dim); cimg_forXYZV(*this,x,y,z,v) res(z,y,x,v) = *(ptr++); return res; }
9902
 
      if (!cimg::strncasecmp(permut,"zyvx",4)) { res.assign(depth,height,dim,width); cimg_forXYZV(*this,x,y,z,v) res(z,y,v,x) = *(ptr++); return res; }
9903
 
      if (!cimg::strncasecmp(permut,"zvxy",4)) { res.assign(depth,dim,width,height); cimg_forXYZV(*this,x,y,z,v) res(z,v,x,y) = *(ptr++); return res; }
9904
 
      if (!cimg::strncasecmp(permut,"zvyx",4)) { res.assign(depth,dim,height,width); cimg_forXYZV(*this,x,y,z,v) res(z,v,y,x) = *(ptr++); return res; }
9905
 
      if (!cimg::strncasecmp(permut,"vxyz",4)) { res.assign(dim,width,height,depth); cimg_forXYZV(*this,x,y,z,v) res(v,x,y,z) = *(ptr++); return res; }
9906
 
      if (!cimg::strncasecmp(permut,"vxzy",4)) { res.assign(dim,width,depth,height); cimg_forXYZV(*this,x,y,z,v) res(v,x,z,y) = *(ptr++); return res; }
9907
 
      if (!cimg::strncasecmp(permut,"vyxz",4)) { res.assign(dim,height,width,depth); cimg_forXYZV(*this,x,y,z,v) res(v,y,x,z) = *(ptr++); return res; }
9908
 
      if (!cimg::strncasecmp(permut,"vyzx",4)) { res.assign(dim,height,depth,width); cimg_forXYZV(*this,x,y,z,v) res(v,y,z,x) = *(ptr++); return res; }
9909
 
      if (!cimg::strncasecmp(permut,"vzxy",4)) { res.assign(dim,depth,width,height); cimg_forXYZV(*this,x,y,z,v) res(v,z,x,y) = *(ptr++); return res; }
9910
 
      if (!cimg::strncasecmp(permut,"vzyx",4)) { res.assign(dim,depth,height,width); cimg_forXYZV(*this,x,y,z,v) res(v,z,y,x) = *(ptr++); return res; }
9911
 
      throw CImgArgumentException("CImg<%s>::permute_axes() : Invalid input permutation '%s'.",pixel_type(),permut);
9912
 
      return res;
9913
 
    }
9914
 
 
9915
 
    //! Permute axes order (in-place version).
9916
 
    CImg& permute_axes(const char *order="vxyz") {
9917
 
      return get_permute_axes(order).swap(*this);
9918
 
    }
9919
 
 
9920
 
    //! Return an half-resized image, using a special filter.
9921
 
    /**
9922
 
       \see resize_halfXY(), resize(), get_resize().
9923
 
    **/
9924
 
    CImg get_resize_halfXY() const {
9925
 
      typedef typename cimg::largest<T,float>::type ftype;
9926
 
      if (is_empty()) return CImg<T>();
9927
 
      CImg<ftype> mask = CImg<ftype>::matrix(0.07842776544f, 0.1231940459f, 0.07842776544f,
9928
 
                                             0.1231940459f,  0.1935127547f, 0.1231940459f,
9929
 
                                             0.07842776544f, 0.1231940459f, 0.07842776544f);
9930
 
      CImg_3x3(I,ftype);
9931
 
      CImg dest(width/2,height/2,depth,dim);
9932
 
      cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I)
9933
 
        if (x%2 && y%2) dest(x/2,y/2,z,k) = (T)cimg_conv3x3(I,mask);
9934
 
      return dest;
9935
 
    }
9936
 
 
9937
 
    //! Half-resize the image, using a special filter
9938
 
    /**
9939
 
       \see get_resize_halfXY(), resize(), get_resize().
9940
 
    **/
9941
 
    CImg& resize_halfXY() {
9942
 
      return get_resize_halfXY().swap(*this);
9943
 
    }
9944
 
 
9945
 
    //! Return a square region of the image, as a new image
9946
 
    /**
9947
 
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
9948
 
       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
9949
 
       \param z0 = Z-coordinate of the upper-left crop rectangle corner.
9950
 
       \param v0 = V-coordinate of the upper-left crop rectangle corner.
9951
 
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
9952
 
       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
9953
 
       \param z1 = Z-coordinate of the lower-right crop rectangle corner.
9954
 
       \param v1 = V-coordinate of the lower-right crop rectangle corner.
9955
 
       \param border_condition = Dirichlet (false) or Neumann border conditions.
9956
 
       \see crop()
9957
 
    **/
9958
 
    CImg get_crop(const int x0, const int y0, const int z0, const int v0,
9959
 
                  const int x1, const int y1, const int z1, const int v1,
9960
 
                  const bool border_condition=false) const {
9961
 
      if (is_empty()) return *this;
9962
 
      const int
9963
 
        nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
9964
 
        ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0,
9965
 
        nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0,
9966
 
        nv0 = v0<v1?v0:v1, nv1 = v0^v1^nv0;
9967
 
      CImg dest(1U+nx1-nx0,1U+ny1-ny0,1U+nz1-nz0,1U+nv1-nv0);
9968
 
      if (nx0<0 || nx1>=dimx() || ny0<0 || ny1>=dimy() || nz0<0 || nz1>=dimz() || nv0<0 || nv1>=dimv()) {
9969
 
        if (border_condition) cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = pix4d(nx0+x,ny0+y,nz0+z,nv0+v);
9970
 
        else dest.fill(0).draw_image(*this,-nx0,-ny0,-nz0,-nv0);
9971
 
      } else dest.draw_image(*this,-nx0,-ny0,-nz0,-nv0);
9972
 
      return dest;
9973
 
    }
9974
 
 
9975
 
    //! Return a square region of the image, as a new image
9976
 
    /**
9977
 
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
9978
 
       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
9979
 
       \param z0 = Z-coordinate of the upper-left crop rectangle corner.
9980
 
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
9981
 
       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
9982
 
       \param z1 = Z-coordinate of the lower-right crop rectangle corner.
9983
 
       \param border_condition = determine the type of border condition if
9984
 
       some of the desired region is outside the image.
9985
 
       \see crop()
9986
 
    **/
9987
 
    CImg get_crop(const int x0, const int y0, const int z0,
9988
 
                  const int x1, const int y1, const int z1,
9989
 
                  const bool border_condition=false) const {
9990
 
      return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
9991
 
    }
9992
 
 
9993
 
    //! Return a square region of the image, as a new image
9994
 
    /**
9995
 
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
9996
 
       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
9997
 
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
9998
 
       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
9999
 
       \param border_condition = determine the type of border condition if
10000
 
       some of the desired region is outside the image.
10001
 
       \see crop()
10002
 
    **/
10003
 
    CImg get_crop(const int x0, const int y0,
10004
 
                  const int x1, const int y1,
10005
 
                  const bool border_condition=false) const {
10006
 
      return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
10007
 
    }
10008
 
 
10009
 
    //! Return a square region of the image, as a new image
10010
 
    /**
10011
 
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
10012
 
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
10013
 
       \param border_condition = determine the type of border condition if
10014
 
       some of the desired region is outside the image.
10015
 
       \see crop()
10016
 
    **/
10017
 
    CImg get_crop(const int x0, const int x1, const bool border_condition=false) const {
10018
 
      return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
10019
 
    }
10020
 
 
10021
 
    //! Replace the image by a square region of the image
10022
 
    /**
10023
 
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
10024
 
       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
10025
 
       \param z0 = Z-coordinate of the upper-left crop rectangle corner.
10026
 
       \param v0 = V-coordinate of the upper-left crop rectangle corner.
10027
 
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
10028
 
       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
10029
 
       \param z1 = Z-coordinate of the lower-right crop rectangle corner.
10030
 
       \param v1 = V-coordinate of the lower-right crop rectangle corner.
10031
 
       \param border_condition = determine the type of border condition if
10032
 
       some of the desired region is outside the image.
10033
 
       \see get_crop()
10034
 
    **/
10035
 
    CImg& crop(const int x0, const int y0, const int z0, const int v0,
10036
 
               const int x1, const int y1, const int z1, const int v1,
10037
 
               const bool border_condition=false) {
10038
 
      return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).swap(*this);
10039
 
    }
10040
 
 
10041
 
    //! Replace the image by a square region of the image
10042
 
    /**
10043
 
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
10044
 
       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
10045
 
       \param z0 = Z-coordinate of the upper-left crop rectangle corner.
10046
 
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
10047
 
       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
10048
 
       \param z1 = Z-coordinate of the lower-right crop rectangle corner.
10049
 
       \param border_condition = determine the type of border condition if
10050
 
       some of the desired region is outside the image.
10051
 
       \see get_crop()
10052
 
    **/
10053
 
    CImg& crop(const int x0, const int y0, const int z0,
10054
 
               const int x1, const int y1, const int z1,
10055
 
               const bool border_condition=false) {
10056
 
      return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
10057
 
    }
10058
 
 
10059
 
    //! Replace the image by a square region of the image
10060
 
    /**
10061
 
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
10062
 
       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
10063
 
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
10064
 
       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
10065
 
       \param border_condition = determine the type of border condition if
10066
 
       some of the desired region is outside the image.
10067
 
       \see get_crop()
10068
 
    **/
10069
 
    CImg& crop(const int x0, const int y0,
10070
 
               const int x1, const int y1,
10071
 
               const bool border_condition=false) {
10072
 
      return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
10073
 
    }
10074
 
 
10075
 
    //! Replace the image by a square region of the image
10076
 
    /**
10077
 
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
10078
 
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
10079
 
       \param border_condition = determine the type of border condition if
10080
 
       some of the desired region is outside the image.
10081
 
       \see get_crop()
10082
 
    **/
10083
 
    CImg& crop(const int x0, const int x1, const bool border_condition=false) {
10084
 
      return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
10085
 
    }
10086
 
 
10087
 
    //! Return a set of columns
10088
 
    CImg get_columns(const unsigned int x0, const unsigned int x1) const {
10089
 
      return get_crop((int)x0,0,0,0,(int)x1,(int)height-1,(int)depth-1,(int)dim-1);
10090
 
    }
10091
 
 
10092
 
    //! Replace the instance image by a set of its columns
10093
 
    CImg& columns(const unsigned int x0, const unsigned int x1) {
10094
 
      return get_columns(x0,x1).swap(*this);
10095
 
    }
10096
 
 
10097
 
    //! Return one column
10098
 
    CImg get_column(const unsigned int x0) const {
10099
 
      return get_columns(x0,x0);
10100
 
    }
10101
 
 
10102
 
    //! Replace the instance image by one of its column
10103
 
    CImg& column(const unsigned int x0) {
10104
 
      return columns(x0,x0);
10105
 
    }
10106
 
 
10107
 
    //! Get a copy of a set of lines of the instance image.
10108
 
    CImg get_lines(const unsigned int y0, const unsigned int y1) const {
10109
 
      return get_crop(0,(int)y0,0,0,(int)width-1,(int)y1,(int)depth-1,(int)dim-1);
10110
 
    }
10111
 
 
10112
 
    //! Replace the instance image by a set of lines of the instance image.
10113
 
    CImg& lines(const unsigned int y0, const unsigned int y1) {
10114
 
      return get_lines(y0,y1).swap(*this);
10115
 
    }
10116
 
 
10117
 
    //! Get a copy of a line of the instance image.
10118
 
    CImg get_line(const unsigned int y0) const {
10119
 
      return get_lines(y0,y0);
10120
 
    }
10121
 
 
10122
 
    //! Replace the instance image by one of its line.
10123
 
    CImg& line(const unsigned int y0) {
10124
 
      return lines(y0,y0);
10125
 
    }
10126
 
 
10127
 
    //! Get a set of slices
10128
 
    CImg get_slices(const unsigned int z0, const unsigned int z1) const {
10129
 
      return get_crop(0,0,(int)z0,0,(int)width-1,(int)height-1,(int)z1,(int)dim-1);
10130
 
    }
10131
 
 
10132
 
    // Replace the image by a set of its z-slices
10133
 
    CImg& slices(const unsigned int z0, const unsigned int z1) {
10134
 
      return get_slices(z0,z1).swap(*this);
10135
 
    }
10136
 
 
10137
 
    //! Get the z-slice \a z of *this, as a new image.
10138
 
    CImg get_slice(const unsigned int z0) const {
10139
 
      return get_slices(z0,z0);
10140
 
    }
10141
 
 
10142
 
    //! Replace the image by one of its slice.
10143
 
    CImg& slice(const unsigned int z0) {
10144
 
      return slices(z0,z0);
10145
 
    }
10146
 
 
10147
 
    //! Return a copy of a set of channels of the instance image.
10148
 
    CImg get_channels(const unsigned int v0, const unsigned int v1) const {
10149
 
      return get_crop(0,0,0,(int)v0,(int)width-1,(int)height-1,(int)depth-1,(int)v1);
10150
 
    }
10151
 
 
10152
 
    //! Replace the instance image by a set of channels of the instance image.
10153
 
    CImg& channels(const unsigned int v0, const unsigned int v1) {
10154
 
      return get_channels(v0,v1).swap(*this);
10155
 
    }
10156
 
 
10157
 
    //! Return a copy of a channel of the instance image.
10158
 
    CImg get_channel(const unsigned int v0) const {
10159
 
      return get_channels(v0,v0);
10160
 
    }
10161
 
 
10162
 
    //! Replace the instance image by one of its channel.
10163
 
    CImg& channel(const unsigned int v0) {
10164
 
      return channels(v0,v0);
10165
 
    }
10166
 
 
10167
 
    //! Get a shared-memory image referencing a set of points of the instance image.
10168
 
    CImg get_shared_points(const unsigned int x0, const unsigned int x1,
10169
 
                           const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) {
10170
 
      const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
10171
 
      if (beg>end || beg>=size() || end>=size())
10172
 
        throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
10173
 
                                    "a (%u,%u,%u,%u) image.",pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
10174
 
      return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
10175
 
    }
10176
 
 
10177
 
    //! Get a shared-memory image referencing a set of points of the instance image (const version).
10178
 
    const CImg get_shared_points(const unsigned int x0, const unsigned int x1,
10179
 
                                 const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const {
10180
 
      const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
10181
 
      if (beg>end || beg>=size() || end>=size())
10182
 
        throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
10183
 
                                    "a (%u,%u,%u,%u) image.",pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
10184
 
      return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
10185
 
    }
10186
 
 
10187
 
    //! Return a shared-memory image referencing a set of lines of the instance image.
10188
 
    CImg get_shared_lines(const unsigned int y0, const unsigned int y1,
10189
 
                          const unsigned int z0=0, const unsigned int v0=0) {
10190
 
      const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
10191
 
      if (beg>end || beg>=size() || end>=size())
10192
 
        throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
10193
 
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
10194
 
      return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
10195
 
    }
10196
 
 
10197
 
    //! Return a shared-memory image referencing a set of lines of the instance image (const version).
10198
 
    const CImg get_shared_lines(const unsigned int y0, const unsigned int y1,
10199
 
                                const unsigned int z0=0, const unsigned int v0=0) const {
10200
 
      const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
10201
 
      if (beg>end || beg>=size() || end>=size())
10202
 
        throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
10203
 
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
10204
 
      return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
10205
 
    }
10206
 
 
10207
 
    //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image.
10208
 
    CImg get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) {
10209
 
      return get_shared_lines(y0,y0,z0,v0);
10210
 
    }
10211
 
 
10212
 
    //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image (const version).
10213
 
    const CImg get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) const {
10214
 
      return get_shared_lines(y0,y0,z0,v0);
10215
 
    }
10216
 
 
10217
 
    //! Return a shared memory image referencing a set of planes (z0->z1,v0) of the instance image.
10218
 
    CImg get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) {
10219
 
      const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
10220
 
      if (beg>end || beg>=size() || end>=size())
10221
 
        throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
10222
 
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
10223
 
      return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
10224
 
    }
10225
 
 
10226
 
    //! Return a shared-memory image referencing a set of planes (z0->z1,v0) of the instance image (const version).
10227
 
    const CImg get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const {
10228
 
      const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
10229
 
      if (beg>end || beg>=size() || end>=size())
10230
 
        throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
10231
 
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
10232
 
      return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
10233
 
    }
10234
 
 
10235
 
    //! Return a shared-memory image referencing one plane (z0,v0) of the instance image.
10236
 
    CImg get_shared_plane(const unsigned int z0, const unsigned int v0=0) {
10237
 
      return get_shared_planes(z0,z0,v0);
10238
 
    }
10239
 
 
10240
 
    //! Return a shared-memory image referencing one plane (z0,v0) of the instance image (const version).
10241
 
    const CImg get_shared_plane(const unsigned int z0, const unsigned int v0=0) const {
10242
 
      return get_shared_planes(z0,z0,v0);
10243
 
    }
10244
 
 
10245
 
    //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image.
10246
 
    CImg get_shared_channels(const unsigned int v0, const unsigned int v1) {
10247
 
      const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
10248
 
      if (beg>end || beg>=size() || end>=size())
10249
 
        throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
10250
 
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
10251
 
      return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
10252
 
    }
10253
 
 
10254
 
    //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image (const version).
10255
 
    const CImg get_shared_channels(const unsigned int v0, const unsigned int v1) const {
10256
 
      const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
10257
 
      if (beg>end || beg>=size() || end>=size())
10258
 
        throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
10259
 
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
10260
 
      return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
10261
 
    }
10262
 
 
10263
 
    //! Return a shared-memory image referencing one channel v0 of the instance image.
10264
 
    CImg get_shared_channel(const unsigned int v0) {
10265
 
      return get_shared_channels(v0,v0);
10266
 
    }
10267
 
 
10268
 
    //! Return a shared-memory image referencing one channel v0 of the instance image (const version).
10269
 
    const CImg get_shared_channel(const unsigned int v0) const {
10270
 
      return get_shared_channels(v0,v0);
10271
 
    }
10272
 
 
10273
 
    //! Return a shared version of the instance image.
10274
 
    CImg get_shared() {
10275
 
      return CImg<T>(data,width,height,depth,dim,true);
10276
 
    }
10277
 
 
10278
 
    //! Return a shared version of the instance image (const version).
10279
 
    const CImg get_shared() const {
10280
 
      return CImg<T>(data,width,height,depth,dim,true);
 
14575
    **/
 
14576
    CImg<T> get_permute_axes(const char *permut="vxyz") const {
 
14577
      const T foo = (T)0;
 
14578
      return get_permute_axes(permut,foo);
 
14579
    }
 
14580
 
 
14581
    //! Permute axes order (in-place).
 
14582
    CImg<T>& permute_axes(const char *order="vxyz") {
 
14583
      return get_permute_axes(order).transfer_to(*this);
10281
14584
    }
10282
14585
 
10283
14586
    //! Mirror an image along the specified axis.
10284
 
    /**
10285
 
       This is the in-place version of get_mirror().
10286
 
       \sa get_mirror().
10287
 
    **/
10288
 
    CImg& mirror(const char axe='x') {
 
14587
    CImg<T> get_mirror(const char axe='x') const {
 
14588
      return (+*this).mirror(axe);
 
14589
    }
 
14590
 
 
14591
    //! Mirror an image along the specified axis (in-place).
 
14592
    CImg<T>& mirror(const char axe='x') {
10289
14593
      if (!is_empty()) {
10290
14594
        T *pf, *pb, *buf = 0;
10291
14595
        switch (cimg::uncase(axe)) {
10292
14596
        case 'x': {
10293
 
          pf = ptr(); pb = ptr(width-1);
 
14597
          pf = data; pb = ptr(width-1);
10294
14598
          for (unsigned int yzv=0; yzv<height*depth*dim; ++yzv) {
10295
14599
            for (unsigned int x=0; x<width/2; ++x) { const T val = *pf; *(pf++) = *pb; *(pb--) = val; }
10296
14600
            pf+=width-width/2;
10299
14603
        } break;
10300
14604
        case 'y': {
10301
14605
          buf = new T[width];
10302
 
          pf = ptr(); pb = ptr(0,height-1);
 
14606
          pf = data; pb = ptr(0,height-1);
10303
14607
          for (unsigned int zv=0; zv<depth*dim; ++zv) {
10304
14608
            for (unsigned int y=0; y<height/2; ++y) {
10305
14609
              std::memcpy(buf,pf,width*sizeof(T));
10314
14618
        } break;
10315
14619
        case 'z': {
10316
14620
          buf = new T[width*height];
10317
 
          pf = ptr(); pb = ptr(0,0,depth-1);
 
14621
          pf = data; pb = ptr(0,0,depth-1);
10318
14622
          cimg_forV(*this,v) {
10319
14623
            for (unsigned int z=0; z<depth/2; ++z) {
10320
14624
              std::memcpy(buf,pf,width*height*sizeof(T));
10329
14633
        } break;
10330
14634
        case 'v': {
10331
14635
          buf = new T[width*height*depth];
10332
 
          pf = ptr(); pb = ptr(0,0,0,dim-1);
 
14636
          pf = data; pb = ptr(0,0,0,dim-1);
10333
14637
          for (unsigned int v=0; v<dim/2; ++v) {
10334
14638
            std::memcpy(buf,pf,width*height*depth*sizeof(T));
10335
14639
            std::memcpy(pf,pb,width*height*depth*sizeof(T));
10346
14650
      return *this;
10347
14651
    }
10348
14652
 
10349
 
    //! Get a mirrored version of the image, along the specified axis.
 
14653
    //! Translate the image.
10350
14654
    /**
10351
 
       \param axe Axe used to mirror the image. Can be \c 'x', \c 'y', \c 'z' or \c 'v'.
10352
 
       \sa mirror().
 
14655
       \param deltax Amount of displacement along the X-axis.
 
14656
       \param deltay Amount of displacement along the Y-axis.
 
14657
       \param deltaz Amount of displacement along the Z-axis.
 
14658
       \param deltav Amount of displacement along the V-axis.
 
14659
       \param border_condition Border condition.
 
14660
 
 
14661
       - \c border_condition can be :
 
14662
          - 0 : Zero border condition (Dirichlet).
 
14663
          - 1 : Nearest neighbors (Neumann).
 
14664
          - 2 : Repeat Pattern (Fourier style).
10353
14665
    **/
10354
 
    CImg get_mirror(const char axe='x') const {
10355
 
      return (+*this).mirror(axe);
 
14666
    CImg<T> get_translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
 
14667
                          const int border_condition=0) const {
 
14668
      return (+*this).translate(deltax,deltay,deltaz,deltav,border_condition);
10356
14669
    }
10357
14670
 
10358
 
    //! Translate the image
10359
 
    /**
10360
 
       This is the in-place version of get_translate().
10361
 
       \sa get_translate().
10362
 
    **/
10363
 
    CImg& translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0, const int border_condition=0) {
 
14671
    //! Translate the image (in-place).
 
14672
    CImg<T>& translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
 
14673
                       const int border_condition=0) {
10364
14674
      if (!is_empty()) {
10365
14675
 
10366
14676
        if (deltax) // Translate along X-axis
10367
14677
          switch (border_condition) {
10368
14678
          case 0:
10369
 
            if (cimg::abs(deltax)>=(int)width) return fill(0);
 
14679
            if (cimg::abs(deltax)>=dimx()) return fill(0);
10370
14680
            if (deltax>0) cimg_forYZV(*this,y,z,k) {
10371
14681
              std::memmove(ptr(0,y,z,k),ptr(deltax,y,z,k),(width-deltax)*sizeof(T));
10372
14682
              std::memset(ptr(width-deltax,y,z,k),0,deltax*sizeof(T));
10377
14687
            break;
10378
14688
          case 1:
10379
14689
            if (deltax>0) {
10380
 
              const int ndeltax = (deltax>=(int)width)?width-1:deltax;
 
14690
              const int ndeltax = (deltax>=dimx())?width-1:deltax;
10381
14691
              if (!ndeltax) return *this;
10382
14692
              cimg_forYZV(*this,y,z,k) {
10383
14693
                std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
10384
14694
                T *ptrd = ptr(width-1,y,z,k);
10385
 
                const T &val = *ptrd;
 
14695
                const T val = *ptrd;
10386
14696
                for (int l=0; l<ndeltax-1; ++l) *(--ptrd) = val;
10387
14697
              }
10388
14698
            } else {
10389
 
              const int ndeltax = (-deltax>=(int)width)?width-1:-deltax;
 
14699
              const int ndeltax = (-deltax>=dimx())?width-1:-deltax;
10390
14700
              if (!ndeltax) return *this;
10391
14701
              cimg_forYZV(*this,y,z,k) {
10392
14702
                std::memmove(ptr(ndeltax,y,z,k),ptr(0,y,z,k),(width-ndeltax)*sizeof(T));
10393
14703
                T *ptrd = ptr(0,y,z,k);
10394
 
                const T &val = *ptrd;
 
14704
                const T val = *ptrd;
10395
14705
                for (int l=0; l<ndeltax-1; ++l) *(++ptrd) = val;
10396
14706
              }
10397
14707
            }
10398
14708
            break;
10399
14709
          case 2: {
10400
 
            const int ml = cimg::mod(deltax,(int)width), ndeltax = (ml<=(int)width/2)?ml:(ml-(int)width);
 
14710
            const int ml = cimg::mod(deltax,dimx()), ndeltax = (ml<=dimx()/2)?ml:(ml-dimx());
10401
14711
            if (!ndeltax) return *this;
10402
14712
            T* buf = new T[cimg::abs(ndeltax)];
10403
14713
            if (ndeltax>0) cimg_forYZV(*this,y,z,k) {
10416
14726
        if (deltay) // Translate along Y-axis
10417
14727
          switch (border_condition) {
10418
14728
          case 0:
10419
 
            if (cimg::abs(deltay)>=(int)height) return fill(0);
 
14729
            if (cimg::abs(deltay)>=dimy()) return fill(0);
10420
14730
            if (deltay>0) cimg_forZV(*this,z,k) {
10421
14731
              std::memmove(ptr(0,0,z,k),ptr(0,deltay,z,k),width*(height-deltay)*sizeof(T));
10422
14732
              std::memset(ptr(0,height-deltay,z,k),0,width*deltay*sizeof(T));
10427
14737
            break;
10428
14738
          case 1:
10429
14739
            if (deltay>0) {
10430
 
              const int ndeltay = (deltay>=(int)height)?height-1:deltay;
 
14740
              const int ndeltay = (deltay>=dimy())?height-1:deltay;
10431
14741
              if (!ndeltay) return *this;
10432
14742
              cimg_forZV(*this,z,k) {
10433
14743
                std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
10435
14745
                for (int l=0; l<ndeltay-1; ++l) { std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
10436
14746
              }
10437
14747
            } else {
10438
 
              const int ndeltay = (-deltay>=(int)height)?height-1:-deltay;
 
14748
              const int ndeltay = (-deltay>=dimy())?height-1:-deltay;
10439
14749
              if (!ndeltay) return *this;
10440
14750
              cimg_forZV(*this,z,k) {
10441
14751
                std::memmove(ptr(0,ndeltay,z,k),ptr(0,0,z,k),width*(height-ndeltay)*sizeof(T));
10445
14755
            }
10446
14756
            break;
10447
14757
          case 2: {
10448
 
            const int ml = cimg::mod(deltay,(int)height), ndeltay = (ml<=(int)height/2)?ml:(ml-(int)height);
 
14758
            const int ml = cimg::mod(deltay,dimy()), ndeltay = (ml<=dimy()/2)?ml:(ml-dimy());
10449
14759
            if (!ndeltay) return *this;
10450
14760
            T* buf = new T[width*cimg::abs(ndeltay)];
10451
14761
            if (ndeltay>0) cimg_forZV(*this,z,k) {
10464
14774
        if (deltaz) // Translate along Z-axis
10465
14775
          switch (border_condition) {
10466
14776
          case 0:
10467
 
            if (cimg::abs(deltaz)>=(int)depth) return fill(0);
 
14777
            if (cimg::abs(deltaz)>=dimz()) return fill(0);
10468
14778
            if (deltaz>0) cimg_forV(*this,k) {
10469
14779
              std::memmove(ptr(0,0,0,k),ptr(0,0,deltaz,k),width*height*(depth-deltaz)*sizeof(T));
10470
14780
              std::memset(ptr(0,0,depth-deltaz,k),0,width*height*deltaz*sizeof(T));
10475
14785
            break;
10476
14786
          case 1:
10477
14787
            if (deltaz>0) {
10478
 
              const int ndeltaz = (deltaz>=(int)depth)?depth-1:deltaz;
 
14788
              const int ndeltaz = (deltaz>=dimz())?depth-1:deltaz;
10479
14789
              if (!ndeltaz) return *this;
10480
14790
              cimg_forV(*this,k) {
10481
14791
                std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
10483
14793
                for (int l=0; l<ndeltaz-1; ++l) { std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
10484
14794
              }
10485
14795
            } else {
10486
 
              const int ndeltaz = (-deltaz>=(int)depth)?depth-1:-deltaz;
 
14796
              const int ndeltaz = (-deltaz>=dimz())?depth-1:-deltaz;
10487
14797
              if (!ndeltaz) return *this;
10488
14798
              cimg_forV(*this,k) {
10489
14799
                std::memmove(ptr(0,0,ndeltaz,k),ptr(0,0,0,k),width*height*(depth-ndeltaz)*sizeof(T));
10493
14803
            }
10494
14804
            break;
10495
14805
          case 2: {
10496
 
            const int ml = cimg::mod(deltaz,(int)depth), ndeltaz = (ml<=(int)depth/2)?ml:(ml-(int)depth);
 
14806
            const int ml = cimg::mod(deltaz,dimz()), ndeltaz = (ml<=dimz()/2)?ml:(ml-dimz());
10497
14807
            if (!ndeltaz) return *this;
10498
14808
            T* buf = new T[width*height*cimg::abs(ndeltaz)];
10499
14809
            if (ndeltaz>0) cimg_forV(*this,k) {
10512
14822
        if (deltav) // Translate along V-axis
10513
14823
          switch (border_condition) {
10514
14824
          case 0:
10515
 
            if (cimg::abs(deltav)>=(int)dim) return fill(0);
 
14825
            if (cimg::abs(deltav)>=dimv()) return fill(0);
10516
14826
            if (deltav>0) {
10517
14827
              std::memmove(data,ptr(0,0,0,deltav),width*height*depth*(dim-deltav)*sizeof(T));
10518
14828
              std::memset(ptr(0,0,0,dim-deltav),0,width*height*depth*deltav*sizeof(T));
10523
14833
            break;
10524
14834
          case 1:
10525
14835
            if (deltav>0) {
10526
 
              const int ndeltav = (deltav>=(int)dim)?dim-1:deltav;
 
14836
              const int ndeltav = (deltav>=dimv())?dim-1:deltav;
10527
14837
              if (!ndeltav) return *this;
10528
14838
              std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
10529
14839
              T *ptrd = ptr(0,0,0,dim-ndeltav), *ptrs = ptr(0,0,0,dim-1);
10530
14840
              for (int l=0; l<ndeltav-1; ++l) { std::memcpy(ptrd,ptrs,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
10531
14841
            } else {
10532
 
              const int ndeltav = (-deltav>=(int)dim)?dim-1:-deltav;
 
14842
              const int ndeltav = (-deltav>=dimv())?dim-1:-deltav;
10533
14843
              if (!ndeltav) return *this;
10534
14844
              std::memmove(ptr(0,0,0,ndeltav),data,width*height*depth*(dim-ndeltav)*sizeof(T));
10535
14845
              T *ptrd = ptr(0,0,0,1);
10537
14847
            }
10538
14848
            break;
10539
14849
          case 2: {
10540
 
            const int ml = cimg::mod(deltav,(int)dim), ndeltav = (ml<=(int)dim/2)?ml:(ml-(int)dim);
 
14850
            const int ml = cimg::mod(deltav,dimv()), ndeltav = (ml<=dimv()/2)?ml:(ml-dimv());
10541
14851
            if (!ndeltav) return *this;
10542
14852
            T* buf = new T[width*height*depth*cimg::abs(ndeltav)];
10543
14853
            if (ndeltav>0) {
10556
14866
      return *this;
10557
14867
    }
10558
14868
 
10559
 
    //! Return a translated image.
10560
 
    /**
10561
 
       \param deltax Amount of displacement along the X-axis.
10562
 
       \param deltay Amount of displacement along the Y-axis.
10563
 
       \param deltaz Amount of displacement along the Z-axis.
10564
 
       \param deltav Amount of displacement along the V-axis.
10565
 
       \param border_condition Border condition.
10566
 
 
10567
 
       - \c border_condition can be :
10568
 
          - 0 : Zero border condition (Dirichlet).
10569
 
          - 1 : Nearest neighbors (Neumann).
10570
 
          - 2 : Repeat Pattern (Fourier style).
10571
 
    **/
10572
 
    CImg get_translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
10573
 
                    const int border_condition=0) const {
10574
 
      return (+*this).translate(deltax,deltay,deltaz,deltav,border_condition);
 
14869
    //! Get a square region of the image.
 
14870
    /**
 
14871
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
 
14872
       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
 
14873
       \param z0 = Z-coordinate of the upper-left crop rectangle corner.
 
14874
       \param v0 = V-coordinate of the upper-left crop rectangle corner.
 
14875
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
 
14876
       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
 
14877
       \param z1 = Z-coordinate of the lower-right crop rectangle corner.
 
14878
       \param v1 = V-coordinate of the lower-right crop rectangle corner.
 
14879
       \param border_condition = Dirichlet (false) or Neumann border conditions.
 
14880
    **/
 
14881
    CImg<T> get_crop(const int x0, const int y0, const int z0, const int v0,
 
14882
                     const int x1, const int y1, const int z1, const int v1,
 
14883
                     const bool border_condition=false) const {
 
14884
      if (is_empty()) return *this;
 
14885
      const int
 
14886
        nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
 
14887
        ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0,
 
14888
        nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0,
 
14889
        nv0 = v0<v1?v0:v1, nv1 = v0^v1^nv0;
 
14890
      CImg<T> dest(1U+nx1-nx0,1U+ny1-ny0,1U+nz1-nz0,1U+nv1-nv0);
 
14891
      if (nx0<0 || nx1>=dimx() || ny0<0 || ny1>=dimy() || nz0<0 || nz1>=dimz() || nv0<0 || nv1>=dimv()) {
 
14892
        if (border_condition) cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = at(nx0+x,ny0+y,nz0+z,nv0+v);
 
14893
        else dest.fill(0).draw_image(*this,-nx0,-ny0,-nz0,-nv0);
 
14894
      } else dest.draw_image(*this,-nx0,-ny0,-nz0,-nv0);
 
14895
      return dest;
 
14896
    }
 
14897
 
 
14898
    //! Get a rectangular part of the instance image (in-place).
 
14899
    CImg<T>& crop(const int x0, const int y0, const int z0, const int v0,
 
14900
                  const int x1, const int y1, const int z1, const int v1,
 
14901
                  const bool border_condition=false) {
 
14902
      return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).transfer_to(*this);
 
14903
    }
 
14904
 
 
14905
    //! Get a rectangular part of the instance image.
 
14906
    /**
 
14907
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
 
14908
       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
 
14909
       \param z0 = Z-coordinate of the upper-left crop rectangle corner.
 
14910
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
 
14911
       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
 
14912
       \param z1 = Z-coordinate of the lower-right crop rectangle corner.
 
14913
       \param border_condition = determine the type of border condition if
 
14914
       some of the desired region is outside the image.
 
14915
    **/
 
14916
    CImg<T> get_crop(const int x0, const int y0, const int z0,
 
14917
                     const int x1, const int y1, const int z1,
 
14918
                     const bool border_condition=false) const {
 
14919
      return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
 
14920
    }
 
14921
 
 
14922
    //! Get a rectangular part of the instance image (in-place).
 
14923
    CImg<T>& crop(const int x0, const int y0, const int z0,
 
14924
                  const int x1, const int y1, const int z1,
 
14925
                  const bool border_condition=false) {
 
14926
      return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
 
14927
    }
 
14928
 
 
14929
    //! Get a rectangular part of the instance image.
 
14930
    /**
 
14931
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
 
14932
       \param y0 = Y-coordinate of the upper-left crop rectangle corner.
 
14933
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
 
14934
       \param y1 = Y-coordinate of the lower-right crop rectangle corner.
 
14935
       \param border_condition = determine the type of border condition if
 
14936
       some of the desired region is outside the image.
 
14937
    **/
 
14938
    CImg<T> get_crop(const int x0, const int y0,
 
14939
                     const int x1, const int y1,
 
14940
                     const bool border_condition=false) const {
 
14941
      return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
 
14942
    }
 
14943
 
 
14944
    //! Get a rectangular part of the instance image (in-place).
 
14945
    CImg<T>& crop(const int x0, const int y0,
 
14946
                  const int x1, const int y1,
 
14947
                  const bool border_condition=false) {
 
14948
      return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
 
14949
    }
 
14950
 
 
14951
    //! Get a rectangular part of the instance image.
 
14952
    /**
 
14953
       \param x0 = X-coordinate of the upper-left crop rectangle corner.
 
14954
       \param x1 = X-coordinate of the lower-right crop rectangle corner.
 
14955
       \param border_condition = determine the type of border condition if
 
14956
       some of the desired region is outside the image.
 
14957
    **/
 
14958
    CImg<T> get_crop(const int x0, const int x1, const bool border_condition=false) const {
 
14959
      return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
 
14960
    }
 
14961
 
 
14962
    //! Get a rectangular part of the instance image (in-place).
 
14963
    CImg<T>& crop(const int x0, const int x1, const bool border_condition=false) {
 
14964
      return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
 
14965
    }
 
14966
 
 
14967
    //! Get a set of columns.
 
14968
    CImg<T> get_columns(const unsigned int x0, const unsigned int x1) const {
 
14969
      return get_crop((int)x0,0,0,0,(int)x1,dimy()-1,dimz()-1,dimv()-1);
 
14970
    }
 
14971
 
 
14972
    //! Get a set of columns (in-place).
 
14973
    CImg<T>& columns(const unsigned int x0, const unsigned int x1) {
 
14974
      return get_columns(x0,x1).transfer_to(*this);
 
14975
    }
 
14976
 
 
14977
    //! Get one column.
 
14978
    CImg<T> get_column(const unsigned int x0) const {
 
14979
      return get_columns(x0,x0);
 
14980
    }
 
14981
 
 
14982
    //! Get one column (in-place).
 
14983
    CImg<T>& column(const unsigned int x0) {
 
14984
      return columns(x0,x0);
 
14985
    }
 
14986
 
 
14987
    //! Get a set of lines.
 
14988
    CImg<T> get_lines(const unsigned int y0, const unsigned int y1) const {
 
14989
      return get_crop(0,(int)y0,0,0,dimx()-1,(int)y1,dimz()-1,dimv()-1);
 
14990
    }
 
14991
 
 
14992
    //! Get a set of lines (in-place).
 
14993
    CImg<T>& lines(const unsigned int y0, const unsigned int y1) {
 
14994
      return get_lines(y0,y1).transfer_to(*this);
 
14995
    }
 
14996
 
 
14997
    //! Get a line.
 
14998
    CImg<T> get_line(const unsigned int y0) const {
 
14999
      return get_lines(y0,y0);
 
15000
    }
 
15001
 
 
15002
    //! Get a line (in-place).
 
15003
    CImg<T>& line(const unsigned int y0) {
 
15004
      return lines(y0,y0);
 
15005
    }
 
15006
 
 
15007
    //! Get a set of slices.
 
15008
    CImg<T> get_slices(const unsigned int z0, const unsigned int z1) const {
 
15009
      return get_crop(0,0,(int)z0,0,dimx()-1,dimy()-1,(int)z1,dimv()-1);
 
15010
    }
 
15011
 
 
15012
    //! Get a set of slices (in-place).
 
15013
    CImg<T>& slices(const unsigned int z0, const unsigned int z1) {
 
15014
      return get_slices(z0,z1).transfer_to(*this);
 
15015
    }
 
15016
 
 
15017
    //! Get a slice.
 
15018
    CImg<T> get_slice(const unsigned int z0) const {
 
15019
      return get_slices(z0,z0);
 
15020
    }
 
15021
 
 
15022
    //! Get a slice (in-place).
 
15023
    CImg<T>& slice(const unsigned int z0) {
 
15024
      return slices(z0,z0);
 
15025
    }
 
15026
 
 
15027
    //! Get a set of channels.
 
15028
    CImg<T> get_channels(const unsigned int v0, const unsigned int v1) const {
 
15029
      return get_crop(0,0,0,(int)v0,dimx()-1,dimy()-1,dimz()-1,(int)v1);
 
15030
    }
 
15031
 
 
15032
    //! Get a set of channels (in-place).
 
15033
    CImg<T>& channels(const unsigned int v0, const unsigned int v1) {
 
15034
      return get_channels(v0,v1).transfer_to(*this);
 
15035
    }
 
15036
 
 
15037
    //! Get a channel.
 
15038
    CImg<T> get_channel(const unsigned int v0) const {
 
15039
      return get_channels(v0,v0);
 
15040
    }
 
15041
 
 
15042
    //! Get a channel (in-place).
 
15043
    CImg<T>& channel(const unsigned int v0) {
 
15044
      return channels(v0,v0);
 
15045
    }
 
15046
 
 
15047
    //! Get a shared-memory image referencing a set of points of the instance image.
 
15048
    CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
 
15049
                           const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) {
 
15050
      const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
 
15051
      if (beg>end || beg>=size() || end>=size())
 
15052
        throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
 
15053
                                    "a (%u,%u,%u,%u) image.",pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
 
15054
      return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
 
15055
    }
 
15056
 
 
15057
    const CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
 
15058
                                 const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const {
 
15059
      const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
 
15060
      if (beg>end || beg>=size() || end>=size())
 
15061
        throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
 
15062
                                    "a (%u,%u,%u,%u) image.",pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
 
15063
      return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
 
15064
    }
 
15065
 
 
15066
    //! Return a shared-memory image referencing a set of lines of the instance image.
 
15067
    CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
 
15068
                          const unsigned int z0=0, const unsigned int v0=0) {
 
15069
      const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
 
15070
      if (beg>end || beg>=size() || end>=size())
 
15071
        throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
 
15072
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
 
15073
      return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
 
15074
    }
 
15075
 
 
15076
    const CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
 
15077
                                const unsigned int z0=0, const unsigned int v0=0) const {
 
15078
      const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
 
15079
      if (beg>end || beg>=size() || end>=size())
 
15080
        throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
 
15081
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
 
15082
      return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
 
15083
    }
 
15084
 
 
15085
    //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image.
 
15086
    CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) {
 
15087
      return get_shared_lines(y0,y0,z0,v0);
 
15088
    }
 
15089
 
 
15090
    const CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) const {
 
15091
      return get_shared_lines(y0,y0,z0,v0);
 
15092
    }
 
15093
 
 
15094
    //! Return a shared memory image referencing a set of planes (z0->z1,v0) of the instance image.
 
15095
    CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) {
 
15096
      const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
 
15097
      if (beg>end || beg>=size() || end>=size())
 
15098
        throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
 
15099
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
 
15100
      return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
 
15101
    }
 
15102
 
 
15103
    const CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const {
 
15104
      const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
 
15105
      if (beg>end || beg>=size() || end>=size())
 
15106
        throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
 
15107
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
 
15108
      return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
 
15109
    }
 
15110
 
 
15111
    //! Return a shared-memory image referencing one plane (z0,v0) of the instance image.
 
15112
    CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) {
 
15113
      return get_shared_planes(z0,z0,v0);
 
15114
    }
 
15115
 
 
15116
    const CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) const {
 
15117
      return get_shared_planes(z0,z0,v0);
 
15118
    }
 
15119
 
 
15120
    //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image.
 
15121
    CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) {
 
15122
      const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
 
15123
      if (beg>end || beg>=size() || end>=size())
 
15124
        throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
 
15125
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
 
15126
      return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
 
15127
    }
 
15128
 
 
15129
    const CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) const {
 
15130
      const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
 
15131
      if (beg>end || beg>=size() || end>=size())
 
15132
        throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
 
15133
                                    "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
 
15134
      return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
 
15135
    }
 
15136
 
 
15137
    //! Return a shared-memory image referencing one channel v0 of the instance image.
 
15138
    CImg<T> get_shared_channel(const unsigned int v0) {
 
15139
      return get_shared_channels(v0,v0);
 
15140
    }
 
15141
 
 
15142
    const CImg<T> get_shared_channel(const unsigned int v0) const {
 
15143
      return get_shared_channels(v0,v0);
 
15144
    }
 
15145
 
 
15146
    //! Return a shared version of the instance image.
 
15147
    CImg<T> get_shared() {
 
15148
      return CImg<T>(data,width,height,depth,dim,true);
 
15149
    }
 
15150
 
 
15151
    const CImg<T> get_shared() const {
 
15152
      return CImg<T>(data,width,height,depth,dim,true);
10575
15153
    }
10576
15154
 
10577
15155
    //! Return a 2D representation of a 3D image, with three slices.
10578
 
    CImg get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0) const {
 
15156
    CImg<T> get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
 
15157
                              const int dx=-100, const int dy=-100, const int dz=-100) const {
10579
15158
      if (is_empty()) return CImg<T>();
10580
15159
      const unsigned int
10581
 
        nx0=(x0>=width)?width-1:x0,
10582
 
        ny0=(y0>=height)?height-1:y0,
10583
 
        nz0=(z0>=depth)?depth-1:z0;
10584
 
      CImg res(width+depth,height+depth,1,dim);
10585
 
      res.fill((*this)[0]);
10586
 
      { cimg_forXYV(*this,x,y,k) res(x,y,0,k)        = (*this)(x,y,nz0,k); }
10587
 
      { cimg_forYZV(*this,y,z,k) res(width+z,y,0,k)  = (*this)(nx0,y,z,k); }
10588
 
      { cimg_forXZV(*this,x,z,k) res(x,height+z,0,k) = (*this)(x,ny0,z,k); }
10589
 
      return res;
10590
 
    }
10591
 
 
10592
 
    //! Return the image histogram.
 
15160
        nx0 = (x0>=width)?width-1:x0,
 
15161
        ny0 = (y0>=height)?height-1:y0,
 
15162
        nz0 = (z0>=depth)?depth-1:z0;
 
15163
      CImg<T>
 
15164
        imgxy(width,height,1,dim),
 
15165
        imgzy(depth,height,1,dim),
 
15166
        imgxz(width,depth,1,dim);
 
15167
      { cimg_forXYV(*this,x,y,k) imgxy(x,y,k) = (*this)(x,y,nz0,k); }
 
15168
      { cimg_forYZV(*this,y,z,k) imgzy(z,y,k) = (*this)(nx0,y,z,k); }
 
15169
      { cimg_forXZV(*this,x,z,k) imgxz(x,z,k) = (*this)(x,ny0,z,k); }
 
15170
      imgxy.resize(dx,dy,1,dim,1);
 
15171
      imgzy.resize(dz,dy,1,dim,1);
 
15172
      imgxz.resize(dx,dz,1,dim,1);
 
15173
      return CImg<T>(imgxy.width+imgzy.width,imgxy.height+imgxz.height,1,dim,0).
 
15174
        draw_image(imgxy,0,0).
 
15175
        draw_image(imgzy,imgxy.width,0).
 
15176
        draw_image(imgxz,0,imgxy.height);
 
15177
    }
 
15178
 
 
15179
    //! Return a 2D representation of a 3D image, with three slices (in-place).
 
15180
    CImg<T>& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
 
15181
                           const int dx=-100, const int dy=-100, const int dz=-100) {
 
15182
      return get_projections2d(x0,y0,z0,dx,dy,dz).transfer_to(*this);
 
15183
    }
 
15184
 
 
15185
    //! Compute the image histogram.
10593
15186
    /**
10594
15187
       The histogram H of an image I is a 1D-function where H(x) is the number of
10595
15188
       occurences of the value x in I.
10606
15199
       H(0) and H(nblevels-1) are respectively equal to the number of occurences of the values val_min and val_max in I.
10607
15200
       \note Histogram computation always returns a 1D function. Histogram of multi-valued (such as color) images
10608
15201
       are not multi-dimensional.
10609
 
       \see get_equalize_histogram(), equalize_histogram()
10610
15202
    **/
10611
 
    CImg<float> get_histogram(const unsigned int nblevels=256, const T val_min=(T)0, const T val_max=(T)0) const {
10612
 
      if (is_empty()) return CImg<float>();
 
15203
    CImg<typename cimg::last<T,float>::type> get_histogram(const unsigned int nblevels=256, const T val_min=(T)0, const T val_max=(T)0) const {
 
15204
      typedef typename cimg::last<T,float>::type t_float;
 
15205
      if (is_empty()) return CImg<Tfloat>();
10613
15206
      if (!nblevels)
10614
15207
        throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with 0 levels",
10615
15208
                                    pixel_type());
10616
15209
      T vmin = val_min, vmax = val_max;
10617
 
      CImg<float> res(nblevels,1,1,1,0);
10618
 
      if (vmin>=vmax && vmin==0) { const CImgStats st(*this,false); vmin = (T)st.min; vmax = (T)st.max; }
 
15210
      CImg<t_float> res(nblevels,1,1,1,0);
 
15211
      if (vmin>=vmax && vmin==0) vmin = minmax(vmax);
10619
15212
      if (vmin<vmax) cimg_for(*this,ptr,T) {
10620
15213
        const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin));
10621
15214
        if (pos>=0 && pos<(int)nblevels) ++res[pos];
10623
15216
      return res;
10624
15217
    }
10625
15218
 
10626
 
    //! Equalize the image histogram
10627
 
    /** This is the in-place version of \ref get_equalize_histogram() **/
10628
 
    CImg& equalize_histogram(const unsigned int nblevels=256, const T val_min=(T)0, const T val_max=(T)0) {
 
15219
    //! Compute the image histogram (in-place).
 
15220
    CImg<T>& histogram(const unsigned int nblevels=256, const T val_min=(T)0, const T val_max=(T)0) {
 
15221
      return get_histogram(nblevels,val_min,val_max).transfer_to(*this);
 
15222
    }
 
15223
 
 
15224
    //! Compute the histogram-equalized version of the instance image.
 
15225
    /**
 
15226
       The histogram equalization is a classical image processing algorithm that enhances the image contrast
 
15227
       by expanding its histogram.
 
15228
       \param nblevels = Number of different levels of the computed histogram.
 
15229
       For classical images, this value is 256 (default value). You should specify more levels
 
15230
       if you are working with CImg<float> or images with high range of pixel values.
 
15231
       \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
 
15232
       won't be changed.
 
15233
       \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
 
15234
       won't be changed.
 
15235
       \note If val_min==val_max==0 (default values), the function acts on all pixel values of the image.
 
15236
       \return A new image with same size is returned, where pixels have been equalized.
 
15237
    **/
 
15238
    CImg<T> get_equalize_histogram(const unsigned int nblevels=256, const T val_min=(T)0, const T val_max=(T)0) const {
 
15239
      return (+*this).equalize_histogram(nblevels,val_min,val_max);
 
15240
    }
 
15241
 
 
15242
    //! Compute the histogram-equalized version of the instance image (in-place).
 
15243
    CImg<T>& equalize_histogram(const unsigned int nblevels=256, const T val_min=(T)0, const T val_max=(T)0) {
10629
15244
      if (!is_empty()) {
10630
15245
        T vmin = val_min, vmax = val_max;
10631
 
        if (vmin==vmax && vmin==0) { const CImgStats st(*this,false); vmin = (T)st.min; vmax = (T)st.max; }
 
15246
        if (vmin==vmax && vmin==0) vmin = minmax(vmax);
10632
15247
        if (vmin<vmax) {
10633
15248
          CImg<float> hist = get_histogram(nblevels,vmin,vmax);
10634
15249
          float cumul = 0;
10642
15257
      return *this;
10643
15258
    }
10644
15259
 
10645
 
    //! Return the histogram-equalized version of the current image.
10646
 
    /**
10647
 
       The histogram equalization is a classical image processing algorithm that enhances the image contrast
10648
 
       by expanding its histogram.
10649
 
       \param nblevels = Number of different levels of the computed histogram.
10650
 
       For classical images, this value is 256 (default value). You should specify more levels
10651
 
       if you are working with CImg<float> or images with high range of pixel values.
10652
 
       \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
10653
 
       won't be changed.
10654
 
       \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
10655
 
       won't be changed.
10656
 
       \note If val_min==val_max==0 (default values), the function acts on all pixel values of the image.
10657
 
       \return A new image with same size is returned, where pixels have been equalized.
10658
 
       \see get_histogram(), equalize_histogram()
10659
 
    **/
10660
 
    CImg get_equalize_histogram(const unsigned int nblevels=256, const T val_min=(T)0, const T val_max=(T)0) const {
10661
 
      return (+*this).equalize_histogram(nblevels,val_min,val_max);
10662
 
    }
10663
 
 
10664
 
    //! Return the scalar image of vector norms.
 
15260
    //! Get a label map of disconnected regions with same intensities.
 
15261
    CImg<typename cimg::last<T,unsigned int>::type> get_label_regions() const {
 
15262
 
 
15263
#define _cimg_get_label_test(p,q) { \
 
15264
  flag = true; \
 
15265
  const T *ptr1 = ptr(x,y) + siz, *ptr2 = ptr(p,q) + siz; \
 
15266
  for (unsigned int i = dim; flag && i; --i) { ptr1-=wh; ptr2-=wh; flag = (*ptr1==*ptr2); } \
 
15267
}
 
15268
 
 
15269
      if (depth>1)
 
15270
        throw CImgInstanceException("CImg<%s>::label_regions() : Instance image must be a 2D image");
 
15271
      typedef typename cimg::last<T,unsigned int>::type uitype;
 
15272
      CImg<uitype> res(width,height,depth,1,0);
 
15273
      unsigned int label = 1;
 
15274
      const unsigned int wh = width*height, siz = width*height*dim;
 
15275
      const int W1 = dimx()-1, H1 = dimy()-1;
 
15276
      bool flag;
 
15277
      cimg_forXY(*this,x,y) {
 
15278
        bool done = false;
 
15279
        if (y) {
 
15280
          _cimg_get_label_test(x,y-1);
 
15281
          if (flag) {
 
15282
            const unsigned int lab = (res(x,y) = res(x,y-1));
 
15283
            done = true;
 
15284
            if (x && res(x-1,y)!=lab) {
 
15285
              _cimg_get_label_test(x-1,y);
 
15286
              if (flag) {
 
15287
                const unsigned int lold = res(x-1,y), *const cptr = res.ptr(x,y);
 
15288
                for (unsigned int *ptr = res.ptr(); ptr<cptr; ++ptr) if (*ptr==lold) *ptr = lab;
 
15289
              }
 
15290
            }
 
15291
          }
 
15292
        }
 
15293
        if (x && !done) { _cimg_get_label_test(x-1,y); if (flag) { res(x,y) = res(x-1,y); done = true; }}
 
15294
        if (!done) res(x,y) = label++;
 
15295
      }
 
15296
      for (int y=H1; y>=0; --y) for (int x=W1; x>=0; --x) {
 
15297
        bool done = false;
 
15298
        if (y<H1) {
 
15299
          _cimg_get_label_test(x,y+1);
 
15300
          if (flag) {
 
15301
            const unsigned int lab = (res(x,y) = res(x,y+1));
 
15302
            done = true;
 
15303
            if (x<W1 && res(x+1,y)!=lab) {
 
15304
              _cimg_get_label_test(x+1,y);
 
15305
              if (flag) {
 
15306
                const unsigned int lold = res(x+1,y), *const cptr = res.ptr(x,y);
 
15307
                for (unsigned int *ptr = res.ptr()+res.size()-1; ptr>cptr; --ptr) if (*ptr==lold) *ptr = lab;
 
15308
              }
 
15309
            }
 
15310
          }
 
15311
        }
 
15312
        if (x<W1 && !done) { _cimg_get_label_test(x+1,y); if (flag) res(x,y) = res(x+1,y); done = true; }
 
15313
      }
 
15314
      const unsigned int lab0 = res.max()+1;
 
15315
      label = lab0;
 
15316
      cimg_foroff(res,off) { // Relabel regions
 
15317
        const unsigned int lab = res[off];
 
15318
        if (lab<lab0) { cimg_for(res,ptr,unsigned int) if (*ptr==lab) *ptr = label; ++label; }
 
15319
      }
 
15320
      return (res-=lab0);
 
15321
    }
 
15322
 
 
15323
    //! Get a label map of disconnected regions with same intensities (in-place).
 
15324
    CImg<T>& label_regions() {
 
15325
      return get_label_regions().transfer_to(*this);
 
15326
    }
 
15327
 
 
15328
    //! Compute the scalar image of vector norms.
10665
15329
    /**
10666
15330
       When dealing with vector-valued images (i.e images with dimv()>1), this function computes the L1,L2 or Linf norm of each
10667
15331
       vector-valued pixel.
10668
15332
       \param norm_type = Type of the norm being computed (1 = L1, 2 = L2, -1 = Linf).
10669
15333
       \return A scalar-valued image CImg<float> with size (dimx(),dimy(),dimz(),1), where each pixel is the norm
10670
15334
       of the corresponding pixels in the original vector-valued image.
10671
 
       \see get_orientation_pointwise, orientation_pointwise, norm_pointwise.
10672
15335
    **/
10673
 
    CImg<typename cimg::largest<T,float>::type> get_norm_pointwise(int norm_type=2) const {
10674
 
      typedef typename cimg::largest<T,float>::type restype;
10675
 
      if (is_empty()) return CImg<restype>();
10676
 
      CImg<restype> res(width,height,depth);
10677
 
      switch(norm_type) {
 
15336
    CImg<Tfloat> get_norm_pointwise(int norm_type=2) const {
 
15337
      if (is_empty()) return *this;
 
15338
      CImg<Tfloat> res(width,height,depth);
 
15339
      switch (norm_type) {
10678
15340
      case -1: {             // Linf norm
10679
15341
        cimg_forXYZ(*this,x,y,z) {
10680
 
          restype n = 0; cimg_forV(*this,v) {
10681
 
            const restype tmp = (restype)cimg::abs((*this)(x,y,z,v));
 
15342
          Tfloat n = 0; cimg_forV(*this,v) {
 
15343
            const Tfloat tmp = (Tfloat)cimg::abs((*this)(x,y,z,v));
10682
15344
            if (tmp>n) n=tmp; res(x,y,z) = n;
10683
15345
          }
10684
15346
        }
10685
15347
      } break;
10686
15348
      case 1: {              // L1 norm
10687
15349
        cimg_forXYZ(*this,x,y,z) {
10688
 
          restype n = 0; cimg_forV(*this,v) n+=cimg::abs((*this)(x,y,z,v)); res(x,y,z) = n;
 
15350
          Tfloat n = 0; cimg_forV(*this,v) n+=cimg::abs((*this)(x,y,z,v)); res(x,y,z) = n;
10689
15351
        }
10690
15352
      } break;
10691
15353
      default: {             // L2 norm
10692
15354
        cimg_forXYZ(*this,x,y,z) {
10693
 
          restype n = 0; cimg_forV(*this,v) n+=(*this)(x,y,z,v)*(*this)(x,y,z,v); res(x,y,z) = (restype)std::sqrt((double)n);
 
15355
          Tfloat n = 0; cimg_forV(*this,v) n+=(*this)(x,y,z,v)*(*this)(x,y,z,v); res(x,y,z) = (Tfloat)std::sqrt((double)n);
10694
15356
        }
10695
 
      } break;
 
15357
      }
10696
15358
      }
10697
15359
      return res;
10698
15360
    }
10699
15361
 
10700
 
    //! Replace each pixel value with its vector norm.
10701
 
    /**
10702
 
       This is the in-place version of \ref get_norm_pointwise().
10703
 
       \note Be careful when using this function on CImg<T> with T=char, unsigned char,unsigned int or int. The vector norm
10704
 
       is usually a floating point value, and a rough cast will be done here.
10705
 
    **/
10706
 
    CImg& norm_pointwise(int norm_type=2) {
10707
 
      return CImg<T>(get_norm_pointwise(norm_type)).swap(*this);
 
15362
    //! Compute the scalar image of vector norms (in-place).
 
15363
    CImg<T>& norm_pointwise(int norm_type=2) {
 
15364
      return get_norm_pointwise(norm_type).transfer_to(*this);
10708
15365
    }
10709
15366
 
10710
 
    //! Return the image of normalized vectors
 
15367
    //! Compute the image of normalized vectors.
10711
15368
    /**
10712
15369
       When dealing with vector-valued images (i.e images with dimv()>1), this function return the image of normalized vectors
10713
15370
       (unit vectors). Null vectors are unchanged. The L2-norm is computed for the normalization.
10714
15371
       \return A new vector-valued image with same size, where each vector-valued pixels have been normalized.
10715
 
       \see get_norm_pointwise, norm_pointwise, orientation_pointwise.
10716
15372
    **/
10717
 
    CImg<typename cimg::largest<T,float>::type> get_orientation_pointwise() const {
10718
 
      typedef typename cimg::largest<T,float>::type restype;
10719
 
      if (is_empty()) return CImg<restype>();
10720
 
      return CImg<restype>(*this,false).orientation_pointwise();
 
15373
    CImg<Tfloat> get_orientation_pointwise() const {
 
15374
      if (is_empty()) return *this;
 
15375
      return CImg<Tfloat>(*this,false).orientation_pointwise();
10721
15376
    }
10722
15377
 
10723
 
    //! Replace each pixel value by its normalized vector
10724
 
    /** This is the in-place version of \ref get_orientation_pointwise() **/
10725
 
    CImg& orientation_pointwise() {
 
15378
    //! Compute the image of normalized vectors (in-place).
 
15379
    CImg<T>& orientation_pointwise() {
10726
15380
      cimg_forXYZ(*this,x,y,z) {
10727
15381
        float n = 0.0f;
10728
15382
        cimg_forV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v));
10780
15434
      } break;
10781
15435
      default:
10782
15436
        throw CImgArgumentException("CImg<%s>::get_split() : Unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
10783
 
        break;
10784
15437
      }
10785
15438
      return res;
10786
15439
    }
10787
15440
 
10788
 
    //! Append an image to another one
10789
 
    CImg get_append(const CImg<T>& img, const char axis='x', const char align='c') const {
 
15441
    //! Append an image to another one.
 
15442
    CImg<T> get_append(const CImg<T>& img, const char axis='x', const char align='c') const {
10790
15443
      if (!img) return *this;
10791
15444
      if (is_empty()) return img;
10792
15445
      CImgList<T> temp(2);
10800
15453
      return res;
10801
15454
    }
10802
15455
 
10803
 
    //! Append an image to another one (in-place version)
10804
 
    CImg& append(const CImg<T>& img, const char axis='x', const char align='c') {
 
15456
    //! Append an image to another one (in-place).
 
15457
    CImg<T>& append(const CImg<T>& img, const char axis='x', const char align='c') {
10805
15458
      if (!img) return *this;
10806
15459
      if (is_empty()) return (*this=img);
10807
 
      return get_append(img,axis,align).swap(*this);
 
15460
      return get_append(img,axis,align).transfer_to(*this);
10808
15461
    }
10809
15462
 
10810
 
    //! Return a list of images, corresponding to the XY-gradients of an image.
 
15463
    //! Compute the list of images, corresponding to the XY-gradients of an image.
10811
15464
    /**
10812
15465
       \param scheme = Numerical scheme used for the gradient computation :
10813
15466
       - -1 = Backward finite differences
10817
15470
       - 3 = Using rotation invariant masks
10818
15471
       - 4 = Using Deriche recusrsive filter.
10819
15472
    **/
10820
 
    CImgList<typename cimg::largest<T,float>::type> get_gradientXY(const int scheme=0) const {
10821
 
      typedef typename cimg::largest<T,float>::type restype;
10822
 
      if (is_empty()) return CImgList<restype>(2);
10823
 
      CImgList<restype> res(2,width,height,depth,dim);
10824
 
      switch(scheme) {
 
15473
    CImgList<Tfloat> get_gradientXY(const int scheme=0) const {
 
15474
      if (is_empty()) return CImgList<Tfloat>(2);
 
15475
      CImgList<Tfloat> res(2,width,height,depth,dim);
 
15476
      switch (scheme) {
10825
15477
      case -1: { // backward finite differences
10826
 
        CImg_3x3(I,restype);
 
15478
        CImg_3x3(I,Tfloat);
10827
15479
        cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) { res[0](x,y,z,k) = Icc-Ipc; res[1](x,y,z,k) = Icc-Icp; }
10828
15480
      } break;
10829
15481
      case 1: { // forward finite differences
10830
 
        CImg_2x2(I,restype);
 
15482
        CImg_2x2(I,Tfloat);
10831
15483
        cimg_forZV(*this,z,k) cimg_for2x2(*this,x,y,z,k,I) { res[0](x,y,0,k) = Inc-Icc; res[1](x,y,z,k) = Icn-Icc; }
10832
15484
      } break;
10833
15485
      case 2: { // using Sobel mask
10834
 
        CImg_3x3(I,restype);
 
15486
        CImg_3x3(I,Tfloat);
10835
15487
        const float a = 1, b = 2;
10836
15488
        cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
10837
15489
          res[0](x,y,z,k) = -a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn;
10839
15491
        }
10840
15492
      } break;
10841
15493
      case 3: { // using rotation invariant mask
10842
 
        CImg_3x3(I,restype);
 
15494
        CImg_3x3(I,Tfloat);
10843
15495
        const float a = (float)(0.25*(2-std::sqrt(2.0))), b = (float)(0.5f*(std::sqrt(2.0)-1));
10844
15496
        cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
10845
15497
          res[0](x,y,z,k) = -a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn;
10851
15503
        res[1] = get_deriche(0,1,'y');
10852
15504
      } break;
10853
15505
      default: { // central finite differences
10854
 
        CImg_3x3(I,restype);
 
15506
        CImg_3x3(I,Tfloat);
10855
15507
        cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
10856
15508
          res[0](x,y,z,k) = 0.5f*(Inc-Ipc);
10857
15509
          res[1](x,y,z,k) = 0.5f*(Icn-Icp);
10858
15510
        }
10859
 
      } break;
 
15511
      }
10860
15512
      }
10861
15513
      return res;
10862
15514
    }
10863
15515
 
10864
 
    //! Return a list of images, corresponding to the XYZ-gradients of an image.
10865
 
    /**
10866
 
       \see get_gradientXY().
10867
 
    **/
10868
 
    CImgList<typename cimg::largest<T,float>::type> get_gradientXYZ(const int scheme=0) const {
10869
 
      typedef typename cimg::largest<T,float>::type restype;
10870
 
      if (is_empty()) return CImgList<restype>(3);
10871
 
      CImgList<restype> res(3,width,height,depth,dim);
10872
 
      CImg_3x3x3(I,restype);
10873
 
      switch(scheme) {
 
15516
    //! Compute a list of images, corresponding to the XYZ-gradients of an image.
 
15517
    CImgList<Tfloat> get_gradientXYZ(const int scheme=0) const {
 
15518
      if (is_empty()) return CImgList<Tfloat>(3);
 
15519
      CImgList<Tfloat> res(3,width,height,depth,dim);
 
15520
      CImg_3x3x3(I,Tfloat);
 
15521
      switch (scheme) {
10874
15522
      case -1: { // backward finite differences
10875
15523
        cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
10876
15524
          res[0](x,y,z,k) = Iccc-Ipcc;
10896
15544
          res[1](x,y,z,k) = 0.5f*(Icnc-Icpc);
10897
15545
          res[2](x,y,z,k) = 0.5f*(Iccn-Iccp);
10898
15546
        }
10899
 
      } break;
 
15547
      }
10900
15548
      }
10901
15549
      return res;
10902
15550
    }
10903
15551
 
10904
 
    //! Return the 2D structure tensor field of an image
10905
 
    CImg<typename cimg::largest<T,float>::type> get_structure_tensorXY(const int scheme=1) const {
10906
 
      typedef typename cimg::largest<T,float>::type restype;
10907
 
      if (is_empty()) return CImg<restype>();
10908
 
      CImg<restype> res(width,height,depth,3,0);
10909
 
      CImg_3x3(I,restype);
 
15552
    //! Compute the 2D structure tensor field of an image.
 
15553
    CImg<Tfloat> get_structure_tensorXY(const int scheme=1) const {
 
15554
      if (is_empty()) return *this;
 
15555
      CImg<Tfloat> res(width,height,depth,3,0);
 
15556
      CImg_3x3(I,Tfloat);
10910
15557
      switch (scheme) {
10911
15558
      case 0: { // classical central finite differences
10912
15559
        cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,0,k,I) {
10913
 
          const restype
 
15560
          const Tfloat
10914
15561
            ix = 0.5f*(Inc-Ipc),
10915
15562
            iy = 0.5f*(Icn-Icp);
10916
15563
          res(x,y,z,0)+=ix*ix;
10920
15567
      } break;
10921
15568
      default: { // Precise forward/backward finite differences
10922
15569
        cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,0,k,I) {
10923
 
          const restype
 
15570
          const Tfloat
10924
15571
            ixf = Inc-Icc, ixb = Icc-Ipc,
10925
15572
            iyf = Icn-Icc, iyb = Icc-Icp;
10926
15573
          res(x,y,z,0) += 0.5f*(ixf*ixf+ixb*ixb);
10927
15574
          res(x,y,z,1) += 0.25f*(ixf*iyf+ixf*iyb+ixb*iyf+ixb*iyb);
10928
15575
          res(x,y,z,2) += 0.5f*(iyf*iyf+iyb*iyb);
10929
15576
        }
10930
 
      } break;
 
15577
      }
10931
15578
      }
10932
15579
      return res;
10933
15580
    }
10934
15581
 
10935
 
    //! In-place version of the previous function
10936
 
    CImg& structure_tensorXY(const int scheme=1) {
10937
 
      return assign(get_structure_tensorXY(scheme));
 
15582
    //! Compute the 2D structure tensor field of an image (in-place).
 
15583
    CImg<T>& structure_tensorXY(const int scheme=1) {
 
15584
      return get_structure_tensorXY(scheme).transfer_to(*this);
10938
15585
    }
10939
15586
 
10940
 
    //! Return the 3D structure tensor field of an image
10941
 
    CImg<typename cimg::largest<T,float>::type> get_structure_tensorXYZ(const int scheme=1) const {
10942
 
      typedef typename cimg::largest<T,float>::type restype;
10943
 
      if (is_empty()) return CImg<restype>();
10944
 
      CImg<restype> res(width,height,depth,6,0);
10945
 
      CImg_3x3x3(I,restype);
 
15587
    //! Compute the 3D structure tensor field of an image.
 
15588
    CImg<Tfloat> get_structure_tensorXYZ(const int scheme=1) const {
 
15589
      if (is_empty()) return *this;
 
15590
      CImg<Tfloat> res(width,height,depth,6,0);
 
15591
      CImg_3x3x3(I,Tfloat);
10946
15592
      switch (scheme) {
10947
15593
      case 0: { // classical central finite differences
10948
15594
        cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
10949
 
          const restype
 
15595
          const Tfloat
10950
15596
            ix = 0.5f*(Incc-Ipcc),
10951
15597
            iy = 0.5f*(Icnc-Icpc),
10952
15598
            iz = 0.5f*(Iccn-Iccp);
10960
15606
      } break;
10961
15607
      default: { // Precise forward/backward finite differences
10962
15608
        cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
10963
 
          const restype
 
15609
          const Tfloat
10964
15610
            ixf = Incc-Iccc, ixb = Iccc-Ipcc,
10965
15611
            iyf = Icnc-Iccc, iyb = Iccc-Icpc,
10966
15612
            izf = Iccn-Iccc, izb = Iccc-Iccp;
10971
15617
          res(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb);
10972
15618
          res(x,y,z,5) += 0.5f*(izf*izf + izb*izb);
10973
15619
        }
10974
 
      } break;
10975
 
      }
10976
 
      return res;
10977
 
    }
10978
 
 
10979
 
    //! In-place version of the previous function
10980
 
    CImg& structure_tensorXYZ(const int scheme=1) {
10981
 
      return assign(get_structure_tensorXYZ(scheme));
10982
 
    }
10983
 
 
10984
 
    //! Get distance function from 0-valued isophotes by the application of the eikonal equation.
10985
 
    CImg<typename cimg::largest<T,float>::type> get_distance_function(const unsigned int nb_iter=100, const float band_size=0.0f, const float precision=0.5f) const {
10986
 
      typedef typename cimg::largest<T,float>::type ftype;
10987
 
      return CImg<ftype>(*this).distance_function(nb_iter,band_size,precision);
10988
 
    }
10989
 
 
10990
 
    //! In-place version of the previous function
10991
 
    CImg& distance_function(const unsigned int nb_iter=100, const float band_size=0.0f, const float precision=0.5f) {
10992
 
      typedef typename cimg::largest<T,float>::type ftype;
 
15620
      }
 
15621
      }
 
15622
      return res;
 
15623
    }
 
15624
 
 
15625
    //! Compute the 3D structure tensor field of an image (in-place).
 
15626
    CImg<T>& structure_tensorXYZ(const int scheme=1) {
 
15627
      return get_structure_tensorXYZ(scheme).transfer_to(*this);
 
15628
    }
 
15629
 
 
15630
    //! Get components of the 2D Hessian matrix of an image.
 
15631
    /**
 
15632
       Components are ordered as : Ixx, Ixy, Iyy
 
15633
    **/
 
15634
    CImgList<Tfloat> get_hessianXY() {
 
15635
      if (is_empty()) return CImgList<Tfloat>(3);
 
15636
      CImgList<Tfloat> res(3,width,height,depth,dim);
 
15637
      CImg_3x3(I,Tfloat);
 
15638
      cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
 
15639
        res[0](x,y,z,k) = Ipc + Inc - 2*Icc;             // Ixx
 
15640
        res[1](x,y,z,k) = 0.25f*(Ipp + Inn - Ipn - Inp); // Ixy
 
15641
        res[2](x,y,z,k) = Icp + Icn - 2*Icc;             // Iyy
 
15642
      }
 
15643
      return res;
 
15644
    }
 
15645
 
 
15646
    //! Get components of the 3D Hessian matrix of an image.
 
15647
    /**
 
15648
       Components are ordered as : Ixx, Ixy, Ixz, Iyy, Iyz, Izz.
 
15649
    **/
 
15650
    CImgList<Tfloat> get_hessianXYZ() {
 
15651
      if (is_empty()) return CImgList<Tfloat>(6);
 
15652
      CImgList<Tfloat> res(6,width,height,depth,dim);
 
15653
      CImg_3x3x3(I,Tfloat);
 
15654
      cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
 
15655
        res[0](x,y,z,k) = Ipcc + Incc - 2*Iccc;              // Ixx
 
15656
        res[1](x,y,z,k) = 0.25f*(Ippc + Innc - Ipnc - Inpc); // Ixy
 
15657
        res[2](x,y,z,k) = 0.25f*(Ipcp + Incn - Ipcn - Incp); // Ixz
 
15658
        res[3](x,y,z,k) = Icpc + Icnc - 2*Iccc;              // Iyy
 
15659
        res[4](x,y,z,k) = 0.25f*(Icpp + Icnn - Icpn - Icnp); // Iyz
 
15660
        res[5](x,y,z,k) = Iccn + Iccp - 2*Iccc;              // Izz
 
15661
      }
 
15662
      return res;
 
15663
    }
 
15664
 
 
15665
    //! Compute distance function from 0-valued isophotes by the application of the eikonal equation.
 
15666
    CImg<Tfloat> get_distance_function(const unsigned int nb_iter=100, const float band_size=0.0f, const float precision=0.5f) const {
 
15667
      return CImg<Tfloat>(*this,false).distance_function(nb_iter,band_size,precision);
 
15668
    }
 
15669
 
 
15670
    //! Compute distance function from 0-valued isophotes by the application of the eikonal equation (in-place).
 
15671
    CImg<T>& distance_function(const unsigned int nb_iter=100, const float band_size=0.0f, const float precision=0.5f) {
10993
15672
      if (is_empty()) return *this;
10994
 
      CImg<ftype> veloc(*this);
 
15673
      CImg<Tfloat> veloc(*this);
10995
15674
      for (unsigned int iter=0; iter<nb_iter; ++iter) {
10996
15675
 
10997
15676
        if (depth>1) { // 3D version
10998
 
          CImg_3x3x3(I,ftype);
 
15677
          CImg_3x3x3(I,Tfloat);
10999
15678
          cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) if (band_size<=0 || cimg::abs(Iccc)<band_size) {
11000
 
            const ftype
 
15679
            const Tfloat
11001
15680
              gx  = 0.5f*(Incc-Ipcc),
11002
15681
              gy  = 0.5f*(Icnc-Icpc),
11003
15682
              gz  = 0.5f*(Iccn-Iccp),
11005
15684
              ix  = gx*sgn>0?Incc-Iccc:Iccc-Ipcc,
11006
15685
              iy  = gy*sgn>0?Icnc-Iccc:Iccc-Icpc,
11007
15686
              iz  = gz*sgn>0?Iccn-Iccc:Iccc-Iccp,
11008
 
              ng  = 1e-5f+(ftype)std::sqrt(gx*gx+gy*gy+gz*gz),
 
15687
              ng  = 1e-5f+(Tfloat)std::sqrt(gx*gx+gy*gy+gz*gz),
11009
15688
              ngx = gx/ng,
11010
15689
              ngy = gy/ng,
11011
15690
              ngz = gz/ng;
11012
15691
            veloc(x,y,z,k) = sgn*(ngx*ix+ngy*iy+ngz*iz-1);
11013
15692
          }
11014
15693
        } else { // 2D version
11015
 
          CImg_3x3(I,ftype);
 
15694
          CImg_3x3(I,Tfloat);
11016
15695
          cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) if (band_size<=0 || cimg::abs(Icc)<band_size) {
11017
 
            const ftype
 
15696
            const Tfloat
11018
15697
              gx  = 0.5f*(Inc-Ipc),
11019
15698
              gy  = 0.5f*(Icn-Icp),
11020
15699
              sgn = -cimg::sign(Icc),
11021
15700
              ix  = gx*sgn>0?Inc-Icc:Icc-Ipc,
11022
15701
              iy  = gy*sgn>0?Icn-Icc:Icc-Icp,
11023
 
              ng  = 1e-5f+(ftype)std::sqrt(gx*gx+gy*gy),
 
15702
              ng  = 1e-5f+(Tfloat)std::sqrt(gx*gx+gy*gy),
11024
15703
              ngx = gx/ng,
11025
15704
              ngy = gy/ng;
11026
15705
            veloc(x,y,k) = sgn*(ngx*ix+ngy*iy-1);
11027
15706
          }
11028
15707
        }
11029
 
        const CImgStats stats(veloc,false);
11030
 
        const float xdt = precision/(float)cimg::max(cimg::abs(stats.min),cimg::abs(stats.max));
 
15708
        float m, M = (float)veloc.maxmin(m), xdt = precision/(float)cimg::max(cimg::abs(m),cimg::abs(M));
11031
15709
        *this+=(veloc*=xdt);
11032
15710
      }
11033
15711
      return *this;
11034
15712
    }
11035
15713
 
 
15714
    //! Compute minimal path in a graph, using the Dijkstra algorithm.
 
15715
    /**
 
15716
       \param distance An object having operator()(unsigned int i, unsigned int j) which returns distance between two nodes (i,j).
 
15717
       \param nb_nodes Number of graph nodes.
 
15718
       \param starting_node Indice of the starting node.
 
15719
       \param ending_node Indice of the ending node (set to ~0U to ignore ending node).
 
15720
       \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
 
15721
       \return Array of distances of each node to the starting node.
 
15722
    **/
 
15723
    template<typename tf, typename t>
 
15724
      static CImg<T> get_dijkstra(const tf& distance, const unsigned int nb_nodes,
 
15725
                               const unsigned int starting_node, const unsigned int ending_node,
 
15726
                               CImg<t>& previous) {
 
15727
 
 
15728
      CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max());
 
15729
      dist(starting_node) = 0;
 
15730
      previous.assign(1,nb_nodes,1,1,(t)-1);
 
15731
      previous(starting_node) = (t)starting_node;
 
15732
      typedef typename cimg::last<T,unsigned int>::type uitype;
 
15733
      CImg<uitype> Q(nb_nodes);
 
15734
      cimg_forX(Q,u) Q(u) = u;
 
15735
      cimg::swap(Q(starting_node),Q(0));
 
15736
      unsigned int sizeQ = nb_nodes;
 
15737
      while (sizeQ) {
 
15738
        // Update neighbors from minimal vertex
 
15739
        const unsigned int umin = Q(0);
 
15740
        if (umin==ending_node) sizeQ = 0;
 
15741
        else {
 
15742
          const T dmin = dist(umin);
 
15743
          const T infty = cimg::type<T>::max();
 
15744
          for (unsigned int q=1; q<sizeQ; ++q) {
 
15745
            const unsigned int v = Q(q);
 
15746
            const T d = (T)distance(v,umin);
 
15747
            if (d<infty) {
 
15748
              const T alt = dmin + d;
 
15749
              if (alt<dist(v)) {
 
15750
                dist(v) = alt;
 
15751
                previous(v) = (t)umin;
 
15752
                const T distpos = dist(Q(q));
 
15753
                for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos+1)/2-1)); pos=par) cimg::swap(Q(pos),Q(par));
 
15754
              }
 
15755
            }
 
15756
          }
 
15757
          // Remove minimal vertex from queue
 
15758
          Q(0) = Q(--sizeQ);
 
15759
          const T distpos = dist(Q(0));
 
15760
          for (unsigned int pos = 0, left = 0, right = 0;
 
15761
               ((right=2*(pos+1),(left=right-1))<sizeQ && distpos>dist(Q(left))) || (right<sizeQ && distpos>dist(Q(right)));) {
 
15762
            if (right<sizeQ) {
 
15763
              if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; }
 
15764
              else { cimg::swap(Q(pos),Q(right)); pos = right; }
 
15765
            } else { cimg::swap(Q(pos),Q(left)); pos = left; }
 
15766
          }
 
15767
        }
 
15768
      }
 
15769
      return dist;
 
15770
    }
 
15771
 
 
15772
    //! Return minimal path in a graph, using the Dijkstra algorithm.
 
15773
    template<typename tf, typename t>
 
15774
      static CImg<T> get_dijkstra(const tf& distance, const unsigned int nb_nodes,
 
15775
                               const unsigned int starting_node, const unsigned int ending_node=~0U) {
 
15776
      typedef typename cimg::last<T,unsigned int>::type uitype;
 
15777
      CImg<uitype> foo;
 
15778
      return get_dijkstra(distance,nb_nodes,starting_node,ending_node,foo);
 
15779
    }
 
15780
 
 
15781
    //! Return minimal path in a graph, using the Dijkstra algorithm.
 
15782
    /**
 
15783
       Instance image corresponds to the adjacency matrix of the graph.
 
15784
       \param starting_node Indice of the starting node.
 
15785
       \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
 
15786
       \return Array of distances of each node to the starting node.
 
15787
    **/
 
15788
    template<typename t> CImg<T> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) const {
 
15789
      if (width!=height || depth!=1 || dim!=1)
 
15790
        throw CImgInstanceException("CImg<%s>::dijkstra() : Instance image (%u,%u,%u,%u,%p) is not a graph adjacency matrix",
 
15791
                                    pixel_type(),width,height,depth,dim,data);
 
15792
      return CImg<T>::get_dijkstra(*this,width,starting_node,ending_node,previous);
 
15793
    }
 
15794
 
 
15795
    //! Return minimal path in a graph, using the Dijkstra algorithm (in-place).
 
15796
    template<typename t> CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) {
 
15797
      return get_dijkstra(starting_node,ending_node,previous).transfer_to(*this);
 
15798
    }
 
15799
 
 
15800
    //! Return minimal path in a graph, using the Dijkstra algorithm
 
15801
    CImg<Tfloat> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const {
 
15802
      typedef typename cimg::last<T,unsigned int>::type uitype;
 
15803
      CImg<uitype> foo;
 
15804
      return get_dijkstra(starting_node,ending_node,foo);
 
15805
    }
 
15806
 
 
15807
    //! Return minimal path in a graph, using the Dijkstra algorithm (in-place).
 
15808
    CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) {
 
15809
      return get_dijkstra(starting_node,ending_node).transfer_to(*this);
 
15810
    }
 
15811
 
11036
15812
    //@}
11037
15813
    //-------------------------------------
11038
15814
    //
11060
15836
      const CImg<T>& ref;
11061
15837
      _marching_squares_func_float(const CImg<T>& pref):ref(pref) {}
11062
15838
      float operator()(const float x, const float y) const {
11063
 
        return (float)ref.linear_pix2d(x,y);
 
15839
        return (float)ref.linear_at2(x,y);
11064
15840
      }
11065
15841
    };
11066
15842
 
11068
15844
      const CImg<T>& ref;
11069
15845
      _marching_cubes_func_float(const CImg<T>& pref):ref(pref) {}
11070
15846
      float operator()(const float x, const float y, const float z) const {
11071
 
        return (float)ref.linear_pix3d(x,y,z);
 
15847
        return (float)ref.linear_at3(x,y,z);
11072
15848
      }
11073
15849
    };
11074
15850
 
11075
 
    //! Get a vectorization of an implicit function defined by the instance image.
 
15851
    //! Compute a vectorization of an implicit function defined by the instance image.
11076
15852
    template<typename tp, typename tf>
11077
 
    const CImg& marching_squares(const float isovalue,CImgList<tp>& points, CImgList<tf>& primitives) const {
 
15853
    const CImg<T>& marching_squares(const float isovalue, CImgList<tp>& points, CImgList<tf>& primitives) const {
11078
15854
      if (height<=1 || depth>1 || dim>1)
11079
15855
        throw CImgInstanceException("CImg<%s>::marching_squares() : Instance image (%u,%u,%u,%u,%p) is not a 2D scalar image.",
11080
15856
                                    pixel_type(),width,height,depth,dim,data);
11083
15859
      return *this;
11084
15860
    }
11085
15861
 
11086
 
    //! Get a vectorization of an implicit function defined by the instance image.
 
15862
    //! Compute a vectorization of an implicit function defined by the instance image.
11087
15863
    /**
11088
15864
       This version allows to specify the marching squares resolution along x,y, and z.
11089
15865
    **/
11090
15866
    template<typename tp, typename tf>
11091
 
    const CImg& marching_squares(const float isovalue,
11092
 
                                 const float resx, const float resy,
11093
 
                                 CImgList<tp>& points, CImgList<tf>& primitives) const {
 
15867
    const CImg<T>& marching_squares(const float isovalue,
 
15868
                                    const float resx, const float resy,
 
15869
                                    CImgList<tp>& points, CImgList<tf>& primitives) const {
11094
15870
      if (height<=1 || depth>1 || dim>1)
11095
15871
        throw CImgInstanceException("CImg<%s>::marching_squares() : Instance image (%u,%u,%u,%u,%p) is not a 2D scalar image.",
11096
15872
                                    pixel_type(),width,height,depth,dim,data);
11099
15875
      return *this;
11100
15876
    }
11101
15877
 
11102
 
    //! Get a triangulation of an implicit function defined by the instance image
 
15878
    //! Compute a triangulation of an implicit function defined by the instance image.
11103
15879
    template<typename tp, typename tf>
11104
 
    const CImg& marching_cubes(const float isovalue,CImgList<tp>& points, CImgList<tf>& primitives,
11105
 
                               const bool invert_faces = false) const {
 
15880
    const CImg<T>& marching_cubes(const float isovalue, CImgList<tp>& points, CImgList<tf>& primitives,
 
15881
                                  const bool invert_faces = false) const {
11106
15882
      if (depth<=1 || dim>1)
11107
15883
        throw CImgInstanceException("CImg<%s>::marching_cubes() : Instance image (%u,%u,%u,%u,%p) is not a 3D scalar image.",
11108
15884
                                    pixel_type(),width,height,depth,dim,data);
11112
15888
      return *this;
11113
15889
    }
11114
15890
 
11115
 
    //! Get a triangulation of an implicit function defined by the instance image
 
15891
    //! Compute a triangulation of an implicit function defined by the instance image.
11116
15892
    /**
11117
15893
       This version allows to specify the marching cube resolution along x,y and z.
11118
15894
    **/
11119
15895
    template<typename tp, typename tf>
11120
 
    const CImg& marching_cubes(const float isovalue,
11121
 
                               const float resx, const float resy, const float resz,
11122
 
                               CImgList<tp>& points, CImgList<tf>& primitives,
11123
 
                               const bool invert_faces = false) const {
 
15896
    const CImg<T>& marching_cubes(const float isovalue,
 
15897
                                  const float resx, const float resy, const float resz,
 
15898
                                  CImgList<tp>& points, CImgList<tf>& primitives,
 
15899
                                  const bool invert_faces = false) const {
11124
15900
      if (depth<=1 || dim>1)
11125
15901
        throw CImgInstanceException("CImg<%s>::marching_cubes() : Instance image (%u,%u,%u,%u,%p) is not a 3D scalar image.",
11126
15902
                                    pixel_type(),width,height,depth,dim,data);
11130
15906
      return *this;
11131
15907
    }
11132
15908
 
 
15909
    //! Return a 3D centered cube.
 
15910
    template<typename tf> static CImg<typename cimg::last<T,float>::type>
 
15911
      cube3d(CImgList<tf>& primitives, const float size=100) {
 
15912
      typedef typename cimg::last<T,float>::type t_float;
 
15913
      const double s = size/2.0;
 
15914
      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);
 
15915
      return CImg<t_float>(8,3,1,1,
 
15916
                           -s,s,s,-s,-s,s,s,-s,
 
15917
                           -s,-s,s,s,-s,-s,s,s,
 
15918
                           -s,-s,-s,-s,s,s,s,s);
 
15919
    }
 
15920
 
 
15921
    //! Return a 3D centered cuboid.
 
15922
    template<typename tf> static CImg<typename cimg::last<T,float>::type>
 
15923
      cuboid3d(CImgList<tf>& primitives,const float sizex=200, const float sizey=100, const float sizez=100) {
 
15924
      typedef typename cimg::last<T,float>::type t_float;
 
15925
      const double sx = sizex/2.0, sy = sizey/2.0, sz = sizez/2.0;
 
15926
      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);
 
15927
      return CImg<t_float>(8,3,1,1,
 
15928
                           -sx,sx,sx,-sx,-sx,sx,sx,-sx,
 
15929
                           -sy,-sy,sy,sy,-sy,-sy,sy,sy,
 
15930
                           -sz,-sz,-sz,-sz,sz,sz,sz,sz);
 
15931
    }
 
15932
 
 
15933
    //! Return a 3D centered cone.
 
15934
    template<typename tf> static CImg<typename cimg::last<T,float>::type>
 
15935
      cone3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
 
15936
             const unsigned int subdivisions=24, const bool symetrize=false) {
 
15937
      typedef typename cimg::last<T,float>::type t_float;
 
15938
      primitives.assign();
 
15939
      if (!subdivisions) return CImg<t_float>();
 
15940
      const double r = (double)radius, h = (double)height/2;
 
15941
      CImgList<t_float> points(2,1,3,1,1,
 
15942
                               0.0,0.0,h,
 
15943
                               0.0,0.0,-h);
 
15944
      const float delta = 360.0f/subdivisions, nh = symetrize?0:-(float)h;
 
15945
      for (float angle = 0.0f; angle<360.0f; angle+=delta) {
 
15946
        const float a = (float)(angle*cimg::valuePI/180);
 
15947
        points.insert(CImg<t_float>::vector((float)(r*std::cos(a)),(float)(r*std::sin(a)),nh));
 
15948
      }
 
15949
      const unsigned int nbr = points.size-2;
 
15950
      for (unsigned int p = 0; p<nbr; ++p) {
 
15951
        const unsigned int curr = 2+p, next = 2+((p+1)%nbr);
 
15952
        primitives.insert(CImg<tf>::vector(1,next,curr)).
 
15953
          insert(CImg<tf>::vector(0,curr,next));
 
15954
      }
 
15955
      return points.get_append('x');
 
15956
    }
 
15957
 
 
15958
    //! Return a 3D centered cylinder.
 
15959
    template<typename tf> static CImg<typename cimg::last<T,float>::type>
 
15960
      cylinder3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
 
15961
                 const unsigned int subdivisions=24) {
 
15962
      typedef typename cimg::last<T,float>::type t_float;
 
15963
      primitives.assign();
 
15964
      if (!subdivisions) return CImg<t_float>();
 
15965
      const double r = (double)radius, h = (double)height/2;
 
15966
      CImgList<t_float> points(2,1,3,1,1,
 
15967
                               0.0,0.0,-h,
 
15968
                               0.0,0.0,h);
 
15969
 
 
15970
      const float delta = 360.0f/subdivisions;
 
15971
      for (float angle = 0.0f; angle<360.0f; angle+=delta) {
 
15972
        const float a = (float)(angle*cimg::valuePI/180);
 
15973
        points.insert(CImg<t_float>::vector((float)(r*std::cos(a)),(float)(r*std::sin(a)),-(float)h));
 
15974
        points.insert(CImg<t_float>::vector((float)(r*std::cos(a)),(float)(r*std::sin(a)),(float)h));
 
15975
      }
 
15976
      const unsigned int nbr = (points.size-2)/2;
 
15977
      for (unsigned int p = 0; p<nbr; ++p) {
 
15978
        const unsigned int curr = 2+2*p, next = 2+(2*((p+1)%nbr));
 
15979
        primitives.insert(CImg<tf>::vector(0,next,curr)).
 
15980
          insert(CImg<tf>::vector(1,curr+1,next+1)).
 
15981
          insert(CImg<tf>::vector(curr,next,next+1,curr+1));
 
15982
      }
 
15983
      return points.get_append('x');
 
15984
    }
 
15985
 
 
15986
    //! Return a 3D centered torus.
 
15987
    template<typename tf> static CImg<typename cimg::last<T,float>::type>
 
15988
      torus3d(CImgList<tf>& primitives, const float radius1=100, const float radius2=30,
 
15989
              const unsigned int subdivisions1=24, const unsigned int subdivisions2=12) {
 
15990
      typedef typename cimg::last<T,float>::type type_float;
 
15991
      primitives.assign();
 
15992
      if (!subdivisions1 || !subdivisions2) return CImg<type_float>();
 
15993
      CImgList<type_float> points;
 
15994
      for (unsigned int v = 0; v<subdivisions1; ++v) {
 
15995
        const float
 
15996
          beta = (float)(v*2*cimg::valuePI/subdivisions1),
 
15997
          xc = radius1*(float)std::cos(beta),
 
15998
          yc = radius1*(float)std::sin(beta);
 
15999
        for (unsigned int u=0; u<subdivisions2; ++u) {
 
16000
          const float
 
16001
            alpha = (float)(u*2*cimg::valuePI/subdivisions2),
 
16002
            x = xc + radius2*(float)(std::cos(alpha)*std::cos(beta)),
 
16003
            y = yc + radius2*(float)(std::cos(alpha)*std::sin(beta)),
 
16004
            z = radius2*(float)std::sin(alpha);
 
16005
          points.insert(CImg<type_float>::vector(x,y,z));
 
16006
        }
 
16007
      }
 
16008
      for (unsigned int vv = 0; vv<subdivisions1; ++vv) {
 
16009
        const unsigned int nv = (vv+1)%subdivisions1;
 
16010
        for (unsigned int uu = 0; uu<subdivisions2; ++uu) {
 
16011
          const unsigned int nu = (uu+1)%subdivisions2, svv = subdivisions2*vv, snv = subdivisions2*nv;
 
16012
          primitives.insert(CImg<tf>::vector(svv+nu,svv+uu,snv+uu));
 
16013
          primitives.insert(CImg<tf>::vector(svv+nu,snv+uu,snv+nu));
 
16014
        }
 
16015
      }
 
16016
      return points.get_append('x');
 
16017
    }
 
16018
 
 
16019
    //! Return a 3D centered XY plane.
 
16020
    template<typename tf> static CImg<typename cimg::last<T,float>::type>
 
16021
      plane3d(CImgList<tf>& primitives, const float sizex=100, const float sizey=100,
 
16022
              const unsigned int subdivisionsx=3, const unsigned int subdivisionsy=3,
 
16023
              const bool double_sided=false) {
 
16024
      typedef typename cimg::last<T,float>::type type_float;
 
16025
      primitives.assign();
 
16026
      if (!subdivisionsx || !subdivisionsy) return CImg<type_float>();
 
16027
      CImgList<type_float> points;
 
16028
      const unsigned int w = subdivisionsx + 1, h = subdivisionsy + 1;
 
16029
      const float w2 = subdivisionsx/2.0f, h2 = subdivisionsy/2.0f, fx = (float)sizex/w, fy = (float)sizey/h;
 
16030
      for (unsigned int yy = 0; yy<h; ++yy)
 
16031
        for (unsigned int xx = 0; xx<w; ++xx)
 
16032
          points.insert(CImg<type_float>::vector(fx*(xx-w2),fy*(yy-h2),0));
 
16033
      for (unsigned int y = 0; y<subdivisionsy; ++y) for (unsigned int x = 0; x<subdivisionsx; ++x) {
 
16034
        const int off1 = x+y*w, off2 = x+1+y*w, off3 = x+1+(y+1)*w, off4 = x+(y+1)*w;
 
16035
        primitives.insert(CImg<tf>::vector(off1,off4,off3,off2));
 
16036
        if (double_sided) primitives.insert(CImg<tf>::vector(off1,off2,off3,off4));
 
16037
      }
 
16038
      return points.get_append('x');
 
16039
    }
 
16040
 
 
16041
    //! Return a 3D centered sphere.
 
16042
    template<typename tf> static CImg<typename cimg::last<T,float>::type>
 
16043
      sphere3d(CImgList<tf>& primitives, const float radius=50, const unsigned int subdivisions=3) {
 
16044
 
 
16045
      // Create initial icosahedron
 
16046
      typedef typename cimg::last<T,float>::type type_float;
 
16047
      primitives.assign();
 
16048
      if (!subdivisions) return CImg<type_float>();
 
16049
      const double tmp = (1+std::sqrt(5.0f))/2.0f, a = 1.0/std::sqrt(1+tmp*tmp), b = tmp*a;
 
16050
      CImgList<type_float> 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,
 
16051
                                  -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a);
 
16052
      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,
 
16053
                        8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3,
 
16054
                        5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2);
 
16055
 
 
16056
      // Recurse subdivisions
 
16057
      for (unsigned int i = 0; i<subdivisions; ++i) {
 
16058
        const unsigned int L = primitives.size;
 
16059
        for (unsigned int l = 0; l<L; ++l) {
 
16060
          const unsigned int
 
16061
            p0 = (unsigned int)primitives(0,0), p1 = (unsigned int)primitives(0,1), p2 = (unsigned int)primitives(0,2);
 
16062
          const float
 
16063
            x0 = points(p0,0), y0 = points(p0,1), z0 = points(p0,2),
 
16064
            x1 = points(p1,0), y1 = points(p1,1), z1 = points(p1,2),
 
16065
            x2 = points(p2,0), y2 = points(p2,1), z2 = points(p2,2),
 
16066
            tnx0 = (x0+x1)/2, tny0 = (y0+y1)/2, tnz0 = (z0+z1)/2, nn0 = (float)std::sqrt(tnx0*tnx0+tny0*tny0+tnz0*tnz0),
 
16067
            tnx1 = (x0+x2)/2, tny1 = (y0+y2)/2, tnz1 = (z0+z2)/2, nn1 = (float)std::sqrt(tnx1*tnx1+tny1*tny1+tnz1*tnz1),
 
16068
            tnx2 = (x1+x2)/2, tny2 = (y1+y2)/2, tnz2 = (z1+z2)/2, nn2 = (float)std::sqrt(tnx2*tnx2+tny2*tny2+tnz2*tnz2),
 
16069
            nx0 = tnx0/nn0, ny0 = tny0/nn0, nz0 = tnz0/nn0,
 
16070
            nx1 = tnx1/nn1, ny1 = tny1/nn1, nz1 = tnz1/nn1,
 
16071
            nx2 = tnx2/nn2, ny2 = tny2/nn2, nz2 = tnz2/nn2;
 
16072
          int i0 = -1, i1 = -1, i2 = -1;
 
16073
          cimglist_for(points,p) {
 
16074
            const float x = (float)points(p,0), y = (float)points(p,1), z = (float)points(p,2);
 
16075
            if (x==nx0 && y==ny0 && z==nz0) i0 = p;
 
16076
            if (x==nx1 && y==ny1 && z==nz1) i1 = p;
 
16077
            if (x==nx2 && y==ny2 && z==nz2) i2 = p;
 
16078
          }
 
16079
          if (i0<0) { points.insert(CImg<>::vector(nx0,ny0,nz0)); i0 = points.size-1; }
 
16080
          if (i1<0) { points.insert(CImg<>::vector(nx1,ny1,nz1)); i1 = points.size-1; }
 
16081
          if (i2<0) { points.insert(CImg<>::vector(nx2,ny2,nz2)); i2 = points.size-1; }
 
16082
          primitives.remove(0);
 
16083
          primitives.insert(CImg<unsigned int>::vector(p0,i0,i1)).
 
16084
            insert(CImg<unsigned int>::vector(i0,p1,i2)).
 
16085
            insert(CImg<unsigned int>::vector(i1,i2,p2)).
 
16086
            insert(CImg<unsigned int>::vector(i1,i0,i2));
 
16087
        }
 
16088
      }
 
16089
      return points.get_append('x')*=radius;
 
16090
    }
 
16091
 
 
16092
    //! Return a 3D centered ellipsoid.
 
16093
    template<typename tf, typename t> static CImg<typename cimg::last<T,float>::type>
 
16094
      ellipsoid3d(CImgList<tf>& primitives, const CImg<t>& tensor, const unsigned int subdivisions=3) {
 
16095
      typedef typename cimg::last<T,float>::type type_float;
 
16096
      primitives.assign();
 
16097
      if (!subdivisions) return CImg<type_float>();
 
16098
      typedef typename cimg::superset<t,float>::type tfloat;
 
16099
      CImg<tfloat> S,V;
 
16100
      tensor.symmetric_eigen(S,V);
 
16101
      const tfloat l0 = S[0], l1 = S[1], l2 = S[2];
 
16102
      CImg<type_float> points = sphere(primitives,subdivisions);
 
16103
      cimg_forX(points,p) {
 
16104
        points(p,0) = (float)(points(p,0)*l0);
 
16105
        points(p,1) = (float)(points(p,1)*l1);
 
16106
        points(p,2) = (float)(points(p,2)*l2);
 
16107
      }
 
16108
      V.transpose();
 
16109
      points = V*points;
 
16110
      return points;
 
16111
    }
 
16112
 
 
16113
    //! Translate a 3D object.
 
16114
    CImg<Tfloat> get_translate_object3d(const float tx, const float ty=0, const float tz=0) const {
 
16115
      return CImg<Tfloat>(*this,false).translate_object3d(tx,ty,tz);
 
16116
    }
 
16117
 
 
16118
    //! Translate a 3D object (in-place).
 
16119
    CImg<T>& translate_object3d(const float tx, const float ty=0, const float tz=0) {
 
16120
      get_shared_line(0)+=tx; get_shared_line(1)+=ty; get_shared_line(2)+=tz;
 
16121
      return *this;
 
16122
    }
 
16123
 
 
16124
    //! Translate a 3D object so that it becomes centered.
 
16125
    CImg<Tfloat> get_translate_object3d() const {
 
16126
      return CImg<Tfloat>(*this,false).translate_object3d();
 
16127
    }
 
16128
 
 
16129
    //! Translate a 3D object so that it becomes centered (in-place).
 
16130
    CImg<T>& translate_object3d() {
 
16131
      CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
 
16132
      float xm, xM = xcoords.maxmin(xm), ym, yM = ycoords.maxmin(ym), zm, zM = zcoords.maxmin(zm);
 
16133
      xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2;
 
16134
      return *this;
 
16135
    }
 
16136
 
 
16137
    //! Resize a 3D object.
 
16138
    CImg<Tfloat> get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const {
 
16139
      return CImg<Tfloat>(*this,false).resize_object3d(sx,sy,sz);
 
16140
    }
 
16141
 
 
16142
    //! Resize a 3D object (in-place).
 
16143
    CImg<T>& resize_object3d(const float sx, const float sy=-100, const float sz=-100) {
 
16144
      CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
 
16145
      float xm, xM = xcoords.maxmin(xm), ym, yM = ycoords.maxmin(ym), zm, zM = zcoords.maxmin(zm);
 
16146
      if (xm<xM) { if (sx>0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; }
 
16147
      if (ym<yM) { if (sy>0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; }
 
16148
      if (zm<zM) { if (sz>0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; }
 
16149
      return *this;
 
16150
    }
 
16151
 
 
16152
    //! Append a 3D object to another one.
 
16153
    template<typename tf, typename tp, typename tff>
 
16154
      CImg<T>& append_object3d(CImgList<tf>& primitives, const CImg<tp>& obj_points, const CImgList<tff>& obj_primitives) {
 
16155
      const unsigned int P = width;
 
16156
      append(obj_points,'x');
 
16157
      const unsigned int N = primitives.size;
 
16158
      primitives.insert(obj_primitives);
 
16159
      for (unsigned int i = N; i<primitives.size; ++i) {
 
16160
        CImg<tf> &p = primitives[i];
 
16161
        if (p.size()!=5) p+=P;
 
16162
        else { p[0]+=P; if (p[2]==0) p[1]+=P; }
 
16163
      }
 
16164
      return *this;
 
16165
    }
 
16166
 
11133
16167
    //@}
11134
16168
    //----------------------------
11135
16169
    //
11136
 
    //! \name Color conversions
 
16170
    //! \name Color bases
11137
16171
    //@{
11138
16172
    //----------------------------
11139
16173
 
11140
 
    //! Return the default 256 colors palette.
 
16174
    //! Return a default indexed color palette with 256 (R,G,B) entries.
11141
16175
    /**
11142
16176
       The default color palette is used by %CImg when displaying images on 256 colors displays.
11143
16177
       It consists in the quantification of the (R,G,B) color space using 3:3:2 bits for color coding
11144
16178
       (i.e 8 levels for the Red and Green and 4 levels for the Blue).
11145
 
       \return A 256x1x1x3 color image defining the palette entries.
 
16179
       \return a 1x256x1x3 color image defining the palette entries.
11146
16180
    **/
11147
 
    static CImg<T> get_default_LUT8() {
11148
 
      static CImg<T> palette;
 
16181
    static CImg<Tuchar> get_default_LUT8() {
 
16182
      static CImg<Tuchar> palette;
11149
16183
      if (!palette) {
11150
16184
        palette.assign(1,256,1,3);
11151
 
        for (unsigned int index=0, r=16; r<256; r+=32)
11152
 
          for (unsigned int g=16; g<256; g+=32)
11153
 
            for (unsigned int b=32; b<256; b+=64) {
11154
 
              palette(index,0) = r;
11155
 
              palette(index,1) = g;
11156
 
              palette(index++,2) = b;
 
16185
        for (unsigned int index = 0, r = 16; r<256; r+=32)
 
16186
          for (unsigned int g = 16; g<256; g+=32)
 
16187
            for (unsigned int b = 32; b<256; b+=64) {
 
16188
              palette(0,index,0) = (Tuchar)r;
 
16189
              palette(0,index,1) = (Tuchar)g;
 
16190
              palette(0,index++,2) = (Tuchar)b;
11157
16191
            }
11158
16192
      }
11159
16193
      return palette;
11160
16194
    }
11161
16195
 
11162
 
    //! Return a rainbow-palette
11163
 
    static CImg<T> get_rainbow_LUT8() {
11164
 
      static CImg<T> palette;
 
16196
    //! Return a rainbow color palette with 256 (R,G,B) entries.
 
16197
    static CImg<Tuchar> get_rainbow_LUT8() {
 
16198
      static CImg<Tuchar> palette;
11165
16199
      if (!palette) {
11166
 
        palette.assign(1,256,1,3,255);
11167
 
        palette.get_shared_channel(0).sequence(0,359);
11168
 
        palette.HSVtoRGB();
 
16200
        CImg<Tint> tmp(1,256,1,3,1);
 
16201
        tmp.get_shared_channel(0).sequence(0,359);
 
16202
        palette = tmp.HSVtoRGB();
11169
16203
      }
11170
16204
      return palette;
11171
16205
    }
11172
16206
 
11173
 
    //! Return contrasted palette optmized for cluster visualization
11174
 
    static CImg<T> get_cluster_LUT8() {
11175
 
      static const unsigned char pal[] =
11176
 
        { 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,
11177
 
          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,
11178
 
          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,
11179
 
          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,
11180
 
          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,
11181
 
          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,
11182
 
          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,
11183
 
          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,
11184
 
          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,
11185
 
          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,
11186
 
          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,
11187
 
          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,
11188
 
          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,
11189
 
          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,
11190
 
          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,
11191
 
          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,
11192
 
          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,
11193
 
          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,
11194
 
          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,
11195
 
          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,
11196
 
          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,
11197
 
          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,
11198
 
          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,
11199
 
          23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 };
11200
 
      static const CImg<T> palette(pal,256,1,1,3);
 
16207
    //! Return a contrasted color palette with 256 (R,G,B) entries.
 
16208
    static CImg<Tuchar> get_contrast_LUT8() {
 
16209
      static const unsigned char pal[] = {
 
16210
        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,
 
16211
        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,
 
16212
        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,
 
16213
        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,
 
16214
        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,
 
16215
        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,
 
16216
        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,
 
16217
        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,
 
16218
        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,
 
16219
        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,
 
16220
        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,
 
16221
        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,
 
16222
        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,
 
16223
        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,
 
16224
        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,
 
16225
        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,
 
16226
        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,
 
16227
        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,
 
16228
        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,
 
16229
        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,
 
16230
        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,
 
16231
        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,
 
16232
        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,
 
16233
        23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 };
 
16234
      static const CImg<Tuchar> palette(pal,1,256,1,3);
11201
16235
      return palette;
11202
16236
    }
11203
16237
 
11204
 
    //! Convert color pixels from (R,G,B) to match a specified palette.
11205
 
    /**
11206
 
       This function return a (R,G,B) image where colored pixels are constrained to match entries
11207
 
       of the specified color \c palette.
11208
 
       \param palette User-defined palette that will constraint the color conversion.
11209
 
       \param dithering Enable/Disable Floyd-Steinberg dithering.
11210
 
       \param indexing If \c true, each resulting image pixel is an index to the given color palette.
11211
 
       Otherwise, (R,G,B) values of the palette are copied instead.
11212
 
    **/
 
16238
    //! Convert (R,G,B) color image to indexed color image.
11213
16239
    template<typename t> CImg<t> get_RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) const {
11214
16240
      if (is_empty()) return CImg<t>();
11215
16241
      if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoLUT() : Input image dimension is dim=%u, "
11217
16243
      if (palette.data && palette.dim!=3)
11218
16244
        throw CImgArgumentException("CImg<%s>::RGBtoLUT() : Given palette dimension is dim=%u, "
11219
16245
                                    "should be a (R,G,B) palette",pixel_type(),palette.dim);
11220
 
      CImg<t> res(width,height,depth,indexing?1:3), pal = palette.data?palette:CImg<t>::get_default_LUT8();
11221
 
      float *line1 = new float[3*width], *line2 = new float[3*width], *pline1 = line1, *pline2 = line2;
 
16246
      CImg<t> res(width,height,depth,indexing?1:3);
 
16247
      float *line1 = new float[3*width], *line2 = new float[3*width];
 
16248
      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);
11222
16249
      cimg_forZ(*this,z) {
11223
 
        float *ptr = pline2; cimg_forX(*this,x) { *(ptr++) = (*this)(x,0,z,0); *(ptr++) = (*this)(x,0,z,1); *(ptr++) = (*this)(x,0,z,2); }
 
16250
        const T *pRs = ptr(0,0,z,0), *pGs = ptr(0,0,z,1), *pBs = ptr(0,0,z,2);
 
16251
        float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
11224
16252
        cimg_forY(*this,y) {
11225
 
          cimg::swap(pline1,pline2);
 
16253
          cimg::swap(line1,line2);
11226
16254
          if (y<dimy()-1) {
11227
 
            const int ny = y+1;
11228
 
            float *ptr = pline2; cimg_forX(*this,x) { *(ptr++) = (*this)(x,ny,z,0); *(ptr++) = (*this)(x,ny,z,1); *(ptr++) = (*this)(x,ny,z,2); }
 
16255
            const int ny = y + 1;
 
16256
            const T *pRs = ptr(0,ny,z,0), *pGs = ptr(0,ny,z,1), *pBs = ptr(0,ny,z,2);
 
16257
            float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
11229
16258
          }
11230
 
          float *ptr1=pline1, *ptr2=pline2;
 
16259
          float *ptr1 = line1, *ptr2 = line2;
11231
16260
          cimg_forX(*this,x) {
11232
16261
            float R = *(ptr1++), G = *(ptr1++), B = *(ptr1++);
11233
16262
            R = R<0?0:(R>255?255:R); G = G<0?0:(G>255?255:G); B = B<0?0:(B>255?255:B);
 
16263
            t Rbest = 0, Gbest = 0, Bbest = 0;
11234
16264
            int best_index = 0;
11235
 
            t Rbest = 0, Gbest = 0, Bbest = 0;
11236
 
            if (palette.data) { // find best match in given color palette
 
16265
            if (palette) { // find best match in given color palette
 
16266
              const t *pRs = palette.ptr(0,0,0,0), *pGs = palette.ptr(0,0,0,1), *pBs = palette.ptr(0,0,0,2);
 
16267
              const unsigned int Npal = palette.width*palette.height*palette.depth;
11237
16268
              float min = cimg::type<float>::max();
11238
 
              cimg_forX(palette,off) {
11239
 
                const t Rp = palette(off,0), Gp = palette(off,1), Bp = palette(off,2);
11240
 
                const float error = (float)((Rp-R)*(Rp-R) + (Gp-G)*(Gp-G) + (Bp-B)*(Bp-B));
11241
 
                if (error<min) { min=error; best_index=off; Rbest=Rp; Gbest=Gp; Bbest=Bp; }
 
16269
              for (unsigned int off = 0; off<Npal; ++off) {
 
16270
                const t Rp = *(pRs++), Gp = *(pGs++), Bp = *(pBs++);
 
16271
                const float error = cimg::sqr((float)Rp-(float)R) + cimg::sqr((float)Gp-(float)G) + cimg::sqr((float)Bp-(float)B);
 
16272
                if (error<min) { min = error; best_index = off; Rbest = Rp; Gbest = Gp; Bbest = Bp; }
11242
16273
              }
11243
16274
            } else {
11244
16275
              Rbest = (t)((unsigned char)R&0xe0); Gbest = (t)((unsigned char)G&0xe0); Bbest = (t)((unsigned char)B&0xc0);
11245
16276
              best_index = (unsigned char)Rbest | ((unsigned char)Gbest>>3) | ((unsigned char)Bbest>>6);
11246
16277
            }
11247
 
            if (indexing) res(x,y,z) = best_index;
11248
 
            else { res(x,y,z,0) = Rbest; res(x,y,z,1) = Gbest; res(x,y,z,2) = Bbest; }
 
16278
            if (indexing) *(pRd++) = (t)best_index; else { *(pRd++) = Rbest; *(pGd++) = Gbest; *(pBd++) = Bbest; }
11249
16279
            if (dithering) { // apply dithering to neighborhood pixels if needed
11250
16280
              const float dR = (float)(R-Rbest), dG = (float)(G-Gbest), dB = (float)(B-Bbest);
11251
16281
              if (x<dimx()-1) { *(ptr1++)+= dR*7/16; *(ptr1++)+= dG*7/16; *(ptr1++)+= dB*7/16; ptr1-=3; }
11263
16293
      return res;
11264
16294
    }
11265
16295
 
11266
 
    //! Convert color pixels from (R,G,B) to match the default 256 colors palette.
11267
 
    /**
11268
 
       Same as get_RGBtoLUT() with the default color palette given by get_default_LUT8().
11269
 
    **/
11270
 
    CImg<T> get_RGBtoLUT(const bool dithering=true, const bool indexing=false) const {
11271
 
      CImg<T> foo;
11272
 
      return get_RGBtoLUT(foo,dithering,indexing);
11273
 
    }
11274
 
 
11275
 
    //! Convert color pixels from (R,G,B) to match the specified color palette.
11276
 
    /** This is the in-place version of get_RGBtoLUT(). **/
11277
 
    CImg& RGBtoLUT(const CImg<T>& palette, const bool dithering=true, const bool indexing=false) {
11278
 
      return get_RGBtoLUT(palette,dithering,indexing).swap(*this);
11279
 
    }
11280
 
 
11281
 
    //! Convert color pixels from (R,G,B) to match the specified color palette.
11282
 
    /** This is the in-place version of get_RGBtoLUT(). **/
11283
 
    CImg& RGBtoLUT(const bool dithering=true, const bool indexing=false) {
11284
 
      CImg<T> foo;
11285
 
      return get_RGBtoLUT(foo,dithering,indexing).swap(*this);
 
16296
    //! Convert color pixels from (R,G,B) colors to match a specified palette (in-place).
 
16297
    template<typename t> CImg<T>& RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) {
 
16298
      return get_RGBtoLUT(palette,dithering,indexing).transfer_to(*this);
 
16299
    }
 
16300
 
 
16301
    //! Convert color pixels from (R,G,B) to match the default palette.
 
16302
    CImg<Tuchar> get_RGBtoLUT(const bool dithering=true, const bool indexing=false) const {
 
16303
      static const CImg<Tuchar> empty;
 
16304
      return get_RGBtoLUT(empty,dithering,indexing);
 
16305
    }
 
16306
 
 
16307
    //! Convert color pixels from (R,G,B) to match the default palette (in-place).
 
16308
    CImg<T>& RGBtoLUT(const bool dithering=true, const bool indexing=false) {
 
16309
      return get_RGBtoLUT(dithering,indexing).transfer_to(*this);
11286
16310
    }
11287
16311
 
11288
16312
    //! Convert an indexed image to a (R,G,B) image using the specified color palette.
11293
16317
      if (palette.data && palette.dim!=3)
11294
16318
        throw CImgArgumentException("CImg<%s>::LUTtoRGB() : Given palette dimension is dim=%u, "
11295
16319
                                    "should be a (R,G,B) palette",pixel_type(),palette.dim);
 
16320
      const CImg<t> pal = palette.data?palette:CImg<t>(get_default_LUT8());
11296
16321
      CImg<t> res(width,height,depth,3);
11297
 
      CImg<t> pal = palette.data?palette:CImg<t>::get_default_LUT8();
11298
 
      cimg_forXYZ(*this,x,y,z) {
11299
 
        const unsigned int index = (unsigned int)(*this)(x,y,z);
11300
 
        res(x,y,z,0) = pal(index,0);
11301
 
        res(x,y,z,1) = pal(index,1);
11302
 
        res(x,y,z,2) = pal(index,2);
 
16322
      const t *pRs = pal.ptr(0,0,0,0), *pGs = pal.ptr(0,0,0,1), *pBs = pal.ptr(0,0,0,2);
 
16323
      t *pRd = res.ptr(0,0,0,1), *pGd = pRd + width*height*depth, *pBd = pGd + width*height*depth;
 
16324
      const unsigned int Npal = palette.width*palette.height*palette.depth;
 
16325
      cimg_for(*this,ptr,T) {
 
16326
        const unsigned int index = ((unsigned int)*ptr)%Npal;
 
16327
        *(--pRd) = pRs[index]; *(--pGd) = pGs[index]; *(--pBd) = pBs[index];
11303
16328
      }
11304
16329
      return res;
11305
16330
    }
11306
16331
 
 
16332
    //! Convert an indexed image to a (R,G,B) image using the specified color palette (in-place).
 
16333
    CImg<T>& LUTtoRGB(const CImg<T>& palette) {
 
16334
      return get_LUTtoRGB(palette).transfer_to(*this);
 
16335
    }
 
16336
 
11307
16337
    //! Convert an indexed image (with the default palette) to a (R,G,B) image.
11308
 
    CImg<T> get_LUTtoRGB() const {
11309
 
      CImg<T> foo;
11310
 
      return get_LUTtoRGB(foo);
11311
 
    }
11312
 
 
11313
 
    //! In-place version of get_LUTtoRGB().
11314
 
    CImg& LUTtoRGB(const CImg<T>& palette) {
11315
 
      return get_LUTtoRGB(palette).swap(*this);
11316
 
    }
11317
 
 
11318
 
    //! In-place version of get_LUTroRGB().
11319
 
    CImg& LUTtoRGB() {
11320
 
      CImg<T> foo;
11321
 
      return get_LUTtoRGB(foo).swap(*this);
 
16338
    CImg<Tuchar> get_LUTtoRGB() const {
 
16339
      static const CImg<Tuchar> empty;
 
16340
      return get_LUTtoRGB(empty);
 
16341
    }
 
16342
 
 
16343
    //! Convert an indexed image (with the default palette) to a (R,G,B) image (in-place).
 
16344
    CImg<T>& LUTtoRGB() {
 
16345
      return get_LUTtoRGB().transfer_to(*this);
11322
16346
    }
11323
16347
 
11324
16348
    //! Convert color pixels from (R,G,B) to (H,S,V).
11325
 
    CImg& RGBtoHSV() {
 
16349
    CImg<Tfloat> get_RGBtoHSV() const {
 
16350
      return CImg<Tfloat>(*this,false).RGBtoHSV();
 
16351
    }
 
16352
 
 
16353
    //! Convert color pixels from (R,G,B) to (H,S,V) (in-place).
 
16354
    CImg<T>& RGBtoHSV() {
11326
16355
      if (!is_empty()) {
11327
16356
        if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoHSV() : Input image dimension is dim=%u, "
11328
16357
                                                "should be a (R,G,B) image.",pixel_type(),dim);
11329
 
        cimg_forXYZ(*this,x,y,z) {
11330
 
          const float
11331
 
            R = (float)((*this)(x,y,z,0)/255.0f),
11332
 
            G = (float)((*this)(x,y,z,1)/255.0f),
11333
 
            B = (float)((*this)(x,y,z,2)/255.0f);
11334
 
          const float m = cimg::min(R,G,B), v = cimg::max(R,G,B);
11335
 
          float h,s;
11336
 
          if (v==m) { h = -1; s = 0; } else {
11337
 
            const float
11338
 
              f = (R==m)?(G-B):((G==m)?(B-R):(R-G)),
11339
 
              i = (R==m)?3.0f:((G==m)?5.0f:1.0f);
11340
 
            h = (i-f/(v-m));
11341
 
            s = (v-m)/v;
11342
 
            if (h>=6.0f) h-=6.0f;
11343
 
            h*=60;
 
16358
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16359
        for (unsigned long N = width*height*depth; N; --N) {
 
16360
          const Tfloat
 
16361
            R = (Tfloat)*p1,
 
16362
            G = (Tfloat)*p2,
 
16363
            B = (Tfloat)*p3,
 
16364
            nR = (R<0?0:(R>255?255:R))/255,
 
16365
            nG = (G<0?0:(G>255?255:G))/255,
 
16366
            nB = (B<0?0:(B>255?255:B))/255,
 
16367
            m = cimg::min(nR,nG,nB),
 
16368
            M = cimg::max(nR,nG,nB);
 
16369
          Tfloat H = 0, S = 0;
 
16370
          if (M!=m) {
 
16371
            const Tfloat
 
16372
              f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
 
16373
              i = (Tfloat)((nR==m)?3:((nG==m)?5:1));
 
16374
            H = (i-f/(M-m));
 
16375
            if (H>=6) H-=6;
 
16376
            H*=60;
 
16377
            S = (M-m)/M;
11344
16378
          }
11345
 
          (*this)(x,y,z,0) = (T)h;
11346
 
          (*this)(x,y,z,1) = (T)s;
11347
 
          (*this)(x,y,z,2) = (T)v;
 
16379
          *(p1++) = (T)H;
 
16380
          *(p2++) = (T)S;
 
16381
          *(p3++) = (T)M;
11348
16382
        }
11349
16383
      }
11350
16384
      return *this;
11351
16385
    }
11352
16386
 
11353
16387
    //! Convert color pixels from (H,S,V) to (R,G,B).
11354
 
    CImg& HSVtoRGB() {
 
16388
    CImg<Tuchar> get_HSVtoRGB() const {
 
16389
      return CImg<Tuchar>(*this,false).HSVtoRGB();
 
16390
    }
 
16391
 
 
16392
    //! Convert color pixels from (H,S,V) to (R,G,B) (in-place).
 
16393
    CImg<T>& HSVtoRGB() {
11355
16394
      if (!is_empty()) {
11356
16395
        if (dim!=3) throw CImgInstanceException("CImg<%s>::HSVtoRGB() : Input image dimension is dim=%u, "
11357
16396
                                                "should be a (H,S,V) image",pixel_type(),dim);
11358
 
        cimg_forXYZ(*this,x,y,z) {
11359
 
          float
11360
 
            H = (float)((*this)(x,y,z,0)),
11361
 
            S = (float)((*this)(x,y,z,1)),
11362
 
            V = (float)((*this)(x,y,z,2));
11363
 
          float R = 0, G = 0, B = 0;
11364
 
          if (H<0) R=G=B=V;
 
16397
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16398
        for (unsigned long N = width*height*depth; N; --N) {
 
16399
          Tfloat
 
16400
            H = (Tfloat)*p1,
 
16401
            S = (Tfloat)*p2,
 
16402
            V = (Tfloat)*p3,
 
16403
            R = 0, G = 0, B = 0;
 
16404
          if (H==0 && S==0) R = G = B = V;
11365
16405
          else {
11366
 
            H/=60.0f;
 
16406
            H/=60;
11367
16407
            const int i = (int)std::floor(H);
11368
 
            const float
11369
 
              f = (i&1)?(H-i):(1.0f-H+i),
11370
 
              m = V*(1.0f-S),
11371
 
              n = V*(1.0f-S*f);
11372
 
            switch(i) {
 
16408
            const Tfloat
 
16409
              f = (i&1)?(H-i):(1-H+i),
 
16410
              m = V*(1-S),
 
16411
              n = V*(1-S*f);
 
16412
            switch (i) {
11373
16413
            case 6:
11374
 
            case 0: R=V; G=n; B=m; break;
11375
 
            case 1: R=n; G=V; B=m; break;
11376
 
            case 2: R=m; G=V; B=n; break;
11377
 
            case 3: R=m; G=n; B=V; break;
11378
 
            case 4: R=n; G=m; B=V; break;
11379
 
            case 5: R=V; G=m; B=n; break;
 
16414
            case 0: R = V; G = n; B = m; break;
 
16415
            case 1: R = n; G = V; B = m; break;
 
16416
            case 2: R = m; G = V; B = n; break;
 
16417
            case 3: R = m; G = n; B = V; break;
 
16418
            case 4: R = n; G = m; B = V; break;
 
16419
            case 5: R = V; G = m; B = n; break;
11380
16420
            }
11381
16421
          }
11382
 
          (*this)(x,y,z,0) = (T)(R*255.0f);
11383
 
          (*this)(x,y,z,1) = (T)(G*255.0f);
11384
 
          (*this)(x,y,z,2) = (T)(B*255.0f);
11385
 
        }
11386
 
      }
11387
 
      return *this;
11388
 
    }
11389
 
 
11390
 
    //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8 (Thanks to Chen Wang).
11391
 
    CImg& RGBtoYCbCr() {
 
16422
          R*=255; G*=255; B*=255;
 
16423
          *(p1++) = (T)(R<0?0:(R>255?255:R));
 
16424
          *(p2++) = (T)(G<0?0:(G>255?255:G));
 
16425
          *(p3++) = (T)(B<0?0:(B>255?255:B));
 
16426
        }
 
16427
      }
 
16428
      return *this;
 
16429
    }
 
16430
 
 
16431
    //! Convert color pixels from (R,G,B) to (H,S,L).
 
16432
    CImg<Tfloat> get_RGBtoHSL() const {
 
16433
      return CImg< Tfloat>(*this,false).RGBtoHSL();
 
16434
    }
 
16435
 
 
16436
    //! Convert color pixels from (R,G,B) to (H,S,L) (in-place).
 
16437
    CImg<T>& RGBtoHSL() {
 
16438
      if (!is_empty()) {
 
16439
        if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoHSL() : Input image dimension is dim=%u, "
 
16440
                                                "should be a (R,G,B) image.",pixel_type(),dim);
 
16441
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16442
        for (unsigned long N = width*height*depth; N; --N) {
 
16443
          const Tfloat
 
16444
            R = (Tfloat)*p1,
 
16445
            G = (Tfloat)*p2,
 
16446
            B = (Tfloat)*p3,
 
16447
            nR = (R<0?0:(R>255?255:R))/255,
 
16448
            nG = (G<0?0:(G>255?255:G))/255,
 
16449
            nB = (B<0?0:(B>255?255:B))/255,
 
16450
            m = cimg::min(nR,nG,nB),
 
16451
            M = cimg::max(nR,nG,nB),
 
16452
            L = (m+M)/2;
 
16453
          Tfloat H = 0, S = 0;
 
16454
          if (M==m) H = S = 0;
 
16455
          else {
 
16456
            const Tfloat
 
16457
              f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
 
16458
              i = (nR==m)?3:((nG==m)?5:1);
 
16459
            H = (i-f/(M-m));
 
16460
            if (H>=6) H-=6;
 
16461
            H*=60;
 
16462
            S = (2*L<=1)?((M-m)/(M+m)):((M-m)/(2-M-m));
 
16463
          }
 
16464
          *(p1++) = (T)H;
 
16465
          *(p2++) = (T)S;
 
16466
          *(p3++) = (T)L;
 
16467
        }
 
16468
      }
 
16469
      return *this;
 
16470
    }
 
16471
 
 
16472
    //! Convert color pixels from (H,S,L) to (R,G,B).
 
16473
    CImg<Tuchar> get_HSLtoRGB() const {
 
16474
      return CImg<Tuchar>(*this,false).HSLtoRGB();
 
16475
    }
 
16476
 
 
16477
    //! Convert color pixels from (H,S,L) to (R,G,B) (in-place).
 
16478
    CImg<T>& HSLtoRGB() {
 
16479
      if (!is_empty()) {
 
16480
        if (dim!=3) throw CImgInstanceException("CImg<%s>::HSLtoRGB() : Input image dimension is dim=%u, "
 
16481
                                                "should be a (H,S,V) image",pixel_type(),dim);
 
16482
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16483
        for (unsigned long N = width*height*depth; N; --N) {
 
16484
          Tfloat
 
16485
            H = (Tfloat)*p1,
 
16486
            S = (Tfloat)*p2,
 
16487
            L = (Tfloat)*p3;
 
16488
          const Tfloat
 
16489
            q = 2*L<1?L*(1+S):(L+S-L*S),
 
16490
            p = 2*L-q,
 
16491
            h = H/360;
 
16492
          Tfloat
 
16493
            tr = h + 1.0f/3,
 
16494
            tg = h,
 
16495
            tb = h - 1.0f/3,
 
16496
            ntr = tr<0?tr+1:(tr>1?tr-1:tr),
 
16497
            ntg = tg<0?tg+1:(tg>1?tg-1:tg),
 
16498
            ntb = tb<0?tb+1:(tb>1?tb-1:tb),
 
16499
            R = 6*ntr<1?p+(q-p)*6*ntr:(2*ntr<1?q:(3*ntr<2?p+(q-p)*6*(2.0f/3-ntr):p)),
 
16500
            G = 6*ntg<1?p+(q-p)*6*ntg:(2*ntg<1?q:(3*ntg<2?p+(q-p)*6*(2.0f/3-ntg):p)),
 
16501
            B = 6*ntb<1?p+(q-p)*6*ntb:(2*ntb<1?q:(3*ntb<2?p+(q-p)*6*(2.0f/3-ntb):p));
 
16502
          R*=255; G*=255; B*=255;
 
16503
          *(p1++) = (T)(R<0?0:(R>255?255:R));
 
16504
          *(p2++) = (T)(G<0?0:(G>255?255:G));
 
16505
          *(p3++) = (T)(B<0?0:(B>255?255:B));
 
16506
        }
 
16507
      }
 
16508
      return *this;
 
16509
    }
 
16510
 
 
16511
    //! Convert color pixels from (R,G,B) to (H,S,I).
 
16512
    //! Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002.
 
16513
    CImg<Tfloat> get_RGBtoHSI() const {
 
16514
      return CImg<Tfloat>(*this,false).RGBtoHSI();
 
16515
    }
 
16516
 
 
16517
    //! Convert color pixels from (R,G,B) to (H,S,I) (in-place).
 
16518
    CImg<T>& RGBtoHSI() {
 
16519
      if (!is_empty()) {
 
16520
        if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoHSI() : Input image dimension is dim=%u, "
 
16521
                                                "should be a (R,G,B) image.",pixel_type(),dim);
 
16522
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16523
        for (unsigned long N = width*height*depth; N; --N) {
 
16524
          const Tfloat
 
16525
            R = (Tfloat)*p1,
 
16526
            G = (Tfloat)*p2,
 
16527
            B = (Tfloat)*p3,
 
16528
            nR = (R<0?0:(R>255?255:R))/255,
 
16529
            nG = (G<0?0:(G>255?255:G))/255,
 
16530
            nB = (B<0?0:(B>255?255:B))/255,
 
16531
            m = cimg::min(nR,nG,nB),
 
16532
            theta = (Tfloat)(std::acos(0.5f*((nR-nG)+(nR-nB))/std::sqrt(std::pow(nR-nG,2)+(nR-nB)*(nG-nB)))*180/cimg::valuePI),
 
16533
            sum = nR + nG + nB;
 
16534
          Tfloat H = 0, S = 0, I = 0;
 
16535
          if (theta>0) H = (nB<=nG)?theta:360-theta;
 
16536
          if (sum>0) S = 1 - 3/sum*m;
 
16537
          I = sum/3;
 
16538
          *(p1++) = (T)H;
 
16539
          *(p2++) = (T)S;
 
16540
          *(p3++) = (T)I;
 
16541
        }
 
16542
      }
 
16543
      return *this;
 
16544
    }
 
16545
 
 
16546
    //! Convert color pixels from (H,S,I) to (R,G,B).
 
16547
    CImg<Tfloat> get_HSItoRGB() const {
 
16548
      return CImg< Tuchar>(*this,false).HSItoRGB();
 
16549
    }
 
16550
 
 
16551
    //! Convert color pixels from (H,S,I) to (R,G,B) (in-place).
 
16552
    CImg<T>& HSItoRGB() {
 
16553
      if (!is_empty()) {
 
16554
        if (dim!=3) throw CImgInstanceException("CImg<%s>::HSItoRGB() : Input image dimension is dim=%u, "
 
16555
                                                "should be a (H,S,I) image",pixel_type(),dim);
 
16556
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16557
        for (unsigned long N = width*height*depth; N; --N) {
 
16558
          Tfloat
 
16559
            H = (Tfloat)*p1,
 
16560
            S = (Tfloat)*p2,
 
16561
            I = (Tfloat)*p3,
 
16562
            a = I*(1-S),
 
16563
            R = 0, G = 0, B = 0;
 
16564
          if (H<120) {
 
16565
            B = a;
 
16566
            R = I*(1+S*std::cos(H*cimg::valuePI/180)/std::cos((60-H)*cimg::valuePI/180));
 
16567
            G = 3*I-(R+B);
 
16568
          } else if (H<240) {
 
16569
            H-=120;
 
16570
            R = a;
 
16571
            G = I*(1+S*std::cos(H*cimg::valuePI/180)/std::cos((60-H)*cimg::valuePI/180));
 
16572
            B = 3*I-(R+G);
 
16573
          } else {
 
16574
            H-=240;
 
16575
            G = a;
 
16576
            B = I*(1+S*std::cos(H*cimg::valuePI/180)/std::cos((60-H)*cimg::valuePI/180));
 
16577
            R = 3*I-(G+B);
 
16578
          }
 
16579
          R*=255; G*=255; B*=255;
 
16580
          *(p1++) = (T)(R<0?0:(R>255?255:R));
 
16581
          *(p2++) = (T)(G<0?0:(G>255?255:G));
 
16582
          *(p3++) = (T)(B<0?0:(B>255?255:B));
 
16583
        }
 
16584
      }
 
16585
      return *this;
 
16586
    }
 
16587
 
 
16588
    //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
 
16589
    CImg<Tuchar> get_RGBtoYCbCr() const {
 
16590
      return CImg<Tuchar>(*this,false).RGBtoYCbCr();
 
16591
    }
 
16592
 
 
16593
    //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8 (in-place).
 
16594
    CImg<T>& RGBtoYCbCr() {
11392
16595
      if (!is_empty()) {
11393
16596
        if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoYCbCr() : Input image dimension is dim=%u, "
11394
16597
                                                "should be a (R,G,B) image (dim=3)",pixel_type(),dim);
11395
 
        cimg_forXYZ(*this,x,y,z) {
11396
 
          const int
11397
 
            R = (int)((*this)(x,y,z,0)),
11398
 
            G = (int)((*this)(x,y,z,1)),
11399
 
            B = (int)((*this)(x,y,z,2));
11400
 
          const int
11401
 
            Y  = ((66*R+129*G+25*B+128)>>8) + 16,
11402
 
            Cb = ((-38*R-74*G+112*B+128)>>8) + 128,
11403
 
            Cr = ((112*R-94*G-18*B+128)>>8) + 128;
11404
 
          (*this)(x,y,z,0) = (T)(Y<0?0:(Y>255?255:Y));
11405
 
          (*this)(x,y,z,1) = (T)(Cb<0?0:(Cb>255?255:Cb));
11406
 
          (*this)(x,y,z,2) = (T)(Cr<0?0:(Cr>255?255:Cr));
 
16598
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16599
        for (unsigned long N = width*height*depth; N; --N) {
 
16600
          const Tfloat
 
16601
            R = (Tfloat)*p1,
 
16602
            G = (Tfloat)*p2,
 
16603
            B = (Tfloat)*p3,
 
16604
            Y  = (66*R + 129*G + 25*B + 128)/256 + 16,
 
16605
            Cb = (-38*R - 74*G + 112*B + 128)/256 + 128,
 
16606
            Cr = (112*R - 94*G - 18*B + 128)/256 + 128;
 
16607
          *(p1++) = (T)(Y<0?0:(Y>255?255:Y));
 
16608
          *(p2++) = (T)(Cb<0?0:(Cb>255?255:Cb));
 
16609
          *(p3++) = (T)(Cr<0?0:(Cr>255?255:Cr));
11407
16610
        }
11408
16611
      }
11409
16612
      return *this;
11410
16613
    }
11411
16614
 
11412
 
    //! Convert color pixels from (Y,Cb,Cr)_8 to (R,G,B).
11413
 
    CImg& YCbCrtoRGB() {
 
16615
    //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
 
16616
    CImg<Tuchar> get_YCbCrtoRGB() const {
 
16617
      return CImg<Tuchar>(*this,false).YCbCrtoRGB();
 
16618
    }
 
16619
 
 
16620
    //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8 (in-place).
 
16621
    CImg<T>& YCbCrtoRGB() {
11414
16622
      if (!is_empty()) {
11415
16623
        if (dim!=3) throw CImgInstanceException("CImg<%s>::YCbCrtoRGB() : Input image dimension is dim=%u, "
11416
16624
                                                "should be a (Y,Cb,Cr)_8 image (dim=3)",pixel_type(),dim);
11417
 
        cimg_forXYZ(*this,x,y,z) {
11418
 
          const int
11419
 
            Y  = (int)((*this)(x, y, z, 0)-16),
11420
 
            Cb = (int)((*this)(x, y, z, 1)-128),
11421
 
            Cr = (int)((*this)(x, y, z, 2)-128);
11422
 
          const int
11423
 
            R = ((298*Y + 409*Cr + 128) >> 8 ),
11424
 
            G = ((298*Y - 100*Cb - 208*Cr + 128) >> 8 ),
11425
 
            B = ((298*Y + 516*Cb + 128) >> 8 );
11426
 
          (*this)(x,y,z,0) = (T)(R<0?0:(R>255?255:R));
11427
 
          (*this)(x,y,z,1) = (T)(G<0?0:(G>255?255:G));
11428
 
          (*this)(x,y,z,2) = (T)(B<0?0:(B>255?255:B));
 
16625
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16626
        for (unsigned long N = width*height*depth; N; --N) {
 
16627
          const Tfloat
 
16628
            Y  = (Tfloat)*p1 - 16,
 
16629
            Cb = (Tfloat)*p2 - 128,
 
16630
            Cr = (Tfloat)*p3 - 128,
 
16631
            R = (298*Y + 409*Cr + 128)/256,
 
16632
            G = (298*Y - 100*Cb - 208*Cr + 128)/256,
 
16633
            B = (298*Y + 516*Cb + 128)/256;
 
16634
          *(p1++) = (T)(R<0?0:(R>255?255:R));
 
16635
          *(p2++) = (T)(G<0?0:(G>255?255:G));
 
16636
          *(p3++) = (T)(B<0?0:(B>255?255:B));
11429
16637
        }
11430
16638
      }
11431
16639
      return *this;
11432
16640
    }
11433
16641
 
11434
16642
    //! Convert color pixels from (R,G,B) to (Y,U,V).
11435
 
    CImg& RGBtoYUV() {
 
16643
    CImg<Tfloat> get_RGBtoYUV() const {
 
16644
      return CImg<Tfloat>(*this,false).RGBtoYUV();
 
16645
    }
 
16646
 
 
16647
    //! Convert color pixels from (R,G,B) to (Y,U,V) (in-place).
 
16648
    CImg<T>& RGBtoYUV() {
11436
16649
      if (!is_empty()) {
11437
16650
        if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoYUV() : Input image dimension is dim=%u, "
11438
16651
                                                "should be a (R,G,B) image (dim=3)",pixel_type(),dim);
11439
 
        cimg_forXYZ(*this,x,y,z) {
11440
 
          const float
11441
 
            R = (*this)(x,y,z,0)/255.0f,
11442
 
            G = (*this)(x,y,z,1)/255.0f,
11443
 
            B = (*this)(x,y,z,2)/255.0f,
11444
 
            Y = (T)(0.299*R + 0.587*G + 0.114*B);
11445
 
          (*this)(x,y,z,0) = (T)Y;
11446
 
          (*this)(x,y,z,1) = (T)(0.492*(B-Y));
11447
 
          (*this)(x,y,z,2) = (T)(0.877*(R-Y));
 
16652
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16653
        for (unsigned long N = width*height*depth; N; --N) {
 
16654
          const Tfloat
 
16655
            R = (Tfloat)*p1/255,
 
16656
            G = (Tfloat)*p2/255,
 
16657
            B = (Tfloat)*p3/255,
 
16658
            Y = 0.299f*R + 0.587f*G + 0.114f*B;
 
16659
          *(p1++) = (T)Y;
 
16660
          *(p2++) = (T)(0.492f*(B-Y));
 
16661
          *(p3++) = (T)(0.877*(R-Y));
11448
16662
        }
11449
16663
      }
11450
16664
      return *this;
11451
16665
    }
11452
16666
 
11453
16667
    //! Convert color pixels from (Y,U,V) to (R,G,B).
11454
 
    CImg& YUVtoRGB() {
 
16668
    CImg<Tuchar> get_YUVtoRGB() const {
 
16669
      return CImg< Tuchar>(*this,false).YUVtoRGB();
 
16670
    }
 
16671
 
 
16672
    //! Convert color pixels from (Y,U,V) to (R,G,B) (in-place).
 
16673
    CImg<T>& YUVtoRGB() {
11455
16674
      if (!is_empty()) {
11456
16675
        if (dim!=3) throw CImgInstanceException("CImg<%s>::YUVtoRGB() : Input image dimension is dim=%u, "
11457
16676
                                                "should be a (Y,U,V) image (dim=3)",pixel_type(),dim);
11458
 
        cimg_forXYZ(*this,x,y,z) {
11459
 
          const T Y = (*this)(x,y,z,0), U = (*this)(x,y,z,1), V = (*this)(x,y,z,2);
11460
 
          (*this)(x,y,z,0) = (T)((Y + 1.140*V)*255.0f);
11461
 
          (*this)(x,y,z,1) = (T)((Y - 0.395*U - 0.581*V)*255.0f);
11462
 
          (*this)(x,y,z,2) = (T)((Y + 2.032*U)*255.0f);
11463
 
        }
11464
 
      }
11465
 
      return *this;
 
16677
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16678
        for (unsigned long N = width*height*depth; N; --N) {
 
16679
          const Tfloat
 
16680
            Y = (Tfloat)*p1,
 
16681
            U = (Tfloat)*p2,
 
16682
            V = (Tfloat)*p3,
 
16683
            R = (Y + 1.140f*V)*255,
 
16684
            G = (Y - 0.395f*U - 0.581f*V)*255,
 
16685
            B = (Y + 2.032f*U)*255;
 
16686
          *(p1++) = (T)(R<0?0:(R>255?255:R));
 
16687
          *(p2++) = (T)(G<0?0:(G>255?255:G));
 
16688
          *(p3++) = (T)(B<0?0:(B>255?255:B));
 
16689
        }
 
16690
      }
 
16691
      return *this;
 
16692
    }
 
16693
 
 
16694
    //! Convert color pixels from (R,G,B) to (C,M,Y).
 
16695
    CImg<Tfloat> get_RGBtoCMY() const {
 
16696
      return CImg<Tfloat>(*this,false).RGBtoCMY();
 
16697
    }
 
16698
 
 
16699
    //! Convert color pixels from (R,G,B) to (C,M,Y) (in-place).
 
16700
    CImg<T>& RGBtoCMY() {
 
16701
      if (!is_empty()) {
 
16702
        if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoCMY() : Input image dimension is dim=%u, "
 
16703
                                                "should be a (R,G,B) image (dim=3)",pixel_type(),dim);
 
16704
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16705
        for (unsigned long N = width*height*depth; N; --N) {
 
16706
          const Tfloat
 
16707
            R = (Tfloat)*p1/255,
 
16708
            G = (Tfloat)*p2/255,
 
16709
            B = (Tfloat)*p3/255;
 
16710
          *(p1++) = (T)(1 - R);
 
16711
          *(p2++) = (T)(1 - G);
 
16712
          *(p3++) = (T)(1 - B);
 
16713
        }
 
16714
      }
 
16715
      return *this;
 
16716
    }
 
16717
 
 
16718
    //! Convert color pixels from (C,M,Y) to (C,M,Y,K).
 
16719
    CImg<Tfloat> get_CMYtoCMYK() const {
 
16720
      if (is_empty()) return *this;
 
16721
      if (dim!=3) throw CImgInstanceException("CImg<%s>::CMYtoCMYK() : Input image dimension is dim=%u, "
 
16722
                                              "should be a (C,M,Y) image (dim=3)",pixel_type(),dim);
 
16723
      CImg<Tfloat> res(width,height,depth,4);
 
16724
      const T *ps1 = ptr(0,0,0,0), *ps2 = ptr(0,0,0,1), *ps3 = ptr(0,0,0,2);
 
16725
      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);
 
16726
      for (unsigned long N = width*height*depth; N; --N) {
 
16727
        Tfloat
 
16728
          C = (Tfloat)*(ps1++),
 
16729
          M = (Tfloat)*(ps2++),
 
16730
          Y = (Tfloat)*(ps3++),
 
16731
          K = cimg::min(C,M,Y);
 
16732
        if (K==1) C = M = Y = 0;
 
16733
        else { const Tfloat K1 = 1 - K; C = (C - K)/K1; M = (M - K)/K1; Y = (Y - K)/K1; }
 
16734
        *(pd1++) = (T)C;
 
16735
        *(pd2++) = (T)M;
 
16736
        *(pd3++) = (T)Y;
 
16737
        *(pd4++) = (T)K;
 
16738
      }
 
16739
      return res;
 
16740
    }
 
16741
 
 
16742
    //! Convert color pixels from (C,M,Y) to (C,M,Y,K) (in-place).
 
16743
    CImg<T>& CMYtoCMYK() {
 
16744
      return get_CMYtoCMYK().transfer_to(*this);
 
16745
    }
 
16746
 
 
16747
    //! Convert (C,M,Y) pixels of a color image into the (R,G,B) color space.
 
16748
    CImg<Tuchar> get_CMYtoRGB() const {
 
16749
      return CImg<Tuchar>(*this,false).CMYtoRGB();
 
16750
    }
 
16751
 
 
16752
    //! Convert (C,M,Y) pixels of a color image into the (R,G,B) color space (in-place).
 
16753
    CImg<T>& CMYtoRGB() {
 
16754
      if (!is_empty()) {
 
16755
        if (dim!=3) throw CImgInstanceException("CImg<%s>::CMYtoRGB() : Input image dimension is dim=%u, "
 
16756
                                                "should be a (C,M,Y) image (dim=3)",pixel_type(),dim);
 
16757
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16758
        for (unsigned long N = width*height*depth; N; --N) {
 
16759
          const Tfloat
 
16760
            C = (Tfloat)*p1,
 
16761
            M = (Tfloat)*p2,
 
16762
            Y = (Tfloat)*p3,
 
16763
            R = 255*(1 - C),
 
16764
            G = 255*(1 - M),
 
16765
            B = 255*(1 - Y);
 
16766
          *(p1++) = (T)(R<0?0:(R>255?255:R));
 
16767
          *(p2++) = (T)(G<0?0:(G>255?255:G));
 
16768
          *(p3++) = (T)(B<0?0:(B>255?255:B));
 
16769
        }
 
16770
      }
 
16771
      return *this;
 
16772
    }
 
16773
 
 
16774
    //! Convert (C,M,Y,K) pixels of a color image into the (C,M,Y) color space.
 
16775
    CImg<Tfloat> get_CMYKtoCMY() const {
 
16776
      if (is_empty()) return *this;
 
16777
      if (dim!=4) throw CImgInstanceException("CImg<%s>::CMYKtoCMY() : Input image dimension is dim=%u, "
 
16778
                                              "should be a (C,M,Y,K) image (dim=4)",pixel_type(),dim);
 
16779
      CImg<Tfloat> res(width,height,depth,3);
 
16780
      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);
 
16781
      Tfloat *pd1 = res.ptr(0,0,0,0), *pd2 = res.ptr(0,0,0,1), *pd3 = res.ptr(0,0,0,2);
 
16782
      for (unsigned long N = width*height*depth; N; --N) {
 
16783
        const Tfloat
 
16784
          C = (Tfloat)*ps1,
 
16785
          M = (Tfloat)*ps2,
 
16786
          Y = (Tfloat)*ps3,
 
16787
          K = (Tfloat)*ps4,
 
16788
          K1 = 1.0f - K;
 
16789
        *(pd1++) = (T)(C*K1 + K);
 
16790
        *(pd2++) = (T)(M*K1 + K);
 
16791
        *(pd3++) = (T)(Y*K1 + K);
 
16792
      }
 
16793
      return res;
 
16794
    }
 
16795
 
 
16796
    //! Convert (C,M,Y,K) pixels of a color image into the (C,M,Y) color space (in-place).
 
16797
    CImg<T>& CMYKtoCMY() {
 
16798
      return get_CMYKtoCMY().transfer_to(*this);
11466
16799
    }
11467
16800
 
11468
16801
    //! Convert color pixels from (R,G,B) to (X,Y,Z)_709.
11469
 
    CImg& RGBtoXYZ() {
 
16802
    CImg<Tfloat> get_RGBtoXYZ() const {
 
16803
      return CImg<Tfloat>(*this,false).RGBtoXYZ();
 
16804
    }
 
16805
 
 
16806
    //! Convert color pixels from (R,G,B) to (X,Y,Z)_709 (in-place).
 
16807
    CImg<T>& RGBtoXYZ() {
11470
16808
      if (!is_empty()) {
11471
16809
        if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, "
11472
16810
                                                "should be a (R,G,B) image (dim=3)",pixel_type(),dim);
11473
 
        cimg_forXYZ(*this,x,y,z) {
11474
 
          const float
11475
 
            R = (float)((*this)(x,y,z,0)/255.0f),
11476
 
            G = (float)((*this)(x,y,z,1)/255.0f),
11477
 
            B = (float)((*this)(x,y,z,2)/255.0f);
11478
 
          (*this)(x,y,z,0) = (T)(0.412453*R + 0.357580*G + 0.180423*B);
11479
 
          (*this)(x,y,z,1) = (T)(0.212671*R + 0.715160*G + 0.072169*B);
11480
 
          (*this)(x,y,z,2) = (T)(0.019334*R + 0.119193*G + 0.950227*B);
 
16811
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16812
        for (unsigned long N = width*height*depth; N; --N) {
 
16813
          const Tfloat
 
16814
            R = (Tfloat)*p1/255,
 
16815
            G = (Tfloat)*p2/255,
 
16816
            B = (Tfloat)*p3/255;
 
16817
          *(p1++) = (T)(0.412453f*R + 0.357580f*G + 0.180423f*B);
 
16818
          *(p2++) = (T)(0.212671f*R + 0.715160f*G + 0.072169f*B);
 
16819
          *(p3++) = (T)(0.019334f*R + 0.119193f*G + 0.950227f*B);
11481
16820
        }
11482
16821
      }
11483
16822
      return *this;
11484
16823
    }
11485
16824
 
11486
16825
    //! Convert (X,Y,Z)_709 pixels of a color image into the (R,G,B) color space.
11487
 
    CImg& XYZtoRGB() {
 
16826
    CImg<Tuchar> get_XYZtoRGB() const {
 
16827
      return CImg<Tuchar>(*this,false).XYZtoRGB();
 
16828
    }
 
16829
 
 
16830
    //! Convert (X,Y,Z)_709 pixels of a color image into the (R,G,B) color space (in-place).
 
16831
    CImg<T>& XYZtoRGB() {
11488
16832
      if (!is_empty()) {
11489
16833
        if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, "
11490
16834
                                                "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
11491
 
        cimg_forXYZ(*this,x,y,z) {
11492
 
          const float
11493
 
            X = (float)(255.0f*(*this)(x,y,z,0)),
11494
 
            Y = (float)(255.0f*(*this)(x,y,z,1)),
11495
 
            Z = (float)(255.0f*(*this)(x,y,z,2));
11496
 
          (*this)(x,y,z,0) = (T)(3.240479*X  - 1.537150*Y - 0.498535*Z);
11497
 
          (*this)(x,y,z,1) = (T)(-0.969256*X + 1.875992*Y + 0.041556*Z);
11498
 
          (*this)(x,y,z,2) = (T)(0.055648*X  - 0.204043*Y + 1.057311*Z);
 
16835
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16836
        for (unsigned long N = width*height*depth; N; --N) {
 
16837
          const Tfloat
 
16838
            X = (Tfloat)*p1*255,
 
16839
            Y = (Tfloat)*p2*255,
 
16840
            Z = (Tfloat)*p3*255,
 
16841
            R = 3.240479f*X  - 1.537150f*Y - 0.498535f*Z,
 
16842
            G = -0.969256f*X + 1.875992f*Y + 0.041556f*Z,
 
16843
            B = 0.055648f*X  - 0.204043f*Y + 1.057311f*Z;
 
16844
          *(p1++) = (T)(R<0?0:(R>255?255:R));
 
16845
          *(p2++) = (T)(G<0?0:(G>255?255:G));
 
16846
          *(p3++) = (T)(B<0?0:(B>255?255:B));
11499
16847
        }
11500
16848
      }
11501
16849
      return *this;
11502
16850
    }
11503
16851
 
11504
16852
    //! Convert (X,Y,Z)_709 pixels of a color image into the (L*,a*,b*) color space.
11505
 
#define cimg_Labf(x)  ((x)>=0.008856?(std::pow(x,1/3.0)):(7.787*(x)+16.0/116.0))
11506
 
#define cimg_Labfi(x) ((x)>=0.206893?((x)*(x)*(x)):(((x)-16.0/116.0)/7.787))
 
16853
    CImg<Tfloat> get_XYZtoLab() const {
 
16854
      return CImg<Tfloat>(*this,false).XYZtoLab();
 
16855
    }
11507
16856
 
11508
 
    CImg& XYZtoLab() {
 
16857
    //! Convert (X,Y,Z)_709 pixels of a color image into the (L*,a*,b*) color space (in-place).
 
16858
    CImg<T>& XYZtoLab() {
 
16859
#define _cimg_Labf(x) ((x)>=0.008856f?(std::pow(x,(Tfloat)1/3)):(7.787f*(x)+16.0f/116))
11509
16860
      if (!is_empty()) {
11510
16861
        if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, "
11511
16862
                                                "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
11512
 
        const double
11513
 
          Xn = 0.412453 + 0.357580 + 0.180423,
11514
 
          Yn = 0.212671 + 0.715160 + 0.072169,
11515
 
          Zn = 0.019334 + 0.119193 + 0.950227;
11516
 
        cimg_forXYZ(*this,x,y,z) {
11517
 
          const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2);
11518
 
          const double
 
16863
        const Tfloat
 
16864
          Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
 
16865
          Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
 
16866
          Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
 
16867
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16868
        for (unsigned long N = width*height*depth; N; --N) {
 
16869
          const Tfloat
 
16870
            X = (Tfloat)*p1,
 
16871
            Y = (Tfloat)*p2,
 
16872
            Z = (Tfloat)*p3,
11519
16873
            XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn,
11520
 
            fX = cimg_Labf(XXn), fY = cimg_Labf(YYn), fZ = cimg_Labf(ZZn);
11521
 
          (*this)(x,y,z,0) = (T)(116*fY-16);
11522
 
          (*this)(x,y,z,1) = (T)(500*(fX-fY));
11523
 
          (*this)(x,y,z,2) = (T)(200*(fY-fZ));
 
16874
            fX = (Tfloat)_cimg_Labf(XXn),
 
16875
            fY = (Tfloat)_cimg_Labf(YYn),
 
16876
            fZ = (Tfloat)_cimg_Labf(ZZn);
 
16877
          *(p1++) = (T)(116*fY - 16);
 
16878
          *(p2++) = (T)(500*(fX - fY));
 
16879
          *(p3++) = (T)(200*(fY - fZ));
11524
16880
        }
11525
16881
      }
11526
16882
      return *this;
11527
16883
    }
11528
16884
 
11529
16885
    //! Convert (L,a,b) pixels of a color image into the (X,Y,Z) color space.
11530
 
    CImg& LabtoXYZ() {
 
16886
    CImg<Tfloat> get_LabtoXYZ() const {
 
16887
      return CImg<Tfloat>(*this,false).LabtoXYZ();
 
16888
    }
 
16889
 
 
16890
    //! Convert (L,a,b) pixels of a color image into the (X,Y,Z) color space (in-place).
 
16891
    CImg<T>& LabtoXYZ() {
 
16892
#define _cimg_Labfi(x) ((x)>=0.206893f?((x)*(x)*(x)):(((x)-16.0f/116)/7.787f))
11531
16893
      if (!is_empty()) {
11532
16894
        if (dim!=3) throw CImgInstanceException("CImg<%s>::LabtoXYZ() : Input image dimension is dim=%u, "
11533
16895
                                                "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
11534
 
        const double
11535
 
          Xn = 0.412453 + 0.357580 + 0.180423,
11536
 
          Yn = 0.212671 + 0.715160 + 0.072169,
11537
 
          Zn = 0.019334 + 0.119193 + 0.950227;
11538
 
        cimg_forXYZ(*this,x,y,z) {
11539
 
          const T L = (*this)(x,y,z,0), a = (*this)(x,y,z,1), b = (*this)(x,y,z,2);
11540
 
          const double
11541
 
            cY = (L+16)/116.0,
11542
 
            Y = Yn*cimg_Labfi(cY),
11543
 
            pY = std::pow(Y/Yn,1.0/3),
11544
 
            cX = a/500+pY,
 
16896
        const Tfloat
 
16897
          Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
 
16898
          Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
 
16899
          Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
 
16900
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16901
        for (unsigned long N = width*height*depth; N; --N) {
 
16902
          const Tfloat
 
16903
            L = (Tfloat)*p1,
 
16904
            a = (Tfloat)*p2,
 
16905
            b = (Tfloat)*p3,
 
16906
            cY = (L + 16)/116,
 
16907
            Y = (Tfloat)(Yn*_cimg_Labfi(cY)),
 
16908
            pY = (Tfloat)std::pow(Y/Yn,(Tfloat)1/3),
 
16909
            cX = a/500 + pY,
11545
16910
            X = Xn*cX*cX*cX,
11546
 
            cZ = pY-b/200,
 
16911
            cZ = pY - b/200,
11547
16912
            Z = Zn*cZ*cZ*cZ;
11548
 
          (*this)(x,y,z,0) = (T)(X);
11549
 
          (*this)(x,y,z,1) = (T)(Y);
11550
 
          (*this)(x,y,z,2) = (T)(Z);
 
16913
          *(p1++) = (T)(X);
 
16914
          *(p2++) = (T)(Y);
 
16915
          *(p3++) = (T)(Z);
11551
16916
        }
11552
16917
      }
11553
16918
      return *this;
11554
16919
    }
11555
16920
 
11556
16921
    //! Convert (X,Y,Z)_709 pixels of a color image into the (x,y,Y) color space.
11557
 
    CImg& XYZtoxyY() {
 
16922
    CImg<Tfloat> get_XYZtoxyY() const {
 
16923
      return CImg<Tfloat>(*this,false).XYZtoxyY();
 
16924
    }
 
16925
 
 
16926
    //! Convert (X,Y,Z)_709 pixels of a color image into the (x,y,Y) color space (in-place).
 
16927
    CImg<T>& XYZtoxyY() {
11558
16928
      if (!is_empty()) {
11559
16929
        if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoxyY() : Input image dimension is dim=%u, "
11560
16930
                                                "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim);
11561
 
        cimg_forXYZ(*this,x,y,z) {
11562
 
          const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2), sum = (X+Y+Z), nsum = sum>0?sum:1;
11563
 
          (*this)(x,y,z,0) = X/nsum;
11564
 
          (*this)(x,y,z,1) = Y/nsum;
11565
 
          (*this)(x,y,z,2) = Y;
 
16931
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16932
        for (unsigned long N = width*height*depth; N; --N) {
 
16933
          const Tfloat
 
16934
            X = (Tfloat)*p1,
 
16935
            Y = (Tfloat)*p2,
 
16936
            Z = (Tfloat)*p3,
 
16937
            sum = (X+Y+Z),
 
16938
            nsum = sum>0?sum:1;
 
16939
          *(p1++) = (T)(X/nsum);
 
16940
          *(p2++) = (T)(Y/nsum);
 
16941
          *(p3++) = (T)Y;
11566
16942
        }
11567
16943
      }
11568
16944
      return *this;
11569
16945
    }
11570
16946
 
11571
16947
    //! Convert (x,y,Y) pixels of a color image into the (X,Y,Z)_709 color space.
11572
 
    CImg& xyYtoXYZ() {
 
16948
    CImg<Tfloat> get_xyYtoXYZ() const {
 
16949
      return CImg<Tfloat>(*this,false).xyYtoXYZ();
 
16950
    }
 
16951
 
 
16952
    //! Convert (x,y,Y) pixels of a color image into the (X,Y,Z)_709 color space (in-place).
 
16953
    CImg<T>& xyYtoXYZ() {
11573
16954
      if (!is_empty()) {
11574
16955
        if (dim!=3) throw CImgInstanceException("CImg<%s>::xyYtoXYZ() : Input image dimension is dim=%u, "
11575
16956
                                                "should be a (x,y,Y) image (dim=3)",pixel_type(),dim);
11576
 
        cimg_forXYZ(*this,x,y,z) {
11577
 
          const T px = (*this)(x,y,z,0), py = (*this)(x,y,z,1), Y = (*this)(x,y,z,2), ny = py>0?py:1;
11578
 
          (*this)(x,y,z,0) = (T)(px*Y/ny);
11579
 
          (*this)(x,y,z,1) = Y;
11580
 
          (*this)(x,y,z,2) = (T)((1-px-py)*Y/ny);
 
16957
        T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
 
16958
        for (unsigned long N = width*height*depth; N; --N) {
 
16959
          const Tfloat
 
16960
           px = (Tfloat)*p1,
 
16961
           py = (Tfloat)*p2,
 
16962
           Y = (Tfloat)*p3,
 
16963
           ny = py>0?py:1;
 
16964
          *(p1++) = (T)(px*Y/ny);
 
16965
          *(p2++) = (T)Y;
 
16966
          *(p3++) = (T)((1-px-py)*Y/ny);
11581
16967
        }
11582
16968
      }
11583
16969
      return *this;
11584
16970
    }
11585
16971
 
11586
 
    //! In-place version of get_RGBtoLab().
11587
 
    CImg& RGBtoLab() {
 
16972
    //! Convert a (R,G,B) image to a (L,a,b) one.
 
16973
    CImg<Tfloat> get_RGBtoLab() const {
 
16974
      return CImg<Tfloat>(*this,false).RGBtoLab();
 
16975
    }
 
16976
 
 
16977
    //! Convert a (R,G,B) image to a (L,a,b) one (in-place).
 
16978
    CImg<T>& RGBtoLab() {
11588
16979
      return RGBtoXYZ().XYZtoLab();
11589
16980
    }
11590
16981
 
11591
 
    //! In-place version of get_LabtoRGb().
11592
 
    CImg& LabtoRGB() {
 
16982
    //! Convert a (L,a,b) image to a (R,G,B) one.
 
16983
    CImg<Tuchar> get_LabtoRGB() const {
 
16984
      return CImg<Tuchar>(*this,false).LabtoRGB();
 
16985
    }
 
16986
 
 
16987
    //! Convert a (L,a,b) image to a (R,G,B) one (in-place).
 
16988
    CImg<T>& LabtoRGB() {
11593
16989
      return LabtoXYZ().XYZtoRGB();
11594
16990
    }
11595
16991
 
11596
 
    //! In-place version of get_RGBtoxyY().
11597
 
    CImg& RGBtoxyY() {
 
16992
    //! Convert a (R,G,B) image to a (x,y,Y) one.
 
16993
    CImg<Tfloat> get_RGBtoxyY() const {
 
16994
      return CImg<Tfloat>(*this,false).RGBtoxyY();
 
16995
    }
 
16996
 
 
16997
    //! Convert a (R,G,B) image to a (x,y,Y) one (in-place).
 
16998
    CImg<T>& RGBtoxyY() {
11598
16999
      return RGBtoXYZ().XYZtoxyY();
11599
17000
    }
11600
17001
 
11601
 
    //! In-place version of get_xyYtoRGB().
11602
 
    CImg& xyYtoRGB() {
 
17002
    //! Convert a (x,y,Y) image to a (R,G,B) one.
 
17003
    CImg<Tuchar> get_xyYtoRGB() const {
 
17004
      return CImg<Tuchar>(*this,false).xyYtoRGB();
 
17005
    }
 
17006
 
 
17007
    //! Convert a (x,y,Y) image to a (R,G,B) one (in-place).
 
17008
    CImg<T>& xyYtoRGB() {
11603
17009
      return xyYtoXYZ().XYZtoRGB();
11604
17010
    }
11605
17011
 
11606
 
    //! Convert a (R,G,B) image to a (H,S,V) one.
11607
 
    CImg get_RGBtoHSV() const {
11608
 
      return (+*this).RGBtoHSV();
11609
 
    }
11610
 
 
11611
 
    //! Convert a (H,S,V) image to a (R,G,B) one.
11612
 
    CImg get_HSVtoRGB() const {
11613
 
      return (+*this).HSVtoRGB();
11614
 
    }
11615
 
 
11616
 
    //! Convert a (R,G,B) image to a (Y,Cb,Cr) one.
11617
 
    CImg get_RGBtoYCbCr() const {
11618
 
      return (+*this).RGBtoYCbCr();
11619
 
    }
11620
 
 
11621
 
    //! Convert a (Y,Cb,Cr) image to a (R,G,B) one.
11622
 
    CImg get_YCbCrtoRGB() const {
11623
 
      return (+*this).YCbCrtoRGB();
11624
 
    }
11625
 
 
11626
 
    //! Convert a (R,G,B) image into a (Y,U,V) one.
11627
 
    CImg<typename cimg::largest<T,float>::type> get_RGBtoYUV() const {
11628
 
      typedef typename cimg::largest<T,float>::type restype;
11629
 
      return CImg<restype>(*this,false).RGBtoYUV();
11630
 
    }
11631
 
 
11632
 
    //! Convert a (Y,U,V) image into a (R,G,B) one.
11633
 
    CImg get_YUVtoRGB() const {
11634
 
      return (+*this).YUVtoRGB();
11635
 
    }
11636
 
 
11637
 
    //! Convert a (R,G,B) image to a (X,Y,Z) one.
11638
 
    CImg<typename cimg::largest<T,float>::type> get_RGBtoXYZ() const {
11639
 
      typedef typename cimg::largest<T,float>::type restype;
11640
 
      return CImg<restype>(*this,false).RGBtoXYZ();
11641
 
    }
11642
 
 
11643
 
    //! Convert a (X,Y,Z) image to a (R,G,B) one.
11644
 
    CImg get_XYZtoRGB() const {
11645
 
      return (+*this).XYZtoRGB();
11646
 
    }
11647
 
 
11648
 
    //! Convert a (X,Y,Z) image to a (L,a,b) one.
11649
 
    CImg get_XYZtoLab() const {
11650
 
      return (+*this).XYZtoLab();
11651
 
    }
11652
 
 
11653
 
    //! Convert a (L,a,b) image to a (X,Y,Z) one.
11654
 
    CImg get_LabtoXYZ() const {
11655
 
      return (+*this).LabtoXYZ();
11656
 
    }
11657
 
 
11658
 
    //! Convert a (X,Y,Z) image to a (x,y,Y) one.
11659
 
    CImg get_XYZtoxyY() const {
11660
 
      return (+*this).XYZtoxyY();
11661
 
    }
11662
 
 
11663
 
    //! Convert a (x,y,Y) image to a (X,Y,Z) one.
11664
 
    CImg get_xyYtoXYZ() const {
11665
 
      return (+*this).xyYtoXYZ();
11666
 
    }
11667
 
 
11668
 
    //! Convert a (R,G,B) image to a (L,a,b) one.
11669
 
    CImg get_RGBtoLab() const {
11670
 
      return (+*this).RGBtoLab();
11671
 
    }
11672
 
 
11673
 
    //! Convert a (L,a,b) image to a (R,G,B) one.
11674
 
    CImg get_LabtoRGB() const {
11675
 
      return (+*this).LabtoRGB();
11676
 
    }
11677
 
 
11678
 
    //! Convert a (R,G,B) image to a (x,y,Y) one.
11679
 
    CImg get_RGBtoxyY() const {
11680
 
      return (+*this).RGBtoxyY();
11681
 
    }
11682
 
 
11683
 
    //! Convert a (x,y,Y) image to a (R,G,B) one.
11684
 
    CImg get_xyYtoRGB() const {
11685
 
      return (+*this).xyYtoRGB();
 
17012
    //! Convert a (R,G,B) image to a (C,M,Y,K) one.
 
17013
    CImg<Tfloat> get_RGBtoCMYK() const {
 
17014
      return CImg<Tfloat>(*this,false).RGBtoCMYK();
 
17015
    }
 
17016
 
 
17017
    //! Convert a (R,G,B) image to a (C,M,Y,K) one (in-place).
 
17018
    CImg<T>& RGBtoCMYK() {
 
17019
      return RGBtoCMY().CMYtoCMYK();
 
17020
    }
 
17021
 
 
17022
    //! Convert a (R,G,B) image to a (C,M,Y,K) one.
 
17023
    CImg<Tuchar> get_CMYKtoRGB() const {
 
17024
      return CImg<Tuchar>(*this,false).CMYKtoRGB();
 
17025
    }
 
17026
 
 
17027
    //! Convert a (R,G,B) image to a (C,M,Y,K) one (in-place).
 
17028
    CImg<T>& CMYKtoRGB() {
 
17029
      return CMYKtoCMY().CMYtoRGB();
 
17030
    }
 
17031
 
 
17032
    //! Convert a (R,G,B) image to a Bayer-coded representation.
 
17033
    /**
 
17034
       \note First (upper-left) pixel if the red component of the pixel color.
 
17035
    **/
 
17036
    CImg<T> get_RGBtoBayer() const {
 
17037
      if (is_empty()) return *this;
 
17038
      if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoBayer() : Input image dimension is dim=%u, "
 
17039
                                              "should be a (R,G,B) image (dim=3)",pixel_type(),dim);
 
17040
      CImg<T> res(width,height,depth,1);
 
17041
      const T *pR = ptr(0,0,0,0), *pG = ptr(0,0,0,1), *pB = ptr(0,0,0,2);
 
17042
      T *ptrd = res.data;
 
17043
      cimg_forXYZ(*this,x,y,z) {
 
17044
        if (y%2) {
 
17045
          if (x%2) *(ptrd++) = *pB;
 
17046
          else *(ptrd++) = *pG;
 
17047
        } else {
 
17048
          if (x%2) *(ptrd++) = *pG;
 
17049
          else *(ptrd++) = *pR;
 
17050
        }
 
17051
        ++pR; ++pG; ++pB;
 
17052
      }
 
17053
      return res;
 
17054
    }
 
17055
 
 
17056
    //! Convert a (R,G,B) image to a Bayer-coded representation (in-place).
 
17057
    CImg<T>& RGBtoBayer() {
 
17058
      return get_RGBtoBayer().transfer_to(*this);
 
17059
    }
 
17060
 
 
17061
    //! Convert a Bayer-coded image to a (R,G,B) color image.
 
17062
    CImg<T> get_BayertoRGB(const unsigned int interpolation_type=3) const {
 
17063
      if (is_empty()) return *this;
 
17064
      if (dim!=1) throw CImgInstanceException("CImg<%s>::BayertoRGB() : Input image dimension is dim=%u, "
 
17065
                                              "should be a Bayer image (dim=1)",pixel_type(),dim);
 
17066
      CImg<T> res(width,height,depth,3);
 
17067
      CImg_3x3(I,T);
 
17068
      T *pR = res.ptr(0,0,0,0), *pG = res.ptr(0,0,0,1), *pB = res.ptr(0,0,0,2);
 
17069
      switch (interpolation_type) {
 
17070
      case 3: { // Edge-directed
 
17071
        CImg_3x3(R,T);
 
17072
        CImg_3x3(G,T);
 
17073
        CImg_3x3(B,T);
 
17074
        cimg_forXYZ(*this,x,y,z) {
 
17075
          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;
 
17076
          cimg_get3x3(*this,x,y,z,0,I);
 
17077
          if (y%2) {
 
17078
            if (x%2) {
 
17079
              const float alpha = cimg::sqr(Inc-Ipc), beta = cimg::sqr(Icn-Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
 
17080
              *pG = (T)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
 
17081
            } else *pG = Icc;
 
17082
          } else {
 
17083
            if (x%2) *pG = Icc;
 
17084
            else {
 
17085
              const float alpha = cimg::sqr(Inc-Ipc), beta = cimg::sqr(Icn-Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
 
17086
              *pG = (T)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
 
17087
            }
 
17088
          }
 
17089
          ++pG;
 
17090
        }
 
17091
        cimg_forXYZ(*this,x,y,z) {
 
17092
          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;
 
17093
          cimg_get3x3(*this,x,y,z,0,I);
 
17094
          cimg_get3x3(res,x,y,z,1,G);
 
17095
          if (y%2) {
 
17096
            if (x%2) *pB = Icc;
 
17097
            else { *pR = (T)((Icn+Icp)/2); *pB = (T)((Inc+Ipc)/2); }
 
17098
          } else {
 
17099
            if (x%2) { *pR = (T)((Inc+Ipc)/2); *pB = (T)((Icn+Icp)/2); }
 
17100
            else *pR = Icc;
 
17101
          }
 
17102
          ++pR; ++pB;
 
17103
        }
 
17104
        pR = res.ptr(0,0,0,0);
 
17105
        pG = res.ptr(0,0,0,1);
 
17106
        pB = res.ptr(0,0,0,2);
 
17107
        cimg_forXYZ(*this,x,y,z) {
 
17108
          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;
 
17109
          cimg_get3x3(res,x,y,z,0,R);
 
17110
          cimg_get3x3(res,x,y,z,1,G);
 
17111
          cimg_get3x3(res,x,y,z,2,B);
 
17112
          if (y%2) {
 
17113
            if (x%2) {
 
17114
              const float alpha = cimg::sqr(Rnc-Rpc), beta = cimg::sqr(Rcn-Rcp), cx = 1/(1+alpha), cy = 1/(1+beta);
 
17115
              *pR = (T)((cx*(Rnc+Rpc) + cy*(Rcn+Rcp))/(2*(cx+cy)));
 
17116
            }
 
17117
          } else {
 
17118
            if (!(x%2)) {
 
17119
              const float alpha = cimg::sqr(Bnc-Bpc), beta = cimg::sqr(Bcn-Bcp), cx = 1/(1+alpha), cy = 1/(1+beta);
 
17120
              *pB = (T)((cx*(Bnc+Bpc) + cy*(Bcn+Bcp))/(2*(cx+cy)));
 
17121
            }
 
17122
          }
 
17123
          ++pR; ++pG; ++pB;
 
17124
        }
 
17125
      } break;
 
17126
      case 2: { // Linear interpolation
 
17127
        cimg_forXYZ(*this,x,y,z) {
 
17128
          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;
 
17129
          cimg_get3x3(*this,x,y,z,0,I);
 
17130
          if (y%2) {
 
17131
            if (x%2) { *pR = (Ipp+Inn+Ipn+Inp)/4; *pG = (Inc+Ipc+Icn+Icp)/4; *pB = Icc; }
 
17132
            else { *pR = (Icp+Icn)/2; *pG = Icc; *pB = (Inc+Ipc)/2; }
 
17133
          } else {
 
17134
            if (x%2) { *pR = (Ipc+Inc)/2; *pG = Icc; *pB = (Icn+Icp)/2; }
 
17135
            else { *pR = Icc; *pG = (Inc+Ipc+Icn+Icp)/4; *pB = (Ipp+Inn+Ipn+Inp)/4; }
 
17136
          }
 
17137
          ++pR; ++pG; ++pB;
 
17138
        }
 
17139
      } break;
 
17140
      case 1: { // Nearest neighbor interpolation
 
17141
        cimg_forXYZ(*this,x,y,z) {
 
17142
          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;
 
17143
          cimg_get3x3(*this,x,y,z,0,I);
 
17144
          if (y%2) {
 
17145
            if (x%2) { *pR = cimg::min(Ipp,Inn,Ipn,Inp); *pG = cimg::min(Inc,Ipc,Icn,Icp); *pB = Icc; }
 
17146
            else { *pR = cimg::min(Icn,Icp); *pG = Icc; *pB = cimg::min(Inc,Ipc); }
 
17147
          } else {
 
17148
            if (x%2) { *pR = cimg::min(Inc,Ipc); *pG = Icc; *pB = cimg::min(Icn,Icp); }
 
17149
            else { *pR = Icc; *pG = cimg::min(Inc,Ipc,Icn,Icp); *pB = cimg::min(Ipp,Inn,Ipn,Inp); }
 
17150
          }
 
17151
          ++pR; ++pG; ++pB;
 
17152
        }
 
17153
      } break;
 
17154
      default: { // 0-filling interpolation
 
17155
        const T *ptrs = data;
 
17156
        res.fill(0);
 
17157
        cimg_forXYZ(*this,x,y,z) {
 
17158
          const T val = *(ptrs++);
 
17159
          if (y%2) { if (x%2) *pB = val; else *pG = val; } else { if (x%2) *pG = val; else *pR = val; }
 
17160
          ++pR; ++pG; ++pB;
 
17161
        }
 
17162
      }
 
17163
      }
 
17164
      return res;
 
17165
    }
 
17166
 
 
17167
    //! Convert a Bayer-coded image to a (R,G,B) color image (in-place).
 
17168
    CImg<T>& BayertoRGB(const unsigned int interpolation_type=3) {
 
17169
      return get_BayertoRGB(interpolation_type).transfer_to(*this);
11686
17170
    }
11687
17171
 
11688
17172
    //@}
11694
17178
 
11695
17179
    // The following _draw_scanline() routines are a *non user-friendly function*, used only by inner functions
11696
17180
    // Pre-requisites : x0<x1, y-coordinate is valid, col is valid.
11697
 
    CImg& _draw_scanline(const int x0, const int x1, const int y, const T *const color,
11698
 
                         const float opacity=1.0f, const float brightness=1.0f, const bool init=false) {
11699
 
      static const T maxval = cimg::type<T>::max(), minval = cimg::type<T>::min();
 
17181
    template<typename tc>
 
17182
      CImg<T>& _draw_scanline(const int x0, const int x1, const int y, const tc *const color,
 
17183
                              const float opacity=1.0f, const float brightness=1.0f, const bool init=false) {
 
17184
      static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
11700
17185
      static float nopacity = 0, copacity = 0;
11701
17186
      static unsigned int whz = 0;
11702
 
      static const T *col = 0;
 
17187
      static const tc *col = 0;
11703
17188
      if (init) {
11704
17189
        nopacity = cimg::abs(opacity);
11705
17190
        copacity = 1.0f - cimg::max(opacity,0.0f);
11706
17191
        whz = width*height*depth;
11707
17192
      } else {
11708
 
        const int nx0 = x0>0?x0:0, nx1 = x1<(int)width?x1:(int)width-1, dx = nx1 - nx0;
 
17193
        const int nx0 = x0>0?x0:0, nx1 = x1<dimx()?x1:dimx()-1, dx = nx1 - nx0;
11709
17194
        if (dx>=0) {
11710
17195
          col = color;
11711
17196
          const unsigned int off = whz-dx-1;
11712
17197
          T *ptrd = ptr(nx0,y);
11713
17198
          if (opacity>=1) { // ** Opaque drawing **
11714
 
            if (brightness==1.0f) {  // Brightness==1
11715
 
              if (sizeof(T)!=1) cimg_forV(*this,k) {
11716
 
                const T val = *(col++);
11717
 
                for (int x=dx; x>=0; --x) *(ptrd++) = val;
11718
 
                ptrd+=off;
11719
 
              } else cimg_forV(*this,k) {
11720
 
                const T val = *(col++);
11721
 
                std::memset(ptrd,(int)val,dx+1);
11722
 
                ptrd+=whz;
11723
 
              }
11724
 
            } else {
11725
 
              if (brightness>1.0f) { // Brightness>1
11726
 
                if (sizeof(T)!=1) cimg_forV(*this,k) {
11727
 
                  const float tval = (float)(*(col++)*brightness);
11728
 
                  const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
11729
 
                  for (int x=dx; x>=0; --x) *(ptrd++) = val;
11730
 
                  ptrd+=off;
11731
 
                } else cimg_forV(*this,k) {
11732
 
                  const float tval = (float)(*(col++)*brightness);
11733
 
                  const T val = tval<(float)maxval?(T)tval:maxval;
11734
 
                  std::memset(ptrd,(int)val,dx+1);
11735
 
                  ptrd+=whz;
11736
 
                }
11737
 
              } else { // Brightness<1
11738
 
                if (sizeof(T)!=1) cimg_forV(*this,k) {
11739
 
                  const T val = (T)(*(col++)*brightness);
11740
 
                  for (int x=dx; x>=0; --x) *(ptrd++) = val;
11741
 
                  ptrd+=off;
11742
 
                } else cimg_forV(*this,k) {
11743
 
                  const T val = (T)(*(col++)*brightness);
11744
 
                  std::memset(ptrd,(int)val,dx+1);
11745
 
                  ptrd+=whz;
11746
 
                }
 
17199
            if (brightness==1) { // Brightness==1
 
17200
              if (sizeof(T)!=1) cimg_forV(*this,k) {
 
17201
                const T val = (T)*(col++);
 
17202
                for (int x=dx; x>=0; --x) *(ptrd++) = val;
 
17203
                ptrd+=off;
 
17204
              } else cimg_forV(*this,k) {
 
17205
                const T val = (T)*(col++);
 
17206
                std::memset(ptrd,(int)val,dx+1);
 
17207
                ptrd+=whz;
 
17208
              }
 
17209
            } else if (brightness<1) { // Brightness<1
 
17210
              if (sizeof(T)!=1) cimg_forV(*this,k) {
 
17211
                const T val = (T)(*(col++)*brightness);
 
17212
                for (int x=dx; x>=0; --x) *(ptrd++) = val;
 
17213
                ptrd+=off;
 
17214
              } else cimg_forV(*this,k) {
 
17215
                const T val = (T)(*(col++)*brightness);
 
17216
                std::memset(ptrd,(int)val,dx+1);
 
17217
                ptrd+=whz;
 
17218
              }
 
17219
            } else { // Brightness>1
 
17220
              if (sizeof(T)!=1) cimg_forV(*this,k) {
 
17221
                const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
 
17222
                for (int x=dx; x>=0; --x) *(ptrd++) = val;
 
17223
                ptrd+=off;
 
17224
              } else cimg_forV(*this,k) {
 
17225
                const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
 
17226
                std::memset(ptrd,(int)val,dx+1);
 
17227
                ptrd+=whz;
11747
17228
              }
11748
17229
            }
11749
17230
          } else { // ** Transparent drawing **
11750
 
            if (brightness==1.0f) { // Brightness==1
11751
 
              cimg_forV(*this,k) {
11752
 
                const T val = *(col++);
11753
 
                for (int x=dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
11754
 
                ptrd+=off;
11755
 
              }
11756
 
            } else {
11757
 
              if (brightness>1.0f) { // Brightness>1
11758
 
                cimg_forV(*this,k) {
11759
 
                  const float tval = (float)(*(col++)*brightness);
11760
 
                  const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
11761
 
                  for (int x=dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
11762
 
                  ptrd+=off;
11763
 
                }
11764
 
              } else { // Brightness<=1
11765
 
                cimg_forV(*this,k) {
11766
 
                  const T val = (T)(*(col++)*brightness);
11767
 
                  for (int x=dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
11768
 
                  ptrd+=off;
11769
 
                }
 
17231
            if (brightness==1) { // Brightness==1
 
17232
              cimg_forV(*this,k) {
 
17233
                const T val = (T)*(col++);
 
17234
                for (int x=dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
 
17235
                ptrd+=off;
 
17236
              }
 
17237
            } else if (brightness<=1) { // Brightness<1
 
17238
              cimg_forV(*this,k) {
 
17239
                const T val = (T)(*(col++)*brightness);
 
17240
                for (int x=dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
 
17241
                ptrd+=off;
 
17242
              }
 
17243
            } else { // Brightness>1
 
17244
              cimg_forV(*this,k) {
 
17245
                const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
 
17246
                for (int x=dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
 
17247
                ptrd+=off;
11770
17248
              }
11771
17249
            }
11772
17250
          }
11775
17253
      return *this;
11776
17254
    }
11777
17255
 
11778
 
    CImg& _draw_scanline(const T *const color, const float opacity=1.0f) {
11779
 
      return _draw_scanline(0,0,0,color,opacity,1.0f,true);
 
17256
    template<typename tc>
 
17257
      CImg<T>& _draw_scanline(const tc *const color, const float opacity=1.0f) {
 
17258
      return _draw_scanline(0,0,0,color,opacity,0,true);
11780
17259
    }
11781
17260
 
11782
17261
    //! Draw a colored point (pixel) in the instance image.
11783
17262
    /**
11784
17263
       \param x0 X-coordinate of the point.
11785
17264
       \param y0 Y-coordinate of the point.
11786
 
       \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 
17265
       \param color Pointer to (or image of) \c dimv() consecutive values, defining the color channels.
11787
17266
       \param opacity Drawing opacity (optional).
11788
17267
       \note
11789
17268
       - Clipping is supported.
11794
17273
       const unsigned char color[] = { 255,128,64 };
11795
17274
       img.draw_point(50,50,color);
11796
17275
       \endcode
11797
 
       \see CImg::operator()().
11798
17276
    **/
11799
 
    CImg& draw_point(const int x0, const int y0,
11800
 
                     const T *const color, const float opacity=1.0f) {
 
17277
    template<typename tc>
 
17278
      CImg<T>& draw_point(const int x0, const int y0, const tc *const color, const float opacity=1.0f) {
11801
17279
      return draw_point(x0,y0,0,color,opacity);
11802
17280
    }
11803
17281
 
 
17282
    //! Draw a colored point (pixel) in the instance image.
 
17283
    template<typename tc>
 
17284
      CImg<T>& draw_point(const int x0, const int y0, const CImg<tc>& color, const float opacity=1.0f) {
 
17285
      return draw_point(x0,y0,color.data,opacity);
 
17286
    }
 
17287
 
11804
17288
    //! Draw a colored point (pixel) in the instance image (for volumetric images).
11805
17289
    /**
11806
17290
       \note
11807
17291
       - Similar to CImg::draw_point() for 3D volumetric images.
11808
17292
    **/
11809
 
    CImg& draw_point(const int x0, const int y0, const int z0,
11810
 
                     const T *const color, const float opacity=1.0f) {
 
17293
    template<typename tc>
 
17294
      CImg<T>& draw_point(const int x0, const int y0, const int z0, const tc *const color, const float opacity=1.0f) {
11811
17295
      if (!is_empty()) {
11812
17296
        if (!color) throw CImgArgumentException("CImg<%s>::draw_point() : Specified color is (null)",pixel_type());
11813
17297
        if (x0>=0 && y0>=0 && z0>=0 && x0<dimx() && y0<dimy() && z0<dimz()) {
11814
 
          const T *col=color;
 
17298
          const tc *col = color;
11815
17299
          const unsigned int whz = width*height*depth;
11816
17300
          const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
11817
17301
          T *ptrd = ptr(x0,y0,z0,0);
11818
 
          if (opacity>=1) cimg_forV(*this,k) { *ptrd = *(col++); ptrd+=whz; }
 
17302
          if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
11819
17303
          else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
11820
17304
        }
11821
17305
      }
11822
17306
      return *this;
11823
17307
    }
11824
17308
 
 
17309
    //! Draw a colored point (pixel) in the instance image (for volumetric images).
 
17310
    template<typename tc>
 
17311
      CImg<T>& draw_point(const int x0, const int y0, const int z0, const CImg<tc>& color, const float opacity=1.0f) {
 
17312
      return draw_point(x0,y0,z0,color.data,opacity);
 
17313
    }
 
17314
 
 
17315
    // Inner routine for drawing a cloud of points with generic type for coordinates.
 
17316
    template<typename t, typename tc>
 
17317
      CImg<T>& _draw_point(const t& points, const tc *const color,
 
17318
                           const float opacity, const unsigned int W, const unsigned int H) {
 
17319
      if (points && W && H>1) {
 
17320
        if (H==2) for (unsigned int i=0; i<W; ++i) {
 
17321
          const int x = (int)points(i,0), y = (int)points(i,1);
 
17322
          draw_point(x,y,color,opacity);
 
17323
        } else for (unsigned int i=0; i<W; ++i) {
 
17324
          const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
 
17325
          draw_point(x,y,z,color,opacity);
 
17326
        }
 
17327
      }
 
17328
      return *this;
 
17329
    }
 
17330
 
 
17331
    //! Draw a cloud of colored points in the instance image.
 
17332
    /**
 
17333
       \param points Coordinates of vertices, stored as a list of vectors.
 
17334
       \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 
17335
       \param opacity Drawing opacity (optional).
 
17336
       \note
 
17337
       - This function uses several call to the single CImg::draw_point() procedure,
 
17338
       depending on the vectors size in \p points.
 
17339
       \par Example:
 
17340
       \code
 
17341
       CImg<unsigned char> img(100,100,1,3,0);
 
17342
       const unsigned char color[] = { 255,128,64 };
 
17343
       CImgList<int> points;
 
17344
       points.insert(CImg<int>::vector(0,0)).
 
17345
             .insert(CImg<int>::vector(70,10)).
 
17346
             .insert(CImg<int>::vector(80,60)).
 
17347
             .insert(CImg<int>::vector(10,90));
 
17348
       img.draw_point(points,color);
 
17349
       \endcode
 
17350
    **/
 
17351
    template<typename t, typename tc>
 
17352
      CImg<T>& draw_point(const CImgList<t>& points, const tc *const color, const float opacity=1.0f) {
 
17353
      unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
 
17354
      return _draw_point(points,color,opacity,points.size,H);
 
17355
    }
 
17356
 
 
17357
    //! Draw a cloud of colored points in the instance image.
 
17358
    template<typename t, typename tc>
 
17359
      CImg<T>& draw_point(const CImgList<t>& points, const CImg<tc>& color, const float opacity=1.0f) {
 
17360
      return draw_point(points,color.data,opacity);
 
17361
    }
 
17362
 
 
17363
    //! Draw a cloud of points in the instance image.
 
17364
    /**
 
17365
       \note
 
17366
       - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
 
17367
       (sequence of vectors aligned along the x-axis).
 
17368
    **/
 
17369
    template<typename t, typename tc>
 
17370
      CImg<T>& draw_point(const CImg<t>& points, const tc *const color, const float opacity=1.0f) {
 
17371
      return _draw_point(points,color,opacity,points.width,points.height);
 
17372
    }
 
17373
 
 
17374
    //! Draw a cloud of points in the instance image.
 
17375
    template<typename t, typename tc>
 
17376
      CImg<T>& draw_point(const CImg<t>& points, const CImg<tc>& color, const float opacity=1.0f) {
 
17377
      return draw_point(points,color.data,opacity);
 
17378
    }
 
17379
 
11825
17380
    //! Draw a colored line in the instance image.
11826
17381
    /**
11827
17382
       \param x0 X-coordinate of the starting line point.
11843
17398
        img.draw_line(40,40,80,70,color);
11844
17399
       \endcode
11845
17400
    **/
11846
 
    CImg& draw_line(const int x0, const int y0,
11847
 
                    const int x1, const int y1,
11848
 
                    const T *const color, const float opacity=1.0f,
11849
 
                    const unsigned int pattern=~0U, const bool init_hatch=true) {
 
17401
    template<typename tc>
 
17402
      CImg<T>& draw_line(const int x0, const int y0, const int x1, const int y1,
 
17403
                         const tc *const color, const float opacity=1.0f,
 
17404
                         const unsigned int pattern=~0U, const bool init_hatch=true) {
11850
17405
      if (!is_empty()) {
11851
17406
        if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",pixel_type());
11852
17407
        static unsigned int hatch = ~0U-(~0U>>1);
11853
17408
        if (init_hatch) hatch = ~0U-(~0U>>1);
11854
 
        const T* col = color;
 
17409
        const tc* col = color;
11855
17410
        const bool xdir = x0<x1, ydir = y0<y1;
11856
17411
        int
11857
17412
          nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
11876
17431
        if (opacity>=1) {
11877
17432
          if (~pattern) for (int error=dx>>1, x=0; x<=dx; ++x) {
11878
17433
            T *ptrd = ptrd0;
11879
 
            if (pattern&hatch) { cimg_forV(*this,k) { *ptrd = *(col++); ptrd+=wh; } col-=dim; }
 
17434
            if (pattern&hatch) { cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; } col-=dim; }
11880
17435
            hatch>>=1; if (!hatch) hatch = ~0U-(~0U>>1);
11881
17436
            ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
11882
17437
          } else for (int error=dx>>1, x=0; x<=dx; ++x) {
11883
17438
            T *ptrd = ptrd0;
11884
 
            cimg_forV(*this,k) { *ptrd = *(col++); ptrd+=wh; } col-=dim;
 
17439
            cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; } col-=dim;
11885
17440
            ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
11886
17441
          }
11887
17442
        } else {
11888
17443
          const float nopacity = cimg::abs(opacity), copacity=1-cimg::max(opacity,0.0f);
11889
17444
          if (~pattern) for (int error=dx>>1, x=0; x<=dx; ++x) {
11890
17445
            T *ptrd = ptrd0;
11891
 
            if (pattern&hatch) { cimg_forV(*this,k) { const T c = *(col++); *ptrd = (T)(c*nopacity + copacity*(*ptrd)); ptrd+=wh; } col-=dim; }
 
17446
            if (pattern&hatch) { cimg_forV(*this,k) { const tc& c = *(col++); *ptrd = (T)(c*nopacity + *ptrd*copacity); ptrd+=wh; } col-=dim; }
11892
17447
            hatch>>=1; if (!hatch) hatch = ~0U-(~0U>>1);
11893
17448
            ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
11894
17449
          } else for (int error=dx>>1, x=0; x<=dx; ++x) {
11895
17450
            T *ptrd = ptrd0;
11896
 
            cimg_forV(*this,k) { const T c = *(col++); *ptrd = (T)(c*nopacity + copacity*(*ptrd)); ptrd+=wh; } col-=dim;
 
17451
            cimg_forV(*this,k) { const tc& c = *(col++); *ptrd = (T)(c*nopacity + *ptrd*copacity); ptrd+=wh; } col-=dim;
11897
17452
            ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
11898
17453
          }
11899
17454
        }
11901
17456
      return *this;
11902
17457
    }
11903
17458
 
 
17459
    //! Draw a colored line in the instance image.
 
17460
    template<typename tc>
 
17461
      CImg<T>& draw_line(const int x0, const int y0, const int x1, const int y1,
 
17462
                         const CImg<tc>& color, const float opacity=1.0f,
 
17463
                         const unsigned int pattern=~0U, const bool init_hatch=true) {
 
17464
      return draw_line(x0,y0,x1,y1,color.data,opacity,pattern,init_hatch);
 
17465
    }
 
17466
 
11904
17467
    //! Draw a colored line in the instance image (for volumetric images).
11905
17468
    /**
11906
17469
       \note
11907
17470
       - Similar to CImg::draw_line() for 3D volumetric images.
11908
17471
    **/
11909
 
    CImg& draw_line(const int x0, const int y0, const int z0,
11910
 
                    const int x1, const int y1, const int z1,
11911
 
                    const T *const color, const float opacity=1.0f,
11912
 
                    const unsigned int pattern=~0U, const bool init_hatch=true) {
 
17472
    template<typename tc>
 
17473
      CImg<T>& draw_line(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1,
 
17474
                         const tc *const color, const float opacity=1.0f,
 
17475
                         const unsigned int pattern=~0U, const bool init_hatch=true) {
11913
17476
      if (!is_empty()) {
11914
17477
        if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",pixel_type());
11915
17478
        static unsigned int hatch = ~0U-(~0U>>1);
11916
17479
        if (init_hatch) hatch = ~0U-(~0U>>1);
11917
 
        const T* col=color;
 
17480
        const tc *col = color;
11918
17481
        int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1;
11919
17482
        if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
11920
17483
        if (nx1<0 || nx0>=dimx()) return *this;
11934
17497
        if (opacity>=1) for (unsigned int t=0; t<=dmax; ++t) {
11935
17498
          if (!(~pattern) || (~pattern && pattern&hatch)) {
11936
17499
            T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0);
11937
 
            cimg_forV(*this,k) { *ptrd = *(col++); ptrd+=whz; }
 
17500
            cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
11938
17501
            col-=dim;
11939
17502
          }
11940
17503
          x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));
11943
17506
          for (unsigned int t=0; t<=dmax; ++t) {
11944
17507
            if (!(~pattern) || (~pattern && pattern&hatch)) {
11945
17508
              T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0);
11946
 
              cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; }
 
17509
              cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
11947
17510
              col-=dim;
11948
17511
            }
11949
17512
            x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1));
11953
17516
      return *this;
11954
17517
    }
11955
17518
 
 
17519
    //! Draw a colored line in the instance image (for volumetric images).
 
17520
    template<typename tc>
 
17521
      CImg<T>& draw_line(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1,
 
17522
                         const CImg<tc>& color, const float opacity=1.0f,
 
17523
                         const unsigned int pattern=~0U, const bool init_hatch=true) {
 
17524
      return draw_line(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
 
17525
    }
 
17526
 
11956
17527
    //! Draw a textured line in the instance image.
11957
17528
    /**
11958
17529
       \param x0 X-coordinate of the starting line point.
11977
17548
       img.draw_line(40,40,80,70,texture,0,0,255,255);
11978
17549
       \endcode
11979
17550
    **/
11980
 
    template<typename t> CImg& draw_line(const int x0, const int y0,
11981
 
                                         const int x1, const int y1,
11982
 
                                         const CImg<t>& texture,
11983
 
                                         const int tx0, const int ty0,
11984
 
                                         const int tx1, const int ty1,
11985
 
                                         const float opacity=1.0f,
11986
 
                                         const unsigned int pattern=~0U,
11987
 
                                         const bool init_hatch=true) {
 
17551
    template<typename t>
 
17552
      CImg<T>& draw_line(const int x0, const int y0, const int x1, const int y1,
 
17553
                         const CImg<t>& texture,
 
17554
                         const int tx0, const int ty0, const int tx1, const int ty1,
 
17555
                         const float opacity=1.0f, const unsigned int pattern=~0U, const bool init_hatch=true) {
11988
17556
      if (!is_empty()) {
11989
17557
        if (!texture || texture.dim<dim)
11990
 
          throw CImgArgumentException("CImg<%s>::draw_line() : specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 
17558
          throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
11991
17559
                                      pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 
17560
        if (is_overlapping(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
11992
17561
        static unsigned int hatch = ~0U-(~0U>>1);
11993
17562
        if (init_hatch) hatch = ~0U-(~0U>>1);
11994
17563
        const bool xdir = x0<x1, ydir = y0<y1;
12060
17629
            T *ptrd = ptrd0;
12061
17630
            if (pattern&hatch) {
12062
17631
              const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
12063
 
              cimg_forV(*this,k) { const T c = (T)texture(tx,ty,0,k); *ptrd = (T)(c*nopacity + copacity*(*ptrd)); ptrd+=wh; }
 
17632
              cimg_forV(*this,k) { const T c = (T)texture(tx,ty,0,k); *ptrd = (T)(c*nopacity + *ptrd*copacity); ptrd+=wh; }
12064
17633
            }
12065
17634
            hatch>>=1; if (!hatch) hatch = ~0U-(~0U>>1);
12066
17635
            ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
12067
17636
          } else for (int error=dx>>1, x=0; x<=dx; ++x) {
12068
17637
            T *ptrd = ptrd0;
12069
17638
            const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
12070
 
            cimg_forV(*this,k) { const T c = (T)texture(tx,ty,0,k); *ptrd = (T)(c*nopacity + copacity*(*ptrd)); ptrd+=wh; }
 
17639
            cimg_forV(*this,k) { const T c = (T)texture(tx,ty,0,k); *ptrd = (T)(c*nopacity + *ptrd*copacity); ptrd+=wh; }
12071
17640
            ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
12072
17641
          }
12073
17642
        }
12076
17645
    }
12077
17646
 
12078
17647
    //! Draw a textured line in the instance image, with perspective correction.
12079
 
    template<typename t> CImg& draw_line(const int x0, const int y0, const float z0,
12080
 
                                         const int x1, const int y1, const float z1,
12081
 
                                         const CImg<t>& texture,
12082
 
                                         const int tx0, const int ty0,
12083
 
                                         const int tx1, const int ty1,
12084
 
                                         const float opacity=1.0f, const unsigned int pattern=~0U,
12085
 
                                         const bool init_hatch=true) {
 
17648
    template<typename t>
 
17649
      CImg<T>& draw_line(const int x0, const int y0, const float z0, const int x1, const int y1, const float z1,
 
17650
                         const CImg<t>& texture,
 
17651
                         const int tx0, const int ty0, const int tx1, const int ty1,
 
17652
                         const float opacity=1.0f, const unsigned int pattern=~0U, const bool init_hatch=true) {
12086
17653
      if (!is_empty() && z0>0 && z1>0) {
12087
17654
        if (!texture || texture.dim<dim)
12088
 
          throw CImgArgumentException("CImg<%s>::draw_line() : specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 
17655
          throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
12089
17656
                                      pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 
17657
        if (is_overlapping(texture)) return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
12090
17658
        static unsigned int hatch = ~0U-(~0U>>1);
12091
17659
        if (init_hatch) hatch = ~0U-(~0U>>1);
12092
17660
        const bool xdir = x0<x1, ydir = y0<y1;
12171
17739
            T *ptrd = ptrd0;
12172
17740
            if (pattern&hatch) {
12173
17741
              const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
12174
 
              cimg_forV(*this,k) { const T c = (T)texture((int)(tx/z),(int)(ty/z),0,k); *ptrd = (T)(c*nopacity + copacity*(*ptrd)); ptrd+=wh; }
 
17742
              cimg_forV(*this,k) { const T c = (T)texture((int)(tx/z),(int)(ty/z),0,k); *ptrd = (T)(c*nopacity + *ptrd*copacity); ptrd+=wh; }
12175
17743
            }
12176
17744
            hatch>>=1; if (!hatch) hatch = ~0U-(~0U>>1);
12177
17745
            ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
12178
17746
          } else for (int error=dx>>1, x=0; x<=dx; ++x) {
12179
17747
            T *ptrd = ptrd0;
12180
17748
            const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
12181
 
            cimg_forV(*this,k) { const T c = (T)texture((int)(tx/z),(int)(ty/z),0,k); *ptrd = (T)(c*nopacity + copacity*(*ptrd)); ptrd+=wh; }
 
17749
            cimg_forV(*this,k) { const T c = (T)texture((int)(tx/z),(int)(ty/z),0,k); *ptrd = (T)(c*nopacity + *ptrd*copacity); ptrd+=wh; }
12182
17750
            ptrd0+=offx; if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
12183
17751
          }
12184
17752
        }
12187
17755
    }
12188
17756
 
12189
17757
    // Inner routine for drawing set of consecutive lines with generic type for coordinates.
12190
 
    template<typename t> CImg& _draw_line(const t& points,
12191
 
                                          const T *const color,
12192
 
                                          const float opacity, const unsigned int pattern, const bool init_hatch,
12193
 
                                          const unsigned int W, const unsigned int H) {
 
17758
    template<typename t, typename tc>
 
17759
      CImg<T>& _draw_line(const t& points, const tc *const color,
 
17760
                          const float opacity, const unsigned int pattern, const bool init_hatch,
 
17761
                          const unsigned int W, const unsigned int H) {
12194
17762
      bool ninit_hatch = init_hatch;
12195
17763
      if (points && W>1 && H>1) {
12196
17764
        if (H==2) {
12219
17787
    //! Draw a set of consecutive colored lines in the instance image.
12220
17788
    /**
12221
17789
       \param points Coordinates of vertices, stored as a list of vectors.
12222
 
       \param closed_polygon Flag telling if the last point is connected with the first one.
12223
17790
       \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
 
17791
       \param opacity Drawing opacity (optional).
12224
17792
       \param pattern An integer whose bits describe the line pattern (optional).
12225
 
       \param opacity Drawing opacity (optional).
 
17793
       \param init_hatch If set to true, init hatch motif.
12226
17794
       \note
12227
17795
       - This function uses several call to the single CImg::draw_line() procedure,
12228
17796
       depending on the vectors size in \p points.
12237
17805
             .insert(CImg<int>::vector(10,90));
12238
17806
       img.draw_line(points,color);
12239
17807
       \endcode
12240
 
       \sa CImg::draw_line().
12241
17808
    **/
12242
 
    template<typename t> CImg& draw_line(const CImgList<t>& points, const T *const color,
12243
 
                                         const float opacity=1.0f, const unsigned int pattern=~0U, const bool init_hatch=true) {
 
17809
    template<typename t, typename tc>
 
17810
      CImg<T>& draw_line(const CImgList<t>& points, const tc *const color,
 
17811
                         const float opacity=1.0f, const unsigned int pattern=~0U, const bool init_hatch=true) {
12244
17812
      unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
12245
17813
      return _draw_line(points,color,opacity,pattern,init_hatch,points.size,H);
12246
17814
    }
12247
17815
 
12248
17816
    //! Draw a set of consecutive colored lines in the instance image.
 
17817
    template<typename t, typename tc>
 
17818
      CImg<T>& draw_line(const CImgList<t>& points, const CImg<tc>& color,
 
17819
                         const float opacity=1.0f, const unsigned int pattern=~0U, const bool init_hatch=true) {
 
17820
      return draw_line(points,color.data,opacity,pattern,init_hatch);
 
17821
    }
 
17822
 
 
17823
    //! Draw a set of consecutive colored lines in the instance image.
12249
17824
    /**
12250
17825
       \note
12251
17826
       - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
12252
17827
       (sequence of vectors aligned along the x-axis).
12253
17828
    **/
12254
 
    template<typename t> CImg& draw_line(const CImg<t>& points, const T *const color,
12255
 
                                         const float opacity=1.0f, const unsigned int pattern=~0U, const bool init_hatch=true) {
 
17829
    template<typename t, typename tc>
 
17830
      CImg<T>& draw_line(const CImg<t>& points, const tc *const color,
 
17831
                         const float opacity=1.0f, const unsigned int pattern=~0U, const bool init_hatch=true) {
12256
17832
      return _draw_line(points,color,opacity,pattern,init_hatch,points.width,points.height);
12257
17833
    }
12258
17834
 
 
17835
    //! Draw a set of consecutive colored lines in the instance image.
 
17836
    template<typename t, typename tc>
 
17837
      CImg<T>& draw_line(const CImg<t>& points, const CImg<tc>& color,
 
17838
                         const float opacity=1.0f, const unsigned int pattern=~0U, const bool init_hatch=true) {
 
17839
      return draw_line(points,color.data,opacity,pattern,init_hatch);
 
17840
    }
 
17841
 
12259
17842
    // Inner routine for a drawing filled polygon with generic type for coordinates.
12260
 
    template<typename t> CImg& _draw_polygon(const t& points, const T *const color, const float opacity, const unsigned int N) {
12261
 
      if (!is_empty()) {
 
17843
    template<typename t, typename tc>
 
17844
      CImg<T>& _draw_polygon(const t& points, const tc *const color, const float opacity, const unsigned int N) {
 
17845
      if (!is_empty() && N>2) {
12262
17846
        if (!color) throw CImgArgumentException("CImg<%s>::draw_polygon() : Specified color is (null).",pixel_type());
12263
17847
        _draw_scanline(color,opacity);
12264
17848
        int xmin = (int)(~0U>>1), xmax = 0, ymin = (int)(~0U>>1), ymax = 0;
12265
 
        { for (unsigned int p=0; p<N; ++p) {
 
17849
        { for (unsigned int p = 0; p<N; ++p) {
12266
17850
          const int x = (int)points(p,0), y = (int)points(p,1);
12267
17851
          if (x<xmin) xmin = x;
12268
17852
          if (x>xmax) xmax = x;
12269
17853
          if (y<ymin) ymin = y;
12270
17854
          if (y>ymax) ymax = y;
12271
17855
        }}
12272
 
        if (xmax<0 || xmin>=(int)width || ymax<0 || ymin>=(int)width) return *this;
 
17856
        if (xmax<0 || xmin>=dimx() || ymax<0 || ymin>=dimx()) return *this;
12273
17857
        const unsigned int
12274
17858
          nymin = ymin<0?0:(unsigned int)ymin,
12275
 
          nymax = ymax>=(int)height?height-1:(unsigned int)ymax,
 
17859
          nymax = ymax>=dimy()?height-1:(unsigned int)ymax,
12276
17860
          dy = 1 + nymax - nymin;
12277
 
        CImg<typename cimg::last<T,int>::type> X(1+N,dy,1,2,0), done(N,2,1,1,0), tmp;
12278
 
        int ox = (int)points(0,0), oy = (int)points(0,1), op = 0;
12279
 
        for (unsigned int p=1; p<=N; ++p) {
12280
 
          const int cp = p!=N?p:0, cx = (int)points(cp,0), cy = (int)points(cp,1),
12281
 
            y0 = oy-nymin, y1 = cy-nymin, dir = (y1>y0?0:1);
12282
 
          for (int x=ox, y=y0, _sx=1, _sy=1,
12283
 
                 _dx = cx>ox?cx-ox:((_sx=-1),ox-cx),
12284
 
                 _dy = y1>y0?y1-y0:((_sy=-1),y0-y1),
12285
 
                 _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy),
12286
 
                 _err = _dx>>1,
12287
 
                 _rx = _dy?(cx-ox)/_dy:0;
12288
 
               _counter>0;
12289
 
               --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0))
12290
 
            if (y>=0 && y<=(int)dy && y!=y0) X(++X(0,y,dir),y,dir) = x;
12291
 
          if (!done(op,dir)) { X(++X(0,y0,dir),y0,dir) = ox; ++done(op,dir); }
12292
 
          if (!done(cp,dir)) { X(++X(0,y1,dir),y1,dir) = cx; ++done(cp,dir); }
12293
 
          ox = cx; oy = cy; op = cp;
 
17861
        typedef typename cimg::last<T,int>::type cint;
 
17862
        CImg<cint> X(1+2*N,dy,1,1,0), tmp;
 
17863
        int cx = (int)points(0,0), cy = (int)points(0,1);
 
17864
 
 
17865
        for (unsigned int cp = 0, p = 0; p<N; ++p) {
 
17866
          const unsigned int np = (p!=N-1)?p+1:0, ap = (np!=N-1)?np+1:0;
 
17867
          const int
 
17868
            nx = (int)points(np,0), ny = (int)points(np,1), ay = (int)points(ap,1),
 
17869
            y0 = cy-nymin, y1 = ny-nymin;
 
17870
          if (y0!=y1) {
 
17871
            const int countermin = ((ny<ay && cy<ny) || (ny>ay && cy>ny))?1:0;
 
17872
            for (int x = cx, y = y0, _sx = 1, _sy = 1,
 
17873
                   _dx = nx>cx?nx-cx:((_sx=-1),cx-nx),
 
17874
                   _dy = y1>y0?y1-y0:((_sy=-1),y0-y1),
 
17875
                   _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy),
 
17876
                   _err = _dx>>1,
 
17877
                   _rx = _dy?(nx-cx)/_dy:0;
 
17878
                 _counter>=countermin;
 
17879
                 --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0))
 
17880
              if (y>=0 && y<(int)dy) X(++X(0,y),y) = x;
 
17881
            cp = np; cx = nx; cy = ny;
 
17882
          } else {
 
17883
            const int pp = (cp?cp-1:N-1), py = (int)points(pp,1);
 
17884
            if ((cy>py && ay>cy) || (cy<py && ay<cy)) X(++X(0,y0),y0) = nx;
 
17885
            if (cy!=ay) { cp = np; cx = nx; cy = ny; }
 
17886
          }
12294
17887
        }
12295
 
        for (int y=0; y<(int)dy; ++y) {
12296
 
          tmp.assign(X.ptr(1,y,0),X(0,y,0),1,1,1,true).sort();
12297
 
          tmp.assign(X.ptr(1,y,1),X(0,y,1),1,1,1,true).sort();
12298
 
          for (int i=X(0,y,0); i>=1; --i) {
12299
 
            const int xb = X(i,y,0), xe = X(i,y,1);
12300
 
            if (xe>xb) _draw_scanline(xb,xe,nymin+y,color,opacity);
12301
 
            else _draw_scanline(xe,xb,nymin+y,color,opacity);
 
17888
        for (int y = 0; y<(int)dy; ++y) {
 
17889
          tmp.assign(X.ptr(1,y),X(0,y),1,1,1,true).sort();
 
17890
          for (int i = 1; i<=X(0,y); ) {
 
17891
            const int xb = X(i++,y), xe = X(i++,y);
 
17892
            _draw_scanline(xb,xe,nymin+y,color,opacity);
12302
17893
          }
12303
17894
        }
12304
17895
      }
12306
17897
    }
12307
17898
 
12308
17899
    //! Draw a filled polygon in the instance image.
12309
 
    template<typename t> CImg& draw_polygon(const CImgList<t>& points, const T *const color, const float opacity=1.0f) {
 
17900
    template<typename t, typename tc>
 
17901
      CImg<T>& draw_polygon(const CImgList<t>& points, const tc *const color, const float opacity=1.0f) {
12310
17902
      return _draw_polygon(points,color,opacity,points.size);
12311
17903
    }
12312
17904
 
12313
17905
    //! Draw a filled polygon in the instance image.
12314
 
    template<typename t> CImg& draw_polygon(const CImg<t>& points, const T *const color, const float opacity=1.0f) {
 
17906
    template<typename t, typename tc>
 
17907
      CImg<T>& draw_polygon(const CImgList<t>& points, const CImg<tc>& color, const float opacity=1.0f) {
 
17908
      return draw_polygon(points,color.data,opacity);
 
17909
    }
 
17910
 
 
17911
    //! Draw a filled polygon in the instance image.
 
17912
    template<typename t, typename tc>
 
17913
      CImg<T>& draw_polygon(const CImg<t>& points, const tc *const color, const float opacity=1.0f) {
12315
17914
      return _draw_polygon(points,color,opacity,points.width);
12316
17915
    }
12317
17916
 
 
17917
    //! Draw a filled polygon in the instance image.
 
17918
    template<typename t, typename tc>
 
17919
      CImg<T>& draw_polygon(const CImg<t>& points, const CImg<tc>& color, const float opacity=1.0f) {
 
17920
      return draw_polygon(points,color.data,opacity);
 
17921
    }
 
17922
 
12318
17923
    // Inner routine for drawing an outlined polygon with generic point coordinates.
12319
 
    template<typename t> CImg& _draw_polygon(const t& points,
12320
 
                                             const T *const color,
12321
 
                                             const float opacity, const unsigned int pattern,
12322
 
                                             const unsigned int W, const unsigned int H) {
 
17924
    template<typename t, typename tc>
 
17925
      CImg<T>& _draw_polygon(const t& points, const tc *const color,
 
17926
                             const float opacity, const unsigned int pattern,
 
17927
                             const unsigned int W, const unsigned int H) {
12323
17928
      bool ninit_hatch = true;
12324
 
      if (points && W>1 && H>1) {
 
17929
      if (points && W>2 && H>1) {
12325
17930
        if (H==2) {
12326
17931
          const int x0 = (int)points(0,0), y0 = (int)points(0,1);
12327
17932
          int ox = x0, oy = y0;
12347
17952
      return *this;
12348
17953
    }
12349
17954
 
12350
 
    // Draw a polygon outline.
12351
 
    template<typename t> CImg& draw_polygon(const CImgList<t>& points, const T *const color,
12352
 
                                            const float opacity, const unsigned int pattern) {
 
17955
    //! Draw a polygon outline.
 
17956
    template<typename t, typename tc>
 
17957
      CImg<T>& draw_polygon(const CImgList<t>& points, const tc *const color,
 
17958
                            const float opacity, const unsigned int pattern) {
12353
17959
      unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
12354
17960
      return _draw_polygon(points,color,opacity,pattern,points.size,H);
12355
17961
    }
12356
17962
 
12357
 
    // Draw a polygon outline.
12358
 
    template<typename t> CImg& draw_polygon(const CImg<t>& points, const T *const color,
12359
 
                                            const float opacity, const unsigned int pattern) {
 
17963
    //! Draw a polygon outline.
 
17964
    template<typename t, typename tc>
 
17965
      CImg<T>& draw_polygon(const CImgList<t>& points, const CImg<tc>& color,
 
17966
                            const float opacity, const unsigned int pattern) {
 
17967
      return draw_polygon(points,color.data,opacity,pattern);
 
17968
    }
 
17969
 
 
17970
    //! Draw a polygon outline.
 
17971
    template<typename t, typename tc>
 
17972
      CImg<T>& draw_polygon(const CImg<t>& points, const tc *const color,
 
17973
                            const float opacity, const unsigned int pattern) {
12360
17974
      return _draw_polygon(points,color,opacity,pattern,points.width,points.height);
12361
17975
    }
12362
17976
 
 
17977
    //! Draw a polygon outline.
 
17978
    template<typename t, typename tc>
 
17979
      CImg<T>& draw_polygon(const CImg<t>& points, const CImg<tc>& color,
 
17980
                            const float opacity, const unsigned int pattern) {
 
17981
      return draw_polygon(points,color.data,opacity,pattern);
 
17982
    }
 
17983
 
12363
17984
    //! Draw a cubic spline curve in the instance image.
12364
17985
    /**
12365
17986
       \param x0 X-coordinate of the starting curve point
12374
17995
       \param precision Curve drawing precision (optional).
12375
17996
       \param opacity Drawing opacity (optional).
12376
17997
       \param pattern An integer whose bits describe the line pattern (optional).
 
17998
       \param init_hatch If \c true, init hatch motif.
12377
17999
       \note
12378
18000
       - The curve is a 2D cubic Bezier spline, from the set of specified starting/ending points
12379
18001
       and corresponding velocity vectors.
12391
18013
       img.draw_spline(30,30,0,100,90,40,0,-100,color);
12392
18014
       \endcode
12393
18015
    **/
12394
 
    CImg& draw_spline(const int x0, const int y0, const float u0, const float v0,
12395
 
                      const int x1, const int y1, const float u1, const float v1,
12396
 
                      const T *const color,
12397
 
                      const float precision=4.0f, const float opacity=1.0f, const unsigned int pattern=~0U,
12398
 
                      const bool init_hatch=true) {
 
18016
    template<typename tc>
 
18017
      CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
 
18018
                           const int x1, const int y1, const float u1, const float v1,
 
18019
                           const tc *const color,
 
18020
                           const float precision=4.0f, const float opacity=1.0f, const unsigned int pattern=~0U,
 
18021
                           const bool init_hatch=true) {
12399
18022
      if (!is_empty()) {
12400
18023
        if (!color) throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",pixel_type());
12401
18024
        bool ninit_hatch = init_hatch;
12425
18048
      return *this;
12426
18049
    }
12427
18050
 
 
18051
    //! Draw a cubic spline curve in the instance image.
 
18052
    template<typename tc>
 
18053
      CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
 
18054
                           const int x1, const int y1, const float u1, const float v1,
 
18055
                           const CImg<tc>& color,
 
18056
                           const float precision=4.0f, const float opacity=1.0f, const unsigned int pattern=~0U,
 
18057
                           const bool init_hatch=true) {
 
18058
      return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,color.data,precision,opacity,pattern,init_hatch);
 
18059
    }
 
18060
 
12428
18061
    //! Draw a cubic spline curve in the instance image (for volumetric images).
12429
18062
    /**
12430
18063
       \note
12431
18064
       - Similar to CImg::draw_spline() for a 3D spline in a volumetric image.
12432
18065
    **/
12433
 
    CImg& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
12434
 
                      const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
12435
 
                      const T *const color,
12436
 
                      const float precision=4.0f, const float opacity=1.0f, const unsigned int pattern=~0U,
12437
 
                      const bool init_hatch=true) {
 
18066
    template<typename tc>
 
18067
      CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
 
18068
                           const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
 
18069
                           const tc *const color,
 
18070
                           const float precision=4.0f, const float opacity=1.0f, const unsigned int pattern=~0U,
 
18071
                           const bool init_hatch=true) {
12438
18072
      if (!is_empty()) {
12439
18073
        if (!color) throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",pixel_type());
12440
18074
        bool ninit_hatch = init_hatch;
12468
18102
      return *this;
12469
18103
    }
12470
18104
 
 
18105
    //! Draw a cubic spline curve in the instance image (for volumetric images).
 
18106
    template<typename tc>
 
18107
      CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
 
18108
                           const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
 
18109
                           const CImg<tc>& color,
 
18110
                           const float precision=4.0f, const float opacity=1.0f, const unsigned int pattern=~0U,
 
18111
                           const bool init_hatch=true) {
 
18112
      return draw_spline(x0,y0,z0,u0,v0,w0,x1,y1,z1,u1,v1,w1,color.data,precision,opacity,pattern,init_hatch);
 
18113
    }
 
18114
 
12471
18115
    //! Draw a cubic spline curve in the instance image.
12472
18116
    /**
12473
18117
       \param x0 X-coordinate of the starting curve point
12486
18130
       \param precision Curve drawing precision (optional).
12487
18131
       \param opacity Drawing opacity (optional).
12488
18132
       \param pattern An integer whose bits describe the line pattern (optional).
 
18133
       \param init_hatch if \c true, reinit hatch motif.
12489
18134
    **/
12490
18135
    template<typename t>
12491
 
      CImg& draw_spline(const int x0, const int y0, const float u0, const float v0,
12492
 
                        const int x1, const int y1, const float u1, const float v1,
12493
 
                        const CImg<t>& texture,
12494
 
                        const int tx0, const int ty0, const int tx1, const int ty1,
12495
 
                        const float precision=4.0f, const float opacity=1.0f, const unsigned int pattern=~0U,
12496
 
                        const bool init_hatch=true) {
 
18136
      CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
 
18137
                           const int x1, const int y1, const float u1, const float v1,
 
18138
                           const CImg<t>& texture,
 
18139
                           const int tx0, const int ty0, const int tx1, const int ty1,
 
18140
                           const float precision=4.0f, const float opacity=1.0f, const unsigned int pattern=~0U,
 
18141
                           const bool init_hatch=true) {
12497
18142
      if (!is_empty()) {
12498
18143
        if (!texture || texture.dim<dim)
12499
 
          throw CImgArgumentException("CImg<%s>::draw_line() : specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 
18144
          throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
12500
18145
                                      pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 
18146
        if (is_overlapping(texture)) return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,+texture,tx0,ty0,tx1,ty1,precision,opacity,pattern,init_hatch);
12501
18147
        bool ninit_hatch = true;
12502
18148
        const float
12503
18149
          dx = (float)(x1-x0),
12528
18174
    }
12529
18175
 
12530
18176
    // Draw a set of connected spline curves in the instance image (inner routines).
12531
 
    template<typename tp, typename tt>
12532
 
      CImg& _draw_spline(const tp& points, const tt& tangents,
12533
 
                         const T *const color, const bool close_set,
12534
 
                         const float precision, const float opacity, const unsigned int pattern, const bool init_hatch,
12535
 
                         const unsigned int W, const unsigned int H) {
 
18177
    template<typename tp, typename tt, typename tc>
 
18178
      CImg<T>& _draw_spline(const tp& points, const tt& tangents,
 
18179
                            const tc *const color, const bool close_set,
 
18180
                            const float precision, const float opacity, const unsigned int pattern, const bool init_hatch,
 
18181
                            const unsigned int W, const unsigned int H) {
12536
18182
      bool ninit_hatch = init_hatch;
12537
18183
      if (points && tangents && W>1 && H>1) {
12538
18184
        if (H==2) {
12566
18212
      return *this;
12567
18213
    }
12568
18214
 
12569
 
    template<typename tp>
12570
 
      CImg& _draw_spline(const tp& points,
12571
 
                         const T *const color, const bool close_set,
12572
 
                         const float precision, const float opacity, const unsigned int pattern, const bool init_hatch,
12573
 
                         const unsigned int W, const unsigned int H) {
12574
 
      typedef typename cimg::largest<T,float>::type ftype;
12575
 
      CImg<ftype> tangents;
 
18215
    template<typename tp, typename tc>
 
18216
      CImg<T>& _draw_spline(const tp& points,
 
18217
                            const tc *const color, const bool close_set,
 
18218
                            const float precision, const float opacity, const unsigned int pattern, const bool init_hatch,
 
18219
                            const unsigned int W, const unsigned int H) {
 
18220
      CImg<Tfloat> tangents;
12576
18221
      if (points && W>1 && H>1) {
12577
18222
        if (H==2) {
12578
18223
          tangents.assign(W,H);
12597
18242
              v = v0/n0 + v1/n1,
12598
18243
              n = 1e-8f + (float)std::sqrt(u*u+v*v),
12599
18244
              fact = 0.5f*(n0 + n1);
12600
 
            tangents(p,0) = (ftype)(fact*u/n);
12601
 
            tangents(p,1) = (ftype)(fact*v/n);
 
18245
            tangents(p,0) = (Tfloat)(fact*u/n);
 
18246
            tangents(p,1) = (Tfloat)(fact*v/n);
12602
18247
          }
12603
18248
        } else {
12604
18249
          tangents.assign(W,H);
12629
18274
              w = w0/n0 + w1/n1,
12630
18275
              n = 1e-8f + (float)std::sqrt(u*u+v*v+w*w),
12631
18276
              fact = 0.5f*(n0 + n1);
12632
 
            tangents(p,0) = (ftype)(fact*u/n);
12633
 
            tangents(p,1) = (ftype)(fact*v/n);
12634
 
            tangents(p,2) = (ftype)(fact*w/n);
 
18277
            tangents(p,0) = (Tfloat)(fact*u/n);
 
18278
            tangents(p,1) = (Tfloat)(fact*v/n);
 
18279
            tangents(p,2) = (Tfloat)(fact*w/n);
12635
18280
          }
12636
18281
        }
12637
18282
        _draw_spline(points,tangents,color,close_set,precision,opacity,pattern,init_hatch,W,H);
12640
18285
    }
12641
18286
 
12642
18287
    //! Draw a set of consecutive colored splines in the instance image.
12643
 
    template<typename tp, typename tt>
12644
 
      CImg& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
12645
 
                        const T *const color, const bool close_set=false,
12646
 
                        const float precision=4.0f, const float opacity=1.0f,
12647
 
                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 
18288
    template<typename tp, typename tt, typename tc>
 
18289
      CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
 
18290
                           const tc *const color, const bool close_set=false,
 
18291
                           const float precision=4.0f, const float opacity=1.0f,
 
18292
                           const unsigned int pattern=~0U, const bool init_hatch=true) {
12648
18293
      unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()),(unsigned int)(tangents[p].size()));
12649
18294
      return _draw_spline(points,tangents,color,close_set,precision,opacity,pattern,init_hatch,points.size,H);
12650
18295
    }
12651
18296
 
12652
18297
    //! Draw a set of consecutive colored splines in the instance image.
12653
 
    template<typename tp, typename tt>
12654
 
      CImg& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
12655
 
                        const T *const color, const bool close_set=false,
12656
 
                        const float precision=4.0f, const float opacity=1.0f,
12657
 
                        const unsigned int pattern=~0U, const bool init_hatch=true) {
 
18298
    template<typename tp, typename tt, typename tc>
 
18299
      CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
 
18300
                           const CImg<tc>& color, const bool close_set=false,
 
18301
                           const float precision=4.0f, const float opacity=1.0f,
 
18302
                           const unsigned int pattern=~0U, const bool init_hatch=true) {
 
18303
      return draw_spline(points,tangents,color.data,close_set,precision,opacity,pattern,init_hatch);
 
18304
    }
 
18305
 
 
18306
    //! Draw a set of consecutive colored splines in the instance image.
 
18307
    template<typename tp, typename tt, typename tc>
 
18308
      CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
 
18309
                           const tc *const color, const bool close_set=false,
 
18310
                           const float precision=4.0f, const float opacity=1.0f,
 
18311
                           const unsigned int pattern=~0U, const bool init_hatch=true) {
12658
18312
      return _draw_spline(points,tangents,color,close_set,precision,opacity,pattern,init_hatch,points.width,points.height);
12659
18313
    }
12660
18314
 
12661
18315
    //! Draw a set of consecutive colored splines in the instance image.
12662
 
    template<typename t> CImg& draw_spline(const CImgList<t>& points, const T *const color,
12663
 
                                           const bool close_set=false,
12664
 
                                           const float precision=4.0f, const float opacity=1.0f,
12665
 
                                           const unsigned int pattern=~0U, const bool init_hatch=true) {
 
18316
    template<typename tp, typename tt, typename tc>
 
18317
      CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
 
18318
                           const CImg<tc>& color, const bool close_set=false,
 
18319
                           const float precision=4.0f, const float opacity=1.0f,
 
18320
                           const unsigned int pattern=~0U, const bool init_hatch=true) {
 
18321
      return draw_spline(points,tangents,color.data,close_set,precision,opacity,pattern,init_hatch);
 
18322
    }
 
18323
 
 
18324
    //! Draw a set of consecutive colored splines in the instance image.
 
18325
    template<typename t, typename tc>
 
18326
      CImg<T>& draw_spline(const CImgList<t>& points, const tc *const color,
 
18327
                           const bool close_set=false, const float precision=4.0f, const float opacity=1.0f,
 
18328
                           const unsigned int pattern=~0U, const bool init_hatch=true) {
12666
18329
      unsigned int H = ~0U;
12667
18330
      cimglist_for(points,p) {
12668
18331
        const unsigned int s = points[p].size();
12671
18334
      return _draw_spline(points,color,close_set,precision,opacity,pattern,init_hatch,points.size,H);
12672
18335
    }
12673
18336
 
 
18337
    //! Draw a set of consecutive colored splines in the instance image.
 
18338
    template<typename t, typename tc>
 
18339
      CImg<T>& draw_spline(const CImgList<t>& points, CImg<tc>& color,
 
18340
                           const bool close_set=false, const float precision=4.0f, const float opacity=1.0f,
 
18341
                           const unsigned int pattern=~0U, const bool init_hatch=true) {
 
18342
      return draw_spline(points,color.data,close_set,precision,opacity,pattern,init_hatch);
 
18343
    }
 
18344
 
12674
18345
    //! Draw a set of consecutive colored lines in the instance image.
12675
 
    template<typename t> CImg& draw_spline(const CImg<t>& points, const T *const color,
12676
 
                                           const bool close_set=false, const float precision=4.0f, const float opacity=1.0f,
12677
 
                                           const unsigned int pattern=~0U, const bool init_hatch=true) {
 
18346
    template<typename t, typename tc>
 
18347
      CImg<T>& draw_spline(const CImg<t>& points, const tc *const color,
 
18348
                           const bool close_set=false, const float precision=4.0f, const float opacity=1.0f,
 
18349
                           const unsigned int pattern=~0U, const bool init_hatch=true) {
12678
18350
      return _draw_spline(points,color,close_set,precision,opacity,pattern,init_hatch,points.width,points.height);
12679
18351
    }
12680
18352
 
 
18353
    //! Draw a set of consecutive colored lines in the instance image.
 
18354
    template<typename t, typename tc>
 
18355
      CImg<T>& draw_spline(const CImg<t>& points, const CImg<tc>& color,
 
18356
                           const bool close_set=false, const float precision=4.0f, const float opacity=1.0f,
 
18357
                           const unsigned int pattern=~0U, const bool init_hatch=true) {
 
18358
      return draw_spline(points,color.data,close_set,precision,opacity,pattern,init_hatch);
 
18359
    }
 
18360
 
12681
18361
    //! Draw a colored arrow in the instance image.
12682
18362
    /**
12683
18363
       \param x0 X-coordinate of the starting arrow point (tail).
12692
18372
       \note
12693
18373
       - Clipping is supported.
12694
18374
    **/
12695
 
    CImg& draw_arrow(const int x0, const int y0, const int x1, const int y1,
12696
 
                     const T *const color,
12697
 
                     const float angle=30, const float length=-10,
12698
 
                     const float opacity=1.0f, const unsigned int pattern=~0U) {
 
18375
    template<typename tc>
 
18376
      CImg<T>& draw_arrow(const int x0, const int y0, const int x1, const int y1,
 
18377
                          const tc *const color,
 
18378
                          const float angle=30, const float length=-10,
 
18379
                          const float opacity=1.0f, const unsigned int pattern=~0U) {
12699
18380
      if (!is_empty()) {
12700
18381
        const float u = (float)(x0-x1), v = (float)(y0-y1), sq = u*u+v*v,
12701
 
          deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f,
 
18382
          deg = (float)(angle*cimg::valuePI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f,
12702
18383
          l = (length>=0)?length:-length*(float)std::sqrt(sq)/100;
12703
18384
        if (sq>0) {
12704
18385
          const double cl = std::cos(ang-deg), sl = std::sin(ang-deg), cr = std::cos(ang+deg), sr = std::sin(ang+deg);
12712
18393
      return *this;
12713
18394
    }
12714
18395
 
 
18396
    //! Draw a colored arrow in the instance image.
 
18397
    template<typename tc>
 
18398
      CImg<T>& draw_arrow(const int x0, const int y0, const int x1, const int y1,
 
18399
                          const CImg<tc>& color,
 
18400
                          const float angle=30, const float length=-10,
 
18401
                          const float opacity=1.0f, const unsigned int pattern=~0U) {
 
18402
      return draw_arrow(x0,y0,x1,y1,color.data,angle,length,opacity,pattern);
 
18403
    }
 
18404
 
12715
18405
    //! Draw a sprite image in the instance image.
12716
18406
    /**
12717
18407
       \param sprite Sprite image.
12723
18413
       \note
12724
18414
       - Clipping is supported.
12725
18415
    **/
12726
 
    template<typename t> CImg& draw_image(const CImg<t>& sprite,
12727
 
                                          const int x0=0, const int y0=0, const int z0=0, const int v0=0,
12728
 
                                          const float opacity=1.0f) {
 
18416
    template<typename t>
 
18417
      CImg<T>& draw_image(const CImg<t>& sprite,
 
18418
                          const int x0, const int y0=0, const int z0=0, const int v0=0,
 
18419
                          const float opacity=1.0f) {
12729
18420
      if (!is_empty()) {
12730
18421
        if (!sprite)
12731
18422
          throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
12732
18423
                                      pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
 
18424
        if (is_overlapping(sprite)) return draw_image(+sprite,x0,y0,z0,v0,opacity);
12733
18425
        const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
12734
18426
        const int
12735
18427
          lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
12737
18429
          lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
12738
18430
          lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
12739
18431
        const t
12740
 
          *ptrs = sprite.ptr() -
 
18432
          *ptrs = sprite.data -
12741
18433
          (bx?x0:0) -
12742
18434
          (by?y0*sprite.dimx():0) -
12743
18435
          (bz?z0*sprite.dimx()*sprite.dimy():0) -
12753
18445
            for (int z=0; z<lZ; ++z) {
12754
18446
              for (int y=0; y<lY; ++y) {
12755
18447
                if (opacity>=1) for (int x=0; x<lX; ++x) *(ptrd++) = (T)*(ptrs++);
12756
 
                else for (int x=0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ++ptrd; }
 
18448
                else for (int x=0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
12757
18449
                ptrd+=offX; ptrs+=soffX;
12758
18450
              }
12759
18451
              ptrd+=offY; ptrs+=soffY;
12765
18457
    }
12766
18458
 
12767
18459
#ifndef cimg_use_visualcpp6
12768
 
    CImg& draw_image(const CImg& sprite,
12769
 
                     const int x0=0, const int y0=0, const int z0=0, const int v0=0,
12770
 
                     const float opacity=1.0f) {
 
18460
    CImg<T>& draw_image(const CImg<T>& sprite,
 
18461
                        const int x0, const int y0=0, const int z0=0, const int v0=0,
 
18462
                        const float opacity=1.0f) {
12771
18463
      if (!is_empty()) {
12772
18464
        if (!sprite)
12773
18465
          throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
12774
18466
                                      pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
12775
 
        if (this==&sprite) return draw_image(CImg<T>(sprite),x0,y0,z0,v0,opacity);
 
18467
        if (is_overlapping(sprite)) return draw_image(+sprite,x0,y0,z0,v0,opacity);
12776
18468
        const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
12777
18469
        const int
12778
18470
          lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0),
12780
18472
          lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0),
12781
18473
          lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0);
12782
18474
        const T
12783
 
          *ptrs = sprite.ptr() -
 
18475
          *ptrs = sprite.data -
12784
18476
          (bx?x0:0) -
12785
18477
          (by?y0*sprite.dimx():0) -
12786
18478
          (bz?z0*sprite.dimx()*sprite.dimy():0) -
12797
18489
            for (int z=0; z<lZ; ++z) {
12798
18490
              if (opacity>=1) for (int y=0; y<lY; ++y) { std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; }
12799
18491
              else for (int y=0; y<lY; ++y) {
12800
 
                for (int x=0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ++ptrd; }
 
18492
                for (int x=0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
12801
18493
                ptrd+=offX; ptrs+=soffX;
12802
18494
              }
12803
18495
              ptrd+=offY; ptrs+=soffY;
12824
18516
       - Clipping is supported.
12825
18517
       - Dimensions along x,y and z of \p sprite and \p mask must be the same.
12826
18518
    **/
12827
 
    template<typename ti,typename tm> CImg& draw_image(const CImg<ti>& sprite, const CImg<tm>& mask,
12828
 
                                                       const int x0=0, const int y0=0, const int z0=0, const int v0=0,
12829
 
                                                       const float mask_valmax=1.0f, const float opacity=1.0f) {
 
18519
    template<typename ti, typename tm>
 
18520
      CImg<T>& draw_image(const CImg<ti>& sprite, const CImg<tm>& mask,
 
18521
                          const int x0, const int y0=0, const int z0=0, const int v0=0,
 
18522
                          const float mask_valmax=1.0f, const float opacity=1.0f) {
12830
18523
      if (!is_empty()) {
12831
18524
        if (!sprite)
12832
18525
          throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
12834
18527
        if (!mask)
12835
18528
          throw CImgArgumentException("CImg<%s>::draw_image() : Specified mask image (%u,%u,%u,%u,%p) is empty.",
12836
18529
                                      pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
12837
 
        if ((void*)this==(void*)&sprite) return draw_image(CImg<T>(sprite),mask,x0,y0,z0,v0);
12838
 
        if(mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
 
18530
        if (is_overlapping(sprite)) return draw_image(+sprite,mask,x0,y0,z0,v0,mask_valmax,opacity);
 
18531
        if (is_overlapping(mask))   return draw_image(sprite,+mask,x0,y0,z0,v0,mask_valmax,opacity);
 
18532
        if (mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
12839
18533
          throw CImgArgumentException("CImg<%s>::draw_image() : Mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)",
12840
18534
                                      pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim);
12841
18535
        const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0);
12847
18541
        const int
12848
18542
          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),
12849
18543
          ssize = mask.dimx()*mask.dimy()*mask.dimz();
12850
 
        const ti *ptrs = sprite.ptr() + coff;
12851
 
        const tm *ptrm = mask.ptr()   + coff;
 
18544
        const ti *ptrs = sprite.data + coff;
 
18545
        const tm *ptrm = mask.data   + coff;
12852
18546
        const unsigned int
12853
18547
          offX = width-lX,                soffX = sprite.width-lX,
12854
18548
          offY = width*(height-lY),       soffY = sprite.width*(sprite.height-lY),
12860
18554
            for (int z=0; z<lZ; ++z) {
12861
18555
              for (int y=0; y<lY; ++y) {
12862
18556
                for (int x=0; x<lX; ++x) {
12863
 
                  const float mopacity = *(ptrm++)*opacity,
 
18557
                  const float mopacity = (float)(*(ptrm++)*opacity),
12864
18558
                    nopacity = cimg::abs(mopacity), copacity = mask_valmax-cimg::max(mopacity,0.0f);
12865
 
                  *ptrd = (T)((nopacity*(*(ptrs++))+copacity*(*ptrd))/mask_valmax);
 
18559
                  *ptrd = (T)((nopacity*(*(ptrs++)) + *ptrd*copacity)/mask_valmax);
12866
18560
                  ++ptrd;
12867
18561
                }
12868
18562
                ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
12890
18584
       \note
12891
18585
       - Clipping is supported.
12892
18586
    **/
12893
 
    CImg& draw_rectangle(const int x0, const int y0, const int z0, const int v0,
12894
 
                         const int x1, const int y1, const int z1, const int v1,
12895
 
                         const T& val, const float opacity=1.0f) {
 
18587
    CImg<T>& draw_rectangle(const int x0, const int y0, const int z0, const int v0,
 
18588
                            const int x1, const int y1, const int z1, const int v1,
 
18589
                            const T val, const float opacity=1.0f) {
12896
18590
      if (!is_empty()) {
12897
18591
        const bool bx=(x0<x1), by=(y0<y1), bz=(z0<z1), bv=(v0<v1);
12898
18592
        const int nx0=bx?x0:x1, nx1=bx?x1:x0, ny0=by?y0:y1, ny1=by?y1:y0, nz0=bz?z0:z1, nz1=bz?z1:z0, nv0=bv?v0:v1, nv1=bv?v1:v0;
12911
18605
                if (opacity>=1) {
12912
18606
                  if (sizeof(T)!=1) { for (int x=0; x<lX; ++x) *(ptrd++) = val; ptrd+=offX; }
12913
18607
                  else { std::memset(ptrd,(int)val,lX); ptrd+=width; }
12914
 
                } else { for (int x=0; x<lX; ++x) { *ptrd = (T)(nopacity*val+copacity*(*ptrd)); ++ptrd; } ptrd+=offX; }
 
18608
                } else { for (int x=0; x<lX; ++x) { *ptrd = (T)(nopacity*val + *ptrd*copacity); ++ptrd; } ptrd+=offX; }
12915
18609
              }
12916
18610
              ptrd+=offY;
12917
18611
            }
12934
18628
       \note
12935
18629
       - Clipping is supported.
12936
18630
    **/
12937
 
    CImg& draw_rectangle(const int x0, const int y0, const int z0,
12938
 
                         const int x1, const int y1, const int z1,
12939
 
                         const T *const color, const float opacity=1.0f) {
 
18631
    template<typename tc>
 
18632
      CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 
18633
                              const int x1, const int y1, const int z1,
 
18634
                              const tc *const color, const float opacity=1.0f) {
12940
18635
      if (!color) throw CImgArgumentException("CImg<%s>::draw_rectangle : specified color is (null)",pixel_type());
12941
18636
      cimg_forV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity);
12942
18637
      return *this;
12943
18638
    }
12944
18639
 
 
18640
    //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1).
 
18641
    template<typename tc>
 
18642
      CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 
18643
                              const int x1, const int y1, const int z1,
 
18644
                              const CImg<tc>& color, const float opacity=1.0f) {
 
18645
      return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity);
 
18646
    }
 
18647
 
12945
18648
    //! Draw a 3D outlined colored rectangle in the instance image.
12946
 
    CImg& draw_rectangle(const int x0, const int y0, const int z0,
12947
 
                         const int x1, const int y1, const int z1,
12948
 
                         const T *const color, const float opacity, const unsigned int pattern) {
 
18649
    template<typename tc>
 
18650
      CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 
18651
                              const int x1, const int y1, const int z1,
 
18652
                              const tc *const color, const float opacity, const unsigned int pattern) {
12949
18653
      return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true).
12950
18654
        draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false).
12951
18655
        draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false).
12960
18664
        draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true);
12961
18665
    }
12962
18666
 
 
18667
    //! Draw a 3D outlined colored rectangle in the instance image.
 
18668
    template<typename tc>
 
18669
      CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
 
18670
                              const int x1, const int y1, const int z1,
 
18671
                              const CImg<tc>& color, const float opacity, const unsigned int pattern) {
 
18672
      return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern);
 
18673
    }
 
18674
 
12963
18675
    //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
12964
18676
    /**
12965
18677
       \param x0 X-coordinate of the upper-left rectangle corner.
12971
18683
       \note
12972
18684
       - Clipping is supported.
12973
18685
    **/
12974
 
    CImg& draw_rectangle(const int x0, const int y0, const int x1, const int y1,
12975
 
                         const T *const color, const float opacity=1.0f) {
 
18686
    template<typename tc>
 
18687
      CImg<T>& draw_rectangle(const int x0, const int y0, const int x1, const int y1,
 
18688
                              const tc *const color, const float opacity=1.0f) {
12976
18689
      return draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity);
12977
18690
    }
12978
18691
 
 
18692
    //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
 
18693
    template<typename tc>
 
18694
      CImg<T>& draw_rectangle(const int x0, const int y0, const int x1, const int y1,
 
18695
                              const CImg<tc>& color, const float opacity=1.0f) {
 
18696
      return draw_rectangle(x0,y0,x1,y1,color.data,opacity);
 
18697
    }
 
18698
 
12979
18699
    //! Draw a 2D outlined colored rectangle.
12980
 
    CImg& draw_rectangle(const int x0, const int y0, const int x1, const int y1,
12981
 
                         const T *const color, const float opacity, const unsigned int pattern) {
 
18700
    template<typename tc>
 
18701
      CImg<T>& draw_rectangle(const int x0, const int y0, const int x1, const int y1,
 
18702
                              const tc *const color, const float opacity, const unsigned int pattern) {
12982
18703
      return draw_line(x0,y0,x1,y0,color,opacity,pattern,true).
12983
18704
        draw_line(x1,y0,x1,y1,color,opacity,pattern,false).
12984
18705
        draw_line(x1,y1,x0,y1,color,opacity,pattern,false).
12985
18706
        draw_line(x0,y1,x0,y0,color,opacity,pattern,false);
12986
18707
    }
12987
18708
 
 
18709
    //! Draw a 2D outlined colored rectangle.
 
18710
    template<typename tc>
 
18711
      CImg<T>& draw_rectangle(const int x0, const int y0, const int x1, const int y1,
 
18712
                              const CImg<tc>& color, const float opacity, const unsigned int pattern) {
 
18713
      return draw_rectangle(x0,y0,x1,y1,color.data,opacity,pattern);
 
18714
    }
 
18715
 
 
18716
    // Inner macro for drawing triangles.
12988
18717
#define _cimg_for_triangle1(img,xl,xr,y,x0,y0,x1,y1,x2,y2) \
12989
18718
        for (int y = y0<0?0:y0, \
12990
18719
               xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
13277
19006
                _errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyl=_rlyn, lyl=ly1, \
13278
19007
                _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
13279
19008
 
13280
 
    // Draw a colored triangle (inner routine, uses bresenham's algorithm)
13281
 
    CImg& _draw_triangle(const int x0, const int y0,
13282
 
                         const int x1, const int y1,
13283
 
                         const int x2, const int y2,
13284
 
                         const T *const color,
13285
 
                         const float opacity,
13286
 
                         const float brightness) {
 
19009
    // Draw a colored triangle (inner routine, uses bresenham's algorithm).
 
19010
    template<typename tc>
 
19011
      CImg<T>& _draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2,
 
19012
                              const tc *const color, const float opacity, const float brightness) {
13287
19013
      _draw_scanline(color,opacity);
 
19014
      const float nbrightness = brightness<0?0:(brightness>2?2:brightness);
13288
19015
      int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
13289
19016
      if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
13290
19017
      if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);
13291
19018
      if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);
13292
19019
      if (ny0<dimy() && ny2>=0) {
13293
19020
        if ((nx1-nx0)*(ny2-ny0)-(nx2-nx0)*(ny1-ny0)<0)
13294
 
          _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xl,xr,y,color,opacity,brightness);
 
19021
          _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xl,xr,y,color,opacity,nbrightness);
13295
19022
        else
13296
 
          _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xr,xl,y,color,opacity,brightness);
 
19023
          _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xr,xl,y,color,opacity,nbrightness);
13297
19024
      }
13298
19025
      return *this;
13299
19026
    }
13300
19027
 
13301
19028
    //! Draw a 2D filled colored triangle in the instance image.
13302
 
    CImg& draw_triangle(const int x0, const int y0,
13303
 
                        const int x1, const int y1,
13304
 
                        const int x2, const int y2,
13305
 
                        const T *const color,
13306
 
                        const float opacity=1.0f) {
 
19029
    template<typename tc>
 
19030
      CImg<T>& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2,
 
19031
                             const tc *const color, const float opacity=1.0f) {
13307
19032
      if (!is_empty()) {
13308
19033
        if (!color) throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",pixel_type());
13309
19034
        _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1.0f);
13311
19036
      return *this;
13312
19037
    }
13313
19038
 
13314
 
    //! Draw a 2D outlined colored triangle
13315
 
    CImg& draw_triangle(const int x0, const int y0,
13316
 
                        const int x1, const int y1,
13317
 
                        const int x2, const int y2,
13318
 
                        const T *const color,
13319
 
                        const float opacity,
13320
 
                        const unsigned int pattern) {
 
19039
    //! Draw a 2D filled colored triangle in the instance image.
 
19040
    template<typename tc>
 
19041
      CImg<T>& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2,
 
19042
                             const CImg<tc>& color, const float opacity=1.0f) {
 
19043
      return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity);
 
19044
    }
 
19045
 
 
19046
    //! Draw a 2D outlined colored triangle.
 
19047
    template<typename tc>
 
19048
      CImg<T>& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2,
 
19049
                             const tc *const color, const float opacity, const unsigned int pattern) {
13321
19050
      if (!is_empty()) {
13322
19051
        if (!color) throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",pixel_type());
13323
19052
        draw_line(x0,y0,x1,y1,color,opacity,pattern,true).
13327
19056
      return *this;
13328
19057
    }
13329
19058
 
 
19059
    //! Draw a 2D outlined colored triangle.
 
19060
    template<typename tc>
 
19061
      CImg<T>& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2,
 
19062
                             const CImg<tc>& color, const float opacity, const unsigned int pattern) {
 
19063
      return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity,pattern);
 
19064
    }
 
19065
 
13330
19066
    //! Draw a 2D Gouraud-filled triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2).
13331
19067
    /**
13332
19068
       \param x0 = X-coordinate of the first corner in the instance image.
13336
19072
       \param x2 = X-coordinate of the third corner in the instance image.
13337
19073
       \param y2 = Y-coordinate of the third corner in the instance image.
13338
19074
       \param color = array of dimv() values of type \c T, defining the global drawing color.
13339
 
       \param c0 = brightness of the first corner.
13340
 
       \param c1 = brightness of the second corner.
13341
 
       \param c2 = brightness of the third corner.
 
19075
       \param brightness0 = brightness of the first corner (in [0,2]).
 
19076
       \param brightness1 = brightness of the second corner (in [0,2]).
 
19077
       \param brightness2 = brightness of the third corner (in [0,2]).
13342
19078
       \param opacity = opacity of the drawing.
13343
19079
       \note Clipping is supported.
13344
19080
    **/
13345
 
    CImg& draw_triangle(const int x0, const int y0,
13346
 
                        const int x1, const int y1,
13347
 
                        const int x2, const int y2,
13348
 
                        const T *const color,
13349
 
                        const float c0,
13350
 
                        const float c1,
13351
 
                        const float c2,
13352
 
                        const float opacity=1.0f) {
 
19081
    template<typename tc>
 
19082
      CImg<T>& draw_triangle(const int x0, const int y0,
 
19083
                             const int x1, const int y1,
 
19084
                             const int x2, const int y2,
 
19085
                             const tc *const color,
 
19086
                             const float brightness0,
 
19087
                             const float brightness1,
 
19088
                             const float brightness2,
 
19089
                             const float opacity=1.0f) {
13353
19090
      if (!is_empty()) {
13354
19091
        if (!color) throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",pixel_type());
13355
 
        static const T minval = cimg::type<T>::min(), maxval = cimg::type<T>::max();
 
19092
        static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
13356
19093
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
13357
19094
        const int whz = width*height*depth, offx = dim*whz-1;
13358
19095
        int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
13359
 
          nc0 = (int)(c0*256), nc1 = (int)(c1*256), nc2 = (int)(c2*256);
 
19096
          nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 
19097
          nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 
19098
          nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
13360
19099
        if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1);
13361
19100
        if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2);
13362
19101
        if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2);
13373
19112
            int errc = dx>>1;
13374
19113
            if (xleft<0 && dx) cleft-=xleft*(cright-cleft)/dx;
13375
19114
            if (xleft<0) xleft=0;
13376
 
            if (xright>=(int)width-1) xright=(int)width-1;
 
19115
            if (xright>=dimx()-1) xright=dimx()-1;
13377
19116
            T* ptrd = ptr(xleft,y,0,0);
13378
19117
            if (opacity>=1) for (int x=xleft; x<=xright; ++x) {
13379
 
              const T *col = color;
 
19118
              const tc *col = color;
13380
19119
              cimg_forV(*this,k) {
13381
 
                const float tval = (float)((cleft**(col++))/256);
13382
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13383
 
                *ptrd = val;
 
19120
                *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
13384
19121
                ptrd+=whz;
13385
19122
              }
13386
19123
              ptrd-=offx;
13387
19124
              cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
13388
19125
            } else for (int x=xleft; x<=xright; ++x) {
13389
 
              const T *col = color;
 
19126
              const tc *col = color;
13390
19127
              cimg_forV(*this,k) {
13391
 
                const float tval = (float)((cleft**(col++))/256);
13392
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13393
 
                *ptrd = (T)(nopacity*val+copacity*(*ptrd));
 
19128
                const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
 
19129
                *ptrd = (T)(nopacity*val + *ptrd*copacity);
13394
19130
                ptrd+=whz;
13395
19131
              }
13396
19132
              ptrd-=offx;
13402
19138
      return *this;
13403
19139
    }
13404
19140
 
 
19141
    //! Draw a 2D Gouraud-filled triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2).
 
19142
    template<typename tc>
 
19143
      CImg<T>& draw_triangle(const int x0, const int y0,
 
19144
                             const int x1, const int y1,
 
19145
                             const int x2, const int y2,
 
19146
                             const CImg<tc>& color,
 
19147
                             const float brightness0,
 
19148
                             const float brightness1,
 
19149
                             const float brightness2,
 
19150
                             const float opacity=1.0f) {
 
19151
      return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,brightness0,brightness1,brightness2,opacity);
 
19152
    }
 
19153
 
13405
19154
    //! Draw a 2D textured triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2).
13406
19155
    /**
13407
19156
       \param x0 = X-coordinate of the first corner in the instance image.
13418
19167
       \param tx2 = X-coordinate of the third corner in the texture image.
13419
19168
       \param ty2 = Y-coordinate of the third corner in the texture image.
13420
19169
       \param opacity = opacity of the drawing.
13421
 
       \param brightness = brightness of the drawing.
 
19170
       \param brightness = brightness of the drawing (in [0,2]).
13422
19171
       \note Clipping is supported, but texture coordinates do not support clipping.
13423
19172
    **/
13424
 
    template<typename t> CImg& draw_triangle(const int x0, const int y0,
13425
 
                                             const int x1, const int y1,
13426
 
                                             const int x2, const int y2,
13427
 
                                             const CImg<t>& texture,
13428
 
                                             const int tx0, const int ty0,
13429
 
                                             const int tx1, const int ty1,
13430
 
                                             const int tx2, const int ty2,
13431
 
                                             const float opacity=1.0f,
13432
 
                                             const float brightness=1.0f) {
 
19173
    template<typename t> CImg<T>& draw_triangle(const int x0, const int y0,
 
19174
                                                const int x1, const int y1,
 
19175
                                                const int x2, const int y2,
 
19176
                                                const CImg<t>& texture,
 
19177
                                                const int tx0, const int ty0,
 
19178
                                                const int tx1, const int ty1,
 
19179
                                                const int tx2, const int ty2,
 
19180
                                                const float opacity=1.0f,
 
19181
                                                const float brightness=1.0f) {
13433
19182
      if (!is_empty()) {
13434
 
        if (!texture) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.",
13435
 
                                                  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
13436
 
        static const T minval = cimg::type<T>::min(), maxval = cimg::type<T>::max();
13437
 
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
 
19183
        if (!texture || texture.dim<dim) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 
19184
                                                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 
19185
        if (is_overlapping(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
 
19186
        static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<t>::max());
 
19187
        const float
 
19188
          nopacity = cimg::abs(opacity),
 
19189
          copacity = 1-cimg::max(opacity,0.0f),
 
19190
          nbrightness = brightness<0?0:(brightness>2?2:brightness);
13438
19191
        const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
13439
19192
        int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
13440
19193
          ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2;
13465
19218
              tyleft-=xleft*(tyright-tyleft)/dx;
13466
19219
            }
13467
19220
            if (xleft<0) xleft=0;
13468
 
            if (xright>=(int)width-1) xright=(int)width-1;
 
19221
            if (xright>=dimx()-1) xright=dimx()-1;
13469
19222
            T* ptrd = ptr(xleft,y,0,0);
13470
19223
            if (opacity>=1) {
13471
 
              if (brightness<=1) for (int x=xleft; x<=xright; ++x) {
13472
 
                const t *col = texture.ptr(txleft,tyleft);
13473
 
                cimg_forV(*this,k) {
13474
 
                  *ptrd = (T)(brightness**col);
 
19224
              if (nbrightness==1) for (int x=xleft; x<=xright; ++x) {
 
19225
                const t *col = texture.ptr(txleft,tyleft);
 
19226
                cimg_forV(*this,k) {
 
19227
                  *ptrd = (T)*col;
 
19228
                  ptrd+=whz; col+=twhz;
 
19229
                }
 
19230
                ptrd-=offx;
 
19231
                txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 
19232
                tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 
19233
              } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) {
 
19234
                const t *col = texture.ptr(txleft,tyleft);
 
19235
                cimg_forV(*this,k) {
 
19236
                  *ptrd = (T)(nbrightness**col);
13475
19237
                  ptrd+=whz; col+=twhz;
13476
19238
                }
13477
19239
                ptrd-=offx;
13480
19242
              } else for (int x=xleft; x<=xright; ++x) {
13481
19243
                const t *col = texture.ptr(txleft,tyleft);
13482
19244
                cimg_forV(*this,k) {
13483
 
                  const float tval = (float)(brightness**col);
13484
 
                  const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13485
 
                  *ptrd = val;
 
19245
                  *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
13486
19246
                  ptrd+=whz; col+=twhz;
13487
19247
                }
13488
19248
                ptrd-=offx;
13490
19250
                tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
13491
19251
              }
13492
19252
            } else {
13493
 
              if (brightness<=1) for (int x=xleft; x<=xright; ++x) {
13494
 
                const t *col = texture.ptr(txleft,tyleft);
13495
 
                cimg_forV(*this,k) {
13496
 
                  *ptrd = (T)(nopacity*brightness**col+copacity*(*ptrd));
 
19253
              if (nbrightness==1) for (int x=xleft; x<=xright; ++x) {
 
19254
                const t *col = texture.ptr(txleft,tyleft);
 
19255
                cimg_forV(*this,k) {
 
19256
                  *ptrd = (T)(nopacity**col + *ptrd*copacity);
 
19257
                  ptrd+=whz; col+=twhz;
 
19258
                }
 
19259
                ptrd-=offx;
 
19260
                txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
 
19261
                tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
 
19262
              } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) {
 
19263
                const t *col = texture.ptr(txleft,tyleft);
 
19264
                cimg_forV(*this,k) {
 
19265
                  *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
13497
19266
                  ptrd+=whz; col+=twhz;
13498
19267
                }
13499
19268
                ptrd-=offx;
13502
19271
              } else for (int x=xleft; x<=xright; ++x) {
13503
19272
                const t *col = texture.ptr(txleft,tyleft);
13504
19273
                cimg_forV(*this,k) {
13505
 
                  const float tval = (float)(brightness**col);
13506
 
                  const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13507
 
                  *ptrd = (T)(nopacity*val+copacity*(*ptrd));
 
19274
                  const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
 
19275
                  *ptrd = (T)(nopacity*val + *ptrd*copacity);
13508
19276
                  ptrd+=whz; col+=twhz;
13509
19277
                }
13510
19278
                ptrd-=offx;
13519
19287
    }
13520
19288
 
13521
19289
    //! Draw a textured triangle with perspective correction.
13522
 
    template<typename t> CImg& draw_triangle(const int x0, const int y0, const float z0,
13523
 
                                             const int x1, const int y1, const float z1,
13524
 
                                             const int x2, const int y2, const float z2,
13525
 
                                             const CImg<t>& texture,
13526
 
                                             const int tx0, const int ty0,
13527
 
                                             const int tx1, const int ty1,
13528
 
                                             const int tx2, const int ty2,
13529
 
                                             const float opacity=1.0f,
13530
 
                                             const float brightness=1.0f) {
 
19290
    template<typename t> CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
 
19291
                                                const int x1, const int y1, const float z1,
 
19292
                                                const int x2, const int y2, const float z2,
 
19293
                                                const CImg<t>& texture,
 
19294
                                                const int tx0, const int ty0,
 
19295
                                                const int tx1, const int ty1,
 
19296
                                                const int tx2, const int ty2,
 
19297
                                                const float opacity=1.0f,
 
19298
                                                const float brightness=1.0f) {
13531
19299
      if (!is_empty() && z0>0 && z1>0 && z2>0) {
13532
 
        if (!texture) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.",
13533
 
                                                  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
13534
 
        static const T minval = cimg::type<T>::min(), maxval = cimg::type<T>::max();
13535
 
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
 
19300
        if (!texture || texture.dim<dim) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 
19301
                                                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 
19302
        if (is_overlapping(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
 
19303
        static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<t>::max());
 
19304
        const float
 
19305
          nopacity = cimg::abs(opacity),
 
19306
          copacity = 1-cimg::max(opacity,0.0f),
 
19307
          nbrightness = brightness<0?0:(brightness>2?2:brightness);
13536
19308
        const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
13537
19309
        int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
13538
19310
        float
13579
19351
              tyleft-=xleft*(tyright-tyleft)/dx;
13580
19352
            }
13581
19353
            if (xleft<0) xleft=0;
13582
 
            if (xright>=(int)width-1) xright=(int)width-1;
 
19354
            if (xright>=dimx()-1) xright=dimx()-1;
13583
19355
            T* ptrd = ptr(xleft,y,0,0);
13584
19356
            if (opacity>=1) {
13585
 
              if (brightness<=1) for (int x=xleft; x<=xright; ++x) {
13586
 
                const float invz = 1.0f/zleft;
13587
 
                const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
13588
 
                cimg_forV(*this,k) {
13589
 
                  *ptrd = (T)(brightness**col);
 
19357
              if (nbrightness==1) for (int x=xleft; x<=xright; ++x) {
 
19358
                const float invz = 1.0f/zleft;
 
19359
                const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 
19360
                cimg_forV(*this,k) {
 
19361
                  *ptrd = (T)*col;
 
19362
                  ptrd+=whz; col+=twhz;
 
19363
                }
 
19364
                ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 
19365
              } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) {
 
19366
                const float invz = 1.0f/zleft;
 
19367
                const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 
19368
                cimg_forV(*this,k) {
 
19369
                  *ptrd = (T)(nbrightness**col);
13590
19370
                  ptrd+=whz; col+=twhz;
13591
19371
                }
13592
19372
                ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
13594
19374
                const float invz = 1.0f/zleft;
13595
19375
                const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
13596
19376
                cimg_forV(*this,k) {
13597
 
                  const float tval = (float)(brightness**col);
13598
 
                  const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13599
 
                  *ptrd = val;
 
19377
                  *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
13600
19378
                  ptrd+=whz; col+=twhz;
13601
19379
                }
13602
19380
                ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
13603
19381
              }
13604
19382
            } else {
13605
 
              if (brightness<=1) for (int x=xleft; x<=xright; ++x) {
13606
 
                const float invz = 1.0f/zleft;
13607
 
                const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
13608
 
                cimg_forV(*this,k) {
13609
 
                  *ptrd = (T)(nopacity*brightness**col+copacity*(*ptrd));
 
19383
              if (nbrightness==1) for (int x=xleft; x<=xright; ++x) {
 
19384
                const float invz = 1.0f/zleft;
 
19385
                const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 
19386
                cimg_forV(*this,k) {
 
19387
                  *ptrd = (T)(nopacity**col + *ptrd*copacity);
 
19388
                  ptrd+=whz; col+=twhz;
 
19389
                }
 
19390
                ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
 
19391
              } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) {
 
19392
                const float invz = 1.0f/zleft;
 
19393
                const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
 
19394
                cimg_forV(*this,k) {
 
19395
                  *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
13610
19396
                  ptrd+=whz; col+=twhz;
13611
19397
                }
13612
19398
                ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
13614
19400
                const float invz = 1.0f/zleft;
13615
19401
                const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
13616
19402
                cimg_forV(*this,k) {
13617
 
                  const float tval = (float)(brightness**col);
13618
 
                  const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13619
 
                  *ptrd = (T)(nopacity*val+copacity*(*ptrd));
 
19403
                  const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
 
19404
                  *ptrd = (T)(nopacity*val + *ptrd*copacity);
13620
19405
                  ptrd+=whz; col+=twhz;
13621
19406
                }
13622
19407
                ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
13648
19433
       \param opacity = opacity of the drawing.
13649
19434
       \note Clipping is supported, but texture coordinates do not support clipping.
13650
19435
    **/
13651
 
    template<typename t> CImg& draw_triangle(const int x0, const int y0,
13652
 
                                             const int x1, const int y1,
13653
 
                                             const int x2, const int y2,
13654
 
                                             const T *const color,
13655
 
                                             const CImg<t>& light,
13656
 
                                             const int lx0, const int ly0,
13657
 
                                             const int lx1, const int ly1,
13658
 
                                             const int lx2, const int ly2,
13659
 
                                             const float opacity=1.0f) {
 
19436
    template<typename tc, typename t>
 
19437
      CImg<T>& draw_triangle(const int x0, const int y0,
 
19438
                             const int x1, const int y1,
 
19439
                             const int x2, const int y2,
 
19440
                             const tc *const color,
 
19441
                             const CImg<t>& light,
 
19442
                             const int lx0, const int ly0,
 
19443
                             const int lx1, const int ly1,
 
19444
                             const int lx2, const int ly2,
 
19445
                             const float opacity=1.0f) {
13660
19446
      if (!is_empty()) {
13661
19447
        if (!color) throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",pixel_type());
13662
19448
        if (!light) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
13663
19449
                                                pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
13664
 
        static const T minval = cimg::type<T>::min(), maxval = cimg::type<T>::max();
 
19450
        if (is_overlapping(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,color,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 
19451
        static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
13665
19452
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
13666
19453
        int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
13667
19454
          nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
13693
19480
              lyleft-=xleft*(lyright-lyleft)/dx;
13694
19481
            }
13695
19482
            if (xleft<0) xleft=0;
13696
 
            if (xright>=(int)width-1) xright=(int)width-1;
 
19483
            if (xright>=dimx()-1) xright=dimx()-1;
13697
19484
            T* ptrd = ptr(xleft,y,0,0);
13698
19485
            if (opacity>=1) for (int x=xleft; x<=xright; ++x) {
13699
 
              const t lightness = light(lxleft,lyleft);
13700
 
              const T *col = color;
 
19486
              const t l = light(lxleft,lyleft);
 
19487
              const tc *col = color;
13701
19488
              cimg_forV(*this,k) {
13702
 
                const float tval = (float)(*(col++)*lightness);
13703
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13704
 
                *ptrd = val;
 
19489
                *ptrd = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
13705
19490
                ptrd+=whz;
13706
19491
              }
13707
19492
              ptrd-=offx;
13708
19493
              lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
13709
19494
              lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
13710
19495
            } else  for (int x=xleft; x<=xright; ++x) {
13711
 
              const t lightness = light(lxleft,lyleft);
13712
 
              const T *col = color;
 
19496
              const t l = light(lxleft,lyleft);
 
19497
              const tc *col = color;
13713
19498
              cimg_forV(*this,k) {
13714
 
                const float tval = (float)(*(col++)*lightness);
13715
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13716
 
                *ptrd = (T)(nopacity*val+copacity*(*ptrd));
 
19499
                const T val = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
 
19500
                *ptrd = (T)(nopacity*val + *ptrd*copacity);
13717
19501
                ptrd+=whz;
13718
19502
              }
13719
19503
              ptrd-=offx;
13726
19510
      return *this;
13727
19511
    }
13728
19512
 
 
19513
    //! Draw a 2D phong-shaded triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2).
 
19514
    template<typename tc, typename t>
 
19515
      CImg<T>& draw_triangle(const int x0, const int y0,
 
19516
                             const int x1, const int y1,
 
19517
                             const int x2, const int y2,
 
19518
                             const CImg<tc>& color,
 
19519
                             const CImg<t>& light,
 
19520
                             const int lx0, const int ly0,
 
19521
                             const int lx1, const int ly1,
 
19522
                             const int lx2, const int ly2,
 
19523
                             const float opacity=1.0f) {
 
19524
      return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
 
19525
    }
 
19526
 
13729
19527
    //! Draw a 2D textured triangle with Gouraud-Shading in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2).
13730
19528
    /**
13731
19529
       \param x0 = X-coordinate of the first corner in the instance image.
13741
19539
       \param ty1 = Y-coordinate of the second corner in the texture image.
13742
19540
       \param tx2 = X-coordinate of the third corner in the texture image.
13743
19541
       \param ty2 = Y-coordinate of the third corner in the texture image.
13744
 
       \param c0 = brightness value of the first corner.
13745
 
       \param c1 = brightness value of the second corner.
13746
 
       \param c2 = brightness value of the third corner.
 
19542
       \param brightness0 = brightness value of the first corner.
 
19543
       \param brightness1 = brightness value of the second corner.
 
19544
       \param brightness2 = brightness value of the third corner.
13747
19545
       \param opacity = opacity of the drawing.
13748
19546
       \note Clipping is supported, but texture coordinates do not support clipping.
13749
19547
    **/
13750
 
    template<typename t> CImg& draw_triangle(const int x0, const int y0,
13751
 
                                             const int x1, const int y1,
13752
 
                                             const int x2, const int y2,
13753
 
                                             const CImg<t>& texture,
13754
 
                                             const int tx0, const int ty0,
13755
 
                                             const int tx1, const int ty1,
13756
 
                                             const int tx2, const int ty2,
13757
 
                                             const float c0,
13758
 
                                             const float c1,
13759
 
                                             const float c2,
13760
 
                                             const float opacity=1) {
 
19548
    template<typename t> CImg<T>& draw_triangle(const int x0, const int y0,
 
19549
                                                const int x1, const int y1,
 
19550
                                                const int x2, const int y2,
 
19551
                                                const CImg<t>& texture,
 
19552
                                                const int tx0, const int ty0,
 
19553
                                                const int tx1, const int ty1,
 
19554
                                                const int tx2, const int ty2,
 
19555
                                                const float brightness0,
 
19556
                                                const float brightness1,
 
19557
                                                const float brightness2,
 
19558
                                                const float opacity=1) {
13761
19559
      if (!is_empty()) {
13762
 
        if (!texture) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.",
 
19560
        if (!texture || texture.dim<dim) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
13763
19561
                                                  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
13764
 
        static const T minval = cimg::type<T>::min(), maxval = cimg::type<T>::max();
 
19562
        if (is_overlapping(texture))
 
19563
          return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,brightness0,brightness1,brightness2,opacity);
 
19564
        static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<t>::max());
13765
19565
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
13766
19566
        const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
13767
19567
        int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
13768
19568
          ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
13769
 
          nc0 = (int)(c0*256), nc1 = (int)(c1*256), nc2 = (int)(c2*256);
 
19569
          nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
 
19570
          nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
 
19571
          nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
13770
19572
        if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1);
13771
19573
        if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2);
13772
19574
        if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2);
13800
19602
              tyleft-=xleft*(tyright-tyleft)/dx;
13801
19603
            }
13802
19604
            if (xleft<0) xleft=0;
13803
 
            if (xright>=(int)width-1) xright=(int)width-1;
 
19605
            if (xright>=dimx()-1) xright=dimx()-1;
13804
19606
            T* ptrd = ptr(xleft,y,0,0);
13805
19607
            if (opacity>=1) for (int x=xleft; x<=xright; ++x) {
13806
19608
              const t *col = texture.ptr(txleft,tyleft);
13807
19609
              cimg_forV(*this,k) {
13808
 
                const float tval = (float)(cleft**col/256);
13809
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13810
 
                *ptrd = (T)val;
 
19610
                *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
13811
19611
                ptrd+=whz; col+=twhz;
13812
19612
              }
13813
19613
              ptrd-=offx;
13817
19617
            } else for (int x=xleft; x<=xright; ++x) {
13818
19618
              const t *col = texture.ptr(txleft,tyleft);
13819
19619
              cimg_forV(*this,k) {
13820
 
                const float tval = (float)(cleft**col/256);
13821
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13822
 
                *ptrd = (T)(nopacity*val+copacity*(*ptrd));
 
19620
                const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 
19621
                *ptrd = (T)(nopacity*val + *ptrd*copacity);
13823
19622
                ptrd+=whz; col+=twhz;
13824
19623
              }
13825
19624
              ptrd-=offx;
13834
19633
    }
13835
19634
 
13836
19635
    //! Draw a gouraud + textured triangle with perspective correction.
13837
 
    template<typename t> CImg& draw_triangle(const int x0, const int y0, const float z0,
13838
 
                                             const int x1, const int y1, const float z1,
13839
 
                                             const int x2, const int y2, const float z2,
13840
 
                                             const CImg<t>& texture,
13841
 
                                             const int tx0, const int ty0,
13842
 
                                             const int tx1, const int ty1,
13843
 
                                             const int tx2, const int ty2,
13844
 
                                             const float c0,
13845
 
                                             const float c1,
13846
 
                                             const float c2,
13847
 
                                             const float opacity=1.0f) {
 
19636
    template<typename t> CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
 
19637
                                                const int x1, const int y1, const float z1,
 
19638
                                                const int x2, const int y2, const float z2,
 
19639
                                                const CImg<t>& texture,
 
19640
                                                const int tx0, const int ty0,
 
19641
                                                const int tx1, const int ty1,
 
19642
                                                const int tx2, const int ty2,
 
19643
                                                const float c0,
 
19644
                                                const float c1,
 
19645
                                                const float c2,
 
19646
                                                const float opacity=1.0f) {
13848
19647
      if (!is_empty() && z0>0 && z1>0 && z2>0) {
13849
 
        if (!texture) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.",
13850
 
                                                  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
13851
 
        static const T minval = cimg::type<T>::min(), maxval = cimg::type<T>::max();
 
19648
        if (!texture || texture.dim<dim) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 
19649
                                                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 
19650
        if (is_overlapping(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,c0,c1,c2,opacity);
 
19651
        static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<t>::max());
13852
19652
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
13853
19653
        const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
13854
19654
        int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
13906
19706
              tyleft-=xleft*(tyright-tyleft)/dx;
13907
19707
            }
13908
19708
            if (xleft<0) xleft=0;
13909
 
            if (xright>=(int)width-1) xright=(int)width-1;
 
19709
            if (xright>=dimx()-1) xright=dimx()-1;
13910
19710
            T* ptrd = ptr(xleft,y,0,0);
13911
19711
            if (opacity>=1) for (int x=xleft; x<=xright; ++x) {
13912
19712
              const float invz = 1.0f/zleft;
13913
19713
              const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
13914
19714
              cimg_forV(*this,k) {
13915
 
                const float tval = (float)(cleft**col/256);
13916
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13917
 
                *ptrd = val;
 
19715
                *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
13918
19716
                ptrd+=whz; col+=twhz;
13919
19717
              }
13920
19718
              ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
13923
19721
              const float invz = 1.0f/zleft;
13924
19722
              const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
13925
19723
              cimg_forV(*this,k) {
13926
 
                const float tval = (float)(cleft**col/256);
13927
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
13928
 
                *ptrd = (T)(nopacity*val+copacity*(*ptrd));
 
19724
                const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
 
19725
                *ptrd = (T)(nopacity*val + *ptrd*copacity);
13929
19726
                ptrd+=whz; col+=twhz;
13930
19727
              }
13931
19728
              ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
13963
19760
       \param opacity = opacity of the drawing.
13964
19761
       \note Clipping is supported, but texture coordinates do not support clipping.
13965
19762
    **/
13966
 
    template<typename t, typename tl> CImg& draw_triangle(const int x0, const int y0,
13967
 
                                                          const int x1, const int y1,
13968
 
                                                          const int x2, const int y2,
13969
 
                                                          const CImg<t>& texture,
13970
 
                                                          const int tx0, const int ty0,
13971
 
                                                          const int tx1, const int ty1,
13972
 
                                                          const int tx2, const int ty2,
13973
 
                                                          const CImg<tl>& light,
13974
 
                                                          const int lx0, const int ly0,
13975
 
                                                          const int lx1, const int ly1,
13976
 
                                                          const int lx2, const int ly2,
13977
 
                                                          const float opacity=1.0f) {
 
19763
    template<typename t, typename tl> CImg<T>& draw_triangle(const int x0, const int y0,
 
19764
                                                             const int x1, const int y1,
 
19765
                                                             const int x2, const int y2,
 
19766
                                                             const CImg<t>& texture,
 
19767
                                                             const int tx0, const int ty0,
 
19768
                                                             const int tx1, const int ty1,
 
19769
                                                             const int tx2, const int ty2,
 
19770
                                                             const CImg<tl>& light,
 
19771
                                                             const int lx0, const int ly0,
 
19772
                                                             const int lx1, const int ly1,
 
19773
                                                             const int lx2, const int ly2,
 
19774
                                                             const float opacity=1.0f) {
13978
19775
      if (!is_empty()) {
13979
 
        if (!texture) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.",
13980
 
                                                  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
13981
 
        static const T minval = cimg::type<T>::min(), maxval = cimg::type<T>::max();
 
19776
        if (!texture || texture.dim<dim) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 
19777
                                                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 
19778
        if (!light) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 
19779
                                                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 
19780
        if (is_overlapping(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);
 
19781
        if (is_overlapping(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);
 
19782
        static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<t>::max());
13982
19783
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
13983
19784
        const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
13984
19785
        int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
14023
19824
              tyleft-=xleft*(tyright-tyleft)/dx;
14024
19825
            }
14025
19826
            if (xleft<0) xleft=0;
14026
 
            if (xright>=(int)width-1) xright=(int)width-1;
 
19827
            if (xright>=dimx()-1) xright=dimx()-1;
14027
19828
            T* ptrd = ptr(xleft,y,0,0);
14028
19829
            if (opacity>=1) for (int x=xleft; x<=xright; ++x) {
14029
 
              const tl lightness = light(lxleft,lyleft);
 
19830
              const tl l = light(lxleft,lyleft);
14030
19831
              const t *col = texture.ptr(txleft,tyleft);
14031
19832
              cimg_forV(*this,k) {
14032
 
                const float tval = (float)(lightness**col);
14033
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
14034
 
                *ptrd = (T)val;
 
19833
                *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
14035
19834
                ptrd+=whz; col+=twhz;
14036
19835
              }
14037
19836
              ptrd-=offx;
14040
19839
              txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
14041
19840
              tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
14042
19841
            } else for (int x=xleft; x<=xright; ++x) {
14043
 
              const tl lightness = light(lxleft,lyleft);
 
19842
              const tl l = light(lxleft,lyleft);
14044
19843
              const t *col = texture.ptr(txleft,tyleft);
14045
19844
              cimg_forV(*this,k) {
14046
 
                const float tval = (float)(lightness**col);
14047
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
14048
 
                *ptrd = (T)(nopacity*val+copacity*(*ptrd));
 
19845
                const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 
19846
                *ptrd = (T)(nopacity*val + *ptrd*copacity);
14049
19847
                ptrd+=whz; col+=twhz;
14050
19848
              }
14051
19849
              ptrd-=offx;
14061
19859
    }
14062
19860
 
14063
19861
    //! Draw a phong + textured triangle with perspective correction.
14064
 
    template<typename t, typename tl> CImg& draw_triangle(const int x0, const int y0, const float z0,
14065
 
                                                          const int x1, const int y1, const float z1,
14066
 
                                                          const int x2, const int y2, const float z2,
14067
 
                                                          const CImg<t>& texture,
14068
 
                                                          const int tx0, const int ty0,
14069
 
                                                          const int tx1, const int ty1,
14070
 
                                                          const int tx2, const int ty2,
14071
 
                                                          const CImg<tl>& light,
14072
 
                                                          const int lx0, const int ly0,
14073
 
                                                          const int lx1, const int ly1,
14074
 
                                                          const int lx2, const int ly2,
14075
 
                                                          const float opacity=1.0f) {
 
19862
    template<typename t, typename tl> CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
 
19863
                                                             const int x1, const int y1, const float z1,
 
19864
                                                             const int x2, const int y2, const float z2,
 
19865
                                                             const CImg<t>& texture,
 
19866
                                                             const int tx0, const int ty0,
 
19867
                                                             const int tx1, const int ty1,
 
19868
                                                             const int tx2, const int ty2,
 
19869
                                                             const CImg<tl>& light,
 
19870
                                                             const int lx0, const int ly0,
 
19871
                                                             const int lx1, const int ly1,
 
19872
                                                             const int lx2, const int ly2,
 
19873
                                                             const float opacity=1.0f) {
14076
19874
      if (!is_empty() && z0>0 && z1>0 && z2>0) {
14077
 
        if (!texture) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.",
14078
 
                                                  pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
14079
 
        static const T minval = cimg::type<T>::min(), maxval = cimg::type<T>::max();
 
19875
        if (!texture || texture.dim<dim) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
 
19876
                                                                     pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
 
19877
        if (!light) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
 
19878
                                                                     pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
 
19879
        if (is_overlapping(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);
 
19880
        if (is_overlapping(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);
 
19881
        static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<t>::max());
14080
19882
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
14081
19883
        const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
14082
19884
        int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
14141
19943
              tyleft-=xleft*(tyright-tyleft)/dx;
14142
19944
            }
14143
19945
            if (xleft<0) xleft=0;
14144
 
            if (xright>=(int)width-1) xright=(int)width-1;
 
19946
            if (xright>=dimx()-1) xright=dimx()-1;
14145
19947
            T* ptrd = ptr(xleft,y,0,0);
14146
19948
            if (opacity>=1) for (int x=xleft; x<=xright; ++x) {
14147
19949
              const float invz = 1.0f/zleft;
14148
 
              const tl lightness = light(lxleft,lyleft);
 
19950
              const tl l = light(lxleft,lyleft);
14149
19951
              const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
14150
19952
              cimg_forV(*this,k) {
14151
 
                const float tval = (float)(lightness**col);
14152
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
14153
 
                *ptrd = val;
 
19953
                *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
14154
19954
                ptrd+=whz; col+=twhz;
14155
19955
              }
14156
19956
              ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
14158
19958
              lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
14159
19959
            } else for (int x=xleft; x<=xright; ++x) {
14160
19960
              const float invz = 1.0f/zleft;
14161
 
              const tl lightness = light(lxleft,lyleft);
 
19961
              const tl l = light(lxleft,lyleft);
14162
19962
              const t *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
14163
19963
              cimg_forV(*this,k) {
14164
 
                const float tval = (float)(lightness**col);
14165
 
                const T val = tval<(float)maxval?(tval>(float)minval?(T)tval:minval):maxval;
14166
 
                *ptrd = (T)(nopacity*val+copacity*(*ptrd));
 
19964
                const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
 
19965
                *ptrd = (T)(nopacity*val + *ptrd*copacity);
14167
19966
                ptrd+=whz; col+=twhz;
14168
19967
              }
14169
19968
              ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
14178
19977
    }
14179
19978
 
14180
19979
    // Draw an ellipse on the instance image (inner routine).
14181
 
    CImg& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
14182
 
                        const T *const color, const float opacity, const unsigned int pattern) {
 
19980
    template<typename tc>
 
19981
      CImg<T>& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 
19982
                             const tc *const color, const float opacity, const unsigned int pattern) {
14183
19983
      if (!is_empty()) {
14184
19984
        if (!color) throw CImgArgumentException("CImg<%s>::draw_ellipse : Specified color is (null).",pixel_type());
14185
19985
        _draw_scanline(color,opacity);
14199
19999
          tymin = y0-yb,
14200
20000
          tymax = y0+yb,
14201
20001
          ymin = tymin<0?0:tymin,
14202
 
          ymax = tymax>=(int)height?height-1:tymax;
 
20002
          ymax = tymax>=dimy()?height-1:tymax;
14203
20003
        int oxmin = 0, oxmax = 0;
14204
20004
        bool first_line = true;
14205
20005
        for (int y=ymin; y<=ymax; ++y) {
14231
20031
      return *this;
14232
20032
    }
14233
20033
 
14234
 
    //! Draw an outlined ellipse.
14235
 
    /**
14236
 
       \param x0 = X-coordinate of the ellipse center.
14237
 
       \param y0 = Y-coordinate of the ellipse center.
14238
 
       \param r1 = First radius of the ellipse.
14239
 
       \param r2 = Second radius of the ellipse.
14240
 
       \param ru = X-coordinate of the orientation vector related to the first radius.
14241
 
       \param rv = Y-coordinate of the orientation vector related to the first radius.
14242
 
       \param color = array of dimv() values of type \c T, defining the drawing color.
14243
 
       \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
14244
 
       \param opacity = opacity of the drawing.
14245
 
    **/
14246
 
    CImg& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
14247
 
                       const T *const color, const float opacity, const unsigned int pattern) {
14248
 
      if (pattern) _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,pattern);
14249
 
      return *this;
14250
 
   }
14251
 
 
14252
20034
    //! Draw a filled ellipse.
14253
20035
    /**
14254
20036
       \param x0 = X-coordinate of the ellipse center.
14260
20042
       \param color = array of dimv() values of type \c T, defining the drawing color.
14261
20043
       \param opacity = opacity of the drawing.
14262
20044
    **/
14263
 
    CImg& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
14264
 
                       const T *const color, const float opacity=1.0f) {
 
20045
    template<typename tc>
 
20046
      CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 
20047
                            const tc *const color, const float opacity=1.0f) {
14265
20048
      return _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,0U);
14266
20049
    }
14267
20050
 
14268
 
    //! Draw a filled ellipse on the instance image
 
20051
    //! Draw a filled ellipse.
 
20052
    template<typename tc>
 
20053
      CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 
20054
                            const CImg<tc>& color, const float opacity=1.0f) {
 
20055
      return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity);
 
20056
    }
 
20057
 
 
20058
    //! Draw a filled ellipse.
14269
20059
    /**
14270
20060
       \param x0 = X-coordinate of the ellipse center.
14271
20061
       \param y0 = Y-coordinate of the ellipse center.
14273
20063
       \param color = array of dimv() values of type \c T, defining the drawing color.
14274
20064
       \param opacity = opacity of the drawing.
14275
20065
    **/
14276
 
    template<typename t> CImg& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
14277
 
                                            const T *color, const float opacity=1.0f) {
 
20066
    template<typename t, typename tc>
 
20067
      CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 
20068
                            const tc *const color, const float opacity=1.0f) {
14278
20069
      CImgList<t> eig = tensor.get_symmetric_eigen();
14279
20070
      const CImg<t> &val = eig[0], &vec = eig[1];
14280
20071
      return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity);
14281
20072
    }
14282
20073
 
14283
 
    //! Draw an outlined ellipse on the instance image
 
20074
    //! Draw a filled ellipse.
 
20075
    template<typename t, typename tc>
 
20076
      CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 
20077
                            const CImg<tc>& color, const float opacity=1.0f) {
 
20078
      return draw_ellipse(x0,y0,tensor,color.data,opacity);
 
20079
    }
 
20080
 
 
20081
    //! Draw an outlined ellipse.
 
20082
    /**
 
20083
       \param x0 = X-coordinate of the ellipse center.
 
20084
       \param y0 = Y-coordinate of the ellipse center.
 
20085
       \param r1 = First radius of the ellipse.
 
20086
       \param r2 = Second radius of the ellipse.
 
20087
       \param ru = X-coordinate of the orientation vector related to the first radius.
 
20088
       \param rv = Y-coordinate of the orientation vector related to the first radius.
 
20089
       \param color = array of dimv() values of type \c T, defining the drawing color.
 
20090
       \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
 
20091
       \param opacity = opacity of the drawing.
 
20092
    **/
 
20093
    template<typename tc>
 
20094
      CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 
20095
                            const tc *const color, const float opacity, const unsigned int pattern) {
 
20096
      if (pattern) _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,pattern);
 
20097
      return *this;
 
20098
    }
 
20099
 
 
20100
    //! Draw an outlined ellipse.
 
20101
    template<typename tc>
 
20102
      CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
 
20103
                            const CImg<tc>& color, const float opacity, const unsigned int pattern) {
 
20104
      return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity,pattern);
 
20105
    }
 
20106
 
 
20107
    //! Draw an outlined ellipse.
14284
20108
    /**
14285
20109
       \param x0 = X-coordinate of the ellipse center.
14286
20110
       \param y0 = Y-coordinate of the ellipse center.
14289
20113
       \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
14290
20114
       \param opacity = opacity of the drawing.
14291
20115
    **/
14292
 
    template<typename t> CImg& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
14293
 
                                            const T *color, const float opacity, const unsigned int pattern) {
 
20116
    template<typename t, typename tc>
 
20117
      CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 
20118
                            const tc *const color, const float opacity, const unsigned int pattern) {
14294
20119
      CImgList<t> eig = tensor.get_symmetric_eigen();
14295
20120
      const CImg<t> &val = eig[0], &vec = eig[1];
14296
20121
      return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity,pattern);
14297
20122
    }
14298
20123
 
14299
 
    //! Draw a filled circle on the instance image
 
20124
    //! Draw an outlined ellipse.
 
20125
    template<typename t, typename tc>
 
20126
      CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
 
20127
                            const CImg<tc>& color, const float opacity, const unsigned int pattern) {
 
20128
      return draw_ellipse(x0,y0,tensor,color.data,opacity,pattern);
 
20129
    }
 
20130
 
 
20131
    //! Draw a filled circle.
14300
20132
    /**
14301
 
       \param x0 = X-coordinate of the circle center.
14302
 
       \param y0 = Y-coordinate of the circle center.
14303
 
       \param r = radius of the circle.
14304
 
       \param color = an array of dimv() values of type \c T, defining the drawing color.
14305
 
       \param opacity = opacity of the drawing.
 
20133
       \param x0 X-coordinate of the circle center.
 
20134
       \param y0 Y-coordinate of the circle center.
 
20135
       \param radius  Circle radius.
 
20136
       \param color Array of dimv() values of type \c T, defining the drawing color.
 
20137
       \param opacity Drawing opacity.
14306
20138
       \note
14307
20139
       - Circle version of the Bresenham's algorithm is used.
14308
20140
    **/
14309
 
    CImg& draw_circle(const int x0, const int y0, int radius, const T *const color, const float opacity=1.0f) {
 
20141
    template<typename tc>
 
20142
      CImg<T>& draw_circle(const int x0, const int y0, int radius, const tc *const color, const float opacity=1.0f) {
14310
20143
      if (!is_empty()) {
14311
20144
        if (!color) throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",pixel_type());
14312
20145
        _draw_scanline(color,opacity);
14313
 
        if (radius<0 || x0-radius>=(int)width || y0+radius<0 || y0-radius>=(int)height) return *this;
14314
 
        if (y0>=0 && y0<(int)height) _draw_scanline(x0-radius,x0+radius,y0,color,opacity);
 
20146
        if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
 
20147
        if (y0>=0 && y0<dimy()) _draw_scanline(x0-radius,x0+radius,y0,color,opacity);
14315
20148
        for (int f=1-radius, ddFx=0, ddFy=-(radius<<1), x=0, y=radius; x<y; ) {
14316
20149
          if (f>=0) {
14317
20150
            const int x1 = x0-x, x2 = x0+x, y1 = y0-y, y2 = y0+y;
14318
 
            if (y1>=0 && y1<(int)height) _draw_scanline(x1,x2,y1,color,opacity);
14319
 
            if (y2>=0 && y2<(int)height) _draw_scanline(x1,x2,y2,color,opacity);
 
20151
            if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
 
20152
            if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
14320
20153
            f+=(ddFy+=2); --y;
14321
20154
          }
14322
20155
          const bool no_diag = y!=(x++);
14323
20156
          ++(f+=(ddFx+=2));
14324
20157
          const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x;
14325
20158
          if (no_diag) {
14326
 
            if (y1>=0 && y1<(int)height) _draw_scanline(x1,x2,y1,color,opacity);
14327
 
            if (y2>=0 && y2<(int)height) _draw_scanline(x1,x2,y2,color,opacity);
 
20159
            if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
 
20160
            if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
14328
20161
          }
14329
20162
        }
14330
20163
      }
14331
20164
      return *this;
14332
20165
    }
14333
20166
 
 
20167
    //! Draw a filled circle.
 
20168
    template<typename tc>
 
20169
      CImg<T>& draw_circle(const int x0, const int y0, int radius, const CImg<tc>& color, const float opacity=1.0f) {
 
20170
      return draw_circle(x0,y0,radius,color.data,opacity);
 
20171
    }
 
20172
 
14334
20173
    //! Draw an outlined circle.
14335
20174
    /**
14336
 
       \param x0 = X-coordinate of the circle center.
14337
 
       \param y0 = Y-coordinate of the circle center.
14338
 
       \param r = radius of the circle.
14339
 
       \param color = an array of dimv() values of type \c T, defining the drawing color.
14340
 
       \param pattern = If zero, the circle is filled, else pattern is an integer whose bits describe the outline pattern.
14341
 
       \param opacity = opacity of the drawing.
 
20175
       \param x0 X-coordinate of the circle center.
 
20176
       \param y0 Y-coordinate of the circle center.
 
20177
       \param radius Circle radius.
 
20178
       \param color Array of dimv() values of type \c T, defining the drawing color.
 
20179
       \param opacity Drawing opacity.
14342
20180
    **/
14343
 
    CImg& draw_circle(const int x0, const int y0, int radius, const T *const color, const float opacity, const unsigned int) {
 
20181
    template<typename tc>
 
20182
      CImg<T>& draw_circle(const int x0, const int y0, int radius, const tc *const color, const float opacity, const unsigned int) {
14344
20183
      if (!is_empty()) {
14345
20184
        if (!color) throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",pixel_type());
14346
 
        if (radius<0 || x0-radius>=(int)width || y0+radius<0 || y0-radius>=(int)height) return *this;
 
20185
        if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
14347
20186
        if (!radius) return draw_point(x0,y0,color,opacity);
14348
20187
        draw_point(x0-radius,y0,color,opacity).draw_point(x0+radius,y0,color,opacity).
14349
20188
          draw_point(x0,y0-radius,color,opacity).draw_point(x0,y0+radius,color,opacity);
14364
20203
      return *this;
14365
20204
    }
14366
20205
 
14367
 
    //! Draw a text into the instance image.
 
20206
    //! Draw an outlined circle.
 
20207
    template<typename tc>
 
20208
      CImg<T>& draw_circle(const int x0, const int y0, int radius, const CImg<tc>& color, const float opacity, const unsigned int foo) {
 
20209
      return draw_circle(x0,y0,radius,color.data,opacity,foo);
 
20210
    }
 
20211
 
 
20212
    //! Draw a text.
14368
20213
    /**
14369
20214
       \param text = a C-string containing the text to display.
14370
20215
       \param x0 = X-coordinate of the text in the instance image.
14371
20216
       \param y0 = Y-coordinate of the text in the instance image.
14372
 
       \param fgcolor = an array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
14373
 
       \param bgcolor = an array of dimv() values of type \c T, defining the background color (0 means 'transparent').
 
20217
       \param foreground_color = an array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
 
20218
       \param background_color = an array of dimv() values of type \c T, defining the background color (0 means 'transparent').
14374
20219
       \param font = List of font characters used for the drawing.
14375
20220
       \param opacity = opacity of the drawing.
14376
20221
       \note Clipping is supported.
14377
 
       \see get_font().
14378
20222
    **/
14379
 
    template<typename t> CImg& draw_text(const char *const text,
14380
 
                                         const int x0, const int y0,
14381
 
                                         const T *const fgcolor, const T *const bgcolor,
14382
 
                                         const CImgList<t>& font, const float opacity=1.0f) {
 
20223
    template<typename tc1, typename tc2, typename t>
 
20224
      CImg<T>& draw_text(const char *const text, const int x0, const int y0,
 
20225
                         const tc1 *const foreground_color, const tc2 *const background_color,
 
20226
                         const CImgList<t>& font, const float opacity=1.0f) {
14383
20227
      if (!text)
14384
20228
        throw CImgArgumentException("CImg<%s>::draw_text() : Specified input string is (null).",pixel_type());
14385
20229
      if (!font)
14389
20233
      if (is_empty()) {
14390
20234
        // If needed, pre-compute needed size of the image
14391
20235
        int x = 0, y = 0, w = 0;
 
20236
        unsigned char c = 0;
14392
20237
        for (int i=0; i<cimg::strlen(text); ++i) {
14393
 
          const unsigned char c = text[i];
 
20238
          c = text[i];
14394
20239
          switch (c) {
14395
20240
          case '\n': y+=font[' '].height; if (x>w) w = x; x = 0; break;
14396
20241
          case '\t': x+=4*font[' '].width; break;
14397
20242
          default: if (c<font.size) x+=font[c].width;
14398
20243
          }
14399
20244
        }
14400
 
        if (x!=0) {
 
20245
        if (x!=0 || c=='\n') {
14401
20246
          if (x>w) w=x;
14402
20247
          y+=font[' '].height;
14403
20248
        }
14404
20249
        assign(x0+w,y0+y,1,font[' '].dim,0);
14405
 
        if (bgcolor) cimg_forV(*this,k) get_shared_channel(k).fill(bgcolor[k]);
 
20250
        if (background_color) cimg_forV(*this,k) get_shared_channel(k).fill((T)background_color[k]);
14406
20251
      }
14407
20252
 
14408
20253
      int x = x0, y = y0;
14414
20259
        case '\t': x+=4*font[' '].width; break;
14415
20260
        default: if (c<font.size) {
14416
20261
          letter = font[c];
14417
 
          const CImg& mask = (c+256)<(int)font.size?font[c+256]:font[c];
14418
 
          if (fgcolor) for (unsigned int p=0; p<letter.width*letter.height; ++p)
14419
 
            if (mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)(letter(p,0,0,k)*fgcolor[k]);
14420
 
          if (bgcolor) for (unsigned int p=0; p<letter.width*letter.height; ++p)
14421
 
            if (!mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = bgcolor[k];
14422
 
          if (!bgcolor && font.size>=512) draw_image(letter,mask,x,y,0,0,(T)1,opacity);
 
20262
          const CImg<T>& mask = (c+256)<(int)font.size?font[c+256]:font[c];
 
20263
          if (foreground_color) for (unsigned int p=0; p<letter.width*letter.height; ++p)
 
20264
            if (mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)(letter(p,0,0,k)*foreground_color[k]);
 
20265
          if (background_color) for (unsigned int p=0; p<letter.width*letter.height; ++p)
 
20266
            if (!mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)background_color[k];
 
20267
          if (!background_color && font.size>=512) draw_image(letter,mask,x,y,0,0,(T)1,opacity);
14423
20268
          else draw_image(letter,x,y,0,0,opacity);
14424
20269
          x+=letter.width;
14425
20270
        }
14429
20274
      return *this;
14430
20275
    }
14431
20276
 
14432
 
    //! Draw a text into the instance image.
 
20277
    //! Draw a text.
 
20278
    template<typename tc1, typename tc2, typename t>
 
20279
      CImg<T>& draw_text(const char *const text, const int x0, const int y0,
 
20280
                         const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
 
20281
                         const CImgList<t>& font, const float opacity=1.0f) {
 
20282
      return draw_text(text,x0,y0,foreground_color.data,background_color.data,font,opacity);
 
20283
    }
 
20284
 
 
20285
    //! Draw a text.
 
20286
    template<typename tc, typename t>
 
20287
      CImg<T>& draw_text(const char *const text, const int x0, const int y0,
 
20288
                         const tc *const foreground_color, const int background_color,
 
20289
                         const CImgList<t>& font, const float opacity=1.0f) {
 
20290
      return draw_text(text,x0,y0,foreground_color,(tc*)background_color,font,opacity);
 
20291
    }
 
20292
 
 
20293
    //! Draw a text.
 
20294
    template<typename tc, typename t>
 
20295
      CImg<T>& draw_text(const char *const text, const int x0, const int y0,
 
20296
                         const int foreground_color, const tc *const background_color,
 
20297
                         const CImgList<t>& font, const float opacity=1.0f) {
 
20298
      return draw_text(text,x0,y0,(tc*)foreground_color,background_color,font,opacity);
 
20299
    }
 
20300
 
 
20301
    //! Draw a text.
14433
20302
    /**
14434
20303
       \param text = a C-string containing the text to display.
14435
20304
       \param x0 = X-coordinate of the text in the instance image.
14436
20305
       \param y0 = Y-coordinate of the text in the instance image.
14437
 
       \param fgcolor = an array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
14438
 
       \param bgcolor = an array of dimv() values of type \c T, defining the background color (0 means 'transparent').
 
20306
       \param foreground_color = an array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
 
20307
       \param background_color = an array of dimv() values of type \c T, defining the background color (0 means 'transparent').
14439
20308
       \param font_size = Height of the desired font (11,13,24,38 or 57)
14440
20309
       \param opacity = opacity of the drawing.
14441
20310
       \note Clipping is supported.
14442
 
       \see get_font().
14443
 
    **/
14444
 
    CImg& draw_text(const char *const text,
14445
 
                    const int x0, const int y0,
14446
 
                    const T *const fgcolor, const T *const bgcolor=0,
14447
 
                    const unsigned int font_size=11, const float opacity=1.0f) {
14448
 
      return draw_text(text,x0,y0,fgcolor,bgcolor,CImgList<T>::get_font(font_size),opacity);
14449
 
    }
14450
 
 
14451
 
 
14452
 
    //! Draw a text into the instance image.
14453
 
    /**
14454
 
       \param x0 = X-coordinate of the text in the instance image.
14455
 
       \param y0 = Y-coordinate of the text in the instance image.
14456
 
       \param fgcolor = an array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
14457
 
       \param bgcolor = an array of dimv() values of type \c T, defining the background color (0 means 'transparent').
14458
 
       \param opacity = opacity of the drawing.
14459
 
       \param format = a 'printf'-style format, followed by arguments.
14460
 
       \note Clipping is supported.
14461
 
    **/
14462
 
    CImg& draw_text(const int x0, const int y0,
14463
 
                    const T *const fgcolor, const T *const bgcolor, const unsigned int font_size,
14464
 
                    const float opacity, const char *format,...) {
14465
 
      char tmp[2048] = { 0 };
14466
 
      std::va_list ap;
14467
 
      va_start(ap,format);
14468
 
      std::vsprintf(tmp,format,ap);
14469
 
      va_end(ap);
14470
 
      return draw_text(tmp,x0,y0,fgcolor,bgcolor,font_size,opacity);
14471
 
    }
14472
 
 
14473
 
    template<typename t> CImg& draw_text(const int x0, const int y0,
14474
 
                                         const T *const fgcolor, const T *const bgcolor,
14475
 
                                         const CImgList<t>& font, const float opacity, const char *format,...) {
14476
 
      char tmp[2048] = { 0 };
14477
 
      std::va_list ap;
14478
 
      va_start(ap,format);
14479
 
      std::vsprintf(tmp,format,ap);
14480
 
      va_end(ap);
14481
 
      return draw_text(tmp,x0,y0,fgcolor,bgcolor,font,opacity);
14482
 
    }
14483
 
 
14484
 
 
14485
 
    //! Draw a vector field in the instance image.
14486
 
    /**
14487
 
       \param flow = a 2d image of 2d vectors used as input data.
14488
 
       \param color = an array of dimv() values of type \c T, defining the drawing color.
14489
 
       \param sampling = length (in pixels) between each arrow.
14490
 
       \param factor = length factor of each arrow (if <0, computed as a percentage of the maximum length).
14491
 
       \param quiver_type = type of plot. Can be 0 (arrows) or 1 (segments).
14492
 
       \param opacity = opacity of the drawing.
14493
 
       \note Clipping is supported.
14494
 
    **/
14495
 
    template<typename t>
14496
 
    CImg& draw_quiver(const CImg<t>& flow, const T *const color,
14497
 
                      const unsigned int sampling=25, const float factor=-20,
14498
 
                      const int quiver_type=0, const float opacity=1.0f, const unsigned int pattern=~0U) {
14499
 
      if (!is_empty()) {
14500
 
        if (!flow || flow.dim<2)
14501
 
          throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.",
14502
 
                                      pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data);
14503
 
        if (!color)
14504
 
          throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified color is (null)",
14505
 
                                      pixel_type());
14506
 
        if (sampling<=0)
14507
 
          throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g",
14508
 
                                      pixel_type(),sampling);
14509
 
 
14510
 
        float vmax,fact;
14511
 
        if (factor<=0) {
14512
 
          const CImgStats st(flow.get_norm_pointwise(2),false);
14513
 
          const float vmaxtmp = (float)cimg::max(cimg::abs(st.min),cimg::abs(st.max));
14514
 
          vmax = vmaxtmp>0?vmaxtmp:1;
14515
 
          fact = -factor;
14516
 
        } else { fact = factor; vmax = 1; }
14517
 
 
14518
 
        for (unsigned int y=sampling/2; y<height; y+=sampling)
14519
 
          for (unsigned int x=sampling/2; x<width; x+=sampling) {
14520
 
            const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
14521
 
            float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
14522
 
            if (!quiver_type) {
14523
 
              const int xx = x+(int)u, yy = y+(int)v;
14524
 
              draw_arrow(x,y,xx,yy,color,45.0f,sampling/5.0f,opacity,pattern);
14525
 
            } 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);
14526
 
          }
14527
 
      }
14528
 
      return *this;
14529
 
    }
14530
 
 
14531
 
    //! Draw a vector field in the instance image, using a colormap.
14532
 
    /**
14533
 
       \param flow = a 2d image of 2d vectors used as input data.
14534
 
       \param color = a 2d image of dimv()-D vectors corresponding to the color of each arrow.
14535
 
       \param sampling = length (in pixels) between each arrow.
14536
 
       \param factor = length factor of each arrow (if <0, computed as a percentage of the maximum length).
14537
 
       \param quiver_type = type of plot. Can be 0 (arrows) or 1 (segments).
14538
 
       \param opacity = opacity of the drawing.
14539
 
       \note Clipping is supported.
14540
 
    **/
14541
 
    template<typename t1,typename t2>
14542
 
      CImg& draw_quiver(const CImg<t1>& flow, const CImg<t2>& color,
14543
 
                        const unsigned int sampling=25, const float factor=-20,
14544
 
                        const int quiver_type=0, const float opacity=1.0f, const unsigned int pattern=~0U) {
 
20311
    **/
 
20312
    template<typename tc1, typename tc2>
 
20313
      CImg<T>& draw_text(const char *const text, const int x0, const int y0,
 
20314
                         const tc1 *const foreground_color, const tc2 *const background_color=0,
 
20315
                         const unsigned int font_size=11, const float opacity=1.0f) {
 
20316
      return draw_text(text,x0,y0,foreground_color,background_color,CImgList<T>::get_font(font_size),opacity);
 
20317
    }
 
20318
 
 
20319
    //! Draw a text.
 
20320
    template<typename tc1, typename tc2>
 
20321
      CImg<T>& draw_text(const char *const text, const int x0, const int y0,
 
20322
                         const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
 
20323
                         const unsigned int font_size=11, const float opacity=1.0f) {
 
20324
      return draw_text(text,x0,y0,foreground_color.data,background_color.data,font_size,opacity);
 
20325
    }
 
20326
 
 
20327
    //! Draw a text.
 
20328
    template<typename tc>
 
20329
      CImg<T>& draw_text(const char *const text, const int x0, const int y0,
 
20330
                         const tc *const foreground_color, int background_color=0,
 
20331
                         const unsigned int font_size=11, const float opacity=1.0f) {
 
20332
      return draw_text(text,x0,y0,foreground_color,(tc*)background_color,CImgList<T>::get_font(font_size),opacity);
 
20333
    }
 
20334
 
 
20335
    //! Draw a text.
 
20336
    template<typename tc>
 
20337
      CImg<T>& draw_text(const char *const text, const int x0, const int y0,
 
20338
                         const int foreground_color, const tc *const background_color=0,
 
20339
                         const unsigned int font_size=11, const float opacity=1.0f) {
 
20340
      return draw_text(text,x0,y0,(tc*)foreground_color,background_color,CImgList<T>::get_font(font_size),opacity);
 
20341
    }
 
20342
 
 
20343
    //! Draw a text.
 
20344
    /**
 
20345
       \param x0 X-coordinate of the text in the instance image.
 
20346
       \param y0 Y-coordinate of the text in the instance image.
 
20347
       \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
 
20348
       \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
 
20349
       \param font_size Size of the font (nearest match).
 
20350
       \param opacity Drawing opacity.
 
20351
       \param format 'printf'-style format string, followed by arguments.
 
20352
       \note Clipping is supported.
 
20353
    **/
 
20354
    template<typename tc1, typename tc2>
 
20355
      CImg<T>& draw_text(const int x0, const int y0,
 
20356
                         const tc1 *const foreground_color, const tc2 *const background_color,
 
20357
                         const unsigned int font_size, const float opacity, const char *format, ...) {
 
20358
      char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,format);
 
20359
      std::vsprintf(tmp,format,ap); va_end(ap);
 
20360
      return draw_text(tmp,x0,y0,foreground_color,background_color,font_size,opacity);
 
20361
    }
 
20362
 
 
20363
    //! Draw a text.
 
20364
    template<typename tc1, typename tc2>
 
20365
      CImg<T>& draw_text(const int x0, const int y0,
 
20366
                         const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
 
20367
                         const unsigned int font_size, const float opacity, const char *format, ...) {
 
20368
      char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,format);
 
20369
      std::vsprintf(tmp,format,ap); va_end(ap);
 
20370
      return draw_text(tmp,x0,y0,foreground_color,background_color,font_size,opacity);
 
20371
    }
 
20372
 
 
20373
    //! Draw a text.
 
20374
    template<typename tc>
 
20375
      CImg<T>& draw_text(const int x0, const int y0,
 
20376
                         const tc *const foreground_color, const int background_color,
 
20377
                         const unsigned int font_size, const float opacity, const char *format, ...) {
 
20378
      char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,format);
 
20379
      std::vsprintf(tmp,format,ap); va_end(ap);
 
20380
      return draw_text(tmp,x0,y0,foreground_color,(tc*)background_color,font_size,opacity);
 
20381
    }
 
20382
 
 
20383
    //! Draw a text.
 
20384
    template<typename tc>
 
20385
      CImg<T>& draw_text(const int x0, const int y0,
 
20386
                         const int foreground_color, const tc *const background_color,
 
20387
                         const unsigned int font_size, const float opacity, const char *format, ...) {
 
20388
      char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,format);
 
20389
      std::vsprintf(tmp,format,ap); va_end(ap);
 
20390
      return draw_text(tmp,x0,y0,(tc*)foreground_color,background_color,font_size,opacity);
 
20391
    }
 
20392
 
 
20393
    //! Draw a text.
 
20394
    /**
 
20395
       \param x0 X-coordinate of the text in the instance image.
 
20396
       \param y0 Y-coordinate of the text in the instance image.
 
20397
       \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
 
20398
       \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
 
20399
       \param font Font used for drawing text.
 
20400
       \param opacity Drawing opacity.
 
20401
       \param format 'printf'-style format string, followed by arguments.
 
20402
       \note Clipping is supported.
 
20403
    **/
 
20404
    template<typename tc1, typename tc2, typename t>
 
20405
      CImg<T>& draw_text(const int x0, const int y0,
 
20406
                         const tc1 *const foreground_color, const tc2 *const background_color,
 
20407
                         const CImgList<t>& font, const float opacity, const char *format, ...) {
 
20408
      char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,format);
 
20409
      std::vsprintf(tmp,format,ap); va_end(ap);
 
20410
      return draw_text(tmp,x0,y0,foreground_color,background_color,font,opacity);
 
20411
    }
 
20412
 
 
20413
    //! Draw a text.
 
20414
    template<typename tc1, typename tc2, typename t>
 
20415
      CImg<T>& draw_text(const int x0, const int y0,
 
20416
                         const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
 
20417
                         const CImgList<t>& font, const float opacity, const char *format, ...) {
 
20418
      char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,format);
 
20419
      std::vsprintf(tmp,format,ap); va_end(ap);
 
20420
      return draw_text(tmp,x0,y0,foreground_color,background_color,font,opacity);
 
20421
    }
 
20422
 
 
20423
    //! Draw a text.
 
20424
    template<typename tc, typename t>
 
20425
      CImg<T>& draw_text(const int x0, const int y0,
 
20426
                         const tc *const foreground_color, const int background_color,
 
20427
                         const CImgList<t>& font, const float opacity, const char *format, ...) {
 
20428
      char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,format);
 
20429
      std::vsprintf(tmp,format,ap); va_end(ap);
 
20430
      return draw_text(tmp,x0,y0,foreground_color,(tc*)background_color,font,opacity);
 
20431
    }
 
20432
 
 
20433
    //! Draw a text.
 
20434
    template<typename tc, typename t>
 
20435
      CImg<T>& draw_text(const int x0, const int y0,
 
20436
                         const int foreground_color, const tc *const background_color,
 
20437
                         const CImgList<t>& font, const float opacity, const char *format, ...) {
 
20438
      char tmp[2048] = { 0 }; std::va_list ap; va_start(ap,format);
 
20439
      std::vsprintf(tmp,format,ap); va_end(ap);
 
20440
      return draw_text(tmp,x0,y0,(tc*)foreground_color,background_color,font,opacity);
 
20441
    }
 
20442
 
 
20443
    //! Draw a vector field in the instance image, using a colormap.
 
20444
    /**
 
20445
       \param flow Image of 2d vectors used as input data.
 
20446
       \param color Image of dimv()-D vectors corresponding to the color of each arrow.
 
20447
       \param sampling Length (in pixels) between each arrow.
 
20448
       \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
 
20449
       \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
 
20450
       \param opacity Opacity of the drawing.
 
20451
       \param pattern Used pattern to draw lines.
 
20452
       \note Clipping is supported.
 
20453
    **/
 
20454
    template<typename t1, typename t2>
 
20455
      CImg<T>& draw_quiver(const CImg<t1>& flow, const t2 *const color,
 
20456
                           const unsigned int sampling=25, const float factor=-20,
 
20457
                           const int quiver_type=0, const float opacity=1.0f, const unsigned int pattern=~0U) {
 
20458
      return draw_quiver(flow,CImg<t2>(color,dim,1,1,1,true),sampling,factor,quiver_type,opacity,pattern);
 
20459
    }
 
20460
 
 
20461
    //! Draw a vector field in the instance image, using a colormap.
 
20462
    /**
 
20463
       \param flow Image of 2d vectors used as input data.
 
20464
       \param color Image of dimv()-D vectors corresponding to the color of each arrow.
 
20465
       \param sampling Length (in pixels) between each arrow.
 
20466
       \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
 
20467
       \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
 
20468
       \param opacity Opacity of the drawing.
 
20469
       \param pattern Used pattern to draw lines.
 
20470
       \note Clipping is supported.
 
20471
    **/
 
20472
    template<typename t1, typename t2>
 
20473
      CImg<T>& draw_quiver(const CImg<t1>& flow, const CImg<t2>& color,
 
20474
                           const unsigned int sampling=25, const float factor=-20,
 
20475
                           const int quiver_type=0, const float opacity=1.0f, const unsigned int pattern=~0U) {
14545
20476
      if (!is_empty()) {
14546
20477
        if (!flow || flow.dim!=2)
14547
20478
          throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.",
14548
20479
                                      pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data);
14549
 
        if (!color || color.width!=flow.width || color.height!=flow.height)
14550
 
          throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified color (%u,%u,%u,%u,%p) has wrong dimensions.",
14551
 
                                      pixel_type(),color.width,color.height,color.depth,color.dim,color.data);
14552
20480
        if (sampling<=0)
14553
20481
          throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g",pixel_type(),sampling);
 
20482
        const bool colorfield = (color.width==flow.width && color.height==flow.height && color.depth==1 && color.dim==dim);
 
20483
        if (is_overlapping(flow)) return draw_quiver(+flow,color,sampling,factor,quiver_type,opacity,pattern);
14554
20484
 
14555
20485
        float vmax,fact;
14556
20486
        if (factor<=0) {
14557
 
          const CImgStats st(flow.get_norm_pointwise(2),false);
14558
 
          vmax = (float)cimg::max(cimg::abs(st.min),cimg::abs(st.max));
 
20487
          float m, M = (float)flow.get_norm_pointwise(2).maxmin(m);
 
20488
          vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
14559
20489
          fact = -factor;
14560
20490
        } else { fact = factor; vmax = 1; }
14561
20491
 
14565
20495
            float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
14566
20496
            if (!quiver_type) {
14567
20497
              const int xx = x+(int)u, yy = y+(int)v;
14568
 
              draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y).data,45.0f,sampling/5.0f,opacity,pattern);
14569
 
            } else
14570
 
            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).data,opacity,pattern);
 
20498
              if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y).data,45.0f,sampling/5.0f,opacity,pattern);
 
20499
              else draw_arrow(x,y,xx,yy,color,45.0f,sampling/5.0f,opacity,pattern);
 
20500
            } else {
 
20501
              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);
 
20502
              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);
 
20503
            }
14571
20504
          }
14572
20505
      }
14573
20506
      return *this;
14575
20508
 
14576
20509
    //! Draw a 1D graph on the instance image.
14577
20510
    /**
14578
 
       \param data = an image containing the graph values I = f(x).
14579
 
       \param color = an array of dimv() values of type \c T, defining the drawing color.
14580
 
       \param gtype = define the type of the plot :
14581
 
                      - 0 = Plot using linear interpolation (segments).
14582
 
                      - 1 = Plot with bars.
14583
 
                      - 2 = Plot using cubic interpolation (3-polynomials).
14584
 
       \param ymin = lower bound of the y-range.
14585
 
       \param ymax = upper bound of the y-range.
14586
 
       \param opacity = opacity of the drawing.
 
20511
       \param data Image containing the graph values I = f(x).
 
20512
       \param color Array of dimv() values of type \c T, defining the drawing color.
 
20513
       \param gtype Define the type of the plot :
 
20514
                      - 0 = Plot using points clouds.
 
20515
                      - 1 = Plot using linear interpolation (segments).
 
20516
                      - 2 = Plot with bars.
 
20517
                      - 3 = Plot using cubic interpolation (3-polynomials).
 
20518
       \param ymin Lower bound of the y-range.
 
20519
       \param ymax Upper bound of the y-range.
 
20520
       \param opacity Drawing opacity.
 
20521
       \param pattern Drawing pattern.
14587
20522
       \note
14588
20523
         - if \c ymin==ymax==0, the y-range is computed automatically from the input sample.
14589
 
       \see draw_axis().
14590
20524
    **/
14591
 
    template<typename t>
14592
 
    CImg& draw_graph(const CImg<t>& data, const T *const color, const unsigned int gtype=0,
14593
 
                     const double ymin=0, const double ymax=0, const float opacity=1.0f,
14594
 
                     const unsigned int pattern=~0U) {
 
20525
    template<typename t, typename tc>
 
20526
    CImg<T>& draw_graph(const CImg<t>& data, const tc *const color, const unsigned int gtype=1,
 
20527
                        const double ymin=0, const double ymax=0, const float opacity=1.0f,
 
20528
                        const unsigned int pattern=~0U) {
14595
20529
      if (!is_empty()) {
14596
20530
        if (!color) throw CImgArgumentException("CImg<%s>::draw_graph() : Specified color is (null)",pixel_type());
14597
 
        T *color1 = new T[dim], *color2 = new T[dim];
14598
 
        cimg_forV(*this,k) { color1[k]=(T)(color[k]*0.6f); color2[k]=(T)(color[k]*0.3f); }
14599
 
        CImgStats st;
14600
 
        if (ymin==ymax) { st = CImgStats(data,false); cimg::swap(st.min,st.max); } else { st.min = ymin; st.max = ymax; }
14601
 
        if (st.min==st.max) { --st.min; ++st.max; }
14602
 
        const float ca = height>1?(float)(st.max-st.min)/(height-1):0, cb = (float)st.min;
14603
 
        const int Y0 = (int)(-cb/ca);
 
20531
        tc *color1 = new tc[dim], *color2 = new tc[dim];
 
20532
        cimg_forV(*this,k) { color1[k]=(tc)(color[k]*0.6f); color2[k]=(tc)(color[k]*0.3f); }
 
20533
        float m = (float)ymin, M = (float)ymax;
 
20534
        if (ymin==ymax) m = (float)data.maxmin(M);
 
20535
        if (m==M) { --m; ++M; }
 
20536
        const float ca = height>1?(float)(M-m)/(height-1):0;
 
20537
        const int Y0 = (int)(-m/ca);
14604
20538
        int pY = 0;
14605
20539
        bool init_hatch = true;
14606
 
        cimg_foroff(data,off) {
14607
 
          const int Y = (int)((data[off]-cb)/ca);
 
20540
        if (gtype<3) cimg_foroff(data,off) {
 
20541
          const int Y = (int)((data[off]-m)/ca);
14608
20542
          switch (gtype) {
14609
 
          case 0: // plot with segments
 
20543
          case 0: { // plot with points
 
20544
            const unsigned int X = off*width/data.size();
 
20545
            draw_point(X,Y,color,opacity);
 
20546
          } break;
 
20547
          case 1: // plot with segments
14610
20548
            if (off>0) {
14611
20549
              draw_line((int)((off-1)*width/data.size()),pY,(int)(off*width/data.size()),Y,color,opacity,pattern,init_hatch);
14612
20550
              init_hatch = false;
14613
20551
            }
14614
20552
            break;
14615
 
          case 1: { // plot with bars
 
20553
          case 2: { // plot with bars
14616
20554
            const unsigned int X = off*width/data.size(), nX = (off+1)*width/data.size()-1;
14617
20555
            draw_rectangle(X,(int)Y0,nX,Y,color1,opacity);
14618
20556
            draw_line(X,Y,X,(int)Y0,color2,opacity);
14621
20559
            draw_line(X,Y,nX,Y,Y<=Y0?color:color2,opacity);
14622
20560
          } break;
14623
20561
          }
14624
 
          pY=Y;
14625
 
        }
14626
 
        if (gtype==2) { // plot with cubic interpolation
 
20562
          pY = Y;
 
20563
        } else { // plot with cubic interpolation
14627
20564
          const CImg<t> ndata = data.get_shared_points(0,data.size()-1);
14628
20565
          cimg_forX(*this,x) {
14629
 
            const int Y = (int)((ndata.cubic_pix1d((float)x*ndata.width/width)-cb)/ca);
 
20566
            const int Y = (int)((ndata.cubic_at1((float)x*ndata.width/width)-m)/ca);
14630
20567
            if (x>0) draw_line(x,pY,x+1,Y,color,opacity,pattern,init_hatch);
14631
20568
            init_hatch = false;
14632
 
            pY=Y;
 
20569
            pY = Y;
14633
20570
          }
14634
20571
        }
14635
20572
        delete[] color1; delete[] color2;
14637
20574
      return *this;
14638
20575
    }
14639
20576
 
 
20577
    //! Draw a 1D graph on the instance image.
 
20578
    template<typename t, typename tc>
 
20579
    CImg<T>& draw_graph(const CImg<t>& data, const CImg<tc>& color, const unsigned int gtype=1,
 
20580
                        const double ymin=0, const double ymax=0, const float opacity=1.0f,
 
20581
                        const unsigned int pattern=~0U) {
 
20582
      return draw_graph(data,color.data,gtype,ymin,ymax,opacity,pattern);
 
20583
    }
 
20584
 
14640
20585
    //! Draw a labeled horizontal axis on the instance image.
14641
20586
    /**
14642
 
       \param x0 = lower bound of the x-range.
14643
 
       \param x1 = upper bound of the x-range.
14644
 
       \param y = Y-coordinate of the horizontal axis in the instance image.
14645
 
       \param color = an array of dimv() values of type \c T, defining the drawing color.
14646
 
       \param precision = precision of the labels.
14647
 
       \param opacity = opacity of the drawing.
 
20587
       \param xvalues Lower bound of the x-range.
 
20588
       \param y Y-coordinate of the horizontal axis in the instance image.
 
20589
       \param color Array of dimv() values of type \c T, defining the drawing color.
 
20590
       \param opacity Drawing opacity.
 
20591
       \param pattern Drawing pattern.
14648
20592
       \note if \c precision==0, precision of the labels is automatically computed.
14649
 
       \see draw_graph().
14650
20593
    **/
14651
 
    template<typename t> CImg& draw_axis(const CImg<t>& xvalues, const int y,
14652
 
                                         const T *const color, const float opacity=1.0f, const unsigned int pattern=~0U) {
 
20594
    template<typename t, typename tc>
 
20595
      CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
 
20596
                         const tc *const color, const float opacity=1.0f, const unsigned int pattern=~0U) {
14653
20597
      if (!is_empty()) {
14654
20598
        int siz = (int)xvalues.size()-1;
14655
20599
        if (siz<=0) draw_line(0,y,width-1,y,color,opacity,pattern);
14662
20606
            std::sprintf(txt,"%g",(double)xvalues(x));
14663
20607
            const int xi=(int)(x*(width-1)/siz), xt = xi-(int)std::strlen(txt)*3;
14664
20608
            draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity).
14665
 
              draw_text(txt,xt<0?0:xt,yt,color,0,11,opacity);
 
20609
              draw_text(txt,xt<0?0:xt,yt,color,(tc*)0,11,opacity);
14666
20610
          }
14667
20611
        }
14668
20612
      }
14669
20613
      return *this;
14670
20614
    }
14671
20615
 
 
20616
    //! Draw a labeled horizontal axis on the instance image.
 
20617
    template<typename t, typename tc>
 
20618
      CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
 
20619
                         const CImg<tc>& color, const float opacity=1.0f, const unsigned int pattern=~0U) {
 
20620
      return draw_axis(xvalues,y,color.data,opacity,pattern);
 
20621
    }
 
20622
 
14672
20623
    //! Draw a labeled vertical axis on the instance image.
14673
 
    template<typename t> CImg& draw_axis(const int x, const CImg<t>& yvalues,
14674
 
                                         const T *const color, const float opacity=1.0f, const unsigned int pattern=~0U) {
 
20624
    template<typename t, typename tc>
 
20625
      CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
 
20626
                         const tc *const color, const float opacity=1.0f, const unsigned int pattern=~0U) {
14675
20627
      if (!is_empty()) {
14676
20628
        int siz = (int)yvalues.size()-1;
14677
20629
        if (siz<=0) draw_line(x,0,x,height-1,color,opacity,pattern);
14684
20636
            const int
14685
20637
              yi = (int)(y*(height-1)/siz),
14686
20638
              tmp = yi-5,
14687
 
              nyi = tmp<0?0:(tmp>=(int)height-11?(int)height-11:tmp),
 
20639
              nyi = tmp<0?0:(tmp>=dimy()-11?dimy()-11:tmp),
14688
20640
              xt = x-(int)std::strlen(txt)*7;
14689
20641
            draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity);
14690
 
            if (xt>0) draw_text(txt,xt,nyi,color,0,11,opacity);
14691
 
            else draw_text(txt,x+3,nyi,color,0,11,opacity);
 
20642
            if (xt>0) draw_text(txt,xt,nyi,color,(tc*)0,11,opacity);
 
20643
            else draw_text(txt,x+3,nyi,color,(tc*)0,11,opacity);
14692
20644
          }
14693
20645
        }
14694
20646
      }
14695
20647
      return *this;
14696
20648
    }
14697
20649
 
 
20650
    //! Draw a labeled vertical axis on the instance image.
 
20651
    template<typename t, typename tc>
 
20652
      CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
 
20653
                         const CImg<tc>& color, const float opacity=1.0f, const unsigned int pattern=~0U) {
 
20654
      return draw_axis(x,yvalues,color.data,opacity,pattern);
 
20655
    }
 
20656
 
14698
20657
    //! Draw a labeled horizontal+vertical axis on the instance image.
14699
 
    template<typename tx, typename ty> CImg& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
14700
 
                                                       const T *const color,
14701
 
                                                       const float opacity=1.0f,
14702
 
                                                       const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 
20658
    template<typename tx, typename ty, typename tc>
 
20659
      CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
 
20660
                         const tc *const color,
 
20661
                         const float opacity=1.0f,
 
20662
                         const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
14703
20663
      if (!is_empty()) {
14704
20664
        const CImg<tx> nxvalues(xvalues.data,xvalues.size(),1,1,1,true);
14705
20665
        const int sizx = (int)xvalues.size()-1, wm1 = (int)(width)-1;
14706
20666
        if (sizx>0) {
14707
20667
          float ox = (float)nxvalues[0];
14708
20668
          for (unsigned int x=1; x<width; ++x) {
14709
 
            const float nx = (float)nxvalues.linear_pix1d((float)x*sizx/wm1);
 
20669
            const float nx = (float)nxvalues.linear_at1((float)x*sizx/wm1);
14710
20670
            if (nx*ox<=0) { draw_axis(nx==0?x:x-1,yvalues,color,opacity,patterny); break; }
14711
20671
            ox = nx;
14712
20672
          }
14716
20676
        if (sizy>0) {
14717
20677
          float oy = (float)nyvalues[0];
14718
20678
          for (unsigned int y=1; y<height; ++y) {
14719
 
            const float ny = (float)nyvalues.linear_pix1d((float)y*sizy/hm1);
 
20679
            const float ny = (float)nyvalues.linear_at1((float)y*sizy/hm1);
14720
20680
            if (ny*oy<=0) { draw_axis(xvalues,ny==0?y:y-1,color,opacity,patternx); break; }
14721
20681
            oy = ny;
14722
20682
          }
14726
20686
    }
14727
20687
 
14728
20688
    //! Draw a labeled horizontal+vertical axis on the instance image.
14729
 
    CImg& draw_axis(const float x0, const float x1, const float y0, const float y1,
14730
 
                    const T *const color,
14731
 
                    const int subdivisionx=-60, const int subdivisiony=-60,
14732
 
                    const float precisionx=0, const float precisiony=0,
14733
 
                    const float opacity=1.0f,
14734
 
                    const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 
20689
    template<typename tx, typename ty, typename tc>
 
20690
      CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
 
20691
                         const CImg<tc>& color,
 
20692
                         const float opacity=1.0f,
 
20693
                         const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 
20694
      return draw_axis(xvalues,yvalues,color.data,opacity,patternx,patterny);
 
20695
    }
 
20696
 
 
20697
    //! Draw a labeled horizontal+vertical axis on the instance image.
 
20698
    template<typename tc>
 
20699
      CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
 
20700
                         const tc *const color,
 
20701
                         const int subdivisionx=-60, const int subdivisiony=-60,
 
20702
                         const float precisionx=0, const float precisiony=0,
 
20703
                         const float opacity=1.0f,
 
20704
                         const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
14735
20705
      const float dx = cimg::abs(x1-x0), dy = cimg::abs(y1-y0);
14736
20706
      const float
14737
20707
        px = (precisionx==0)?(float)std::pow(10.0,(int)std::log10(dx)-2.0):precisionx,
14738
20708
        py = (precisiony==0)?(float)std::pow(10.0,(int)std::log10(dy)-2.0):precisiony;
14739
 
      return draw_axis(CImg<float>::sequence(subdivisionx>0?subdivisionx:1-(int)width/subdivisionx,x0,x1).round(px),
14740
 
                       CImg<float>::sequence(subdivisiony>0?subdivisiony:1-(int)height/subdivisiony,y0,y1).round(py),
 
20709
      return draw_axis(CImg<float>::sequence(subdivisionx>0?subdivisionx:1-dimx()/subdivisionx,x0,x1).round(px),
 
20710
                       CImg<float>::sequence(subdivisiony>0?subdivisiony:1-dimy()/subdivisiony,y0,y1).round(py),
14741
20711
                       color,opacity,patternx,patterny);
14742
20712
    }
14743
20713
 
14744
 
    //! Draw grid on the instance image
14745
 
    template<typename tx, typename ty>
14746
 
      CImg& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues, const T *const color,
14747
 
                      const float opacity=1.0f, const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 
20714
    //! Draw a labeled horizontal+vertical axis on the instance image.
 
20715
    template<typename tc>
 
20716
      CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
 
20717
                         const CImg<tc>& color,
 
20718
                         const int subdivisionx=-60, const int subdivisiony=-60,
 
20719
                         const float precisionx=0, const float precisiony=0,
 
20720
                         const float opacity=1.0f,
 
20721
                         const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 
20722
      return draw_axis(x0,x1,y0,y1,color.data,subdivisionx,subdivisiony,precisionx,precisiony,opacity,patternx,patterny);
 
20723
    }
 
20724
 
 
20725
    //! Draw grid.
 
20726
    template<typename tx, typename ty, typename tc>
 
20727
      CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues, const tc *const color,
 
20728
                         const float opacity=1.0f, const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
14748
20729
      if (!is_empty()) {
14749
20730
        if (xvalues) cimg_foroff(xvalues,x) {
14750
20731
          const int xi = (int)xvalues[x];
14751
 
          if (xi>=0 && xi<(int)width) draw_line(xi,0,xi,height-1,color,opacity,patternx);
 
20732
          if (xi>=0 && xi<dimx()) draw_line(xi,0,xi,height-1,color,opacity,patternx);
14752
20733
        }
14753
20734
        if (yvalues) cimg_foroff(yvalues,y) {
14754
20735
          const int yi = (int)yvalues[y];
14755
 
          if (yi>=0 && yi<(int)height) draw_line(0,yi,width-1,yi,color,opacity,patterny);
 
20736
          if (yi>=0 && yi<dimy()) draw_line(0,yi,width-1,yi,color,opacity,patterny);
14756
20737
        }
14757
20738
      }
14758
20739
      return *this;
14759
20740
    }
14760
20741
 
14761
 
    //! Draw grid on the instance image
14762
 
    CImg& draw_grid(const float deltax,  const float deltay,
14763
 
                    const float offsetx, const float offsety,
14764
 
                    const bool invertx, const bool inverty,
14765
 
                    const T *const color,
14766
 
                    const float opacity=1.0f, const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 
20742
    //! Draw grid.
 
20743
    template<typename tx, typename ty, typename tc>
 
20744
      CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues, const CImg<tc>& color,
 
20745
                         const float opacity=1.0f, const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 
20746
      return draw_grid(xvalues,yvalues,color.data,opacity,patternx,patterny);
 
20747
    }
 
20748
 
 
20749
    //! Draw grid.
 
20750
    template<typename tc>
 
20751
      CImg<T>& draw_grid(const float deltax,  const float deltay,
 
20752
                         const float offsetx, const float offsety,
 
20753
                         const bool invertx, const bool inverty,
 
20754
                         const tc *const color,
 
20755
                         const float opacity=1.0f, const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
14767
20756
      CImg<unsigned int> seqx, seqy;
14768
20757
      if (deltax!=0) {
14769
20758
        const float dx = deltax>0?deltax:width*-deltax/100;
14780
20769
        if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y)+offsety,(float)height);
14781
20770
        if (inverty) cimg_foroff(seqy,y) seqy(y) = height-1-seqy(y);
14782
20771
     }
14783
 
 
14784
20772
      return draw_grid(seqx,seqy,color,opacity,patternx,patterny);
14785
20773
    }
14786
20774
 
14787
 
    // INNER CLASS used by function CImg<>::draw_fill()
14788
 
    template<typename T1,typename T2> struct _draw_fill {
14789
 
      const T1 *const color;
14790
 
      float sigma, opacity;
14791
 
      const CImg<T1> value;
14792
 
      CImg<T2> region;
14793
 
 
14794
 
      _draw_fill(const CImg<T1>& img, const int x, const int y, const int z,
14795
 
                 const T *const pcolor, const float psigma, const float popacity):
14796
 
        color(pcolor),sigma(psigma),opacity(popacity),
14797
 
        value(img.get_vector_at(x,y,z)), region(CImg<T2>(img.width,img.height,img.depth,1,(T2)false)) {
14798
 
      }
14799
 
 
14800
 
      _draw_fill& operator=(const _draw_fill& d) {
14801
 
        color = d.color;
14802
 
        sigma = d.sigma;
14803
 
        opacity = d.opacity;
14804
 
        value = d.value;
14805
 
        region = d.region;
14806
 
        return *this;
14807
 
      }
14808
 
 
14809
 
      bool comp(const CImg<T1>& A, const CImg<T1>& B) const {
14810
 
        bool res=true;
14811
 
        const T *pA=A.data+A.size();
14812
 
        for (const T *pB=B.data+B.size(); res && pA>A.data; res=(cimg::abs(*(--pA)-(*(--pB)))<=sigma) );
14813
 
        return res;
14814
 
      }
14815
 
 
14816
 
      void fill(CImg<T1>& img, const int x, const int y, const int z) {
14817
 
        if (x<0 || x>=img.dimx() || y<0 || y>=img.dimy() || z<0 || z>=img.dimz()) return;
14818
 
        if (!region(x,y,z) && comp(value,img.get_vector_at(x,y,z))) {
14819
 
          const T *col=color;
14820
 
          const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
14821
 
          int xmin,xmax;
14822
 
          if (opacity>=1) cimg_forV(img,k) img(x,y,z,k) = *(col++);
14823
 
          else cimg_forV(img,k) img(x,y,z,k) = (T1)(*(col++)*opacity+copacity*img(x,y,z,k));
14824
 
          col-=img.dim;
14825
 
          region(x,y,z) = (T2)true;
14826
 
          for (xmin=x-1; xmin>=0 && comp(value,img.get_vector_at(xmin,y,z)); --xmin) {
14827
 
            if (opacity>=1) cimg_forV(img,k) img(xmin,y,z,k) = *(col++);
14828
 
            else cimg_forV(img,k) img(xmin,y,z,k) = (T1)(*(col++)*nopacity+copacity*img(xmin,y,z,k));
14829
 
            col-=img.dim;
14830
 
            region(xmin,y,z) = (T2)true;
14831
 
          }
14832
 
          for (xmax=x+1; xmax<img.dimx() && comp(value,img.get_vector_at(xmax,y,z)); ++xmax) {
14833
 
            if (opacity>=1) cimg_forV(img,k) img(xmax,y,z,k) = *(col++);
14834
 
            else cimg_forV(img,k) img(xmax,y,z,k) = (T1)(*(col++)*nopacity+copacity*img(xmax,y,z,k));
14835
 
            col-=img.dim;
14836
 
            region(xmax,y,z) = (T2)true;
14837
 
          }
14838
 
          ++xmin; --xmax;
14839
 
          for (; xmin<=xmax; ++xmin) {
14840
 
            fill(img,xmin,y-1,z);
14841
 
            fill(img,xmin,y+1,z);
14842
 
            fill(img,xmin,y,z-1);
14843
 
            fill(img,xmin,y,z+1);
14844
 
          }
14845
 
        }
14846
 
      }
14847
 
    };
 
20775
    //! Draw grid.
 
20776
    template<typename tc>
 
20777
      CImg<T>& draw_grid(const float deltax,  const float deltay,
 
20778
                         const float offsetx, const float offsety,
 
20779
                         const bool invertx, const bool inverty,
 
20780
                         const CImg<tc>& color,
 
20781
                         const float opacity=1.0f, const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
 
20782
      return draw_grid(deltax,deltay,offsetx,offsety,invertx,inverty,color.data,opacity,patternx,patterny);
 
20783
    }
14848
20784
 
14849
20785
    //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
14850
20786
    /**
14851
 
       \param x = X-coordinate of the starting point of the region to fill.
14852
 
       \param y = Y-coordinate of the starting point of the region to fill.
14853
 
       \param z = Z-coordinate of the starting point of the region to fill.
14854
 
       \param color = an array of dimv() values of type \c T, defining the drawing color.
14855
 
       \param region = image that will contain the mask of the filled region mask, as an output.
14856
 
       \param sigma = tolerance concerning neighborhood values.
14857
 
       \param opacity = opacity of the drawing.
14858
 
 
 
20787
       \param x X-coordinate of the starting point of the region to fill.
 
20788
       \param y Y-coordinate of the starting point of the region to fill.
 
20789
       \param z Z-coordinate of the starting point of the region to fill.
 
20790
       \param color An array of dimv() values of type \c T, defining the drawing color.
 
20791
       \param region Image that will contain the mask of the filled region mask, as an output.
 
20792
       \param sigma Tolerance concerning neighborhood values.
 
20793
       \param opacity Opacity of the drawing.
 
20794
       \param high_connexity Tells if 8-connexity must be used (only for 2D images).
14859
20795
       \return \p region is initialized with the binary mask of the filled region.
14860
20796
    **/
14861
 
    template<typename t> CImg& draw_fill(const int x, const int y, const int z,
14862
 
                                         const T *const color, CImg<t>& region, const float sigma=0,
14863
 
                                         const float opacity=1.0f) {
14864
 
      _draw_fill<T,t> F(*this,x,y,z,color,sigma,opacity);
14865
 
      F.fill(*this,x,y,z);
14866
 
      region = F.region;
 
20797
    template<typename tc, typename t>
 
20798
      CImg<T>& draw_fill(const int x, const int y, const int z,
 
20799
                         const tc *const color, CImg<t>& region, const float sigma=0,
 
20800
                         const float opacity=1.0f, const bool high_connexity=false) {
 
20801
 
 
20802
#define _cimg_draw_fill_test(x,y,z,res) if (region(x,y,z)) res = false; else { \
 
20803
  res = true; \
 
20804
  const T *reference_col = reference_color.ptr() + dim, *ptrs = ptr(x,y,z) + siz; \
 
20805
  for (unsigned int i = dim; res && i; --i) { ptrs-=whz; res = (cimg::abs(*ptrs - *(--reference_col))<=sigma); } \
 
20806
  region(x,y,z) = (t)(res?1:noregion); \
 
20807
}
 
20808
 
 
20809
#define _cimg_draw_fill_set(x,y,z) { \
 
20810
  const tc *col = color; \
 
20811
  T *ptrd = ptr(x,y,z); \
 
20812
  if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; } \
 
20813
  else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; } \
 
20814
}
 
20815
 
 
20816
#define _cimg_draw_fill_insert(x,y,z) { \
 
20817
  if (posr1>=remaining.height) remaining.resize(3,remaining.height<<1,1,1,0); \
 
20818
  unsigned int *ptrr = remaining.ptr(0,posr1); \
 
20819
  *(ptrr++) = x; *(ptrr++) = y; *(ptrr++) = z; ++posr1; \
 
20820
}
 
20821
 
 
20822
#define _cimg_draw_fill_test_neighbor(x,y,z,cond) if (cond) { \
 
20823
  const unsigned int tx = x, ty = y, tz = z; \
 
20824
  _cimg_draw_fill_test(tx,ty,tz,res); if (res) _cimg_draw_fill_insert(tx,ty,tz); \
 
20825
}
 
20826
 
 
20827
      if (!color) throw CImgArgumentException("CImg<%s>::draw_fill() : Specified color is (null).",pixel_type());
 
20828
      region.assign(width,height,depth,1,(t)0);
 
20829
      if (x>=0 || x<dimx() || y>=0 || y<dimy() || z>=0 || z<dimz()) {
 
20830
        typedef typename cimg::last<T,unsigned int>::type itype;
 
20831
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
 
20832
        const unsigned int whz = width*height*depth, siz = dim*whz, W1 = width-1, H1 = height-1, D1 = depth-1;
 
20833
        const bool threed = depth>1;
 
20834
        const CImg<T> reference_color = get_vector_at(x,y,z);
 
20835
        CImg<itype> remaining(3,512,1,1,0);
 
20836
        remaining(0,0) = x; remaining(1,0) = y; remaining(2,0) = z;
 
20837
        unsigned int posr0 = 0, posr1 = 1;
 
20838
        region(x,y,z) = (t)1;
 
20839
        const t noregion = ((t)1==(t)2)?(t)0:(t)(-1);
 
20840
        if (threed) do { // 3D version of the filling algorithm
 
20841
          const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++), zc = *(pcurr++);
 
20842
          if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
 
20843
          bool cont, res;
 
20844
          unsigned int nxc = xc;
 
20845
          do { // X-backward
 
20846
            _cimg_draw_fill_set(nxc,yc,zc);
 
20847
            _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
 
20848
            _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
 
20849
            _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
 
20850
            _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
 
20851
            if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
 
20852
          } while (cont);
 
20853
          nxc = xc;
 
20854
          do { // X-forward
 
20855
            if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
 
20856
            if (cont) {
 
20857
              _cimg_draw_fill_set(nxc,yc,zc);
 
20858
              _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
 
20859
              _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
 
20860
              _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
 
20861
              _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
 
20862
            }
 
20863
          } while (cont);
 
20864
          unsigned int nyc = yc;
 
20865
          do { // Y-backward
 
20866
            if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
 
20867
            if (cont) {
 
20868
              _cimg_draw_fill_set(xc,nyc,zc);
 
20869
              _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
 
20870
              _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
 
20871
              _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
 
20872
              _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
 
20873
            }
 
20874
          } while (cont);
 
20875
          nyc = yc;
 
20876
          do { // Y-forward
 
20877
            if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
 
20878
            if (cont) {
 
20879
              _cimg_draw_fill_set(xc,nyc,zc);
 
20880
              _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
 
20881
              _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
 
20882
              _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
 
20883
              _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
 
20884
            }
 
20885
          } while (cont);
 
20886
          unsigned int nzc = zc;
 
20887
          do { // Z-backward
 
20888
            if (nzc) { --nzc; _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
 
20889
            if (cont) {
 
20890
              _cimg_draw_fill_set(xc,yc,nzc);
 
20891
              _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
 
20892
              _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
 
20893
              _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
 
20894
              _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
 
20895
            }
 
20896
          } while (cont);
 
20897
          nzc = zc;
 
20898
          do { // Z-forward
 
20899
            if ((++nzc)<=D1) { _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
 
20900
            if (cont) {
 
20901
              _cimg_draw_fill_set(xc,nyc,zc);
 
20902
              _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
 
20903
              _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
 
20904
              _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
 
20905
              _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
 
20906
            }
 
20907
          } while (cont);
 
20908
        } while (posr1>posr0);
 
20909
        else do { // 2D version of the filling algorithm
 
20910
          const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++);
 
20911
          if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
 
20912
          bool cont, res;
 
20913
          unsigned int nxc = xc;
 
20914
          do { // X-backward
 
20915
            _cimg_draw_fill_set(nxc,yc,0);
 
20916
            _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
 
20917
            _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
 
20918
            if (high_connexity) {
 
20919
              _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
 
20920
              _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
 
20921
              _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
 
20922
              _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
 
20923
            }
 
20924
            if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
 
20925
          } while (cont);
 
20926
          nxc = xc;
 
20927
          do { // X-forward
 
20928
            if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
 
20929
            if (cont) {
 
20930
              _cimg_draw_fill_set(nxc,yc,0);
 
20931
              _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
 
20932
              _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
 
20933
              if (high_connexity) {
 
20934
                _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
 
20935
                _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
 
20936
                _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
 
20937
                _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
 
20938
              }
 
20939
            }
 
20940
          } while (cont);
 
20941
          unsigned int nyc = yc;
 
20942
          do { // Y-backward
 
20943
            if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
 
20944
            if (cont) {
 
20945
              _cimg_draw_fill_set(xc,nyc,0);
 
20946
              _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
 
20947
              _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
 
20948
              if (high_connexity) {
 
20949
                _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
 
20950
                _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
 
20951
                _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
 
20952
                _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
 
20953
              }
 
20954
            }
 
20955
          } while (cont);
 
20956
          nyc = yc;
 
20957
          do { // Y-forward
 
20958
            if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
 
20959
            if (cont) {
 
20960
              _cimg_draw_fill_set(xc,nyc,0);
 
20961
              _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
 
20962
              _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
 
20963
              if (high_connexity) {
 
20964
                _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
 
20965
                _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
 
20966
                _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
 
20967
                _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
 
20968
              }
 
20969
            }
 
20970
          } while (cont);
 
20971
        } while (posr1>posr0);
 
20972
        if (noregion) cimg_for(region,ptr,t) if (*ptr==noregion) *ptr = (t)0;
 
20973
      }
14867
20974
      return *this;
14868
20975
    }
14869
20976
 
14870
20977
    //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
 
20978
    template<typename tc, typename t>
 
20979
      CImg<T>& draw_fill(const int x, const int y, const int z,
 
20980
                         const CImg<tc>& color, CImg<t>& region, const float sigma=0,
 
20981
                         const float opacity=1.0f, const bool high_connexity=false) {
 
20982
      return draw_fill(x,y,z,color.data,region,sigma,opacity,high_connexity);
 
20983
    }
 
20984
 
 
20985
    //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
14871
20986
    /**
14872
20987
       \param x = X-coordinate of the starting point of the region to fill.
14873
20988
       \param y = Y-coordinate of the starting point of the region to fill.
14876
20991
       \param sigma = tolerance concerning neighborhood values.
14877
20992
       \param opacity = opacity of the drawing.
14878
20993
    **/
14879
 
    CImg& draw_fill(const int x, const int y, const int z, const T *const color, const float sigma=0, const float opacity=1.0f) {
 
20994
    template<typename tc>
 
20995
      CImg<T>& draw_fill(const int x, const int y, const int z, const tc *const color, const float sigma=0,
 
20996
                         const float opacity=1.0f, const bool high_connexity=false) {
14880
20997
      CImg<bool> tmp;
14881
 
      return draw_fill(x,y,z,color,tmp,sigma,opacity);
 
20998
      return draw_fill(x,y,z,color,tmp,sigma,opacity,high_connexity);
 
20999
    }
 
21000
 
 
21001
    //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
 
21002
    template<typename tc>
 
21003
      CImg<T>& draw_fill(const int x, const int y, const int z, const CImg<tc>& color, const float sigma=0,
 
21004
                         const float opacity=1.0f, const bool high_connexity=false) {
 
21005
      return draw_fill(x,y,z,color.data,sigma,opacity,high_connexity);
14882
21006
    }
14883
21007
 
14884
21008
    //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
14889
21013
       \param sigma = tolerance concerning neighborhood values.
14890
21014
       \param opacity = opacity of the drawing.
14891
21015
    **/
14892
 
    CImg& draw_fill(const int x, const int y, const T *const color, const float sigma=0, const float opacity=1.0f) {
 
21016
    template<typename tc>
 
21017
      CImg<T>& draw_fill(const int x, const int y, const tc *const color, const float sigma=0,
 
21018
                         const float opacity=1.0f, const bool high_connexity=false) {
14893
21019
      CImg<bool> tmp;
14894
 
      return draw_fill(x,y,0,color,tmp,sigma,opacity);
14895
 
    }
14896
 
 
14897
 
    //! Draw a plasma square in the instance image.
 
21020
      return draw_fill(x,y,0,color,tmp,sigma,opacity,high_connexity);
 
21021
    }
 
21022
 
 
21023
    //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
 
21024
    template<typename tc>
 
21025
      CImg<T>& draw_fill(const int x, const int y, const CImg<tc>& color, const float sigma=0,
 
21026
                         const float opacity=1.0f, const bool high_connexity=false) {
 
21027
      return draw_fill(x,y,color.data,sigma,opacity,high_connexity);
 
21028
    }
 
21029
 
 
21030
    //! Draw a plasma random texture.
14898
21031
    /**
14899
21032
       \param x0 = X-coordinate of the upper-left corner of the plasma.
14900
21033
       \param y0 = Y-coordinate of the upper-left corner of the plasma.
14904
21037
       \param beta = Beta-parameter of the plasma.
14905
21038
       \param opacity = opacity of the drawing.
14906
21039
    **/
14907
 
    CImg& draw_plasma(const int x0, const int y0, const int x1, const int y1,
14908
 
                      const double alpha=1.0, const double beta=1.0, const float opacity=1.0f) {
 
21040
    CImg<T>& draw_plasma(const int x0, const int y0, const int x1, const int y1,
 
21041
                         const double alpha=1.0, const double beta=1.0, const float opacity=1.0f) {
14909
21042
      if (!is_empty()) {
 
21043
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
14910
21044
        int nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1;
14911
21045
        if (nx1<nx0) cimg::swap(nx0,nx1);
14912
21046
        if (ny1<ny0) cimg::swap(ny0,ny1);
14915
21049
        if (ny0<0) ny0 = 0;
14916
21050
        if (ny1>=dimy()) ny1 = height-1;
14917
21051
        const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx = (xc-nx0), dy = (yc-ny0);
14918
 
        const double dc = std::sqrt((double)(dx*dx+dy*dy))*alpha + beta;
14919
 
        float val = 0;
 
21052
        const Tfloat dc = (Tfloat)(std::sqrt((double)(dx*dx+dy*dy))*alpha + beta);
 
21053
        Tfloat val = 0;
14920
21054
        cimg_forV(*this,k) {
14921
21055
          if (opacity>=1) {
14922
 
            (*this)(xc,ny0,0,k) = (T)(0.5f*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k)));
14923
 
            (*this)(xc,ny1,0,k) = (T)(0.5f*((*this)(nx0,ny1,0,k)+(*this)(nx1,ny1,0,k)));
14924
 
            (*this)(nx0,yc,0,k) = (T)(0.5f*((*this)(nx0,ny0,0,k)+(*this)(nx0,ny1,0,k)));
14925
 
            (*this)(nx1,yc,0,k) = (T)(0.5f*((*this)(nx1,ny0,0,k)+(*this)(nx1,ny1,0,k)));
 
21056
            const Tfloat
 
21057
              val0 = (*this)(nx0,ny0,0,k), val1 = (*this)(nx1,ny0,0,k),
 
21058
              val2 = (*this)(nx0,ny1,0,k), val3 = (*this)(nx1,ny1,0,k);
 
21059
            (*this)(xc,ny0,0,k) = (T)((val0+val1)/2);
 
21060
            (*this)(xc,ny1,0,k) = (T)((val2+val3)/2);
 
21061
            (*this)(nx0,yc,0,k) = (T)((val0+val2)/2);
 
21062
            (*this)(nx1,yc,0,k) = (T)((val1+val3)/2);
14926
21063
            do {
14927
 
              val = (float)(0.25f*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) +
14928
 
                                   (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand());
14929
 
            } while (val<(float)cimg::type<T>::min() || val>(float)cimg::type<T>::max());
 
21064
              val = (Tfloat)(0.25f*((Tfloat)((*this)(nx0,ny0,0,k)) +
 
21065
                                   (Tfloat)((*this)(nx1,ny0,0,k)) +
 
21066
                                   (Tfloat)((*this)(nx1,ny1,0,k)) +
 
21067
                                   (Tfloat)((*this)(nx0,ny1,0,k))) +
 
21068
                            dc*cimg::grand());
 
21069
            } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
14930
21070
            (*this)(xc,yc,0,k)  = (T)val;
14931
21071
          } else {
14932
 
            const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
14933
 
            (*this)(xc,ny0,0,k) = (T)(0.5f*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k))*nopacity + copacity*(*this)(xc,ny0,0,k));
14934
 
            (*this)(xc,ny1,0,k) = (T)(0.5f*((*this)(nx0,ny1,0,k)+(*this)(nx1,ny1,0,k))*nopacity + copacity*(*this)(xc,ny1,0,k));
14935
 
            (*this)(nx0,yc,0,k) = (T)(0.5f*((*this)(nx0,ny0,0,k)+(*this)(nx0,ny1,0,k))*nopacity + copacity*(*this)(nx0,yc,0,k));
14936
 
            (*this)(nx1,yc,0,k) = (T)(0.5f*((*this)(nx1,ny0,0,k)+(*this)(nx1,ny1,0,k))*nopacity + copacity*(*this)(nx1,yc,0,k));
 
21072
            const Tfloat
 
21073
              val0 = (*this)(nx0,ny0,0,k), val1 = (*this)(nx1,ny0,0,k),
 
21074
              val2 = (*this)(nx0,ny1,0,k), val3 = (*this)(nx1,ny1,0,k);
 
21075
            (*this)(xc,ny0,0,k) = (T)(((val0+val1)*nopacity + copacity*(*this)(xc,ny0,0,k))/2);
 
21076
            (*this)(xc,ny1,0,k) = (T)(((val2+val3)*nopacity + copacity*(*this)(xc,ny1,0,k))/2);
 
21077
            (*this)(nx0,yc,0,k) = (T)(((val0+val2)*nopacity + copacity*(*this)(nx0,yc,0,k))/2);
 
21078
            (*this)(nx1,yc,0,k) = (T)(((val1+val3)*nopacity + copacity*(*this)(nx1,yc,0,k))/2);
14937
21079
            do {
14938
 
              val = (float)(0.25f*(((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) +
14939
 
                                             (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand())*nopacity
14940
 
                            + copacity*(*this)(xc,yc,0,k));
14941
 
            } while (val<(float)cimg::type<T>::min() || val>(float)cimg::type<T>::max());
 
21080
              val = (Tfloat)(0.25f*(((Tfloat)((*this)(nx0,ny0,0,k)) +
 
21081
                                    (Tfloat)((*this)(nx1,ny0,0,k)) +
 
21082
                                    (Tfloat)((*this)(nx1,ny1,0,k)) +
 
21083
                                    (Tfloat)((*this)(nx0,ny1,0,k))) +
 
21084
                                   dc*cimg::grand())*nopacity + copacity*(*this)(xc,yc,0,k));
 
21085
            } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
14942
21086
            (*this)(xc,yc,0,k)  = (T)val;
14943
21087
          }
14944
21088
        }
14952
21096
      return *this;
14953
21097
    }
14954
21098
 
14955
 
    //! Draw a plasma in the instance image.
 
21099
    //! Draw a plasma random texture.
14956
21100
    /**
14957
21101
       \param alpha = Alpha-parameter of the plasma.
14958
21102
       \param beta = Beta-parameter of the plasma.
14959
21103
       \param opacity = opacity of the drawing.
14960
21104
    **/
14961
 
    CImg& draw_plasma(const double alpha=1.0, const double beta=1.0, const float opacity=1.0f) {
 
21105
    CImg<T>& draw_plasma(const double alpha=1.0, const double beta=1.0, const float opacity=1.0f) {
14962
21106
      return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity);
14963
21107
    }
14964
21108
 
 
21109
    //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
 
21110
    template<typename tc>
 
21111
    CImg<T>& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1,
 
21112
                             const CImg<tc>& color_palette,
 
21113
                             const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
 
21114
                             const unsigned int itermax=255,
 
21115
                             const bool normalized_iteration=false,
 
21116
                             const bool julia_set=false,
 
21117
                             const double paramr=0, const double parami=0,
 
21118
                             const float opacity=1.0f) {
 
21119
      if (is_empty()) return *this;
 
21120
      CImg<tc> palette;
 
21121
      if (color_palette) palette.assign(color_palette.data,color_palette.size()/color_palette.dim,1,1,color_palette.dim,true);
 
21122
      if (palette && palette.dim!=dim)
 
21123
        throw CImgArgumentException("CImg<%s>::draw_mandelbrot() : Specified color palette (%u,%u,%u,%u,%p) is not \n"
 
21124
                                    "compatible with instance image (%u,%u,%u,%u,%p).",
 
21125
                                    pixel_type(),color_palette.width,color_palette.height,color_palette.depth,color_palette.dim,
 
21126
                                    color_palette.data,width,height,depth,dim,data);
 
21127
      const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f), ln2 = (float)std::log(2.0);
 
21128
      unsigned int iter = 0;
 
21129
      cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
 
21130
        const double x = z0r + p*(z1r-z0r)/width, y = z0i + q*(z1i-z0i)/height;
 
21131
        double zr, zi, cr, ci;
 
21132
        if (julia_set) { zr = x; zi = y; cr = paramr; ci = parami; }
 
21133
        else { zr = paramr; zi = parami; cr = x; ci = y; }
 
21134
        for (iter=1; zr*zr + zi*zi<=4 && iter<=itermax; ++iter) {
 
21135
          const double temp = zr*zr - zi*zi + cr;
 
21136
          zi = 2*zr*zi + ci;
 
21137
          zr = temp;
 
21138
        }
 
21139
        if (iter>itermax) {
 
21140
          if (palette) {
 
21141
            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette(0,k);
 
21142
            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(0,k)*nopacity + (*this)(p,q,0,k)*copacity);
 
21143
          } else {
 
21144
            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)0;
 
21145
            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)((*this)(p,q,0,k)*copacity);
 
21146
          }
 
21147
        } else if (normalized_iteration) {
 
21148
          const float
 
21149
            normz = (float)cimg::abs(zr*zr+zi*zi),
 
21150
            niter = (float)(iter + 1 - std::log(std::log(normz))/ln2);
 
21151
          if (palette) {
 
21152
            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette.linear_at1(niter,k);
 
21153
            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette.linear_at1(niter,k)*nopacity + (*this)(p,q,0,k)*copacity);
 
21154
          } else {
 
21155
            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)niter;
 
21156
            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(niter*nopacity + (*this)(p,q,0,k)*copacity);
 
21157
          }
 
21158
        } else {
 
21159
          if (palette) {
 
21160
            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette.at1(iter,k);
 
21161
            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(iter,k)*nopacity + (*this)(p,q,0,k)*copacity);
 
21162
          } else {
 
21163
            if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)iter;
 
21164
            else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(iter*nopacity + (*this)(p,q,0,k)*copacity);
 
21165
          }
 
21166
        }
 
21167
      }
 
21168
      return *this;
 
21169
    }
 
21170
 
 
21171
    //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
 
21172
    template<typename tc>
 
21173
    CImg<T>& draw_mandelbrot(const CImg<tc>& color_palette,
 
21174
                             const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
 
21175
                             const unsigned int itermax=255,
 
21176
                             const bool normalized_iteration=false,
 
21177
                             const bool julia_set=false,
 
21178
                             const double paramr=0, const double parami=0,
 
21179
                             const float opacity=1.0f) {
 
21180
      return draw_mandelbrot(0,0,width-1,height-1,color_palette,z0r,z0i,z1r,z1i,itermax,normalized_iteration,julia_set,paramr,parami,opacity);
 
21181
    }
 
21182
 
14965
21183
    //! Draw a 1D gaussian function in the instance image.
14966
21184
    /**
14967
21185
       \param xc = X-coordinate of the gaussian center.
14969
21187
       \param color = array of dimv() values of type \c T, defining the drawing color.
14970
21188
       \param opacity = opacity of the drawing.
14971
21189
    **/
14972
 
    CImg& draw_gaussian(const float xc, const double sigma, const T *const color, const float opacity=1.0f) {
 
21190
    template<typename tc>
 
21191
      CImg<T>& draw_gaussian(const float xc, const double sigma, const tc *const color, const float opacity=1.0f) {
14973
21192
      if (!is_empty()) {
14974
21193
        if (!color) throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",pixel_type());
14975
21194
        const double sigma2 = 2*sigma*sigma;
14976
21195
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
14977
21196
        const unsigned int whz = width*height*depth;
14978
 
        const T *col = color;
 
21197
        const tc *col = color;
14979
21198
        cimg_forX(*this,x) {
14980
21199
          const float dx = (x-xc);
14981
21200
          const double val = std::exp( -dx*dx/sigma2 );
14982
21201
          T *ptrd = ptr(x,0,0,0);
14983
21202
          if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
14984
 
          else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
 
21203
          else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
14985
21204
          col-=dim;
14986
21205
        }
14987
21206
      }
14988
21207
      return *this;
14989
21208
    }
14990
21209
 
14991
 
    //! Draw an anisotropic 2D gaussian function in the instance image.
 
21210
    //! Draw a 1D gaussian function in the instance image.
 
21211
    template<typename tc>
 
21212
      CImg<T>& draw_gaussian(const float xc, const double sigma, const CImg<tc>& color, const float opacity=1.0f) {
 
21213
      return draw_gaussian(xc,sigma,color.data,opacity);
 
21214
    }
 
21215
 
 
21216
    //! Draw an anisotropic 2D gaussian function.
14992
21217
    /**
14993
21218
       \param xc = X-coordinate of the gaussian center.
14994
21219
       \param yc = Y-coordinate of the gaussian center.
14996
21221
       \param color = array of dimv() values of type \c T, defining the drawing color.
14997
21222
       \param opacity = opacity of the drawing.
14998
21223
    **/
14999
 
    template<typename t> CImg& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
15000
 
                                             const T *const color, const float opacity=1.0f) {
 
21224
    template<typename t, typename tc>
 
21225
      CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
 
21226
                             const tc *const color, const float opacity=1.0f) {
 
21227
      typedef typename cimg::superset<t,float>::type tfloat;
15001
21228
      if (!is_empty()) {
15002
21229
        if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1)
15003
21230
          throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 2x2 matrix.",
15004
21231
                                      pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
15005
21232
        if (!color) throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",pixel_type());
15006
 
        const CImg<t> invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0);
15007
 
        const t &a=invT2(0,0), &b=2*invT2(1,0), &c=invT2(1,1);
 
21233
        const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
 
21234
        const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1);
15008
21235
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
15009
21236
        const unsigned int whz = width*height*depth;
15010
 
        const T *col = color;
 
21237
        const tc *col = color;
15011
21238
        float dy = -yc;
15012
21239
        cimg_forY(*this,y) {
15013
21240
          float dx = -xc;
15015
21242
            const float val = (float)std::exp(a*dx*dx + b*dx*dy + c*dy*dy);
15016
21243
            T *ptrd = ptr(x,y,0,0);
15017
21244
            if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
15018
 
            else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
 
21245
            else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
15019
21246
            col-=dim;
15020
21247
            ++dx;
15021
21248
          }
15025
21252
      return *this;
15026
21253
    }
15027
21254
 
15028
 
    //! Draw an isotropic 2D gaussian function in the instance image
 
21255
    //! Draw an anisotropic 2D gaussian function.
 
21256
    template<typename t, typename tc>
 
21257
      CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
 
21258
                             const CImg<tc>& color, const float opacity=1.0f) {
 
21259
      return draw_gaussian(xc,yc,tensor,color.data,opacity);
 
21260
    }
 
21261
 
 
21262
    //! Draw an isotropic 2D gaussian function.
15029
21263
    /**
15030
21264
       \param xc = X-coordinate of the gaussian center.
15031
21265
       \param yc = Y-coordinate of the gaussian center.
15033
21267
       \param color = array of dimv() values of type \c T, defining the drawing color.
15034
21268
       \param opacity = opacity of the drawing.
15035
21269
    **/
15036
 
    CImg& draw_gaussian(const float xc, const float yc, const float sigma, const T *const color, const float opacity=1.0f) {
 
21270
    template<typename tc>
 
21271
      CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma, const tc *const color, const float opacity=1.0f) {
15037
21272
      return draw_gaussian(xc,yc,CImg<float>::diagonal(sigma,sigma),color,opacity);
15038
21273
    }
15039
21274
 
15040
 
    //! Draw an anisotropic 3D gaussian function in the instance image.
 
21275
    //! Draw an isotropic 2D gaussian function.
 
21276
    template<typename tc>
 
21277
      CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma, const CImg<tc>& color, const float opacity=1.0f) {
 
21278
      return draw_gaussian(xc,yc,sigma,color.data,opacity);
 
21279
    }
 
21280
 
 
21281
    //! Draw an anisotropic 3D gaussian function.
15041
21282
    /**
15042
21283
       \param xc = X-coordinate of the gaussian center.
15043
21284
       \param yc = Y-coordinate of the gaussian center.
15046
21287
       \param color = array of dimv() values of type \c T, defining the drawing color.
15047
21288
       \param opacity = opacity of the drawing.
15048
21289
    **/
15049
 
    template<typename t> CImg& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
15050
 
                                             const T *const color, const float opacity=1.0f) {
 
21290
    template<typename t, typename tc>
 
21291
      CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
 
21292
                             const tc *const color, const float opacity=1.0f) {
15051
21293
      if (!is_empty()) {
15052
21294
        if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1)
15053
21295
          throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 3x3 matrix.",
15054
21296
                                      pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
15055
 
        const CImg<t> invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0);
 
21297
        const CImg<t> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
15056
21298
        const t 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);
15057
21299
        const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f);
15058
21300
        const unsigned int whz = width*height*depth;
15059
 
        const T *col = color;
 
21301
        const tc *col = color;
15060
21302
        cimg_forXYZ(*this,x,y,z) {
15061
21303
          const float dx = (x-xc), dy = (y-yc), dz = (z-zc);
15062
21304
          const double val = std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz);
15063
21305
          T *ptrd = ptr(x,y,z,0);
15064
21306
          if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
15065
 
          else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; }
 
21307
          else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
15066
21308
          col-=dim;
15067
21309
        }
15068
21310
      }
15069
21311
      return *this;
15070
21312
    }
15071
21313
 
15072
 
    //! Draw an isotropic 3D gaussian function in the instance image
 
21314
    //! Draw an anisotropic 3D gaussian function.
 
21315
    template<typename t, typename tc>
 
21316
      CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
 
21317
                             const CImg<tc>& color, const float opacity=1.0f) {
 
21318
      return draw_gaussian(xc,yc,zc,tensor,color.data,opacity);
 
21319
    }
 
21320
 
 
21321
    //! Draw an isotropic 3D gaussian function.
15073
21322
   /**
15074
21323
       \param xc = X-coordinate of the gaussian center.
15075
21324
       \param yc = Y-coordinate of the gaussian center.
15078
21327
       \param color = array of dimv() values of type \c T, defining the drawing color.
15079
21328
       \param opacity = opacity of the drawing.
15080
21329
    **/
15081
 
    CImg& draw_gaussian(const float xc, const float yc, const float zc,
15082
 
                        const double sigma, const T *const color, const float opacity=1.0f) {
 
21330
    template<typename tc>
 
21331
      CImg<T>& draw_gaussian(const float xc, const float yc, const float zc,
 
21332
                             const double sigma, const tc *const color, const float opacity=1.0f) {
15083
21333
      return draw_gaussian(xc,yc,zc,CImg<float>::diagonal(sigma,sigma,sigma),color,opacity);
15084
21334
    }
15085
21335
 
15086
 
    //! Draw a 3D object in the instance image
 
21336
    //! Draw an isotropic 3D gaussian function.
 
21337
    template<typename tc>
 
21338
      CImg<T>& draw_gaussian(const float xc, const float yc, const float zc,
 
21339
                             const double sigma, const CImg<tc>& color, const float opacity=1.0f) {
 
21340
      return draw_gaussian(xc,yc,zc,sigma,color.data,opacity);
 
21341
    }
 
21342
 
 
21343
    //! Draw a 3D object.
15087
21344
    /**
15088
21345
       \param X = X-coordinate of the 3d object position
15089
21346
       \param Y = Y-coordinate of the 3d object position
15098
21355
       \param lightx = X-coordinate of the light
15099
21356
       \param lighty = Y-coordinate of the light
15100
21357
       \param lightz = Z-coordinate of the light
15101
 
       \param ambient_light = Brightness of the ambient light
 
21358
       \param specular_shine = Shininess of the object
15102
21359
    **/
15103
 
    template<typename tp, typename tf, typename to>
15104
 
      CImg& draw_object3d(const float X, const float Y, const float Z,
15105
 
                          const CImg<tp>& points, const CImgList<tf>& primitives,
15106
 
                          const CImgList<T>& colors, const CImgList<to>& opacities,
15107
 
                          const unsigned int render_type=4,
15108
 
                          const bool double_sided=false, const float focale=500,
15109
 
                          const float lightx=0, const float lighty=0, const float lightz=-5000,
15110
 
                          const float ambient_light=0.05f) {
15111
 
 
 
21360
 
 
21361
#ifndef cimg_use_board
 
21362
    template<typename tp, typename tf, typename tc, typename to>
 
21363
      CImg<T>& draw_object3d(const float X, const float Y, const float Z,
 
21364
                             const CImg<tp>& points, const CImgList<tf>& primitives,
 
21365
                             const CImgList<tc>& colors, const CImgList<to>& opacities,
 
21366
                             const unsigned int render_type=4,
 
21367
                             const bool double_sided=false, const float focale=500,
 
21368
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
21369
                             const float specular_light=0.2f, const float specular_shine=0.1f) {
 
21370
#else
 
21371
    template<typename tp, typename tf, typename tc, typename to>
 
21372
      CImg<T>& draw_object3d(const float X, const float Y, const float Z,
 
21373
                             const CImg<tp>& points, const CImgList<tf>& primitives,
 
21374
                             const CImgList<tc>& colors, const CImgList<to>& opacities,
 
21375
                             const unsigned int render_type=4,
 
21376
                             const bool double_sided=false, const float focale=500,
 
21377
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
21378
                             const float specular_light=0.2f, const float specular_shine=0.1f) {
 
21379
      return draw_object3d(0,X,Y,Z,points,primitives,colors,opacities,render_type,double_sided,focale,lightx,
 
21380
                           lighty,lightz,specular_light,specular_shine);
 
21381
    }
 
21382
 
 
21383
    template<typename tp, typename tf, typename tc, typename to>
 
21384
      CImg<T>& draw_object3d(BoardLib::Board& board,
 
21385
                             const float X, const float Y, const float Z,
 
21386
                             const CImg<tp>& points, const CImgList<tf>& primitives,
 
21387
                             const CImgList<tc>& colors, const CImgList<to>& opacities,
 
21388
                             const unsigned int render_type=4,
 
21389
                             const bool double_sided=false, const float focale=500,
 
21390
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
21391
                             const float specular_light=0.2f, const float specular_shine=0.1f) {
 
21392
      return draw_object3d(&board,X,Y,Z,points,primitives,colors,opacities,render_type,double_sided,focale,lightx,
 
21393
                           lighty,lightz,specular_light,specular_shine);
 
21394
    }
 
21395
 
 
21396
    template<typename tp, typename tf, typename tc, typename to>
 
21397
      CImg<T>& draw_object3d(BoardLib::Board *const board,
 
21398
                             const float X, const float Y, const float Z,
 
21399
                             const CImg<tp>& points, const CImgList<tf>& primitives,
 
21400
                             const CImgList<tc>& colors, const CImgList<to>& opacities,
 
21401
                             const unsigned int render_type=4,
 
21402
                             const bool double_sided=false, const float focale=500,
 
21403
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
21404
                             const float specular_light=0.2f, const float specular_shine=0.1f) {
 
21405
#endif
15112
21406
      static CImg<float> light_texture;
15113
21407
      if (is_empty() || !points || !primitives) return *this;
15114
21408
      if (!colors || !opacities)
15116
21410
 
15117
21411
      if (points.height<3)
15118
21412
        return draw_object3d(X,Y,Z,points.get_resize(-100,3,1,1,0),primitives,colors,opacities,
15119
 
                             render_type,double_sided,focale,lightx,lighty,lightz,ambient_light);
 
21413
                             render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 
21414
 
 
21415
      const float
 
21416
        nspec = 1-(specular_light<0?0:(specular_light>1?1:specular_light)),
 
21417
        nspec2 = 1+(specular_shine<0?0:specular_shine),
 
21418
        nsl1 = (nspec2-1)/cimg::sqr(nspec-1),
 
21419
        nsl2 = (1-2*nsl1*nspec),
 
21420
        nsl3 = nspec2-nsl1-nsl2;
15120
21421
 
15121
21422
      // Create light texture for phong-like rendering
15122
21423
      if (render_type==5) {
15123
21424
        if (colors.size>primitives.size) light_texture.assign(colors[primitives.size])/=255;
15124
21425
        else {
15125
 
          static float olightx = 0, olighty = 0, olightz = 0, oambient_light = 0;
15126
 
          if (!light_texture || lightx!=olightx || lighty!=olighty || lightz!=olightz || ambient_light!=oambient_light) {
 
21426
          static float olightx = 0, olighty = 0, olightz = 0, ospecular_shine = 0;
 
21427
          if (!light_texture || lightx!=olightx || lighty!=olighty || lightz!=olightz || specular_shine!=ospecular_shine) {
15127
21428
            light_texture.assign(512,512);
15128
21429
            const float white[] = { 1.0f },
15129
21430
              dlx = lightx-X, dly = lighty-Y, dlz = lightz-Z,
15130
21431
                nl = (float)std::sqrt(dlx*dlx+dly*dly+dlz*dlz),
15131
21432
                nlx = light_texture.width/2*(1+dlx/nl),
15132
21433
                nly = light_texture.height/2*(1+dly/nl);
15133
 
              (light_texture.draw_gaussian(nlx,nly,light_texture.width/4.0f,white)+=ambient_light);
15134
 
              olightx = lightx; olighty = lighty; olightz = lightz; oambient_light = ambient_light;
 
21434
              light_texture.draw_gaussian(nlx,nly,light_texture.width/3.0f,white);
 
21435
              cimg_forXY(light_texture,x,y) {
 
21436
                const float factor = light_texture(x,y);
 
21437
                if (factor>nspec) light_texture(x,y) = cimg::min(2.0f,nsl1*factor*factor+nsl2*factor+nsl3);
 
21438
              }
 
21439
              olightx = lightx; olighty = lighty; olightz = lightz; ospecular_shine = specular_shine;
15135
21440
          }
15136
21441
        }
15137
21442
      }
15291
21596
              ly = Y+(y0+y1+y2)/3-lighty,
15292
21597
              lz = Z+(z0+z1+z2)/3-lightz,
15293
21598
              nl = (float)std::sqrt(1e-5f+lx*lx+ly*ly+lz*lz),
15294
 
              factor = cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl);
15295
 
            lightprops[l] = cimg::max(factor,0.0f) + ambient_light;
 
21599
              factor = cimg::max(cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl),0.0f);
 
21600
            lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
15296
21601
          } else lightprops[l] = 1.0f;
15297
21602
        }
15298
21603
      } break;
15299
21604
 
15300
21605
      case 4: // Gouraud Shading
15301
21606
      case 5: { // Phong-Shading
15302
 
        CImg<float> points_normals(points.width,double_sided?7:3,1,1,0);
 
21607
        CImg<float> points_normals(points.width,3,1,1,0);
15303
21608
        for (unsigned int l=0; l<nb_visibles; ++l) {
15304
21609
          const CImg<tf>& primitive = primitives[visibles(l)];
15305
21610
          const unsigned int psize = primitive.size();
15325
21630
              nx = nnx/norm,
15326
21631
              ny = nny/norm,
15327
21632
              nz = nnz/norm;
15328
 
            if (double_sided) {
15329
 
              unsigned int ind = nz>0?3U:0U;
15330
 
              const float incr = nz>0?-1.0f:1.0f;
15331
 
              points_normals(i0,  ind)+=nx; points_normals(i1,ind)+=nx; points_normals(i2,ind)+=nx;
15332
 
              points_normals(i0,++ind)+=ny; points_normals(i1,ind)+=ny; points_normals(i2,ind)+=ny;
15333
 
              points_normals(i0,++ind)+=nz; points_normals(i1,ind)+=nz; points_normals(i2,ind)+=nz;
15334
 
              points_normals(i0,6)+=incr; points_normals(i1,6)+=incr; points_normals(i2,6)+=incr;
15335
 
              if (rectangle_flag) {
15336
 
                points_normals(i3,ind)+=nz; points_normals(i3,--ind)+=ny; points_normals(i3,--ind)+=nz; points_normals(i3,6)+=incr;
15337
 
              }
15338
 
            } else {
15339
 
              points_normals(i0,0)+=nx; points_normals(i0,1)+=ny; points_normals(i0,2)+=nz;
15340
 
              points_normals(i1,0)+=nx; points_normals(i1,1)+=ny; points_normals(i1,2)+=nz;
15341
 
              points_normals(i2,0)+=nx; points_normals(i2,1)+=ny; points_normals(i2,2)+=nz;
15342
 
              if (rectangle_flag) { points_normals(i3,0)+=nx; points_normals(i3,1)+=ny; points_normals(i3,2)+=nz; }
15343
 
            }
 
21633
            points_normals(i0,0)+=nx; points_normals(i0,1)+=ny; points_normals(i0,2)+=nz;
 
21634
            points_normals(i1,0)+=nx; points_normals(i1,1)+=ny; points_normals(i1,2)+=nz;
 
21635
            points_normals(i2,0)+=nx; points_normals(i2,1)+=ny; points_normals(i2,2)+=nz;
 
21636
            if (rectangle_flag) { points_normals(i3,0)+=nx; points_normals(i3,1)+=ny; points_normals(i3,2)+=nz; }
15344
21637
          }
15345
21638
        }
15346
21639
 
15347
 
        if (double_sided) cimg_forX(points_normals,l) if (points_normals(l,6)<0) {
15348
 
          points_normals(l,0) = -points_normals(l,3);
15349
 
          points_normals(l,1) = -points_normals(l,4);
15350
 
          points_normals(l,2) = -points_normals(l,5);
 
21640
        if (double_sided) cimg_forX(points_normals,p) if (points_normals(p,2)>0) {
 
21641
          points_normals(p,0) = -points_normals(p,0);
 
21642
          points_normals(p,1) = -points_normals(p,1);
 
21643
          points_normals(p,2) = -points_normals(p,2);
15351
21644
        }
15352
21645
 
15353
21646
        if (render_type==4) {
15362
21655
              ly = (float)(Y+points(ll,1)-lighty),
15363
21656
              lz = (float)(Z+points(ll,2)-lightz),
15364
21657
              nl = (float)std::sqrt(1e-5f+lx*lx+ly*ly+lz*lz),
15365
 
              factor = (-lx*nx-ly*ny-lz*nz)/(norm*nl);
15366
 
            lightprops[ll] = cimg::max(factor,0.0f) + ambient_light;
 
21658
              factor = cimg::max((-lx*nx-ly*ny-lz*nz)/(norm*nl),0.0f);
 
21659
            lightprops[ll] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
15367
21660
          }
15368
21661
        } else {
15369
21662
          const unsigned int
15390
21683
      { for (unsigned int l=0; l<nb_visibles; ++l) {
15391
21684
        const unsigned int n_primitive = visibles(permutations(l));
15392
21685
        const CImg<tf>& primitive = primitives[n_primitive];
15393
 
        const CImg<T>& color = colors[n_primitive%colors.size];
 
21686
        const CImg<tc>& color = colors[n_primitive%colors.size];
15394
21687
        const CImg<to>& opacity = opacities[n_primitive%opacsize];
15395
21688
        const float opac = opacity.size()?(float)opacity(0):1.0f;
15396
21689
 
15398
21691
        case 1: { // Colored point or sprite
15399
21692
          const unsigned int n0 = (unsigned int)primitive[0];
15400
21693
          const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
15401
 
          if (color.size()==dim) draw_point(x0,y0,color.ptr(),opac);
15402
 
          else {
 
21694
          if (color.size()==dim) {
 
21695
            draw_point(x0,y0,color,opac);
 
21696
#ifdef cimg_use_board
 
21697
            if (board) {
 
21698
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21699
              board->fillCircle((float)x0,dimy()-(float)y0,0);
 
21700
            }
 
21701
#endif
 
21702
          } else {
15403
21703
            const float z = Z + points(n0,2);
15404
21704
            const int
15405
21705
              factor = (int)(focale*100/(z+focale)),
15406
21706
              sw = color.width*factor/200,
15407
21707
              sh = color.height*factor/200;
15408
 
            if (x0+sw>=0 && x0-sw<(int)width && y0+sh>=0 && y0-sh<(int)height) {
 
21708
            if (x0+sw>=0 && x0-sw<dimx() && y0+sh>=0 && y0-sh<dimy()) {
15409
21709
              const CImg<T> sprite = color.get_resize(-factor,-factor,1,-100,render_type<=3?1:3);
15410
 
              if (opacity.width==color.width && opacity.height==color.height)
 
21710
              if (opacity.width==color.width && opacity.height==color.height) {
15411
21711
                draw_image(sprite,opacity.get_resize(sprite.width,sprite.height,1,sprite.dim,1),x0-sw,y0-sh,0,0);
15412
 
              else draw_image(sprite,x0-sw,y0-sh,0,0,opac);
 
21712
#ifdef cimg_use_board
 
21713
                if (board) {
 
21714
                  board->setPenColorRGBi(128,128,128);
 
21715
                  board->setFillColor(BoardLib::Color::none);
 
21716
                  board->drawRectangle((float)x0-sw,dimy()-(float)y0+sh,sw,sh);
 
21717
                }
 
21718
#endif
 
21719
              } else {
 
21720
                draw_image(sprite,x0-sw,y0-sh,0,0,opac);
 
21721
#ifdef cimg_use_board
 
21722
                if (board) {
 
21723
                  board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
21724
                  board->setFillColor(BoardLib::Color::none);
 
21725
                  board->drawRectangle((float)x0-sw,dimy()-(float)y0+sh,sw,sh);
 
21726
                }
 
21727
#endif
 
21728
              }
15413
21729
            }
15414
21730
          }
15415
21731
        } break;
15420
21736
          const int
15421
21737
            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
15422
21738
            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
15423
 
          if (render_type) draw_line(x0,y0,x1,y1,color.ptr(),opac);
15424
 
          else draw_point(x0,y0,color.ptr(),opac).draw_point(x1,y1,color.ptr(),opac);
 
21739
          if (render_type) {
 
21740
            draw_line(x0,y0,x1,y1,color,opac);
 
21741
#ifdef cimg_use_board
 
21742
            if (board) {
 
21743
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21744
              board->drawLine((float)x0,dimy()-(float)y0,x1,dimy()-(float)y1);
 
21745
            }
 
21746
#endif
 
21747
          } else {
 
21748
            draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac);
 
21749
#ifdef cimg_use_board
 
21750
            if (board) {
 
21751
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21752
              board->drawCircle((float)x0,dimy()-(float)y0,0);
 
21753
              board->drawCircle((float)x1,dimy()-(float)y1,0);
 
21754
            }
 
21755
#endif
 
21756
          }
15425
21757
        } break;
15426
21758
        case 5: { // Colored sphere
15427
21759
          const unsigned int
15440
21772
          }
15441
21773
          switch (render_type) {
15442
21774
          case 0:
15443
 
            draw_point(x0,y0,color.ptr(),opac);
 
21775
            draw_point(x0,y0,color,opac);
 
21776
#ifdef cimg_use_board
 
21777
            if (board) {
 
21778
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21779
              board->fillCircle((float)x0,dimy()-(float)y0,0);
 
21780
            }
 
21781
#endif
15444
21782
            break;
15445
21783
          case 1:
15446
 
            draw_circle(x0,y0,radius,color.ptr(),opac,~0U);
 
21784
            draw_circle(x0,y0,radius,color,opac,~0U);
 
21785
#ifdef cimg_use_board
 
21786
            if (board) {
 
21787
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21788
              board->setFillColor(BoardLib::Color::none);
 
21789
              board->drawCircle((float)x0,dimy()-(float)y0,(float)radius);
 
21790
            }
 
21791
#endif
15447
21792
            break;
15448
21793
          default:
15449
 
            draw_circle(x0,y0,radius,color.ptr(),opac);
 
21794
            draw_circle(x0,y0,radius,color,opac);
 
21795
#ifdef cimg_use_board
 
21796
            if (board) {
 
21797
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21798
              board->fillCircle((float)x0,dimy()-(float)y0,(float)radius);
 
21799
            }
 
21800
#endif
15450
21801
            break;
15451
21802
          }
15452
21803
        } break;
15464
21815
          const float
15465
21816
            z0 = points(n0,2) + Z + focale,
15466
21817
            z1 = points(n1,2) + Z + focale;
15467
 
          if (render_type) draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac);
15468
 
          else draw_point(x0,y0,color.get_vector_at(tx0,ty0).ptr(),opac).
15469
 
                 draw_point(x1,y1,color.get_vector_at(tx1,ty1).ptr(),opac);
 
21818
          if (render_type) {
 
21819
            draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac);
 
21820
#ifdef cimg_use_board
 
21821
            if (board) {
 
21822
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
21823
              board->drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 
21824
            }
 
21825
#endif
 
21826
          } else {
 
21827
            draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
 
21828
              draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac);
 
21829
#ifdef cimg_use_board
 
21830
            if (board) {
 
21831
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
21832
              board->drawCircle((float)x0,dimy()-(float)y0,0);
 
21833
              board->drawCircle((float)x1,dimy()-(float)y1,0);
 
21834
            }
 
21835
#endif
 
21836
          }
15470
21837
        } break;
15471
21838
        case 3: { // Colored triangle
15472
21839
          const unsigned int
15477
21844
            x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
15478
21845
            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
15479
21846
            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
15480
 
          switch(render_type) {
 
21847
          switch (render_type) {
15481
21848
          case 0:
15482
 
            draw_point(x0,y0,color.ptr(),opac).draw_point(x1,y1,color.ptr(),opac).draw_point(x2,y2,color.ptr(),opac);
 
21849
            draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).draw_point(x2,y2,color,opac);
 
21850
#ifdef cimg_use_board
 
21851
            if (board) {
 
21852
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21853
              board->drawCircle((float)x0,dimy()-(float)y0,0);
 
21854
              board->drawCircle((float)x1,dimy()-(float)y1,0);
 
21855
              board->drawCircle((float)x2,dimy()-(float)y2,0);
 
21856
            }
 
21857
#endif
15483
21858
            break;
15484
21859
          case 1:
15485
 
            draw_line(x0,y0,x1,y1,color.ptr(),opac).draw_line(x0,y0,x2,y2,color.ptr(),opac).
15486
 
              draw_line(x1,y1,x2,y2,color.ptr(),opac);
 
21860
            draw_line(x0,y0,x1,y1,color,opac).draw_line(x0,y0,x2,y2,color,opac).
 
21861
              draw_line(x1,y1,x2,y2,color,opac);
 
21862
#ifdef cimg_use_board
 
21863
            if (board) {
 
21864
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21865
              board->drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 
21866
              board->drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
 
21867
              board->drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
21868
            }
 
21869
#endif
15487
21870
            break;
15488
21871
          case 2:
15489
 
            draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opac);
 
21872
            draw_triangle(x0,y0,x1,y1,x2,y2,color,opac);
 
21873
#ifdef cimg_use_board
 
21874
            if (board) {
 
21875
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21876
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
21877
            }
 
21878
#endif
15490
21879
            break;
15491
21880
          case 3:
15492
 
            _draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opac,lightprops(l));
 
21881
            _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l));
 
21882
#ifdef cimg_use_board
 
21883
            if (board) {
 
21884
              const float lp = cimg::min(lightprops(l),1.0f);
 
21885
              board->setPenColorRGBi((unsigned char)(color[0]*lp),
 
21886
                                     (unsigned char)(color[1]*lp),
 
21887
                                     (unsigned char)(color[2]*lp),
 
21888
                                     (unsigned char)(opac*255));
 
21889
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
21890
            }
 
21891
#endif
15493
21892
            break;
15494
21893
          case 4:
15495
 
            draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),lightprops(n0),lightprops(n1),lightprops(n2),opac);
 
21894
            draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
 
21895
#ifdef cimg_use_board
 
21896
            if (board) {
 
21897
              board->setPenColorRGBi((unsigned char)(color[0]),
 
21898
                                     (unsigned char)(color[1]),
 
21899
                                     (unsigned char)(color[2]),
 
21900
                                     (unsigned char)(opac*255));
 
21901
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
 
21902
                                         (float)x1,dimy()-(float)y1,lightprops(n1),
 
21903
                                         (float)x2,dimy()-(float)y2,lightprops(n2));
 
21904
            }
 
21905
#endif
15496
21906
            break;
15497
 
          case 5:
 
21907
          case 5: {
15498
21908
            const unsigned int
15499
21909
              lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
15500
21910
              lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
15501
21911
              lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1);
15502
 
            draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
15503
 
            break;
 
21912
            draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
 
21913
#ifdef cimg_use_board
 
21914
            if (board) {
 
21915
              const float
 
21916
                l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
 
21917
                l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
 
21918
                l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
 
21919
              board->setPenColorRGBi((unsigned char)(color[0]),
 
21920
                                     (unsigned char)(color[1]),
 
21921
                                     (unsigned char)(color[2]),
 
21922
                                     (unsigned char)(opac*255));
 
21923
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 
21924
                                         (float)x1,dimy()-(float)y1,l1,
 
21925
                                         (float)x2,dimy()-(float)y2,l2);
 
21926
            }
 
21927
#endif
 
21928
          } break;
15504
21929
          }
15505
21930
        } break;
15506
21931
        case 4: { // Colored rectangle
15514
21939
            x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
15515
21940
            x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
15516
21941
            x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
15517
 
          switch(render_type) {
 
21942
          switch (render_type) {
15518
21943
          case 0:
15519
 
            draw_point(x0,y0,color.ptr(),opac).draw_point(x1,y1,color.ptr(),opac).
15520
 
              draw_point(x2,y2,color.ptr(),opac).draw_point(x3,y3,color.ptr(),opac);
 
21944
            draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).
 
21945
              draw_point(x2,y2,color,opac).draw_point(x3,y3,color,opac);
 
21946
#ifdef cimg_use_board
 
21947
            if (board) {
 
21948
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21949
              board->drawCircle((float)x0,dimy()-(float)y0,0);
 
21950
              board->drawCircle((float)x1,dimy()-(float)y1,0);
 
21951
              board->drawCircle((float)x2,dimy()-(float)y2,0);
 
21952
              board->drawCircle((float)x3,dimy()-(float)y3,0);
 
21953
            }
 
21954
#endif
15521
21955
            break;
15522
21956
          case 1:
15523
 
            draw_line(x0,y0,x1,y1,color.ptr(),opac).draw_line(x1,y1,x2,y2,color.ptr(),opac).
15524
 
              draw_line(x2,y2,x3,y3,color.ptr(),opac).draw_line(x3,y3,x0,y0,color.ptr(),opac);
 
21957
            draw_line(x0,y0,x1,y1,color,opac).draw_line(x1,y1,x2,y2,color,opac).
 
21958
              draw_line(x2,y2,x3,y3,color,opac).draw_line(x3,y3,x0,y0,color,opac);
 
21959
#ifdef cimg_use_board
 
21960
            if (board) {
 
21961
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21962
              board->drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 
21963
              board->drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
21964
              board->drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 
21965
              board->drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
 
21966
            }
 
21967
#endif
15525
21968
            break;
15526
21969
          case 2:
15527
 
            draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opac).draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),opac);
 
21970
            draw_triangle(x0,y0,x1,y1,x2,y2,color,opac).draw_triangle(x0,y0,x2,y2,x3,y3,color,opac);
 
21971
#ifdef cimg_use_board
 
21972
            if (board) {
 
21973
              board->setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
 
21974
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
21975
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 
21976
            }
 
21977
#endif
15528
21978
            break;
15529
21979
          case 3:
15530
 
            _draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opac,lightprops(l)).
15531
 
              _draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),opac,lightprops(l));
 
21980
            _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l)).
 
21981
              _draw_triangle(x0,y0,x2,y2,x3,y3,color.data,opac,lightprops(l));
 
21982
#ifdef cimg_use_board
 
21983
            if (board) {
 
21984
              const float lp = cimg::min(lightprops(l),1.0f);
 
21985
              board->setPenColorRGBi((unsigned char)(color[0]*lp),
 
21986
                                     (unsigned char)(color[1]*lp),
 
21987
                                     (unsigned char)(color[2]*lp),(unsigned char)(opac*255));
 
21988
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
21989
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 
21990
            }
 
21991
#endif
15532
21992
            break;
15533
21993
          case 4: {
15534
21994
            const float
15535
21995
              lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
15536
21996
              lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
15537
 
            draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),lightprop0,lightprop1,lightprop2,opac).
15538
 
              draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),lightprop0,lightprop2,lightprop3,opac);
 
21997
            draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprop0,lightprop1,lightprop2,opac).
 
21998
              draw_triangle(x0,y0,x2,y2,x3,y3,color,lightprop0,lightprop2,lightprop3,opac);
 
21999
#ifdef cimg_use_board
 
22000
            if (board) {
 
22001
              board->setPenColorRGBi((unsigned char)(color[0]),
 
22002
                                     (unsigned char)(color[1]),
 
22003
                                     (unsigned char)(color[2]),
 
22004
                                     (unsigned char)(opac*255));
 
22005
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 
22006
                                         (float)x1,dimy()-(float)y1,lightprop1,
 
22007
                                         (float)x2,dimy()-(float)y2,lightprop2);
 
22008
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 
22009
                                         (float)x2,dimy()-(float)y2,lightprop2,
 
22010
                                         (float)x3,dimy()-(float)y3,lightprop3);
 
22011
            }
 
22012
#endif
15539
22013
          } break;
15540
22014
          case 5: {
15541
22015
            const unsigned int
15543
22017
              lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
15544
22018
              lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
15545
22019
              lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
15546
 
            draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
15547
 
              draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
 
22020
            draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
 
22021
              draw_triangle(x0,y0,x2,y2,x3,y3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
 
22022
#ifdef cimg_use_board
 
22023
            if (board) {
 
22024
              const float
 
22025
                l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
 
22026
                l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
 
22027
                l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
 
22028
                l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
 
22029
              board->setPenColorRGBi((unsigned char)(color[0]),
 
22030
                                     (unsigned char)(color[1]),
 
22031
                                     (unsigned char)(color[2]),
 
22032
                                     (unsigned char)(opac*255));
 
22033
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 
22034
                                         (float)x1,dimy()-(float)y1,l1,
 
22035
                                         (float)x2,dimy()-(float)y2,l2);
 
22036
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 
22037
                                         (float)x2,dimy()-(float)y2,l2,
 
22038
                                         (float)x3,dimy()-(float)y3,l3);
 
22039
            }
 
22040
#endif
15548
22041
          } break;
15549
22042
          }
15550
22043
        } break;
15567
22060
            z0 = points(n0,2) + Z + focale,
15568
22061
            z1 = points(n1,2) + Z + focale,
15569
22062
            z2 = points(n2,2) + Z + focale;
15570
 
          switch(render_type) {
 
22063
          switch (render_type) {
15571
22064
          case 0:
15572
 
            draw_point(x0,y0,color.get_vector_at(tx0,ty0).ptr(),opac).
15573
 
              draw_point(x1,y1,color.get_vector_at(tx1,ty1).ptr(),opac).
15574
 
              draw_point(x2,y2,color.get_vector_at(tx2,ty2).ptr(),opac);
 
22065
            draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
 
22066
              draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
 
22067
              draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac);
 
22068
#ifdef cimg_use_board
 
22069
            if (board) {
 
22070
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
22071
              board->drawCircle((float)x0,dimy()-(float)y0,0);
 
22072
              board->drawCircle((float)x1,dimy()-(float)y1,0);
 
22073
              board->drawCircle((float)x2,dimy()-(float)y2,0);
 
22074
            }
 
22075
#endif
15575
22076
            break;
15576
22077
          case 1:
15577
22078
            draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
15578
22079
              draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
15579
22080
              draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
 
22081
#ifdef cimg_use_board
 
22082
            if (board) {
 
22083
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
22084
              board->drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 
22085
              board->drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
 
22086
              board->drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
22087
            }
 
22088
#endif
15580
22089
            break;
15581
22090
          case 2:
15582
22091
            draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
 
22092
#ifdef cimg_use_board
 
22093
            if (board) {
 
22094
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
22095
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
22096
            }
 
22097
#endif
15583
22098
            break;
15584
22099
          case 3:
15585
22100
            draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
 
22101
#ifdef cimg_use_board
 
22102
            if (board) {
 
22103
              const float lp = cimg::min(lightprops(l),1.0f);
 
22104
              board->setPenColorRGBi((unsigned char)(128*lp),
 
22105
                                     (unsigned char)(128*lp),
 
22106
                                     (unsigned char)(128*lp),
 
22107
                                     (unsigned char)(opac*255));
 
22108
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
22109
            }
 
22110
#endif
15586
22111
            break;
15587
22112
          case 4:
15588
22113
            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);
 
22114
#ifdef cimg_use_board
 
22115
            if (board) {
 
22116
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
22117
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
 
22118
                                         (float)x1,dimy()-(float)y1,lightprops(n1),
 
22119
                                         (float)x2,dimy()-(float)y2,lightprops(n2));
 
22120
            }
 
22121
#endif
15589
22122
            break;
15590
22123
          case 5:
15591
22124
            draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
15593
22126
                          (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
15594
22127
                          (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
15595
22128
                          opac);
 
22129
#ifdef cimg_use_board
 
22130
            if (board) {
 
22131
              const float
 
22132
                l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
 
22133
                l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
 
22134
                l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
 
22135
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
22136
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,(float)x1,dimy()-(float)y1,l1,(float)x2,dimy()-(float)y2,l2);
 
22137
            }
 
22138
#endif
15596
22139
            break;
15597
22140
          }
15598
22141
        } break;
15620
22163
            z1 = points(n1,2) + Z + focale,
15621
22164
            z2 = points(n2,2) + Z + focale,
15622
22165
            z3 = points(n3,2) + Z + focale;
15623
 
          switch(render_type) {
 
22166
          switch (render_type) {
15624
22167
          case 0:
15625
 
            draw_point(x0,y0,color.get_vector_at(tx0,ty0).ptr(),opac).
15626
 
              draw_point(x1,y1,color.get_vector_at(tx1,ty1).ptr(),opac).
15627
 
              draw_point(x2,y2,color.get_vector_at(tx2,ty2).ptr(),opac).
15628
 
              draw_point(x3,y3,color.get_vector_at(tx3,ty3).ptr(),opac);
 
22168
            draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
 
22169
              draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
 
22170
              draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac).
 
22171
              draw_point(x3,y3,color.get_vector_at(tx3,ty3),opac);
 
22172
#ifdef cimg_use_board
 
22173
            if (board) {
 
22174
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
22175
              board->drawCircle((float)x0,dimy()-(float)y0,0);
 
22176
              board->drawCircle((float)x1,dimy()-(float)y1,0);
 
22177
              board->drawCircle((float)x2,dimy()-(float)y2,0);
 
22178
              board->drawCircle((float)x3,dimy()-(float)y3,0);
 
22179
            }
 
22180
#endif
15629
22181
            break;
15630
22182
          case 1:
15631
22183
            draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
15632
22184
              draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
15633
22185
              draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
15634
22186
              draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
 
22187
#ifdef cimg_use_board
 
22188
            if (board) {
 
22189
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
22190
              board->drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
 
22191
              board->drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
22192
              board->drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 
22193
              board->drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
 
22194
            }
 
22195
#endif
15635
22196
            break;
15636
22197
          case 2:
15637
22198
            draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
15638
22199
              draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
 
22200
#ifdef cimg_use_board
 
22201
            if (board) {
 
22202
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
22203
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
22204
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 
22205
            }
 
22206
#endif
15639
22207
            break;
15640
22208
          case 3:
15641
22209
            draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
15642
22210
              draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
 
22211
#ifdef cimg_use_board
 
22212
            if (board) {
 
22213
              const float lp = cimg::min(lightprops(l),1.0f);
 
22214
              board->setPenColorRGBi((unsigned char)(128*lp),
 
22215
                                     (unsigned char)(128*lp),
 
22216
                                     (unsigned char)(128*lp),
 
22217
                                     (unsigned char)(opac*255));
 
22218
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
 
22219
              board->fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
 
22220
            }
 
22221
#endif
15643
22222
            break;
15644
22223
          case 4: {
15645
22224
            const float
15647
22226
              lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
15648
22227
            draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
15649
22228
              draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
 
22229
#ifdef cimg_use_board
 
22230
            if (board) {
 
22231
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
22232
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 
22233
                                         (float)x1,dimy()-(float)y1,lightprop1,
 
22234
                                         (float)x2,dimy()-(float)y2,lightprop2);
 
22235
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
 
22236
                                         (float)x2,dimy()-(float)y2,lightprop2,
 
22237
                                         (float)x3,dimy()-(float)y3,lightprop3);
 
22238
            }
 
22239
#endif
15650
22240
          } break;
15651
22241
          case 5: {
15652
22242
            const unsigned int
15656
22246
              lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
15657
22247
            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).
15658
22248
              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);
 
22249
#ifdef cimg_use_board
 
22250
            if (board) {
 
22251
              const float
 
22252
                l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
 
22253
                l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
 
22254
                l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
 
22255
                l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
 
22256
              board->setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
 
22257
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 
22258
                                         (float)x1,dimy()-(float)y1,l1,
 
22259
                                         (float)x2,dimy()-(float)y2,l2);
 
22260
              board->fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
 
22261
                                         (float)x2,dimy()-(float)y2,l2,
 
22262
                                         (float)x3,dimy()-(float)y3,l3);
 
22263
            }
 
22264
#endif
15659
22265
          } break;
15660
22266
          }
15661
22267
        } break;
15665
22271
      return *this;
15666
22272
    }
15667
22273
 
15668
 
    //! Draw a 3D object in the instance image
15669
 
    template<typename tp, typename tf, typename to>
15670
 
      CImg& draw_object3d(const float X, const float Y, const float Z,
15671
 
                          const CImgList<tp>& points, const CImgList<tf>& primitives,
15672
 
                          const CImgList<T>& colors, const CImgList<to>& opacities,
15673
 
                          const unsigned int render_type=4,
15674
 
                          const bool double_sided=false, const float focale=500,
15675
 
                          const float lightx=0, const float lighty=0, const float lightz=-5000,
15676
 
                          const float ambient_light=0.05f) {
 
22274
 
 
22275
    //! Draw a 3D object.
 
22276
    template<typename tp, typename tf, typename tc, typename to>
 
22277
      CImg<T>& draw_object3d(const float X, const float Y, const float Z,
 
22278
                             const CImgList<tp>& points, const CImgList<tf>& primitives,
 
22279
                             const CImgList<tc>& colors, const CImgList<to>& opacities,
 
22280
                             const unsigned int render_type=4,
 
22281
                             const bool double_sided=false, const float focale=500,
 
22282
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
22283
                             const float specular_light=0.2f, const float specular_shine=0.1f) {
15677
22284
      if (!points) return *this;
15678
22285
      CImg<tp> npoints(points.size,3,1,1,0);
15679
 
      tp *ptrX = npoints.ptr(), *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2);
 
22286
      tp *ptrX = npoints.data, *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2);
15680
22287
      cimg_forX(npoints,l) {
15681
22288
        const CImg<tp>& point = points[l];
15682
22289
        const unsigned int siz = point.size();
15688
22295
        *(ptrX++) = point(0);
15689
22296
      }
15690
22297
      return draw_object3d(X,Y,Z,npoints,primitives,colors,opacities,
15691
 
                           render_type,double_sided,focale,lightx,lighty,lightz,ambient_light);
15692
 
    }
15693
 
 
15694
 
    //! Draw a 3D object in the instance image
15695
 
    template<typename tp, typename tf, typename to>
15696
 
      CImg& draw_object3d(const float X, const float Y, const float Z,
15697
 
                          const CImg<tp>& points, const CImgList<tf>& primitives,
15698
 
                          const CImgList<T>& colors, const CImg<to>& opacities,
15699
 
                          const unsigned int render_type=4,
15700
 
                          const bool double_sided=false, const float focale=500,
15701
 
                          const float lightx=0, const float lighty=0, const float lightz=-5000,
15702
 
                          const float ambient_light=0.05f) {
 
22298
                           render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 
22299
    }
 
22300
 
 
22301
#ifdef cimg_use_board
 
22302
    template<typename tp, typename tf, typename tc, typename to>
 
22303
      CImg<T>& draw_object3d(BoardLib::Board& board,
 
22304
                             const float X, const float Y, const float Z,
 
22305
                             const CImgList<tp>& points, const CImgList<tf>& primitives,
 
22306
                             const CImgList<tc>& colors, const CImgList<to>& opacities,
 
22307
                             const unsigned int render_type=4,
 
22308
                             const bool double_sided=false, const float focale=500,
 
22309
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
22310
                             const float specular_light=0.2f, const float specular_shine=0.1f) {
 
22311
      if (!points) return *this;
 
22312
      CImg<tp> npoints(points.size,3,1,1,0);
 
22313
      tp *ptrX = npoints.data, *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2);
 
22314
      cimg_forX(npoints,l) {
 
22315
        const CImg<tp>& point = points[l];
 
22316
        const unsigned int siz = point.size();
 
22317
        if (!siz)
 
22318
          throw CImgArgumentException("CImg<%s>::draw_object3d() : Given points (size=%u) contains a null element at "
 
22319
                                      "position %u.",pixel_type(),points.size,l);
 
22320
        *(ptrZ++) = (siz>2)?point(2):0;
 
22321
        *(ptrY++) = (siz>1)?point(1):0;
 
22322
        *(ptrX++) = point(0);
 
22323
      }
 
22324
      return draw_object3d(board,X,Y,Z,npoints,primitives,colors,opacities,
 
22325
                           render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 
22326
    }
 
22327
#endif
 
22328
 
 
22329
    //! Draw a 3D object.
 
22330
    template<typename tp, typename tf, typename tc, typename to>
 
22331
      CImg<T>& draw_object3d(const float X, const float Y, const float Z,
 
22332
                             const CImg<tp>& points, const CImgList<tf>& primitives,
 
22333
                             const CImgList<tc>& colors, const CImg<to>& opacities,
 
22334
                             const unsigned int render_type=4,
 
22335
                             const bool double_sided=false, const float focale=500,
 
22336
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
22337
                             const float specular_light=0.2f, const float specular_shine=0.1f) {
15703
22338
      CImgList<to> nopacities(opacities.size(),1);
15704
22339
      cimglist_for(nopacities,l) nopacities(l,0) = opacities(l);
15705
22340
      return draw_object3d(X,Y,Z,points,primitives,colors,nopacities,
15706
 
                           render_type,double_sided,focale,lightx,lighty,lightz,ambient_light);
15707
 
    }
15708
 
 
15709
 
    //! Draw a 3D object in the instance image
15710
 
    template<typename tp, typename tf, typename to>
15711
 
      CImg& draw_object3d(const float X, const float Y, const float Z,
15712
 
                          const CImgList<tp>& points, const CImgList<tf>& primitives,
15713
 
                          const CImgList<T>& colors, const CImg<to>& opacities,
15714
 
                          const unsigned int render_type=4,
15715
 
                          const bool double_sided=false, const float focale=500,
15716
 
                          const float lightx=0, const float lighty=0, const float lightz=-5000,
15717
 
                          const float ambient_light=0.05f) {
 
22341
                           render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 
22342
    }
 
22343
 
 
22344
#ifdef cimg_use_board
 
22345
    template<typename tp, typename tf, typename tc, typename to>
 
22346
      CImg<T>& draw_object3d(BoardLib::Board& board,
 
22347
                             const float X, const float Y, const float Z,
 
22348
                             const CImg<tp>& points, const CImgList<tf>& primitives,
 
22349
                             const CImgList<tc>& colors, const CImg<to>& opacities,
 
22350
                             const unsigned int render_type=4,
 
22351
                             const bool double_sided=false, const float focale=500,
 
22352
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
22353
                             const float specular_light=0.2f, const float specular_shine=0.1f) {
 
22354
      CImgList<to> nopacities(opacities.size(),1);
 
22355
      cimglist_for(nopacities,l) nopacities(l,0) = opacities(l);
 
22356
      return draw_object3d(board,X,Y,Z,points,primitives,colors,nopacities,
 
22357
                           render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 
22358
    }
 
22359
#endif
 
22360
 
 
22361
    //! Draw a 3D object.
 
22362
    template<typename tp, typename tf, typename tc, typename to>
 
22363
      CImg<T>& draw_object3d(const float X, const float Y, const float Z,
 
22364
                             const CImgList<tp>& points, const CImgList<tf>& primitives,
 
22365
                             const CImgList<tc>& colors, const CImg<to>& opacities,
 
22366
                             const unsigned int render_type=4,
 
22367
                             const bool double_sided=false, const float focale=500,
 
22368
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
22369
                             const float specular_light=0.2f, const float specular_shine=0.1f) {
15718
22370
      CImgList<to> nopacities(opacities.size(),1);
15719
22371
      { cimglist_for(nopacities,l) nopacities(l,0) = opacities(l); }
15720
22372
      if (!points) return *this;
15721
22373
      CImg<tp> npoints(points.size,3,1,1,0);
15722
 
      tp *ptrX = npoints.ptr(), *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2);
 
22374
      tp *ptrX = npoints.data, *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2);
15723
22375
      cimg_forX(npoints,l) {
15724
22376
        const CImg<tp>& point = points[l];
15725
22377
        const unsigned int siz = point.size();
15731
22383
        *(ptrX++) = point(0);
15732
22384
      }
15733
22385
      return draw_object3d(X,Y,Z,npoints,primitives,colors,nopacities,
15734
 
                           render_type,double_sided,focale,lightx,lighty,lightz,ambient_light);
15735
 
    }
15736
 
 
15737
 
    //! Draw a 3D object in the instance image
15738
 
    template<typename tp, typename tf>
15739
 
      CImg& draw_object3d(const float X, const float Y, const float Z,
15740
 
                          const tp& points, const CImgList<tf>& primitives,
15741
 
                          const CImgList<T>& colors,
15742
 
                          const unsigned int render_type=4,
15743
 
                          const bool double_sided=false, const float focale=500,
15744
 
                          const float lightx=0, const float lighty=0, const float lightz=-5000,
15745
 
                          const float ambient_light=0.05f,
15746
 
                          const float opacity=1.0f) {
 
22386
                           render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 
22387
    }
 
22388
 
 
22389
#ifdef cimg_use_board
 
22390
    template<typename tp, typename tf, typename tc, typename to>
 
22391
      CImg<T>& draw_object3d(BoardLib::Board& board,
 
22392
                             const float X, const float Y, const float Z,
 
22393
                             const CImgList<tp>& points, const CImgList<tf>& primitives,
 
22394
                             const CImgList<tc>& colors, const CImg<to>& opacities,
 
22395
                             const unsigned int render_type=4,
 
22396
                             const bool double_sided=false, const float focale=500,
 
22397
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
22398
                             const float specular_light=0.2f, const float specular_shine=0.1f) {
 
22399
      CImgList<to> nopacities(opacities.size(),1);
 
22400
      { cimglist_for(nopacities,l) nopacities(l,0) = opacities(l); }
 
22401
      if (!points) return *this;
 
22402
      CImg<tp> npoints(points.size,3,1,1,0);
 
22403
      tp *ptrX = npoints.data, *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2);
 
22404
      cimg_forX(npoints,l) {
 
22405
        const CImg<tp>& point = points[l];
 
22406
        const unsigned int siz = point.size();
 
22407
        if (!siz)
 
22408
          throw CImgArgumentException("CImg<%s>::draw_object3d() : Given points (size=%u) contains a null element at "
 
22409
                                      "position %u.",pixel_type(),points.size,l);
 
22410
        *(ptrZ++) = (siz>2)?point(2):0;
 
22411
        *(ptrY++) = (siz>1)?point(1):0;
 
22412
        *(ptrX++) = point(0);
 
22413
      }
 
22414
      return draw_object3d(board,X,Y,Z,npoints,primitives,colors,nopacities,
 
22415
                           render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
 
22416
    }
 
22417
#endif
 
22418
 
 
22419
    //! Draw a 3D object.
 
22420
    template<typename tp, typename tf, typename tc>
 
22421
      CImg<T>& draw_object3d(const float X, const float Y, const float Z,
 
22422
                             const tp& points, const CImgList<tf>& primitives,
 
22423
                             const CImgList<tc>& colors,
 
22424
                             const unsigned int render_type=4,
 
22425
                             const bool double_sided=false, const float focale=500,
 
22426
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
22427
                             const float specular_light=0.2f, const float specular_shine=0.1f,
 
22428
                             const float opacity=1.0f) {
15747
22429
      return draw_object3d(X,Y,Z,points,primitives,colors,
15748
22430
                           CImg<float>(primitives.size,1,1,1,opacity),
15749
22431
                           render_type,double_sided,focale,lightx,lighty,lightz,
15750
 
                           ambient_light);
15751
 
    }
 
22432
                           specular_light,specular_shine);
 
22433
    }
 
22434
 
 
22435
#ifdef cimg_use_board
 
22436
    template<typename tp, typename tf, typename tc>
 
22437
      CImg<T>& draw_object3d(BoardLib::Board& board,
 
22438
                             const float X, const float Y, const float Z,
 
22439
                             const tp& points, const CImgList<tf>& primitives,
 
22440
                             const CImgList<tc>& colors,
 
22441
                             const unsigned int render_type=4,
 
22442
                             const bool double_sided=false, const float focale=500,
 
22443
                             const float lightx=0, const float lighty=0, const float lightz=-5000,
 
22444
                             const float specular_light=0.2f, const float specular_shine=0.1f,
 
22445
                             const float opacity=1.0f) {
 
22446
      return draw_object3d(board,X,Y,Z,points,primitives,colors,
 
22447
                           CImg<float>(primitives.size,1,1,1,opacity),
 
22448
                           render_type,double_sided,focale,lightx,lighty,lightz,
 
22449
                           specular_light,specular_shine);
 
22450
    }
 
22451
#endif
15752
22452
 
15753
22453
    //@}
15754
22454
    //----------------------------
15767
22467
       \param cond = the border condition type (0=zero, 1=dirichlet)
15768
22468
       \param weighted_correl = enable local normalization.
15769
22469
    **/
15770
 
    template<typename t> CImg<typename cimg::largest<T,t>::type>
 
22470
    template<typename t> CImg<typename cimg::superset2<T,t,float>::type>
15771
22471
    get_correlate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_correl=false) const {
15772
 
      typedef typename cimg::largest<T,t>::type restype;
15773
 
      typedef typename cimg::largest2<T,t,float>::type ftype;
15774
 
 
15775
 
      if (is_empty()) return CImg<restype>();
 
22472
      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 
22473
      if (is_empty()) return *this;
15776
22474
      if (!mask || mask.dim!=1)
15777
22475
        throw CImgArgumentException("CImg<%s>::correlate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
15778
22476
                                    pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
15779
 
      CImg<restype> dest(width,height,depth,dim);
 
22477
      CImg<Ttfloat> dest(width,height,depth,dim);
15780
22478
      if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) {
15781
 
        // A special optimization is done for 2x2,3x3,4x4,5x5,2x2x2 and 3x3x3 mask (with cond=1)
 
22479
        // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with cond=1)
15782
22480
        switch (mask.depth) {
15783
22481
        case 3: {
15784
 
          CImg_3x3x3(I,T);
15785
 
          if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr3x3x3(I,mask);
15786
 
          else cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) {
15787
 
            const double norm = (double)cimg_squaresum3x3x3(I);
15788
 
            dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr3x3x3(I,mask)/std::sqrt(norm)):0;
 
22482
          T I[27] = { 0 };
 
22483
          cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 
22484
            (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] +
 
22485
             I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
 
22486
             I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] +
 
22487
             I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
 
22488
             I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
 
22489
             I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
 
22490
             I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] +
 
22491
             I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
 
22492
             I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26]);
 
22493
          if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) {
 
22494
            const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] +
 
22495
                                           I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +
 
22496
                                           I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] +
 
22497
                                           I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
 
22498
                                           I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
 
22499
                                           I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
 
22500
                                           I[18]*I[18] + I[19]*I[19] + I[20]*I[20] +
 
22501
                                           I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
 
22502
                                           I[24]*I[24] + I[25]*I[25] + I[26]*I[26]);
 
22503
            if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
15789
22504
          }
15790
22505
        } break;
15791
22506
        case 2: {
15792
 
          CImg_2x2x2(I,T);
15793
 
          if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr2x2x2(I,mask);
15794
 
          else cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) {
15795
 
            const double norm = (double)cimg_squaresum2x2x2(I);
15796
 
            dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr2x2x2(I,mask)/std::sqrt(norm)):0;
 
22507
          T I[8] = { 0 };
 
22508
          cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 
22509
            (I[0]*mask[0] + I[1]*mask[1] +
 
22510
             I[2]*mask[2] + I[3]*mask[3] +
 
22511
             I[4]*mask[4] + I[5]*mask[5] +
 
22512
             I[6]*mask[6] + I[7]*mask[7]);
 
22513
          if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) {
 
22514
            const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
 
22515
                                           I[2]*I[2] + I[3]*I[3] +
 
22516
                                           I[4]*I[4] + I[5]*I[5] +
 
22517
                                           I[6]*I[6] + I[7]*I[7]);
 
22518
            if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
15797
22519
          }
15798
22520
        } break;
15799
22521
        default:
15800
22522
        case 1:
15801
22523
          switch (mask.width) {
 
22524
          case 6: {
 
22525
            T I[36] = { 0 };
 
22526
            cimg_forZV(*this,z,v) cimg_for6x6(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 
22527
              (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
 
22528
               I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
 
22529
               I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
 
22530
               I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
 
22531
               I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26] + I[27]*mask[27] + I[28]*mask[28] + I[29]*mask[29] +
 
22532
               I[30]*mask[30] + I[31]*mask[31] + I[32]*mask[32] + I[33]*mask[33] + I[34]*mask[34] + I[35]*mask[35]);
 
22533
            if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
 
22534
              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] +
 
22535
                                             I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
 
22536
                                             I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
 
22537
                                             I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
 
22538
                                             I[24]*I[24] + I[25]*I[25] + I[26]*I[26] + I[27]*I[27] + I[28]*I[28] + I[29]*I[29] +
 
22539
                                             I[30]*I[30] + I[31]*I[31] + I[32]*I[32] + I[33]*I[33] + I[34]*I[34] + I[35]*I[35]);
 
22540
              if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
 
22541
            }
 
22542
          } break;
15802
22543
          case 5: {
15803
 
            CImg_5x5(I,T);
15804
 
            if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr5x5(I,mask);
15805
 
            else cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
15806
 
              const double norm = (double)cimg_squaresum5x5(I);
15807
 
              dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr5x5(I,mask)/std::sqrt(norm)):0;
 
22544
            T I[25] = { 0 };
 
22545
            cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 
22546
              (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] +
 
22547
               I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] +
 
22548
               I[10]*mask[10] + I[11]*mask[11] + I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
 
22549
               I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] + I[18]*mask[18] + I[19]*mask[19] +
 
22550
               I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] + I[24]*mask[24]);
 
22551
            if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
 
22552
              const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] +
 
22553
                                             I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] +
 
22554
                                             I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
 
22555
                                             I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] +
 
22556
                                             I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24]);
 
22557
              if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
15808
22558
            }
15809
22559
          } break;
15810
22560
          case 4: {
15811
 
            CImg_4x4(I,T);
15812
 
            if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr4x4(I,mask);
15813
 
            else cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) {
15814
 
              const double norm = (double)cimg_squaresum4x4(I);
15815
 
              dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr4x4(I,mask)/std::sqrt(norm)):0;
 
22561
            T I[16] = { 0 };
 
22562
            cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 
22563
              (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] +
 
22564
               I[ 4]*mask[ 4] + I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] +
 
22565
               I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
 
22566
               I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15]);
 
22567
            if (weighted_correl) cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) {
 
22568
              const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] +
 
22569
                                             I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] +
 
22570
                                             I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
 
22571
                                             I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15]);
 
22572
              if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
15816
22573
            }
15817
22574
          } break;
15818
22575
          case 3: {
15819
 
            CImg_3x3(I,T);
15820
 
            if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr3x3(I,mask);
15821
 
            else cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) {
15822
 
              const double norm = (double)cimg_squaresum3x3(I);
15823
 
              dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr3x3(I,mask)/std::sqrt(norm)):0;
 
22576
            T I[9] = { 0 };
 
22577
            cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 
22578
              (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
 
22579
               I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
 
22580
               I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
 
22581
            if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) {
 
22582
              const double weight = (double)(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] +
 
22583
                                             I[3]*I[3] + I[4]*I[4] + I[5]*I[5] +
 
22584
                                             I[6]*I[6] + I[7]*I[7] + I[8]*I[8]);
 
22585
              if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
15824
22586
            }
15825
22587
          } break;
15826
22588
          case 2: {
15827
 
            CImg_2x2(I,T);
15828
 
            if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr2x2(I,mask);
15829
 
            else cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) {
15830
 
              const double norm = (double)cimg_squaresum2x2(I);
15831
 
              dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr2x2(I,mask)/std::sqrt(norm)):0;
 
22589
            T I[4] = { 0 };
 
22590
            cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
 
22591
              (I[0]*mask[0] + I[1]*mask[1] +
 
22592
               I[2]*mask[2] + I[3]*mask[3]);
 
22593
            if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) {
 
22594
              const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
 
22595
                                             I[2]*I[2] + I[3]*I[3]);
 
22596
              if (weight>0) dest(x,y,z,v)/=(Ttfloat)std::sqrt(weight);
15832
22597
            }
15833
22598
          } break;
15834
22599
          case 1: (dest.assign(*this))*=mask(0); break;
15835
22600
          }
15836
22601
        }
15837
 
      } else {
15838
 
        // Generic version for other masks
15839
 
        const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.depth%2);
 
22602
      } else { // Generic version for other masks
 
22603
        const int
 
22604
          mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
 
22605
          mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
 
22606
          mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
15840
22607
        cimg_forV(*this,v)
15841
 
          if (!weighted_correl) {       // Classical correlation
15842
 
            for (int z=czm; z<dimz()-czm; ++z) for (int y=cym; y<dimy()-cym; ++y) for (int x=cxm; x<dimx()-cxm; ++x) {
15843
 
              ftype val = 0;
15844
 
              for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
15845
 
                val+= (*this)(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
15846
 
              dest(x,y,z,v) = (restype)val;
15847
 
            }
15848
 
            if (cond) cimg_forYZV(*this,y,z,v)
15849
 
              for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
15850
 
                ftype val = 0;
15851
 
                for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
15852
 
                  val+= pix3d(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
15853
 
                dest(x,y,z,v) = (restype)val;
15854
 
              }
15855
 
            else cimg_forYZV(*this,y,z,v)
15856
 
              for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
15857
 
                ftype val = 0;
15858
 
                for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
15859
 
                  val+= pix3d(x+xm,y+ym,z+zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0);
15860
 
                dest(x,y,z,v) = (restype)val;
15861
 
              }
15862
 
          } else {      // Weighted correlation
15863
 
            for (int z=czm; z<dimz()-czm; ++z) for (int y=cym; y<dimy()-cym; ++y) for (int x=cxm; x<dimx()-cxm; ++x) {
15864
 
              ftype val = 0, norm = 0;
15865
 
              for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm) {
15866
 
                const T cval = (*this)(x+xm,y+ym,z+zm,v);
15867
 
                val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
15868
 
                norm+= cval*cval;
15869
 
              }
15870
 
              dest(x,y,z,v) = (norm!=0)?(restype)(val/std::sqrt((double)norm)):0;
15871
 
            }
15872
 
            if (cond) cimg_forYZV(*this,y,z,v)
15873
 
             for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
15874
 
                ftype val = 0, norm = 0;
15875
 
                for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm) {
15876
 
                  const T cval = pix3d(x+xm,y+ym,z+zm,v);
15877
 
                  val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
15878
 
                  norm+=cval*cval;
15879
 
                }
15880
 
                dest(x,y,z,v) = (norm!=0)?(restype)(val/std::sqrt((double)norm)):0;
15881
 
              }
15882
 
            else cimg_forYZV(*this,y,z,v)
15883
 
              for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
15884
 
                ftype val = 0, norm = 0;
15885
 
                for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm) {
15886
 
                  const T cval = pix3d(x+xm,y+ym,z+zm,v,0);
15887
 
                  val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
15888
 
                  norm+= cval*cval;
15889
 
                }
15890
 
                dest(x,y,z,v) = (norm!=0)?(restype)(val/std::sqrt((double)norm)):0;
15891
 
              }
 
22608
          if (!weighted_correl) { // Classical correlation
 
22609
            for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 
22610
              Ttfloat val = 0;
 
22611
              for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
 
22612
                val+=(*this)(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
 
22613
              dest(x,y,z,v) = (Ttfloat)val;
 
22614
            }
 
22615
            if (cond)
 
22616
              cimg_forYZV(*this,y,z,v)
 
22617
                for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22618
                  Ttfloat val = 0;
 
22619
                  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
 
22620
                    val+=at3(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
 
22621
                  dest(x,y,z,v) = (Ttfloat)val;
 
22622
                }
 
22623
            else
 
22624
              cimg_forYZV(*this,y,z,v)
 
22625
                for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22626
                  Ttfloat val = 0;
 
22627
                  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
 
22628
                    val+=at3(x+xm,y+ym,z+zm,v,0)*mask(mx1+xm,my1+ym,mz1+zm);
 
22629
                  dest(x,y,z,v) = (Ttfloat)val;
 
22630
                }
 
22631
          } else { // Weighted correlation
 
22632
            for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 
22633
              Ttfloat val = 0, weight = 0;
 
22634
              for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22635
                const Ttfloat cval = (Ttfloat)(*this)(x+xm,y+ym,z+zm,v);
 
22636
                val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
 
22637
                weight+=cval*cval;
 
22638
              }
 
22639
              dest(x,y,z,v) = (weight>0)?(Ttfloat)(val/std::sqrt((double)weight)):0;
 
22640
            }
 
22641
            if (cond)
 
22642
              cimg_forYZV(*this,y,z,v)
 
22643
                for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22644
                  Ttfloat val = 0, weight = 0;
 
22645
                  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22646
                    const Ttfloat cval = (Ttfloat)at3(x+xm,y+ym,z+zm,v);
 
22647
                    val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
 
22648
                    weight+=cval*cval;
 
22649
                  }
 
22650
                  dest(x,y,z,v) = (weight>0)?(Ttfloat)(val/std::sqrt((double)weight)):0;
 
22651
                }
 
22652
            else
 
22653
              cimg_forYZV(*this,y,z,v)
 
22654
                for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22655
                  Ttfloat val = 0, weight = 0;
 
22656
                  for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22657
                    const Ttfloat cval = (Ttfloat)at3(x+xm,y+ym,z+zm,v,0);
 
22658
                    val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
 
22659
                    weight+=cval*cval;
 
22660
                  }
 
22661
                  dest(x,y,z,v) = (weight>0)?(Ttfloat)(val/std::sqrt((double)weight)):0;
 
22662
                }
15892
22663
          }
15893
22664
      }
15894
22665
      return dest;
15895
22666
    }
15896
22667
 
15897
 
 
15898
 
    //! Correlate the image by a mask
15899
 
    /**
15900
 
       This is the in-place version of get_correlate.
15901
 
       \see get_correlate
15902
 
    **/
15903
 
    template<typename t> CImg& correlate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_correl=false) {
15904
 
      return get_correlate(mask,cond,weighted_correl).swap(*this);
 
22668
    //! Compute the correlation of the instance image by a mask (in-place).
 
22669
    template<typename t> CImg<T>& correlate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_correl=false) {
 
22670
      return get_correlate(mask,cond,weighted_correl).transfer_to(*this);
15905
22671
    }
15906
22672
 
15907
 
    //! Return the convolution of the image by a mask
 
22673
    //! Compute the convolution of the image by a mask.
15908
22674
    /**
15909
22675
       The result \p res of the convolution of an image \p img by a mask \p mask is defined to be :
15910
22676
 
15914
22680
       \param cond = the border condition type (0=zero, 1=dirichlet)
15915
22681
       \param weighted_convol = enable local normalization.
15916
22682
    **/
15917
 
    template<typename t> CImg<typename cimg::largest<T,t>::type>
15918
 
    get_convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) const {
15919
 
      typedef typename cimg::largest<T,t>::type restype;
15920
 
      typedef typename cimg::largest2<T,t,float>::type ftype;
15921
 
 
15922
 
      if (is_empty()) return CImg<restype>();
 
22683
    template<typename t> CImg<typename cimg::superset2<T,t,float>::type>
 
22684
      get_convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) const {
 
22685
      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 
22686
      if (is_empty()) return *this;
15923
22687
      if (!mask || mask.dim!=1)
15924
22688
        throw CImgArgumentException("CImg<%s>::convolve() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
15925
22689
                                    pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
15926
 
      CImg<restype> dest(width,height,depth,dim);
15927
 
      if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) { // optimized version
15928
 
        switch (mask.depth) {
15929
 
        case 3: {
15930
 
          CImg_3x3x3(I,T);
15931
 
          if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_conv3x3x3(I,mask);
15932
 
          else cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) {
15933
 
            const double norm = (double)cimg_squaresum3x3x3(I);
15934
 
            dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv3x3x3(I,mask)/std::sqrt(norm)):0;
15935
 
          }
15936
 
        } break;
15937
 
        case 2: {
15938
 
          CImg_2x2x2(I,T);
15939
 
          if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_conv2x2x2(I,mask);
15940
 
          else cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) {
15941
 
            const double norm = (double)cimg_squaresum2x2x2(I);
15942
 
            dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv2x2x2(I,mask)/std::sqrt(norm)):0;
15943
 
          }
15944
 
        } break;
15945
 
        default:
15946
 
        case 1:
15947
 
          switch (mask.width) {
15948
 
          case 5: {
15949
 
            CImg_5x5(I,T);
15950
 
            if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_conv5x5(I,mask);
15951
 
            else cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
15952
 
              const double norm = (double)cimg_squaresum5x5(I);
15953
 
              dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv5x5(I,mask)/std::sqrt(norm)):0;
15954
 
            }
15955
 
          } break;
15956
 
          case 4: {
15957
 
            CImg_4x4(I,T);
15958
 
            if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv4x4(I,mask);
15959
 
            else cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) {
15960
 
              const double norm = (double)cimg_squaresum4x4(I);
15961
 
              dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv4x4(I,mask)/std::sqrt(norm)):0;
15962
 
            }
15963
 
          } break;
15964
 
          case 3: {
15965
 
            CImg_3x3(I,T);
15966
 
            if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv3x3(I,mask);
15967
 
            else cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) {
15968
 
              const double norm = (double)cimg_squaresum3x3(I);
15969
 
              dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv3x3(I,mask)/std::sqrt(norm)):0;
15970
 
            }
15971
 
          } break;
15972
 
          case 2: {
15973
 
            CImg_2x2(I,T);
15974
 
            if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv2x2(I,mask);
15975
 
            else cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) {
15976
 
              const double norm = (double)cimg_squaresum2x2(I);
15977
 
              dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv2x2(I,mask)/std::sqrt(norm)):0;
15978
 
            }
15979
 
          } break;
15980
 
          case 1: (dest.assign(*this))*=mask(0); break;
15981
 
          }
15982
 
        }
15983
 
      } else { // generic version
15984
 
 
15985
 
        const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.depth%2);
15986
 
        cimg_forV(*this,v)
15987
 
          if (!weighted_convol) {       // Classical convolution
15988
 
            for (int z=czm; z<dimz()-czm; ++z) for (int y=cym; y<dimy()-cym; ++y) for (int x=cxm; x<dimx()-cxm; ++x) {
15989
 
              ftype val = 0;
15990
 
              for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
15991
 
                val+= (*this)(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
15992
 
              dest(x,y,z,v) = (restype)val;
15993
 
            }
15994
 
            if (cond) cimg_forYZV(*this,y,z,v)
15995
 
              for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
15996
 
                ftype val = 0;
15997
 
                for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
15998
 
                  val+= pix3d(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0);
15999
 
                dest(x,y,z,v) = (restype)val;
16000
 
              }
16001
 
            else cimg_forYZV(*this,y,z,v)
16002
 
              for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
16003
 
                ftype val = 0;
16004
 
                for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym)  for (int xm=-cxm; xm<=fxm; ++xm)
16005
 
                  val+= pix3d(x-xm,y-ym,z-zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0);
16006
 
                dest(x,y,z,v) = (restype)val;
16007
 
              }
16008
 
          } else {      // Weighted convolution
16009
 
            for (int z=czm; z<dimz()-czm; ++z) for (int y=cym; y<dimy()-cym; ++y) for (int x=cxm; x<dimx()-cxm; ++x) {
16010
 
              ftype val = 0, norm = 0;
16011
 
              for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm) {
16012
 
                const T cval = (*this)(x-xm,y-ym,z-zm,v);
16013
 
                val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
16014
 
                norm+= cval*cval;
16015
 
              }
16016
 
              dest(x,y,z,v) = (norm!=0)?(restype)(val/std::sqrt(norm)):0;
16017
 
            }
16018
 
            if (cond) cimg_forYZV(*this,y,z,v)
16019
 
              for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
16020
 
                ftype val = 0, norm = 0;
16021
 
                for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm) {
16022
 
                  const T cval = pix3d(x-xm,y-ym,z-zm,v);
16023
 
                  val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
16024
 
                  norm+=cval*cval;
16025
 
                }
16026
 
                dest(x,y,z,v) = (norm!=0)?(restype)(val/std::sqrt(norm)):0;
16027
 
              }
16028
 
            else cimg_forYZV(*this,y,z,v)
16029
 
              for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
16030
 
                double val = 0, norm = 0;
16031
 
                for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym)  for (int xm=-cxm; xm<=fxm; ++xm) {
16032
 
                  const T cval = pix3d(x-xm,y-ym,z-zm,v,0);
16033
 
                  val+= cval*mask(cxm+xm,cym+ym,czm+zm,0);
16034
 
                  norm+= cval*cval;
16035
 
                }
16036
 
                dest(x,y,z,v) = (norm!=0)?(restype)(val/std::sqrt(norm)):0;
16037
 
              }
16038
 
          }
16039
 
      }
16040
 
      return dest;
 
22690
      return get_correlate(CImg<t>(mask.ptr(),mask.size(),1,1,1,true).get_mirror('x').resize(mask,-1),cond,weighted_convol);
16041
22691
    }
16042
22692
 
16043
 
    //! Convolve the image by a mask
16044
 
    /**
16045
 
       This is the in-place version of get_convolve().
16046
 
       \see get_convolve()
16047
 
    **/
16048
 
    template<typename t> CImg& convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) {
16049
 
      return get_convolve(mask,cond,weighted_convol).swap(*this);
 
22693
    //! Compute the convolution of the image by a mask (in-place).
 
22694
    template<typename t> CImg<T>& convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) {
 
22695
      return get_convolve(mask,cond,weighted_convol).transfer_to(*this);
16050
22696
    }
16051
22697
 
16052
22698
    //! Return the erosion of the image by a structuring element.
16053
 
    template<typename t> CImg<typename cimg::largest<T,t>::type>
 
22699
    template<typename t> CImg<typename cimg::superset<T,t>::type>
16054
22700
    get_erode(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) const {
16055
 
      typedef typename cimg::largest<T,t>::type restype;
16056
 
      if (is_empty()) return CImg<restype>();
 
22701
      typedef typename cimg::superset<T,t>::type Tt;
 
22702
      if (is_empty()) return *this;
16057
22703
      if (!mask || mask.dim!=1)
16058
22704
        throw CImgArgumentException("CImg<%s>::erode() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
16059
22705
                                    pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
16060
 
      CImg<restype> dest(width,height,depth,dim);
16061
 
      const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2,
16062
 
        fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.depth%2);
 
22706
      CImg<Tt> dest(width,height,depth,dim);
 
22707
      const int
 
22708
        mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
 
22709
        mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
 
22710
        mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
16063
22711
      cimg_forV(*this,v)
16064
 
        if (!weighted_erosion) {        // Classical erosion
16065
 
          for (int z=czm; z<dimz()-czm; ++z) for (int y=cym; y<dimy()-cym; ++y) for (int x=cxm; x<dimx()-cxm; ++x) {
16066
 
            restype min_val = cimg::type<restype>::max();
16067
 
            for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16068
 
              if (mask(cxm+xm,cym+ym,czm+zm,0)) min_val = cimg::min((restype)(*this)(x+xm,y+ym,z+zm,v),min_val);
 
22712
        if (!weighted_erosion) { // Classical erosion
 
22713
          for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 
22714
            Tt min_val = cimg::type<Tt>::max();
 
22715
            for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22716
              const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
 
22717
              if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
 
22718
            }
16069
22719
            dest(x,y,z,v) = min_val;
16070
22720
          }
16071
 
          if (cond) cimg_forYZV(*this,y,z,v)
16072
 
                      for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
16073
 
                        restype min_val = cimg::type<restype>::max();
16074
 
                        for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16075
 
                          if (mask(cxm+xm,cym+ym,czm+zm,0)) min_val = cimg::min((restype)pix3d(x+xm,y+ym,z+zm,v),min_val);
16076
 
                        dest(x,y,z,v) = min_val;
16077
 
                      }
16078
 
          else cimg_forYZV(*this,y,z,v)
16079
 
                 for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
16080
 
                   restype min_val = cimg::type<restype>::max();
16081
 
                   for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16082
 
                     if (mask(cxm+xm,cym+ym,czm+zm,0)) min_val = cimg::min((restype)pix3d(x+xm,y+ym,z+zm,v,0),min_val);
16083
 
                   dest(x,y,z,v) = min_val;
16084
 
                 }
 
22721
          if (cond)
 
22722
            cimg_forYZV(*this,y,z,v)
 
22723
              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22724
                Tt min_val = cimg::type<Tt>::max();
 
22725
                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22726
                  const T cval = (Tt)at3(x+xm,y+ym,z+zm,v);
 
22727
                  if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
 
22728
                }
 
22729
                dest(x,y,z,v) = min_val;
 
22730
              }
 
22731
          else
 
22732
            cimg_forYZV(*this,y,z,v)
 
22733
              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22734
                Tt min_val = cimg::type<Tt>::max();
 
22735
                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22736
                  const T cval = (Tt)at3(x+xm,y+ym,z+zm,v,0);
 
22737
                  if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
 
22738
                }
 
22739
                dest(x,y,z,v) = min_val;
 
22740
              }
16085
22741
        } else { // Weighted erosion
16086
 
          t mval=0;
16087
 
          for (int z=czm; z<dimz()-czm; ++z) for (int y=cym; y<dimy()-cym; ++y) for (int x=cxm; x<dimx()-cxm; ++x) {
16088
 
            restype min_val = cimg::type<restype>::max();
16089
 
            for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16090
 
              if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) min_val = cimg::min((restype)((*this)(x+xm,y+ym,z+zm,v)+mval),min_val);
 
22742
          for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 
22743
            Tt min_val = cimg::type<Tt>::max();
 
22744
            for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22745
              const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 
22746
              const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) + mval);
 
22747
              if (mval && cval<min_val) min_val = cval;
 
22748
            }
16091
22749
            dest(x,y,z,v) = min_val;
16092
22750
          }
16093
 
          if (cond) cimg_forYZV(*this,y,z,v)
16094
 
                      for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
16095
 
                        restype min_val = cimg::type<restype>::max();
16096
 
                        for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16097
 
                          if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) min_val = cimg::min((restype)(pix3d(x+xm,y+ym,z+zm,v)+mval),min_val);
16098
 
                        dest(x,y,z,v) = min_val;
16099
 
                      }
16100
 
          else cimg_forYZV(*this,y,z,v)
16101
 
                 for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
16102
 
                   restype min_val = cimg::type<restype>::max();
16103
 
                   for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16104
 
                     if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) min_val = cimg::min((restype)(pix3d(x+xm,y+ym,z+zm,v,0)+mval),min_val);
16105
 
                   dest(x,y,z,v) = min_val;
16106
 
                 }
 
22751
          if (cond)
 
22752
            cimg_forYZV(*this,y,z,v)
 
22753
              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22754
                Tt min_val = cimg::type<Tt>::max();
 
22755
                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22756
                  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 
22757
                  const Tt cval = (Tt)(at3(x+xm,y+ym,z+zm,v) + mval);
 
22758
                  if (mval && cval<min_val) min_val = cval;
 
22759
                }
 
22760
                dest(x,y,z,v) = min_val;
 
22761
              }
 
22762
          else
 
22763
            cimg_forYZV(*this,y,z,v)
 
22764
              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22765
                Tt min_val = cimg::type<Tt>::max();
 
22766
                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22767
                  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 
22768
                  const Tt cval = (Tt)(at3(x+xm,y+ym,z+zm,v,0) + mval);
 
22769
                  if (mval && cval<min_val) min_val = cval;
 
22770
                }
 
22771
                dest(x,y,z,v) = min_val;
 
22772
              }
16107
22773
        }
16108
22774
      return dest;
16109
22775
    }
16110
22776
 
16111
 
    //! Erode the image by a structuring element
16112
 
    /**
16113
 
       This is the in-place version of get_erode().
16114
 
       \see get_erode()
16115
 
    **/
16116
 
    template<typename t> CImg& erode(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) {
16117
 
      return get_erode(mask,cond,weighted_erosion).swap(*this);
 
22777
    //! Return the erosion of the image by a structuring element (in-place).
 
22778
    template<typename t> CImg<T>& erode(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) {
 
22779
      return get_erode(mask,cond,weighted_erosion).transfer_to(*this);
16118
22780
    }
16119
22781
 
16120
 
    //! Erode the image by a square structuring element of size n
16121
 
    CImg get_erode(const unsigned int n, const unsigned int cond=1) const {
 
22782
    //! Erode the image by a square structuring element of size n.
 
22783
    CImg<T> get_erode(const unsigned int n, const unsigned int cond=1) const {
16122
22784
      static CImg<T> mask;
16123
22785
      if (n<2) return *this;
16124
22786
      if (mask.width!=n) mask.assign(n,n,1,1,1);
16127
22789
      return res;
16128
22790
    }
16129
22791
 
16130
 
    //! Erode the image by a square structuring element of size n
16131
 
    CImg& erode(const unsigned int n, const unsigned int cond=1) {
 
22792
    //! Erode the image by a square structuring element of size n (in-place).
 
22793
    CImg<T>& erode(const unsigned int n, const unsigned int cond=1) {
16132
22794
      if (n<2) return *this;
16133
 
      return get_erode(n,cond).swap(*this);
 
22795
      return get_erode(n,cond).transfer_to(*this);
16134
22796
    }
16135
22797
 
16136
 
    //! Return the dilatation of the image by a structuring element.
16137
 
    template<typename t> CImg<typename cimg::largest<T,t>::type>
 
22798
    //! Dilate the image by a structuring element.
 
22799
    template<typename t> CImg<typename cimg::superset<T,t>::type>
16138
22800
    get_dilate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) const {
16139
 
      typedef typename cimg::largest<T,t>::type restype;
16140
 
      if (is_empty()) return CImg<restype>();
 
22801
      typedef typename cimg::superset<T,t>::type Tt;
 
22802
      if (is_empty()) return *this;
16141
22803
      if (!mask || mask.dim!=1)
16142
22804
        throw CImgArgumentException("CImg<%s>::dilate() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
16143
22805
                                    pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
16144
 
      CImg<restype> dest(width,height,depth,dim);
16145
 
      const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2,
16146
 
        fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.depth%2);
 
22806
      CImg<Tt> dest(width,height,depth,dim);
 
22807
      const int
 
22808
        mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
 
22809
        mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
 
22810
        mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
16147
22811
      cimg_forV(*this,v)
16148
22812
        if (!weighted_dilatation) { // Classical dilatation
16149
 
          for (int z=czm; z<dimz()-czm; ++z) for (int y=cym; y<dimy()-cym; ++y) for (int x=cxm; x<dimx()-cxm; ++x) {
16150
 
            restype max_val = cimg::type<restype>::min();
16151
 
            for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16152
 
              if (mask(cxm+xm,cym+ym,czm+zm,0)) max_val = cimg::max((restype)(*this)(x+xm,y+ym,z+zm,v),max_val);
 
22813
          for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 
22814
            Tt max_val = cimg::type<Tt>::min();
 
22815
            for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22816
              const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
 
22817
              if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
 
22818
            }
16153
22819
            dest(x,y,z,v) = max_val;
16154
22820
          }
16155
 
          if (cond) cimg_forYZV(*this,y,z,v)
16156
 
                      for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
16157
 
                        restype max_val = cimg::type<restype>::min();
16158
 
                        for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16159
 
                          if (mask(cxm+xm,cym+ym,czm+zm,0)) max_val = cimg::max((restype)pix3d(x+xm,y+ym,z+zm,v),max_val);
16160
 
                        dest(x,y,z,v) = max_val;
16161
 
                      }
16162
 
          else cimg_forYZV(*this,y,z,v)
16163
 
                 for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
16164
 
                   restype max_val = cimg::type<restype>::min();
16165
 
                   for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16166
 
                     if (mask(cxm+xm,cym+ym,czm+zm,0)) max_val = cimg::max((restype)pix3d(x+xm,y+ym,z+zm,v,0),max_val);
16167
 
                   dest(x,y,z,v) = max_val;
16168
 
                 }
 
22821
          if (cond)
 
22822
            cimg_forYZV(*this,y,z,v)
 
22823
              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22824
                Tt max_val = cimg::type<Tt>::min();
 
22825
                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22826
                  const T cval = (Tt)at3(x+xm,y+ym,z+zm,v);
 
22827
                  if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
 
22828
                }
 
22829
                dest(x,y,z,v) = max_val;
 
22830
              }
 
22831
          else
 
22832
            cimg_forYZV(*this,y,z,v)
 
22833
              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22834
                Tt max_val = cimg::type<Tt>::min();
 
22835
                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22836
                  const T cval = (Tt)at3(x+xm,y+ym,z+zm,v,0);
 
22837
                  if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
 
22838
                }
 
22839
                dest(x,y,z,v) = max_val;
 
22840
              }
16169
22841
        } else { // Weighted dilatation
16170
 
          t mval=0;
16171
 
          for (int z=czm; z<dimz()-czm; ++z) for (int y=cym; y<dimy()-cym; ++y) for (int x=cxm; x<dimx()-cxm; ++x) {
16172
 
            restype max_val = cimg::type<restype>::min();
16173
 
            for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16174
 
              if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) max_val = cimg::max((restype)((*this)(x+xm,y+ym,z+zm,v)-mval),max_val);
 
22842
          for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
 
22843
            Tt max_val = cimg::type<Tt>::min();
 
22844
            for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22845
              const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 
22846
              const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) - mval);
 
22847
              if (mval && cval>max_val) max_val = cval;
 
22848
            }
16175
22849
            dest(x,y,z,v) = max_val;
16176
22850
          }
16177
 
          if (cond) cimg_forYZV(*this,y,z,v)
16178
 
                      for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
16179
 
                        restype max_val = cimg::type<restype>::min();
16180
 
                        for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16181
 
                          if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) max_val = cimg::max((restype)(pix3d(x+xm,y+ym,z+zm,v)-mval),max_val);
16182
 
                        dest(x,y,z,v) = max_val;
16183
 
                      }
16184
 
          else cimg_forYZV(*this,y,z,v)
16185
 
                 for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) {
16186
 
                   restype max_val = cimg::type<restype>::min();
16187
 
                   for (int zm=-czm; zm<=fzm; ++zm) for (int ym=-cym; ym<=fym; ++ym) for (int xm=-cxm; xm<=fxm; ++xm)
16188
 
                     if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) max_val = cimg::max((restype)(pix3d(x+xm,y+ym,z+zm,v,0)-mval),max_val);
16189
 
                   dest(x,y,z,v) = max_val;
16190
 
                 }
 
22851
          if (cond)
 
22852
            cimg_forYZV(*this,y,z,v)
 
22853
              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22854
                Tt max_val = cimg::type<Tt>::min();
 
22855
                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22856
                  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 
22857
                  const Tt cval = (Tt)(at3(x+xm,y+ym,z+zm,v) - mval);
 
22858
                  if (mval && cval>max_val) max_val = cval;
 
22859
                }
 
22860
                dest(x,y,z,v) = max_val;
 
22861
              }
 
22862
          else
 
22863
            cimg_forYZV(*this,y,z,v)
 
22864
              for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
 
22865
                Tt max_val = cimg::type<Tt>::min();
 
22866
                for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
 
22867
                  const t mval = mask(mx1+xm,my1+ym,mz1+zm);
 
22868
                  const Tt cval = (Tt)(at3(x+xm,y+ym,z+zm,v,0) - mval);
 
22869
                  if (mval && cval>max_val) max_val = cval;
 
22870
                }
 
22871
                dest(x,y,z,v) = max_val;
 
22872
              }
16191
22873
        }
16192
22874
      return dest;
16193
22875
    }
16194
22876
 
16195
 
    //! Dilate the image by a structuring element
16196
 
    /**
16197
 
       This is the in-place version of get_dilate().
16198
 
       \see get_dilate()
16199
 
    **/
16200
 
    template<typename t> CImg& dilate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) {
16201
 
      return get_dilate(mask,cond,weighted_dilatation).swap(*this);
 
22877
    //! Dilate the image by a structuring element (in-place).
 
22878
    template<typename t> CImg<T>& dilate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) {
 
22879
      return get_dilate(mask,cond,weighted_dilatation).transfer_to(*this);
16202
22880
    }
16203
22881
 
16204
 
    //! Dilate the image by a square structuring element of size n
16205
 
    CImg get_dilate(const unsigned int n, const unsigned int cond=1) const {
 
22882
    //! Dilate the image by a square structuring element of size n.
 
22883
    CImg<T> get_dilate(const unsigned int n, const unsigned int cond=1) const {
16206
22884
      static CImg<T> mask;
16207
22885
      if (n<2) return *this;
16208
22886
      if (mask.width!=n) mask.assign(n,n,1,1,1);
16211
22889
      return res;
16212
22890
    }
16213
22891
 
16214
 
    //! Dilate the image by a square structuring element of size n
16215
 
    CImg& dilate(const unsigned int n, const unsigned int cond=1) {
 
22892
    //! Dilate the image by a square structuring element of size n (in-place).
 
22893
    CImg<T>& dilate(const unsigned int n, const unsigned int cond=1) {
16216
22894
      if (n<2) return *this;
16217
 
      return get_dilate(n,cond).swap(*this);
 
22895
      return get_dilate(n,cond).transfer_to(*this);
16218
22896
    }
16219
22897
 
16220
 
    //! Add noise to the image
 
22898
    //! Add noise to the image.
16221
22899
    /**
16222
 
       This is the in-place version of get_noise.
16223
 
       \see get_noise.
 
22900
       \param sigma = power of the noise. if sigma<0, it corresponds to the percentage of the maximum image value.
 
22901
       \param ntype = noise type. can be 0=gaussian, 1=uniform or 2=Salt and Pepper.
 
22902
       \return A noisy version of the instance image.
16224
22903
    **/
16225
 
    CImg& noise(const double sigma=-20, const unsigned int ntype=0) {
 
22904
    CImg<T> get_noise(const double sigma=-20, const unsigned int ntype=0) const {
 
22905
      return (+*this).noise(sigma,ntype);
 
22906
    }
 
22907
 
 
22908
    //! Add noise to the image (in-place).
 
22909
    CImg<T>& noise(const double sigma=-20, const unsigned int ntype=0) {
16226
22910
      if (!is_empty()) {
16227
22911
        double nsigma = sigma, max = (double)cimg::type<T>::max(), min = (double)cimg::type<T>::min();
16228
 
        static bool first_time = true;
16229
 
        if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; }
16230
 
        CImgStats st;
 
22912
        cimg::srand();
 
22913
        Tfloat m = 0, M = 0;
16231
22914
        if (nsigma==0) return *this;
16232
 
        if (nsigma<0 || ntype==2) st = CImgStats(*this,false);
16233
 
        if (nsigma<0) nsigma = -nsigma*(st.max-st.min)/100.0;
 
22915
        if (nsigma<0 || ntype==2) m = (Tfloat)minmax(M);
 
22916
        if (nsigma<0) nsigma = -nsigma*(M-m)/100.0;
16234
22917
        switch (ntype) {
16235
22918
        case 0: { // Gaussian noise
16236
22919
          cimg_for(*this,ptr,T) {
16237
 
            double val = *ptr+nsigma*cimg::grand();
 
22920
            double val = *ptr + nsigma*cimg::grand();
16238
22921
            if (val>max) val = max;
16239
22922
            if (val<min) val = min;
16240
22923
            *ptr = (T)val;
16242
22925
        } break;
16243
22926
        case 1: { // Uniform noise
16244
22927
          cimg_for(*this,ptr,T) {
16245
 
            double val = *ptr+nsigma*cimg::crand();
 
22928
            double val = *ptr + nsigma*cimg::crand();
16246
22929
            if (val>max) val = max;
16247
22930
            if (val<min) val = min;
16248
22931
            *ptr = (T)val;
16249
22932
          }
16250
22933
        } break;
16251
22934
        case 2: { // Salt & Pepper noise
16252
 
          if (st.max==st.min) { st.min = 0; st.max = 255; }
16253
 
          cimg_for(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr = (T)(cimg::rand()<0.5?st.max:st.min);
 
22935
          if (M==m) { m = 0; M = 255; }
 
22936
          cimg_for(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr = (T)(cimg::rand()<0.5?M:m);
16254
22937
        } break;
16255
22938
        case 3: { // Poisson Noise
16256
22939
          cimg_for(*this,ptr,T) {
16260
22943
              if (z>100.0) *ptr = (T)(unsigned int)((std::sqrt(z) * cimg::grand()) + z);
16261
22944
              else {
16262
22945
                unsigned int k = 0;
16263
 
                const double y=std::exp(-z);
16264
 
                for (double s=1.0; s>=y; ++k) s *= cimg::rand();
 
22946
                const double y = std::exp(-z);
 
22947
                for (double s = 1.0; s>=y; ++k) s *= cimg::rand();
16265
22948
                *ptr = (T)(k-1);
16266
22949
              }
16267
22950
            }
16285
22968
      return *this;
16286
22969
    }
16287
22970
 
16288
 
    //! Return a noisy image
16289
 
    /**
16290
 
       \param sigma = power of the noise. if sigma<0, it corresponds to the percentage of the maximum image value.
16291
 
       \param ntype = noise type. can be 0=gaussian, 1=uniform or 2=Salt and Pepper.
16292
 
       \return A noisy version of the instance image.
16293
 
    **/
16294
 
    CImg get_noise(const double sigma=-20, const unsigned int ntype=0) const {
16295
 
      return (+*this).noise(sigma,ntype);
16296
 
    }
16297
 
 
16298
 
#define cimg_deriche_apply(x0,y0,z0,k0,nb,offset,T) { \
16299
 
    ima = ptr(x0,y0,z0,k0); \
16300
 
    I1 = *ima; \
16301
 
    I0 = *(ima+=offset); \
16302
 
    Y2 = *(Y++) = sumg0*I1; \
16303
 
    Y1 = *(Y++) = g0*I0 + sumg1*I1; \
16304
 
    ima+=offset; \
16305
 
    for (int i=2; i<(int)nb; ++i) { I0 = *ima; ima+=offset; Y0 = *(Y++) = a0*I0 + a1*I1 - b1*Y1 - b2*Y2; I1 = I0; Y2 = Y1; Y1 = Y0; } \
16306
 
    I1 = *(ima-=offset); \
16307
 
    Y2 = Y1 = parity*sumg1*I1; \
16308
 
    *ima = (T)(*(--Y)+Y2); \
16309
 
    I0 = *(ima-=offset); \
16310
 
    *ima = (T)(*(--Y)+Y1); \
16311
 
    for (int ii=(int)nb-3; ii>=0; --ii) { Y0 = a2*I0 + a3*I1 - b1*Y1 - b2*Y2; I1 = I0; I0 = *(ima-=offset); *ima = (T)(*(--Y)+Y0); Y2 = Y1; Y1 = Y0; } \
16312
 
  }
16313
 
 
16314
 
    //! Apply a deriche filter on the image
16315
 
    /**
16316
 
       This is the in-place version of get_deriche
16317
 
       \see get_deriche.
16318
 
    **/
16319
 
    CImg& deriche(const float sigma, const int order=0, const char axe='x', const bool cond=true) {
16320
 
      if (!is_empty()) {
16321
 
        if (sigma<0) throw CImgArgumentException("CImg<%s>::deriche() : Given filter variance (sigma = %g) is negative",pixel_type(),sigma);
16322
 
        if (order<0 || order>2) throw CImgArgumentException("CImg<%s>::deriche() : Given filter order (order = %u) must be 0,1 or 2",pixel_type(),order);
16323
 
        if (sigma==0.0f) return *this;
16324
 
        typedef typename cimg::largest<T,float>::type ftype;
16325
 
        const ftype
16326
 
          alpha = 1.695f/sigma,
16327
 
          expa = (float)std::exp(alpha),
16328
 
          expma = (float)std::exp(-alpha),
16329
 
          expm2a = expma*expma,
16330
 
          b1 = -2*expma,
16331
 
          b2 = expm2a;
16332
 
        ftype valk = 0, valkn = 0, a0 = 0, a1 = 0, a2 = 0, a3 = 0, g0 = 0, sumg1 = 0, sumg0 = 0, *Y = 0, Y0 = 0, Y1 = 0, Y2 = 0;
16333
 
        int parity = 0;
16334
 
        T *ima, I0, I1;
16335
 
        switch (order) {
16336
 
        case 0: // smoothing (0-th derivative)
16337
 
          valk = (1-expma)*(1-expma)/(1+2*alpha*expma-expm2a);
16338
 
          a0 = valk;
16339
 
          a1 = valk*expma*(alpha-1);
16340
 
          a2 = valk*expma*(alpha+1);
16341
 
          a3 = -valk*expm2a;
16342
 
          parity = 1;
16343
 
          if (cond) { sumg1 = valk*(alpha*expa+expa-1)/((expa-1)*(expa-1)); g0 = valk; sumg0 = g0 + sumg1; }
16344
 
          else g0 = sumg0 = sumg1 = 0;
16345
 
          break;
16346
 
        case 1: // first derivative
16347
 
          valk = -(1-expma)*(1-expma)*(1-expma)/(2*(expma+1)*expma);
16348
 
          a0 = a3 = 0;
16349
 
          a1 = valk*expma;
16350
 
          a2 = -valk*expma;
16351
 
          parity =-1;
16352
 
          if (cond) { sumg1 = (valk*expa)/((expa-1)*(expa-1)); g0 = 0; sumg0 = g0+sumg1; }
16353
 
          else g0 = sumg0 = sumg1 = 0;
16354
 
          break;
16355
 
        case 2: // second derivative
16356
 
          valkn = (-2*(-1+3*expa-3*expa*expa+expa*expa*expa)/(3*expa+1+3*expa*expa+expa*expa*expa) );
16357
 
          valk = -(expm2a-1)/(2*alpha*expma);
16358
 
          a0 = valkn;
16359
 
          a1 = -valkn*(1+valk*alpha)*expma;
16360
 
          a2 = valkn*(1-valk*alpha)*expma;
16361
 
          a3 = -valkn*expm2a;
16362
 
          parity = 1;
16363
 
          if (cond) { sumg1 = valkn/2; g0 = valkn; sumg0 = g0+sumg1; }
16364
 
          else g0 = sumg0 = sumg1 = 0;
16365
 
          break;
16366
 
        }
16367
 
        switch(cimg::uncase(axe)) {
16368
 
        case 'x': if (width>1) {
16369
 
          Y = new ftype[width];
16370
 
          const unsigned int offset = 1;
16371
 
          cimg_forYZV(*this,y,z,k) cimg_deriche_apply(0,y,z,k,width,offset,T);
16372
 
        } break;
16373
 
        case 'y': if (height>1) {
16374
 
          Y = new ftype[height];
16375
 
          const unsigned int offset = width;
16376
 
          cimg_forXZV(*this,x,z,k) cimg_deriche_apply(x,0,z,k,height,offset,T);
16377
 
        } break;
16378
 
        case 'z': if (depth>1) {
16379
 
          Y = new ftype[depth];
16380
 
          const unsigned int offset = width*height;
16381
 
          cimg_forXYV(*this,x,y,k) cimg_deriche_apply(x,y,0,k,depth,offset,T);
16382
 
        } break;
16383
 
        case 'v': if (dim>1) {
16384
 
          Y = new ftype[dim];
16385
 
          const unsigned int offset = width*height*depth;
16386
 
          cimg_forXYZ(*this,x,y,z) cimg_deriche_apply(x,y,z,0,dim,offset,T);
16387
 
        } break;
16388
 
        default: throw CImgArgumentException("CImg<%s>::deriche() : Unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
16389
 
        }
16390
 
        delete[] Y;
16391
 
      }
16392
 
      return *this;
16393
 
    }
16394
 
 
16395
 
    //! Return the result of the Deriche filter
 
22971
    //! Compute the result of the Deriche filter.
16396
22972
    /**
16397
22973
       The Canny-Deriche filter is a recursive algorithm allowing to compute blurred derivatives of
16398
22974
       order 0,1 or 2 of an image.
16399
 
       \see blur
16400
22975
    **/
16401
 
    CImg<typename cimg::largest<T,float>::type> get_deriche(const float sigma, const int order=0, const char axe='x', const bool cond=true) const {
16402
 
      typedef typename cimg::largest<T,float>::type ftype;
16403
 
      return CImg<ftype>(*this).deriche(sigma,order,axe,cond);
16404
 
    }
16405
 
 
16406
 
    //! Blur the image with a Deriche filter (anisotropically)
 
22976
    CImg<Tfloat> get_deriche(const float sigma, const int order=0,
 
22977
                                                             const char axe='x', const bool cond=true) const {
 
22978
      return CImg<Tfloat>(*this,false).deriche(sigma,order,axe,cond);
 
22979
    }
 
22980
 
 
22981
    //! Compute the result of the Deriche filter (in-place).
 
22982
    CImg<T>& deriche(const float sigma, const int order=0, const char axe='x', const bool cond=true) {
 
22983
#define _cimg_deriche2_apply \
 
22984
  Tfloat *ptrY = Y.data, yb = 0, yp = 0; \
 
22985
  T xp = (T)0; \
 
22986
  if (cond) { xp = *ptrX; yb = yp = (Tfloat)(coefp*xp); } \
 
22987
  for (int m=0; m<N; ++m) { \
 
22988
    const T xc = *ptrX; ptrX+=off; \
 
22989
    const Tfloat yc = *(ptrY++) = (Tfloat)(a0*xc + a1*xp - b1*yp - b2*yb); \
 
22990
    xp = xc; yb = yp; yp = yc; \
 
22991
  } \
 
22992
  T xn = (T)0, xa = (T)0; \
 
22993
  Tfloat yn = 0, ya = 0; \
 
22994
  if (cond) { xn = xa = *(ptrX-off); yn = ya = (Tfloat)coefn*xn; } \
 
22995
  for (int n=N-1; n>=0; --n) { \
 
22996
    const T xc = *(ptrX-=off); \
 
22997
    const Tfloat yc = (Tfloat)(a2*xn + a3*xa - b1*yn - b2*ya); \
 
22998
    xa = xn; xn = xc; ya = yn; yn = yc; \
 
22999
    *ptrX = (T)(*(--ptrY)+yc); \
 
23000
  }
 
23001
      if (sigma<0)
 
23002
        throw CImgArgumentException("CImg<%s>::deriche() : Given filter variance (sigma = %g) is negative",pixel_type(),sigma);
 
23003
      if (is_empty() || (sigma<0.1 && !order)) return *this;
 
23004
      const float
 
23005
        nsigma = sigma<0.1f?0.1f:sigma,
 
23006
        alpha = 1.695f/nsigma,
 
23007
        ema = (float)std::exp(-alpha),
 
23008
        ema2 = (float)std::exp(-2*alpha),
 
23009
        b1 = -2*ema,
 
23010
        b2 = ema2;
 
23011
      float a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0;
 
23012
      switch (order) {
 
23013
      case 0: {
 
23014
        const float k = (1-ema)*(1-ema)/(1+2*alpha*ema-ema2);
 
23015
        a0 = k;
 
23016
        a1 = k*(alpha-1)*ema;
 
23017
        a2 = k*(alpha+1)*ema;
 
23018
        a3 = -k*ema2;
 
23019
      } break;
 
23020
      case 1: {
 
23021
        const float k = (1-ema)*(1-ema)/ema;
 
23022
        a0 = k*ema;
 
23023
        a1 = a3 = 0;
 
23024
        a2 = -a0;
 
23025
      } break;
 
23026
      case 2: {
 
23027
        const float
 
23028
          ea = (float)std::exp(-alpha),
 
23029
          k = -(ema2-1)/(2*alpha*ema),
 
23030
          kn = (-2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea));
 
23031
        a0 = kn;
 
23032
        a1 = -kn*(1+k*alpha)*ema;
 
23033
        a2 = kn*(1-k*alpha)*ema;
 
23034
        a3 = -kn*ema2;
 
23035
      } break;
 
23036
      default:
 
23037
        throw CImgArgumentException("CImg<%s>::deriche() : Given filter order (order = %u) must be 0,1 or 2",pixel_type(),order);
 
23038
      }
 
23039
      coefp = (a0+a1)/(1+b1+b2);
 
23040
      coefn = (a2+a3)/(1+b1+b2);
 
23041
      switch (cimg::uncase(axe)) {
 
23042
      case 'x': {
 
23043
        const int N = width, off = 1;
 
23044
        CImg<Tfloat> Y(N);
 
23045
        cimg_forYZV(*this,y,z,v) { T *ptrX = ptr(0,y,z,v); _cimg_deriche2_apply; }
 
23046
      } break;
 
23047
      case 'y': {
 
23048
        const int N = height, off = width;
 
23049
        CImg<Tfloat> Y(N);
 
23050
        cimg_forXZV(*this,x,z,v) { T *ptrX = ptr(x,0,z,v); _cimg_deriche2_apply; }
 
23051
      } break;
 
23052
      case 'z': {
 
23053
        const int N = depth, off = width*height;
 
23054
        CImg<Tfloat> Y(N);
 
23055
        cimg_forXYV(*this,x,y,v) { T *ptrX = ptr(x,y,0,v); _cimg_deriche2_apply; }
 
23056
      } break;
 
23057
      case 'v': {
 
23058
        const int N = dim, off = width*height*depth;
 
23059
        CImg<Tfloat> Y(N);
 
23060
        cimg_forXYZ(*this,x,y,z) { T *ptrX = ptr(x,y,z,0); _cimg_deriche2_apply; }
 
23061
      } break;
 
23062
      }
 
23063
      return *this;
 
23064
    }
 
23065
 
 
23066
    //! Return a blurred version of the image, using a Canny-Deriche filter.
16407
23067
    /**
16408
 
       This is the in-place version of get_blur().
16409
 
       \see get_blur().
 
23068
       Blur the image with an anisotropic exponential filter (Deriche filter of order 0).
16410
23069
    **/
16411
 
    CImg& blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) {
 
23070
    CImg<Tfloat> get_blur(const float sigmax, const float sigmay, const float sigmaz,
 
23071
                                                          const bool cond=true) const {
 
23072
      return CImg<Tfloat>(*this,false).blur(sigmax,sigmay,sigmaz,cond);
 
23073
    }
 
23074
 
 
23075
    //! Return a blurred version of the image, using a Canny-Deriche filter (in-place).
 
23076
    CImg<T>& blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) {
16412
23077
      if (!is_empty()) {
16413
23078
        if (width>1  && sigmax>0) deriche(sigmax,0,'x',cond);
16414
23079
        if (height>1 && sigmay>0) deriche(sigmay,0,'y',cond);
16417
23082
      return *this;
16418
23083
    }
16419
23084
 
16420
 
    //! Blur the image with a Canny-Deriche filter.
16421
 
    /** This is the in-place version of get_blur(). **/
16422
 
    CImg& blur(const float sigma, const bool cond=true) {
 
23085
    //! Return a blurred version of the image, using a Canny-Deriche filter.
 
23086
     CImg<Tfloat> get_blur(const float sigma, const bool cond=true) const {
 
23087
      return CImg<Tfloat>(*this,false).blur(sigma,cond);
 
23088
    }
 
23089
 
 
23090
    //! Return a blurred version of the image, using a Canny-Deriche filter (in-place).
 
23091
    CImg<T>& blur(const float sigma, const bool cond=true) {
16423
23092
      return blur(sigma,sigma,sigma,cond);
16424
23093
    }
16425
23094
 
16426
 
    //! Return a blurred version of the image, using a Canny-Deriche filter.
 
23095
    //! Blur the image anisotropically following a field of diffusion tensors.
16427
23096
    /**
16428
 
       Blur the image with an anisotropic exponential filter (Deriche filter of order 0).
 
23097
       \param G = Field of square roots of diffusion tensors used to drive the smoothing.
 
23098
       \param amplitude = amplitude of the smoothing.
 
23099
       \param dl = spatial discretization.
 
23100
       \param da = angular discretization.
 
23101
       \param gauss_prec = precision of the gaussian function.
 
23102
       \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
 
23103
       \param fast_approx = Tell to use the fast approximation or not.
16429
23104
    **/
16430
 
    CImg<typename cimg::largest<T,float>::type> get_blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) const {
16431
 
      typedef typename cimg::largest<T,float>::type ftype;
16432
 
      return CImg<ftype>(*this).blur(sigmax,sigmay,sigmaz,cond);
16433
 
    }
16434
 
 
16435
 
    //! Return a blurred version of the image, using a Canny-Deriche filter.
16436
 
     CImg<typename cimg::largest<T,float>::type> get_blur(const float sigma, const bool cond=true) const {
16437
 
      typedef typename cimg::largest<T,float>::type ftype;
16438
 
      return CImg<ftype>(*this).blur(sigma,cond);
16439
 
    }
16440
 
 
16441
 
    //! Blur an image following a field of diffusion tensors.
16442
 
    /** This is the in-place version of get_blur_anisotropic(). **/
16443
 
    template<typename t>
16444
 
    CImg& blur_anisotropic(const CImg<t>& G, const float amplitude=60.0f, const float dl=0.8f, const float da=30.0f,
16445
 
                           const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true) {
16446
 
#define cimg_valign2d(i,j) \
16447
 
    { ftype &u = W(i,j,0,0), &v = W(i,j,0,1); \
 
23105
    template<typename t>
 
23106
      CImg<T> get_blur_anisotropic(const CImg<t>& G, const float amplitude=60.0f, const float dl=0.8f, const float da=30.0f,
 
23107
                                   const float gauss_prec=2.0f, const unsigned int interpolation_type=0, const bool fast_approx=true) const {
 
23108
      return (+*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
 
23109
    }
 
23110
 
 
23111
    //! Blur the image anisotropically following a field of diffusion tensors (in-place).
 
23112
    template<typename t>
 
23113
    CImg<T>& blur_anisotropic(const CImg<t>& G, const float amplitude=60.0f, const float dl=0.8f, const float da=30.0f,
 
23114
                              const float gauss_prec=2.0f, const unsigned int interpolation_type=0, const bool fast_approx=true) {
 
23115
#define _cimg_valign2d(i,j) \
 
23116
    { Tfloat &u = W(i,j,0,0), &v = W(i,j,0,1); \
16448
23117
    if (u*curru + v*currv<0) { u=-u; v=-v; }}
16449
 
#define cimg_valign3d(i,j,k) \
16450
 
    { ftype &u = W(i,j,k,0), &v = W(i,j,k,1), &w = W(i,j,k,2); \
 
23118
#define _cimg_valign3d(i,j,k) \
 
23119
    { Tfloat &u = W(i,j,k,0), &v = W(i,j,k,1), &w = W(i,j,k,2); \
16451
23120
    if (u*curru + v*currv + w*currw<0) { u=-u; v=-v; w=-w; }}
16452
23121
 
16453
23122
      // Check arguments and init variables
16454
 
      typedef typename cimg::largest<T,float>::type ftype;
16455
23123
      if (!is_empty() && amplitude>0) {
16456
23124
        if (!G || (G.dim!=3 && G.dim!=6) || G.width!=width || G.height!=height || G.depth!=depth)
16457
23125
          throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Specified tensor field (%u,%u,%u,%u) is not valid.",
16463
23131
          dx1 = dimx()-1,
16464
23132
          dy1 = dimy()-1,
16465
23133
          dz1 = dimz()-1;
16466
 
        CImg<ftype>
 
23134
        CImg<Tfloat>
16467
23135
          dest(width,height,depth,dim,0),
16468
23136
          W(width,height,depth,threed?4:3),
16469
23137
          tmp(dim);
16473
23141
          // 3D version of the algorithm
16474
23142
          for (float phi=(180%(int)da)/2.0f; phi<=180; phi+=da) {
16475
23143
            const float
16476
 
              phir = (float)(phi*cimg::PI/180),
 
23144
              phir = (float)(phi*cimg::valuePI/180),
16477
23145
              datmp = (float)(da/std::cos(phir)),
16478
23146
              da2 = datmp<1?360.0f:datmp;
16479
23147
 
16480
23148
            for (float theta=0; theta<360; (theta+=da2),++N) {
16481
23149
              const float
16482
 
                thetar = (float)(theta*cimg::PI/180),
 
23150
                thetar = (float)(theta*cimg::valuePI/180),
16483
23151
                vx = (float)(std::cos(thetar)*std::cos(phir)),
16484
23152
                vy = (float)(std::sin(thetar)*std::cos(phir)),
16485
23153
                vz = (float)std::sin(phir);
16490
23158
                *pd = G.ptr(0,0,0,3),
16491
23159
                *pe = G.ptr(0,0,0,4),
16492
23160
                *pf = G.ptr(0,0,0,5);
16493
 
              ftype
 
23161
              Tfloat
16494
23162
                *pd0 = W.ptr(0,0,0,0),
16495
23163
                *pd1 = W.ptr(0,0,0,1),
16496
23164
                *pd2 = W.ptr(0,0,0,2),
16505
23173
                  w = (float)(c*vx + e*vy + f*vz),
16506
23174
                  n = (float)std::sqrt(1e-5+u*u+v*v+w*w),
16507
23175
                  dln = dl/n;
16508
 
                *(pd0++) = (ftype)(u*dln);
16509
 
                *(pd1++) = (ftype)(v*dln);
16510
 
                *(pd2++) = (ftype)(w*dln);
16511
 
                *(pd3++) = (ftype)n;
 
23176
                *(pd0++) = (Tfloat)(u*dln);
 
23177
                *(pd1++) = (Tfloat)(v*dln);
 
23178
                *(pd2++) = (Tfloat)(w*dln);
 
23179
                *(pd3++) = (Tfloat)n;
16512
23180
              }
16513
23181
 
16514
23182
              cimg_forXYZ(*this,x,y,z) {
16530
23198
                  Y = (float)y,
16531
23199
                  Z = (float)z;
16532
23200
 
16533
 
                switch (interpolation) {
 
23201
                switch (interpolation_type) {
16534
23202
                case 0: {
16535
23203
                  // Nearest neighbor
16536
23204
                  for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
16543
23211
                      v = (float)W(cx,cy,cz,1),
16544
23212
                      w = (float)W(cx,cy,cz,2);
16545
23213
                    if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
16546
 
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)(*this)(cx,cy,cz,k); ++S; }
 
23214
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,cz,k); ++S; }
16547
23215
                    else {
16548
23216
                      const float coef = (float)std::exp(-l*l/fsigma2);
16549
 
                      cimg_forV(*this,k) tmp[k]+=(ftype)(coef*(*this)(cx,cy,cz,k));
 
23217
                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,cz,k));
16550
23218
                      S+=coef;
16551
23219
                    }
16552
23220
                    X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
16564
23232
                      curru = (float)W(cx,cy,cz,0),
16565
23233
                      currv = (float)W(cx,cy,cz,1),
16566
23234
                      currw = (float)W(cx,cy,cz,2);
16567
 
                    cimg_valign3d(px,py,pz); cimg_valign3d(cx,py,pz); cimg_valign3d(nx,py,pz);
16568
 
                    cimg_valign3d(px,cy,pz); cimg_valign3d(cx,cy,pz); cimg_valign3d(nx,cy,pz);
16569
 
                    cimg_valign3d(px,ny,pz); cimg_valign3d(cx,ny,pz); cimg_valign3d(nx,ny,pz);
16570
 
                    cimg_valign3d(px,py,cz); cimg_valign3d(cx,py,cz); cimg_valign3d(nx,py,cz);
16571
 
                    cimg_valign3d(px,cy,cz);                          cimg_valign3d(nx,cy,cz);
16572
 
                    cimg_valign3d(px,ny,cz); cimg_valign3d(cx,ny,cz); cimg_valign3d(nx,ny,cz);
16573
 
                    cimg_valign3d(px,py,nz); cimg_valign3d(cx,py,nz); cimg_valign3d(nx,py,nz);
16574
 
                    cimg_valign3d(px,cy,nz); cimg_valign3d(cx,cy,nz); cimg_valign3d(nx,cy,nz);
16575
 
                    cimg_valign3d(px,ny,nz); cimg_valign3d(cx,ny,nz); cimg_valign3d(nx,ny,nz);
 
23235
                    _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
 
23236
                    _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
 
23237
                    _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
 
23238
                    _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
 
23239
                    _cimg_valign3d(px,cy,cz);                           _cimg_valign3d(nx,cy,cz);
 
23240
                    _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
 
23241
                    _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
 
23242
                    _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
 
23243
                    _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
16576
23244
                    float
16577
 
                      u = (float)(W.linear_pix3d(X,Y,Z,0)),
16578
 
                      v = (float)(W.linear_pix3d(X,Y,Z,1)),
16579
 
                      w = (float)(W.linear_pix3d(X,Y,Z,2));
 
23245
                      u = (float)(W.linear_at3(X,Y,Z,0)),
 
23246
                      v = (float)(W.linear_at3(X,Y,Z,1)),
 
23247
                      w = (float)(W.linear_at3(X,Y,Z,2));
16580
23248
                    if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
16581
 
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)linear_pix3d(X,Y,Z,k); ++S; }
 
23249
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)linear_at3(X,Y,Z,k); ++S; }
16582
23250
                    else {
16583
23251
                      const float coef = (float)std::exp(-l*l/fsigma2);
16584
 
                      cimg_forV(*this,k) tmp[k]+=(ftype)(coef*linear_pix3d(X,Y,Z,k));
 
23252
                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*linear_at3(X,Y,Z,k));
16585
23253
                      S+=coef;
16586
23254
                    }
16587
23255
                    X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
16599
23267
                      curru = (float)W(cx,cy,cz,0),
16600
23268
                      currv = (float)W(cx,cy,cz,1),
16601
23269
                      currw = (float)W(cx,cy,cz,2);
16602
 
                    cimg_valign3d(px,py,pz); cimg_valign3d(cx,py,pz); cimg_valign3d(nx,py,pz);
16603
 
                    cimg_valign3d(px,cy,pz); cimg_valign3d(cx,cy,pz); cimg_valign3d(nx,cy,pz);
16604
 
                    cimg_valign3d(px,ny,pz); cimg_valign3d(cx,ny,pz); cimg_valign3d(nx,ny,pz);
16605
 
                    cimg_valign3d(px,py,cz); cimg_valign3d(cx,py,cz); cimg_valign3d(nx,py,cz);
16606
 
                    cimg_valign3d(px,cy,cz);                          cimg_valign3d(nx,cy,cz);
16607
 
                    cimg_valign3d(px,ny,cz); cimg_valign3d(cx,ny,cz); cimg_valign3d(nx,ny,cz);
16608
 
                    cimg_valign3d(px,py,nz); cimg_valign3d(cx,py,nz); cimg_valign3d(nx,py,nz);
16609
 
                    cimg_valign3d(px,cy,nz); cimg_valign3d(cx,cy,nz); cimg_valign3d(nx,cy,nz);
16610
 
                    cimg_valign3d(px,ny,nz); cimg_valign3d(cx,ny,nz); cimg_valign3d(nx,ny,nz);
 
23270
                    _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
 
23271
                    _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
 
23272
                    _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
 
23273
                    _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
 
23274
                    _cimg_valign3d(px,cy,cz);                           _cimg_valign3d(nx,cy,cz);
 
23275
                    _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
 
23276
                    _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
 
23277
                    _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
 
23278
                    _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
16611
23279
                    const float
16612
 
                      u0 = (float)(0.5f*W.linear_pix3d(X,Y,Z,0)),
16613
 
                      v0 = (float)(0.5f*W.linear_pix3d(X,Y,Z,1)),
16614
 
                      w0 = (float)(0.5f*W.linear_pix3d(X,Y,Z,2));
 
23280
                      u0 = (float)(0.5f*W.linear_at3(X,Y,Z,0)),
 
23281
                      v0 = (float)(0.5f*W.linear_at3(X,Y,Z,1)),
 
23282
                      w0 = (float)(0.5f*W.linear_at3(X,Y,Z,2));
16615
23283
                    float
16616
 
                      u = (float)(W.linear_pix3d(X+u0,Y+v0,Z+w0,0)),
16617
 
                      v = (float)(W.linear_pix3d(X+u0,Y+v0,Z+w0,1)),
16618
 
                      w = (float)(W.linear_pix3d(X+u0,Y+v0,Z+w0,2));
 
23284
                      u = (float)(W.linear_at3(X+u0,Y+v0,Z+w0,0)),
 
23285
                      v = (float)(W.linear_at3(X+u0,Y+v0,Z+w0,1)),
 
23286
                      w = (float)(W.linear_at3(X+u0,Y+v0,Z+w0,2));
16619
23287
                    if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
16620
 
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)linear_pix3d(X,Y,Z,k); ++S; }
 
23288
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)linear_at3(X,Y,Z,k); ++S; }
16621
23289
                    else {
16622
23290
                      const float coef = (float)std::exp(-l*l/fsigma2);
16623
 
                      cimg_forV(*this,k) tmp[k]+=(ftype)(coef*linear_pix3d(X,Y,Z,k));
 
23291
                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*linear_at3(X,Y,Z,k));
16624
23292
                      S+=coef;
16625
23293
                    }
16626
23294
                    X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
16628
23296
                } break;
16629
23297
                }
16630
23298
                if (S>0) cimg_forV(dest,k) dest(x,y,z,k)+=tmp[k]/S;
16631
 
                else cimg_forV(dest,k) dest(x,y,z,k)+=(ftype)((*this)(x,y,z,k));
16632
 
#ifdef cimg_plugin_greycstoration
16633
 
                if (!*(greycstoration_params->stop_request)) ++(*greycstoration_params->counter);
16634
 
                else return *this;
16635
 
#endif
 
23299
                else cimg_forV(dest,k) dest(x,y,z,k)+=(Tfloat)((*this)(x,y,z,k));
 
23300
                cimg_plugin_greycstoration_count;
16636
23301
              }
16637
23302
            }
16638
23303
          } else
16639
23304
            // 2D version of the algorithm
16640
23305
            for (float theta=(360%(int)da)/2.0f; theta<360; (theta+=da),++N) {
16641
23306
              const float
16642
 
                thetar = (float)(theta*cimg::PI/180),
 
23307
                thetar = (float)(theta*cimg::valuePI/180),
16643
23308
                vx = (float)(std::cos(thetar)),
16644
23309
                vy = (float)(std::sin(thetar));
16645
23310
              const t
16646
23311
                *pa = G.ptr(0,0,0,0),
16647
23312
                *pb = G.ptr(0,0,0,1),
16648
23313
                *pc = G.ptr(0,0,0,2);
16649
 
              ftype
 
23314
              Tfloat
16650
23315
                *pd0 = W.ptr(0,0,0,0),
16651
23316
                *pd1 = W.ptr(0,0,0,1),
16652
23317
                *pd2 = W.ptr(0,0,0,2);
16657
23322
                  v = (float)(b*vx + c*vy),
16658
23323
                  n = (float)std::sqrt(1e-5+u*u+v*v),
16659
23324
                  dln = dl/n;
16660
 
                *(pd0++) = (ftype)(u*dln);
16661
 
                *(pd1++) = (ftype)(v*dln);
16662
 
                *(pd2++) = (ftype)n;
 
23325
                *(pd0++) = (Tfloat)(u*dln);
 
23326
                *(pd1++) = (Tfloat)(v*dln);
 
23327
                *(pd2++) = (Tfloat)n;
16663
23328
              }
16664
23329
 
16665
23330
              cimg_forXY(*this,x,y) {
16678
23343
                  X = (float)x,
16679
23344
                  Y = (float)y;
16680
23345
 
16681
 
                switch (interpolation) {
 
23346
                switch (interpolation_type) {
16682
23347
 
16683
23348
                case 0: {
16684
23349
                  // Nearest-neighbor interpolation for 2D images
16690
23355
                      u = (float)W(cx,cy,0,0),
16691
23356
                      v = (float)W(cx,cy,0,1);
16692
23357
                    if ((pu*u + pv*v)<0) { u=-u; v=-v; }
16693
 
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)(*this)(cx,cy,0,k); ++S; }
 
23358
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,0,k); ++S; }
16694
23359
                    else {
16695
23360
                      const float coef = (float)std::exp(-l*l/fsigma2);
16696
 
                      cimg_forV(*this,k) tmp[k]+=(ftype)(coef*(*this)(cx,cy,0,k));
 
23361
                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,0,k));
16697
23362
                      S+=coef;
16698
23363
                    }
16699
23364
                    X+=(pu=u); Y+=(pv=v);
16709
23374
                    const float
16710
23375
                      curru = (float)W(cx,cy,0,0),
16711
23376
                      currv = (float)W(cx,cy,0,1);
16712
 
                    cimg_valign2d(px,py); cimg_valign2d(cx,py); cimg_valign2d(nx,py);
16713
 
                    cimg_valign2d(px,cy);                       cimg_valign2d(nx,cy);
16714
 
                    cimg_valign2d(px,ny); cimg_valign2d(cx,ny); cimg_valign2d(nx,ny);
 
23377
                    _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
 
23378
                    _cimg_valign2d(px,cy);                        _cimg_valign2d(nx,cy);
 
23379
                    _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
16715
23380
                    float
16716
 
                      u = (float)(W.linear_pix2d(X,Y,0,0)),
16717
 
                      v = (float)(W.linear_pix2d(X,Y,0,1));
 
23381
                      u = (float)(W.linear_at2(X,Y,0,0)),
 
23382
                      v = (float)(W.linear_at2(X,Y,0,1));
16718
23383
                    if ((pu*u + pv*v)<0) { u=-u; v=-v; }
16719
 
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)linear_pix2d(X,Y,0,k); ++S; }
 
23384
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)linear_at2(X,Y,0,k); ++S; }
16720
23385
                    else {
16721
23386
                      const float coef = (float)std::exp(-l*l/fsigma2);
16722
 
                      cimg_forV(*this,k) tmp[k]+=(ftype)(coef*linear_pix2d(X,Y,0,k));
 
23387
                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*linear_at2(X,Y,0,k));
16723
23388
                      S+=coef;
16724
23389
                    }
16725
23390
                    X+=(pu=u); Y+=(pv=v);
16735
23400
                    const float
16736
23401
                      curru = (float)W(cx,cy,0,0),
16737
23402
                      currv = (float)W(cx,cy,0,1);
16738
 
                    cimg_valign2d(px,py); cimg_valign2d(cx,py); cimg_valign2d(nx,py);
16739
 
                    cimg_valign2d(px,cy);                       cimg_valign2d(nx,cy);
16740
 
                    cimg_valign2d(px,ny); cimg_valign2d(cx,ny); cimg_valign2d(nx,ny);
 
23403
                    _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
 
23404
                    _cimg_valign2d(px,cy);                        _cimg_valign2d(nx,cy);
 
23405
                    _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
16741
23406
                    const float
16742
 
                      u0 = (float)(0.5f*W.linear_pix2d(X,Y,0,0)),
16743
 
                      v0 = (float)(0.5f*W.linear_pix2d(X,Y,0,1));
 
23407
                      u0 = (float)(0.5f*W.linear_at2(X,Y,0,0)),
 
23408
                      v0 = (float)(0.5f*W.linear_at2(X,Y,0,1));
16744
23409
                    float
16745
 
                      u = (float)(W.linear_pix2d(X+u0,Y+v0,0,0)),
16746
 
                      v = (float)(W.linear_pix2d(X+u0,Y+v0,0,1));
 
23410
                      u = (float)(W.linear_at2(X+u0,Y+v0,0,0)),
 
23411
                      v = (float)(W.linear_at2(X+u0,Y+v0,0,1));
16747
23412
                    if ((pu*u + pv*v)<0) { u=-u; v=-v; }
16748
 
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)linear_pix2d(X,Y,0,k); ++S; }
 
23413
                    if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)linear_at2(X,Y,0,k); ++S; }
16749
23414
                    else {
16750
23415
                      const float coef = (float)std::exp(-l*l/fsigma2);
16751
 
                      cimg_forV(*this,k) tmp[k]+=(ftype)(coef*linear_pix2d(X,Y,0,k));
 
23416
                      cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*linear_at2(X,Y,0,k));
16752
23417
                      S+=coef;
16753
23418
                    }
16754
23419
                    X+=(pu=u); Y+=(pv=v);
16756
23421
                } break;
16757
23422
                }
16758
23423
                if (S>0) cimg_forV(dest,k) dest(x,y,0,k)+=tmp[k]/S;
16759
 
                else cimg_forV(dest,k) dest(x,y,0,k)+=(ftype)((*this)(x,y,0,k));
16760
 
#ifdef cimg_plugin_greycstoration
16761
 
                if (!*(greycstoration_params->stop_request)) ++(*greycstoration_params->counter);
16762
 
                else return *this;
16763
 
#endif
 
23424
                else cimg_forV(dest,k) dest(x,y,0,k)+=(Tfloat)((*this)(x,y,0,k));
 
23425
                cimg_plugin_greycstoration_count;
16764
23426
              }
16765
23427
            }
16766
 
        const ftype *ptrs = dest.data+dest.size();
 
23428
        const Tfloat *ptrs = dest.data+dest.size();
16767
23429
        const T m = cimg::type<T>::min(), M = cimg::type<T>::max();
16768
 
        cimg_for(*this,ptrd,T) { const ftype val = *(--ptrs)/N; *ptrd = val<m?m:(val>M?M:(T)val); }
 
23430
        cimg_for(*this,ptrd,T) { const Tfloat val = *(--ptrs)/N; *ptrd = val<m?m:(val>M?M:(T)val); }
16769
23431
      }
16770
23432
      return *this;
16771
23433
    }
16772
23434
 
16773
 
    //! Get a blurred version of an image following a field of diffusion tensors.
 
23435
    //! Blur an image in an anisotropic way.
16774
23436
    /**
16775
 
       \param G = Field of square roots of diffusion tensors used to drive the smoothing.
16776
 
       \param amplitude = amplitude of the smoothing.
16777
 
       \param dl = spatial discretization.
16778
 
       \param da = angular discretization.
16779
 
       \param gauss_prec = precision of the gaussian function.
16780
 
       \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
16781
 
       \param fast_approx = Tell to use the fast approximation or not.
 
23437
       \param mask Binary mask.
 
23438
       \param amplitude Amplitude of the anisotropic blur.
 
23439
       \param sharpness Contour preservation.
 
23440
       \param anisotropy Smoothing anisotropy.
 
23441
       \param alpha Image pre-blurring (gaussian).
 
23442
       \param sigma Regularity of the tensor-valued geometry.
 
23443
       \param dl Spatial discretization.
 
23444
       \param da Angular discretization.
 
23445
       \param gauss_prec Precision of the gaussian function.
 
23446
       \param interpolation_type Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
 
23447
       \param fast_approx Tell to use the fast approximation or not
 
23448
       \param geom_factor Geometry factor.
16782
23449
    **/
16783
 
    template<typename t>
16784
 
      CImg get_blur_anisotropic(const CImg<t>& G, const float amplitude=60.0f, const float dl=0.8f, const float da=30.0f,
16785
 
                                const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true) const {
16786
 
      return (+*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation,fast_approx);
 
23450
    template<typename tm>
 
23451
      CImg<T> get_blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 
23452
                                   const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
 
23453
                                   const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation_type=0,
 
23454
                                   const bool fast_approx=true, const float geom_factor=1.0f) const {
 
23455
      return (+*this).blur_anisotropic(mask,amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
16787
23456
    }
16788
23457
 
16789
 
    //! Blur an image following a field of diffusion tensors.
 
23458
    //! Blur an image in an anisotropic way (in-place).
16790
23459
    template<typename tm>
16791
 
      CImg& blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
16792
 
                             const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30.0f,
16793
 
                             const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true,
16794
 
                             const float geom_factor=1.0f) {
 
23460
      CImg<T>& blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 
23461
                                const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30.0f,
 
23462
                                const float gauss_prec=2.0f, const unsigned int interpolation_type=0, const bool fast_approx=true,
 
23463
                                const float geom_factor=1.0f) {
16795
23464
      if (!is_empty() && amplitude>0) {
16796
23465
        if (amplitude==0) return *this;
16797
23466
        if (amplitude<0 || sharpness<0 || anisotropy<0 || anisotropy>1 || alpha<0 || sigma<0 || dl<0 || da<0 || gauss_prec<0)
16802
23471
                                      pixel_type(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec);
16803
23472
        const bool threed = (depth>1), no_mask = mask.is_empty();
16804
23473
        const float nsharpness = cimg::max(sharpness,1e-5f), power1 = 0.5f*nsharpness, power2 = power1/(1e-7f+1.0f-anisotropy);
16805
 
 
16806
23474
        CImg<float> blurred = CImg<float>(*this,false).blur(alpha);
16807
23475
        if (geom_factor>0) blurred*=geom_factor;
16808
23476
        else blurred.normalize(0,-geom_factor);
16809
23477
 
16810
23478
        if (threed) { // Field for 3D volumes
 
23479
          cimg_plugin_greycstoration_lock;
16811
23480
          CImg<float> val(3), vec(3,3), G(blurred.get_structure_tensorXYZ());
16812
23481
          if (sigma>0) G.blur(sigma);
16813
23482
          cimg_forXYZ(*this,x,y,z) {
16826
23495
              G(x,y,z,4) = n1*(uy*uz + vy*vz) + n2*wy*wz;
16827
23496
              G(x,y,z,5) = n1*(uz*uz + vz*vz) + n2*wz*wz;
16828
23497
            } 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;
16829
 
#ifdef cimg_plugin_greycstoration
16830
 
            if (!*(greycstoration_params->stop_request)) ++(*greycstoration_params->counter);
16831
 
            else return *this;
16832
 
#endif
 
23498
            cimg_plugin_greycstoration_count;
16833
23499
          }
16834
 
          blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation,fast_approx);
 
23500
          cimg_plugin_greycstoration_unlock;
 
23501
          blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
16835
23502
        } else { // Field for 2D images
 
23503
          cimg_plugin_greycstoration_lock;
16836
23504
          CImg<float> val(2), vec(2,2), G(blurred.get_structure_tensorXY());
16837
23505
          if (sigma>0) G.blur(sigma);
16838
23506
          cimg_forXY(*this,x,y) {
16847
23515
              G(x,y,0,1) = n1*ux*uy + n2*vx*vy;
16848
23516
              G(x,y,0,2) = n1*uy*uy + n2*vy*vy;
16849
23517
            } else G(x,y,0,0) = G(x,y,0,1) = G(x,y,0,2) = 0;
16850
 
#ifdef cimg_plugin_greycstoration
16851
 
            if (!*(greycstoration_params->stop_request)) ++(*greycstoration_params->counter);
16852
 
            else return *this;
16853
 
#endif
 
23518
            cimg_plugin_greycstoration_count;
16854
23519
          }
16855
 
          blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation,fast_approx);
 
23520
          cimg_plugin_greycstoration_unlock;
 
23521
          blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
16856
23522
        }
16857
23523
      }
16858
23524
      return *this;
16859
23525
    }
16860
23526
 
16861
 
    //! Blur an image in an anisotropic way.
 
23527
    //! Blur an image following in an anisotropic way.
 
23528
    CImg<T> get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 
23529
                                 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
 
23530
                                 const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation_type=0,
 
23531
                                 const bool fast_approx=true, const float geom_factor=1.0f) const {
 
23532
      return (+*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
 
23533
    }
 
23534
 
 
23535
    //! Blur an image following in an anisotropic way (in-place).
 
23536
    CImg<T>& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
 
23537
                              const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30.0f,
 
23538
                              const float gauss_prec=2.0f, const unsigned int interpolation_type=0, const bool fast_approx=true,
 
23539
                              const float geom_factor=1.0f) {
 
23540
      return blur_anisotropic(CImg<T>(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
 
23541
    }
 
23542
 
 
23543
    //! Blur an image using the bilateral filter.
16862
23544
    /**
16863
 
       \param amplitude = amplitude of the anisotropic blur.
16864
 
       \param sharpness = define the contour preservation.
16865
 
       \param anisotropy = define the smoothing anisotropy.
16866
 
       \param alpha = image pre-blurring (gaussian).
16867
 
       \param sigma = regularity of the tensor-valued geometry.
16868
 
       \param dl = spatial discretization.
16869
 
       \param da = angular discretization.
16870
 
       \param gauss_prec = precision of the gaussian function.
16871
 
       \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
16872
 
       \param fast_approx = Tell to use the fast approximation or not
 
23545
       \param sigmax Amount of blur along the X-axis.
 
23546
       \param sigmay Amount of blur along the Y-axis.
 
23547
       \param sigmaz Amount of blur along the Z-axis.
 
23548
       \param sigmar Amount of blur along the range axis.
 
23549
       \param bgridx Size of the bilateral grid along the X-axis.
 
23550
       \param bgridy Size of the bilateral grid along the Y-axis.
 
23551
       \param bgridz Size of the bilateral grid along the Z-axis.
 
23552
       \param bgridr Size of the bilateral grid along the range axis.
 
23553
       \param interpolation_type Use interpolation for image slicing.
 
23554
       \note This algorithm uses the optimisation technique proposed by S. Paris and F. Durand, in ECCV'2006
 
23555
       (extended for 3D volumetric images).
16873
23556
    **/
16874
 
    template<typename tm>
16875
 
      CImg get_blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
16876
 
                                const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
16877
 
                                const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation=0,
16878
 
                                const bool fast_approx=true, const float geom_factor=1.0f) const {
16879
 
      return (+*this).blur_anisotropic(mask,amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation,fast_approx,geom_factor);
16880
 
    }
16881
 
 
16882
 
    //! Blur an image following in an anisotropic way.
16883
 
    CImg& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
16884
 
                           const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30.0f,
16885
 
                           const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true,
16886
 
                           const float geom_factor=1.0f) {
16887
 
      return blur_anisotropic(CImg<T>(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation,fast_approx,geom_factor);
16888
 
    }
16889
 
 
16890
 
    //! Blur an image following in an anisotropic way.
16891
 
    CImg get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
16892
 
                              const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
16893
 
                              const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation=0,
16894
 
                              const bool fast_approx=true, const float geom_factor=1.0f) const {
16895
 
      return (+*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation,fast_approx,geom_factor);
16896
 
    }
16897
 
 
16898
 
    //! Return the Fast Fourier Transform of an image (along a specified axis)
16899
 
    CImgList<typename cimg::largest<T,float>::type> get_FFT(const char axe, const bool inverse=false) const {
16900
 
      typedef typename cimg::largest<T,float>::type restype;
16901
 
      return CImgList<restype>(*this).FFT(axe,inverse);
16902
 
    }
16903
 
 
16904
 
    //! Return the Fast Fourier Transform on an image
16905
 
    CImgList<typename cimg::largest<T,float>::type> get_FFT(const bool inverse=false) const {
16906
 
      typedef typename cimg::largest<T,float>::type restype;
16907
 
      return CImgList<restype>(*this).FFT(inverse);
 
23557
    CImg<T> get_blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
 
23558
                               const int bgridx, const int bgridy, const int bgridz, const int bgridr,
 
23559
                               const bool interpolation_type=true) const {
 
23560
      return (+*this).blur_bilateral(sigmax,sigmay,sigmaz,sigmar,bgridx,bgridy,bgridz,bgridr,interpolation_type);
 
23561
    }
 
23562
 
 
23563
    //! Blur an image using the bilateral filter (in-place).
 
23564
    CImg<T>& blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
 
23565
                            const int bgridx, const int bgridy, const int bgridz, const int bgridr,
 
23566
                            const bool interpolation_type=true) {
 
23567
      T m, M = maxmin(m);
 
23568
      const float range = (float)(1.0f+M-m);
 
23569
      const unsigned int
 
23570
        bx0 = bgridx>=0?bgridx:width*(-bgridx)/100,
 
23571
        by0 = bgridy>=0?bgridy:height*(-bgridy)/100,
 
23572
        bz0 = bgridz>=0?bgridz:depth*(-bgridz)/100,
 
23573
        br0 = bgridr>=0?bgridr:(int)(-range*bgridr/100),
 
23574
        bx = bx0>0?bx0:1,
 
23575
        by = by0>0?by0:1,
 
23576
        bz = bz0>0?bz0:1,
 
23577
        br = br0>0?br0:1;
 
23578
      const float
 
23579
        nsigmax = sigmax*bx/width,
 
23580
        nsigmay = sigmay*by/height,
 
23581
        nsigmaz = sigmaz*bz/depth,
 
23582
        nsigmar = sigmar*br/range;
 
23583
      if (nsigmax>0 || nsigmay>0 || nsigmaz>0 || nsigmar>0) {
 
23584
        const bool threed = depth>1;
 
23585
        if (threed) { // 3d version of the algorithm
 
23586
          typedef typename cimg::last<T,float>::type type_float;
 
23587
          CImg<type_float> bgrid(bx,by,bz,br), bgridw(bx,by,bz,br);
 
23588
          cimg_forV(*this,k) {
 
23589
            bgrid.fill(0); bgridw.fill(0);
 
23590
            cimg_forXYZ(*this,x,y,z) {
 
23591
              const T val = (*this)(x,y,z,k);
 
23592
              const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
 
23593
              bgrid(X,Y,Z,R) = (float)val;
 
23594
              bgridw(X,Y,Z,R) = 1;
 
23595
            }
 
23596
            bgrid.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
 
23597
            bgridw.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
 
23598
            if (interpolation_type) cimg_forXYZ(*this,x,y,z) {
 
23599
              const T val = (*this)(x,y,z,k);
 
23600
              const float X = (float)x*bx/width, Y = (float)y*by/height, Z = (float)z*bz/depth, R = (val-m)*br/range,
 
23601
                bval0 = bgrid.linear_at(X,Y,Z,R), bval1 = bgridw.linear_at(X,Y,Z,R);
 
23602
              (*this)(x,y,z,k) = (T)(bval0/bval1);
 
23603
            } else cimg_forXYZ(*this,x,y,z) {
 
23604
              const T val = (*this)(x,y,z,k);
 
23605
              const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
 
23606
              const float bval0 = bgrid(X,Y,Z,R), bval1 = bgridw(X,Y,Z,R);
 
23607
              (*this)(x,y,z,k) = (T)(bval0/bval1);
 
23608
            }
 
23609
          }
 
23610
        } else { // 2d version of the algorithm
 
23611
          typedef typename cimg::last<T,float>::type type_float;
 
23612
          CImg<type_float> bgrid(bx,by,br,2);
 
23613
          cimg_forV(*this,k) {
 
23614
            bgrid.fill(0);
 
23615
            cimg_forXY(*this,x,y) {
 
23616
              const T val = (*this)(x,y,k);
 
23617
              const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
 
23618
              bgrid(X,Y,R,0) = (float)val;
 
23619
              bgrid(X,Y,R,1) = 1;
 
23620
            }
 
23621
            bgrid.blur(nsigmax,nsigmay,0,true).blur(0,0,nsigmar,false);
 
23622
            if (interpolation_type) cimg_forXY(*this,x,y) {
 
23623
              const T val = (*this)(x,y,k);
 
23624
              const float X = (float)x*bx/width, Y = (float)y*by/height, R = (val-m)*br/range,
 
23625
                bval0 = bgrid.linear_at3(X,Y,R,0), bval1 = bgrid.linear_at3(X,Y,R,1);
 
23626
              (*this)(x,y,k) = (T)(bval0/bval1);
 
23627
            } else cimg_forXY(*this,x,y) {
 
23628
              const T val = (*this)(x,y,k);
 
23629
              const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
 
23630
              const float bval0 = bgrid(X,Y,R,0), bval1 = bgrid(X,Y,R,1);
 
23631
              (*this)(x,y,k) = (T)(bval0/bval1);
 
23632
            }
 
23633
          }
 
23634
        }
 
23635
      }
 
23636
      return *this;
 
23637
    }
 
23638
 
 
23639
    //! Blur an image using the bilateral filter.
 
23640
    CImg<T> get_blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
 
23641
                               const bool interpolation_type=true) const {
 
23642
      return (+*this).blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
 
23643
    }
 
23644
 
 
23645
    //! Blur an image using the bilateral filter (in-place).
 
23646
    CImg<T>& blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
 
23647
                            const bool interpolation_type=true) {
 
23648
      return blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
 
23649
    }
 
23650
 
 
23651
    //! Blur an image in its patch-based space.
 
23652
    CImg<T> get_blur_patch(const unsigned int patch_size=3, const float sigma_p=10.0f, const float sigma_s=10.0f,
 
23653
                           const unsigned int lookup_size=4, const bool fast_approx=true) const {
 
23654
      return (+*this).blur_patch(patch_size,sigma_p,sigma_s,lookup_size,fast_approx);
 
23655
    }
 
23656
 
 
23657
    //! Blur an image in its patch-based space (in-place).
 
23658
    CImg<T>& blur_patch(const unsigned int patch_size=3, const float sigma_p=10.0f, const float sigma_s=10.0f,
 
23659
                        const unsigned int lookup_size=4, const bool fast_approx=true) {
 
23660
 
 
23661
#define _cimg_blur_patch_fastfunc(x) ((x)>3?0:1)
 
23662
#define _cimg_blur_patch_slowfunc(x) std::exp(-(x))
 
23663
#define _cimg_blur_patch3d(N,func) { \
 
23664
  const unsigned int N3 = N*N*N; \
 
23665
  cimg_for##N##XYZ(*this,x,y,z) { \
 
23666
    cimg_plugin_greycstoration_count; \
 
23667
    cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,x,y,z,k,P.ptr(N3*k)); \
 
23668
    const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \
 
23669
    float sum_weights = 0; \
 
23670
    cimg_for_in##N##XYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) { \
 
23671
      cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,p,q,r,k,Q.ptr(N3*k)); \
 
23672
      float distance2 = 0; \
 
23673
      const T *pQ = Q.end(); \
 
23674
      cimg_for(P,pP,T) { const float dI = (float)*pP-(float)*(--pQ); distance2+=dI*dI; } \
 
23675
      distance2/=Pnorm; \
 
23676
      const float dx = (float)p-x, dy = (float)q-y, dz = (float)r-z, \
 
23677
        alldist = distance2 + (dx*dx+dy*dy+dz*dz)/sigma_s2, weight = (float)func(alldist); \
 
23678
      sum_weights+=weight; \
 
23679
      { cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k); } \
 
23680
    } \
 
23681
    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) = (*this)(x,y,z,k); \
 
23682
  }}
 
23683
#define _cimg_blur_patch2d(N,func) { \
 
23684
  const unsigned int N2 = N*N; \
 
23685
  cimg_for##N##XY(*this,x,y) { \
 
23686
    cimg_plugin_greycstoration_count; \
 
23687
    cimg_forV(*this,k) cimg_get##N##x##N(*this,x,y,0,k,P.ptr(N2*k)); \
 
23688
    const int x0 = x-rsize1, y0 = y-rsize1, x1 = x+rsize2, y1 = y+rsize2; \
 
23689
    float sum_weights = 0; \
 
23690
    cimg_for_in##N##XY(*this,x0,y0,x1,y1,p,q) { \
 
23691
      cimg_forV(*this,k) cimg_get##N##x##N(*this,p,q,0,k,Q.ptr(N2*k)); \
 
23692
      float distance2 = 0; \
 
23693
      const T *pQ = Q.end(); \
 
23694
      cimg_for(P,pP,T) { const float dI = (float)*pP-(float)*(--pQ); distance2+=dI*dI; } \
 
23695
      distance2/=Pnorm; \
 
23696
      const float dx = (float)p-x, dy = (float)q-y, \
 
23697
        alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = (float)func(alldist); \
 
23698
      sum_weights+=weight; \
 
23699
      { cimg_forV(*this,k) res(x,y,k)+=weight*(*this)(p,q,k); } \
 
23700
    } \
 
23701
    if (sum_weights>0) cimg_forV(*this,k) res(x,y,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,k) = (*this)(x,y,k); \
 
23702
  }}
 
23703
 
 
23704
      CImg<Tfloat> res(width,height,depth,dim,0);
 
23705
      CImg<T> P(patch_size*patch_size*dim), Q(P);
 
23706
      const float sigma_s2 = sigma_s*sigma_s, sigma_p2 = sigma_p*sigma_p, Pnorm = P.size()*sigma_p2;
 
23707
      const int rsize2 = (int)lookup_size/2, rsize1 = rsize2-1+(lookup_size%2);
 
23708
      if (depth>1) switch (patch_size) { // 3D version
 
23709
      case 2:
 
23710
        if (fast_approx) { _cimg_blur_patch3d(2,_cimg_blur_patch_fastfunc); }
 
23711
        else { _cimg_blur_patch3d(2,_cimg_blur_patch_slowfunc); }
 
23712
        break;
 
23713
      case 3:
 
23714
        if (fast_approx) { _cimg_blur_patch3d(3,_cimg_blur_patch_fastfunc); }
 
23715
        else { _cimg_blur_patch3d(3,_cimg_blur_patch_slowfunc); }
 
23716
        break;
 
23717
      default: {
 
23718
        const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
 
23719
        cimg_forXYZ(*this,x,y,z) {
 
23720
          cimg_plugin_greycstoration_count;
 
23721
          P = get_crop(x-psize0,y-psize0,z-psize0,x+psize1,y+psize1,z+psize1,true);
 
23722
          const int x0 = x-rsize1, y0 = y-rsize1, z0 = z-rsize1, x1 = x+rsize2, y1 = y+rsize2, z1 = z+rsize2;
 
23723
          float sum_weights = 0;
 
23724
          cimg_for_inXYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) {
 
23725
            (Q = get_crop(p-psize0,q-psize0,r-psize0,p+psize1,q+psize1,r+psize1,true))-=P;
 
23726
            const float
 
23727
              dx = (float)x-p, dy = (float)y-q, dz = (float)z-r,
 
23728
              distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),
 
23729
              weight = (float)std::exp(-distance2);
 
23730
            sum_weights+=weight;
 
23731
            cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k);
 
23732
          }
 
23733
          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) = (*this)(x,y,z,k);
 
23734
        }
 
23735
      } break;
 
23736
      } else switch (patch_size) { // 2D version
 
23737
      case 2:
 
23738
        if (fast_approx) { _cimg_blur_patch2d(2,_cimg_blur_patch_fastfunc); }
 
23739
        else { _cimg_blur_patch2d(2,_cimg_blur_patch_slowfunc); }
 
23740
        break;
 
23741
      case 3:
 
23742
        if (fast_approx) { _cimg_blur_patch2d(3,_cimg_blur_patch_fastfunc); }
 
23743
        else { _cimg_blur_patch2d(3,_cimg_blur_patch_slowfunc); }
 
23744
        break;
 
23745
      case 4:
 
23746
        if (fast_approx) { _cimg_blur_patch2d(4,_cimg_blur_patch_fastfunc); }
 
23747
        else { _cimg_blur_patch2d(4,_cimg_blur_patch_slowfunc); }
 
23748
        break;
 
23749
      case 5:
 
23750
        if (fast_approx) { _cimg_blur_patch2d(5,_cimg_blur_patch_fastfunc); }
 
23751
        else { _cimg_blur_patch2d(5,_cimg_blur_patch_slowfunc); }
 
23752
        break;
 
23753
      case 6:
 
23754
        if (fast_approx) { _cimg_blur_patch2d(6,_cimg_blur_patch_fastfunc); }
 
23755
        else { _cimg_blur_patch2d(6,_cimg_blur_patch_slowfunc); }
 
23756
        break;
 
23757
      case 7:
 
23758
        if (fast_approx) { _cimg_blur_patch2d(7,_cimg_blur_patch_fastfunc); }
 
23759
        else { _cimg_blur_patch2d(7,_cimg_blur_patch_slowfunc); }
 
23760
        break;
 
23761
      case 8:
 
23762
        if (fast_approx) { _cimg_blur_patch2d(8,_cimg_blur_patch_fastfunc); }
 
23763
        else { _cimg_blur_patch2d(8,_cimg_blur_patch_slowfunc); }
 
23764
        break;
 
23765
      case 9:
 
23766
        if (fast_approx) { _cimg_blur_patch2d(9,_cimg_blur_patch_fastfunc); }
 
23767
        else { _cimg_blur_patch2d(9,_cimg_blur_patch_slowfunc); }
 
23768
        break;
 
23769
      default: {
 
23770
        const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
 
23771
        cimg_forXY(*this,x,y) {
 
23772
          cimg_plugin_greycstoration_count;
 
23773
          P = get_crop(x-psize0,y-psize0,x+psize1,y+psize1,true);
 
23774
          const int x0 = x-rsize1, y0 = y-rsize1, x1 = x+rsize2, y1 = y+rsize2;
 
23775
          float sum_weights = 0;
 
23776
          cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
 
23777
            (Q = get_crop(p-psize0,q-psize0,p+psize1,q+psize1,true))-=P;
 
23778
            const float
 
23779
              dx = (float)x-p, dy = (float)y-q,
 
23780
              distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),
 
23781
              weight = (float)std::exp(-distance2);
 
23782
            sum_weights+=weight;
 
23783
            cimg_forV(*this,k) res(x,y,0,k)+=weight*(*this)(p,q,0,k);
 
23784
          }
 
23785
          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) = (*this)(x,y,0,k);
 
23786
        }
 
23787
      } break;
 
23788
      }
 
23789
      return res.transfer_to(*this);
 
23790
    }
 
23791
 
 
23792
    //! Compute the Fast Fourier Transform of an image (along a specified axis).
 
23793
    CImgList<Tfloat> get_FFT(const char axe, const bool invert=false) const {
 
23794
      return CImgList<Tfloat>(*this).FFT(axe,invert);
 
23795
    }
 
23796
 
 
23797
    //! Compute the Fast Fourier Transform on an image.
 
23798
    CImgList<Tfloat> get_FFT(const bool invert=false) const {
 
23799
      return CImgList<Tfloat>(*this).FFT(invert);
16908
23800
    }
16909
23801
 
16910
23802
    //! Apply a median filter.
16911
 
    CImg get_blur_median(const unsigned int n=3) {
 
23803
    CImg<T> get_blur_median(const unsigned int n=3) {
16912
23804
      CImg<T> res(width,height,depth,dim);
16913
23805
      if (!n || n==1) return *this;
16914
23806
      const int hl=n/2, hr=hl-1+n%2;
16915
23807
      if (res.depth!=1) {  // 3D median filter
16916
23808
        CImg<T> vois;
16917
23809
        cimg_forXYZV(*this,x,y,z,k) {
16918
 
          vois = get_crop(x-hl,y-hl,z-hl,k,x+hr,y+hr,z+hr,k);
 
23810
          const int
 
23811
            x0 = x - hl, y0 = y - hl, z0 = z-hl, x1 = x + hr, y1 = y + hr, z1 = z+hr,
 
23812
            nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,
 
23813
            nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1, nz1 = z1>=dimz()?dimz()-1:z1;
 
23814
          vois = get_crop(nx0,ny0,nz0,k,nx1,ny1,nz1,k);
16919
23815
          res(x,y,z,k) = vois.median();
16920
23816
        }
16921
 
      } else { // 2D median filter
16922
 
#define _median_sort(a,b) if ((a)>(b)) cimg::swap(a,b)
16923
 
        switch (n) {
 
23817
      } else {
 
23818
#define _cimg_median_sort(a,b) if ((a)>(b)) cimg::swap(a,b)
 
23819
        if (res.height!=1) switch (n) { // 2D median filter
16924
23820
        case 3: {
16925
 
          CImg_3x3(I,T);
 
23821
          T I[9] = { 0 };
16926
23822
          CImg_3x3(J,T);
16927
23823
          cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
16928
 
            cimg_copy3x3(I,J);
16929
 
            _median_sort(Jcp, Jnp); _median_sort(Jcc, Jnc); _median_sort(Jcn, Jnn);
16930
 
            _median_sort(Jpp, Jcp); _median_sort(Jpc, Jcc); _median_sort(Jpn, Jcn);
16931
 
            _median_sort(Jcp, Jnp); _median_sort(Jcc, Jnc); _median_sort(Jcn, Jnn);
16932
 
            _median_sort(Jpp, Jpc); _median_sort(Jnc, Jnn); _median_sort(Jcc, Jcn);
16933
 
            _median_sort(Jpc, Jpn); _median_sort(Jcp, Jcc); _median_sort(Jnp, Jnc);
16934
 
            _median_sort(Jcc, Jcn); _median_sort(Jcc, Jnp); _median_sort(Jpn, Jcc);
16935
 
            _median_sort(Jcc, Jnp);
 
23824
            std::memcpy(J,I,9*sizeof(T));
 
23825
            _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
 
23826
            _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jpn, Jcn);
 
23827
            _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
 
23828
            _cimg_median_sort(Jpp, Jpc); _cimg_median_sort(Jnc, Jnn); _cimg_median_sort(Jcc, Jcn);
 
23829
            _cimg_median_sort(Jpc, Jpn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jnp, Jnc);
 
23830
            _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcc, Jnp); _cimg_median_sort(Jpn, Jcc);
 
23831
            _cimg_median_sort(Jcc, Jnp);
16936
23832
            res(x,y,0,k) = Jcc;
16937
23833
          }
16938
23834
        } break;
16939
23835
        case 5: {
16940
 
          CImg_5x5(I,T);
 
23836
          T I[25] = { 0 };
16941
23837
          CImg_5x5(J,T);
16942
23838
          cimg_forV(*this,k) cimg_for5x5(*this,x,y,0,k,I) {
16943
 
            cimg_copy5x5(I,J);
16944
 
            _median_sort(Jbb, Jpb); _median_sort(Jnb, Jab); _median_sort(Jcb, Jab); _median_sort(Jcb, Jnb);
16945
 
            _median_sort(Jpp, Jcp); _median_sort(Jbp, Jcp); _median_sort(Jbp, Jpp); _median_sort(Jap, Jbc);
16946
 
            _median_sort(Jnp, Jbc); _median_sort(Jnp, Jap); _median_sort(Jcc, Jnc); _median_sort(Jpc, Jnc);
16947
 
            _median_sort(Jpc, Jcc); _median_sort(Jbn, Jpn); _median_sort(Jac, Jpn); _median_sort(Jac, Jbn);
16948
 
            _median_sort(Jnn, Jan); _median_sort(Jcn, Jan); _median_sort(Jcn, Jnn); _median_sort(Jpa, Jca);
16949
 
            _median_sort(Jba, Jca); _median_sort(Jba, Jpa); _median_sort(Jna, Jaa); _median_sort(Jcb, Jbp);
16950
 
            _median_sort(Jnb, Jpp); _median_sort(Jbb, Jpp); _median_sort(Jbb, Jnb); _median_sort(Jab, Jcp);
16951
 
            _median_sort(Jpb, Jcp); _median_sort(Jpb, Jab); _median_sort(Jpc, Jac); _median_sort(Jnp, Jac);
16952
 
            _median_sort(Jnp, Jpc); _median_sort(Jcc, Jbn); _median_sort(Jap, Jbn); _median_sort(Jap, Jcc);
16953
 
            _median_sort(Jnc, Jpn); _median_sort(Jbc, Jpn); _median_sort(Jbc, Jnc); _median_sort(Jba, Jna);
16954
 
            _median_sort(Jcn, Jna); _median_sort(Jcn, Jba); _median_sort(Jpa, Jaa); _median_sort(Jnn, Jaa);
16955
 
            _median_sort(Jnn, Jpa); _median_sort(Jan, Jca); _median_sort(Jnp, Jcn); _median_sort(Jap, Jnn);
16956
 
            _median_sort(Jbb, Jnn); _median_sort(Jbb, Jap); _median_sort(Jbc, Jan); _median_sort(Jpb, Jan);
16957
 
            _median_sort(Jpb, Jbc); _median_sort(Jpc, Jba); _median_sort(Jcb, Jba); _median_sort(Jcb, Jpc);
16958
 
            _median_sort(Jcc, Jpa); _median_sort(Jnb, Jpa); _median_sort(Jnb, Jcc); _median_sort(Jnc, Jca);
16959
 
            _median_sort(Jab, Jca); _median_sort(Jab, Jnc); _median_sort(Jac, Jna); _median_sort(Jbp, Jna);
16960
 
            _median_sort(Jbp, Jac); _median_sort(Jbn, Jaa); _median_sort(Jpp, Jaa); _median_sort(Jpp, Jbn);
16961
 
            _median_sort(Jcp, Jpn); _median_sort(Jcp, Jan); _median_sort(Jnc, Jpa); _median_sort(Jbn, Jna);
16962
 
            _median_sort(Jcp, Jnc); _median_sort(Jcp, Jbn); _median_sort(Jpb, Jap); _median_sort(Jnb, Jpc);
16963
 
            _median_sort(Jbp, Jcn); _median_sort(Jpc, Jcn); _median_sort(Jap, Jcn); _median_sort(Jab, Jbc);
16964
 
            _median_sort(Jpp, Jcc); _median_sort(Jcp, Jac); _median_sort(Jab, Jpp); _median_sort(Jab, Jcp);
16965
 
            _median_sort(Jcc, Jac); _median_sort(Jbc, Jac); _median_sort(Jpp, Jcp); _median_sort(Jbc, Jcc);
16966
 
            _median_sort(Jpp, Jbc); _median_sort(Jpp, Jcn); _median_sort(Jcc, Jcn); _median_sort(Jcp, Jcn);
16967
 
            _median_sort(Jcp, Jbc); _median_sort(Jcc, Jnn); _median_sort(Jcp, Jcc); _median_sort(Jbc, Jnn);
16968
 
            _median_sort(Jcc, Jba); _median_sort(Jbc, Jba); _median_sort(Jbc, Jcc);
 
23839
            std::memcpy(J,I,25*sizeof(T));
 
23840
            _cimg_median_sort(Jbb, Jpb); _cimg_median_sort(Jnb, Jab); _cimg_median_sort(Jcb, Jab); _cimg_median_sort(Jcb, Jnb);
 
23841
            _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbp, Jcp); _cimg_median_sort(Jbp, Jpp); _cimg_median_sort(Jap, Jbc);
 
23842
            _cimg_median_sort(Jnp, Jbc); _cimg_median_sort(Jnp, Jap); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jpc, Jnc);
 
23843
            _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jbn, Jpn); _cimg_median_sort(Jac, Jpn); _cimg_median_sort(Jac, Jbn);
 
23844
            _cimg_median_sort(Jnn, Jan); _cimg_median_sort(Jcn, Jan); _cimg_median_sort(Jcn, Jnn); _cimg_median_sort(Jpa, Jca);
 
23845
            _cimg_median_sort(Jba, Jca); _cimg_median_sort(Jba, Jpa); _cimg_median_sort(Jna, Jaa); _cimg_median_sort(Jcb, Jbp);
 
23846
            _cimg_median_sort(Jnb, Jpp); _cimg_median_sort(Jbb, Jpp); _cimg_median_sort(Jbb, Jnb); _cimg_median_sort(Jab, Jcp);
 
23847
            _cimg_median_sort(Jpb, Jcp); _cimg_median_sort(Jpb, Jab); _cimg_median_sort(Jpc, Jac); _cimg_median_sort(Jnp, Jac);
 
23848
            _cimg_median_sort(Jnp, Jpc); _cimg_median_sort(Jcc, Jbn); _cimg_median_sort(Jap, Jbn); _cimg_median_sort(Jap, Jcc);
 
23849
            _cimg_median_sort(Jnc, Jpn); _cimg_median_sort(Jbc, Jpn); _cimg_median_sort(Jbc, Jnc); _cimg_median_sort(Jba, Jna);
 
23850
            _cimg_median_sort(Jcn, Jna); _cimg_median_sort(Jcn, Jba); _cimg_median_sort(Jpa, Jaa); _cimg_median_sort(Jnn, Jaa);
 
23851
            _cimg_median_sort(Jnn, Jpa); _cimg_median_sort(Jan, Jca); _cimg_median_sort(Jnp, Jcn); _cimg_median_sort(Jap, Jnn);
 
23852
            _cimg_median_sort(Jbb, Jnn); _cimg_median_sort(Jbb, Jap); _cimg_median_sort(Jbc, Jan); _cimg_median_sort(Jpb, Jan);
 
23853
            _cimg_median_sort(Jpb, Jbc); _cimg_median_sort(Jpc, Jba); _cimg_median_sort(Jcb, Jba); _cimg_median_sort(Jcb, Jpc);
 
23854
            _cimg_median_sort(Jcc, Jpa); _cimg_median_sort(Jnb, Jpa); _cimg_median_sort(Jnb, Jcc); _cimg_median_sort(Jnc, Jca);
 
23855
            _cimg_median_sort(Jab, Jca); _cimg_median_sort(Jab, Jnc); _cimg_median_sort(Jac, Jna); _cimg_median_sort(Jbp, Jna);
 
23856
            _cimg_median_sort(Jbp, Jac); _cimg_median_sort(Jbn, Jaa); _cimg_median_sort(Jpp, Jaa); _cimg_median_sort(Jpp, Jbn);
 
23857
            _cimg_median_sort(Jcp, Jpn); _cimg_median_sort(Jcp, Jan); _cimg_median_sort(Jnc, Jpa); _cimg_median_sort(Jbn, Jna);
 
23858
            _cimg_median_sort(Jcp, Jnc); _cimg_median_sort(Jcp, Jbn); _cimg_median_sort(Jpb, Jap); _cimg_median_sort(Jnb, Jpc);
 
23859
            _cimg_median_sort(Jbp, Jcn); _cimg_median_sort(Jpc, Jcn); _cimg_median_sort(Jap, Jcn); _cimg_median_sort(Jab, Jbc);
 
23860
            _cimg_median_sort(Jpp, Jcc); _cimg_median_sort(Jcp, Jac); _cimg_median_sort(Jab, Jpp); _cimg_median_sort(Jab, Jcp);
 
23861
            _cimg_median_sort(Jcc, Jac); _cimg_median_sort(Jbc, Jac); _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbc, Jcc);
 
23862
            _cimg_median_sort(Jpp, Jbc); _cimg_median_sort(Jpp, Jcn); _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcp, Jcn);
 
23863
            _cimg_median_sort(Jcp, Jbc); _cimg_median_sort(Jcc, Jnn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jbc, Jnn);
 
23864
            _cimg_median_sort(Jcc, Jba); _cimg_median_sort(Jbc, Jba); _cimg_median_sort(Jbc, Jcc);
16969
23865
            res(x,y,0,k) = Jcc;
16970
23866
          }
16971
23867
        } break;
16972
23868
        default: {
16973
23869
          CImg<T> vois;
16974
23870
          cimg_forXYV(*this,x,y,k) {
16975
 
            vois = get_crop(x-hl,y-hl,0,k,x+hr,y+hr,0,k);
 
23871
            const int
 
23872
              x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,
 
23873
              nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,
 
23874
              nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1;
 
23875
            vois = get_crop(nx0,ny0,0,k,nx1,ny1,0,k);
16976
23876
            res(x,y,0,k) = vois.median();
16977
23877
          }
16978
23878
        } break;
 
23879
        } else switch (n) { // 1D median filter
 
23880
        case 2: {
 
23881
          T I[4] = { 0 };
 
23882
          cimg_forV(*this,k) cimg_for2x2(*this,x,y,0,k,I) res(x,0,0,k) = (T)(0.5f*(I[0]+I[1]));
 
23883
        } break;
 
23884
        case 3: {
 
23885
          T I[9] = { 0 };
 
23886
          cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
 
23887
            res(x,0,0,k) = I[3]<I[4]?
 
23888
              (I[4]<I[5]?I[4]:
 
23889
               (I[3]<I[5]?I[5]:I[3])):
 
23890
              (I[3]<I[5]?I[3]:
 
23891
               (I[4]<I[5]?I[5]:I[4]));
 
23892
          }
 
23893
        } break;
 
23894
        default: {
 
23895
          CImg<T> vois;
 
23896
          cimg_forXV(*this,x,k) {
 
23897
            const int
 
23898
              x0 = x - hl, x1 = x + hr,
 
23899
              nx0 = x0<0?0:x0, nx1 = x1>=dimx()?dimx()-1:x1;
 
23900
            vois = get_crop(nx0,0,0,k,nx1,0,0,k);
 
23901
            res(x,0,0,k) = vois.median();
 
23902
          }
 
23903
        } break;
16979
23904
        }
16980
23905
      }
16981
23906
      return res;
16982
23907
    }
16983
23908
 
16984
 
    //! Apply a median filter
16985
 
    CImg& blur_median(const unsigned int n=3) {
16986
 
      return get_blur_median(n).swap(*this);
16987
 
    }
16988
 
 
16989
 
    //! Sharpen image using anisotropic shock filters
16990
 
    CImg& sharpen(const float amplitude=50.0f, const float edge=1.0f, const float alpha=0.0f, const float sigma=0.0f) {
 
23909
    //! Apply a median filter (in-place).
 
23910
    CImg<T>& blur_median(const unsigned int n=3) {
 
23911
      return get_blur_median(n).transfer_to(*this);
 
23912
    }
 
23913
 
 
23914
    //! Sharpen image using anisotropic shock filters.
 
23915
    CImg<T> get_sharpen(const float amplitude=50.0f, const float edge=1.0f, const float alpha=0.0f, const float sigma=0.0f) const {
 
23916
      return (+*this).sharpen(amplitude,edge,alpha,sigma);
 
23917
    }
 
23918
 
 
23919
    //! Sharpen image using anisotropic shock filters (in-place).
 
23920
    CImg<T>& sharpen(const float amplitude=50.0f, const float edge=1.0f, const float alpha=0.0f, const float sigma=0.0f) {
16991
23921
      if (is_empty()) return *this;
16992
23922
      const bool threed = (depth>1);
16993
23923
      const float nedge = 0.5f*edge;
16994
 
      typedef typename cimg::largest<T,float>::type ftype;
16995
 
      CImg<ftype> val, vec, veloc(width,height,depth,dim);
 
23924
      CImg<Tfloat> val, vec, veloc(width,height,depth,dim);
16996
23925
 
16997
23926
      if (threed) {
16998
 
        CImg<ftype> G = (alpha>0?get_blur(alpha).get_structure_tensorXYZ():get_structure_tensorXYZ());
 
23927
        CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensorXYZ():get_structure_tensorXYZ());
16999
23928
        if (sigma>0) G.blur(sigma);
17000
23929
        CImg_3x3x3(I,float);
17001
23930
        cimg_forXYZ(G,x,y,z) {
17028
23957
          veloc(x,y,z,k) = -amp*cimg::sign(itt)*cimg::abs(it);
17029
23958
        }
17030
23959
      } else {
17031
 
        CImg<ftype> G = (alpha>0?get_blur(alpha).get_structure_tensorXY():get_structure_tensorXY());
 
23960
        CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensorXY():get_structure_tensorXY());
17032
23961
        if (sigma>0) G.blur(sigma);
17033
23962
        CImg_3x3(I,float);
17034
23963
        cimg_forXY(G,x,y) {
17054
23983
          veloc(x,y,k) = -amp*cimg::sign(itt)*cimg::abs(it);
17055
23984
        }
17056
23985
      }
17057
 
      const CImgStats stats(veloc);
17058
 
      const float vmax = (float)cimg::max(cimg::abs(stats.min),cimg::abs(stats.max));
 
23986
      float m, M = (float)veloc.maxmin(m);
 
23987
      const float vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
17059
23988
      if (vmax!=0) { veloc*=amplitude/vmax; (*this)+=veloc; }
17060
23989
      return *this;
17061
23990
    }
17062
23991
 
17063
 
    CImg get_sharpen(const float amplitude=50.0f, const float edge=1.0f, const float alpha=0.0f, const float sigma=0.0f) const {
17064
 
      return (+*this).sharpen(amplitude,edge,alpha,sigma);
17065
 
    }
17066
 
 
17067
 
    //! Estimate displacement field between instance image and given reference image.
17068
 
    CImg<typename cimg::largest<T,float>::type> get_displacement_field(const CImg<T>& reference,
17069
 
                                                                       const float smooth=0.1f, const float precision=1e-6f,
17070
 
                                                                       const unsigned int nb_scale=0,
17071
 
                                                                       const unsigned int itermax=10000) const {
17072
 
 
17073
 
      typedef typename cimg::largest<T,float>::type ftype;
17074
 
      if (is_empty() || !reference) return *this;
17075
 
      if (!is_sameXYZ(reference))
17076
 
        throw CImgArgumentException("CImg<%s>::get_displacement_field() : Instance image (%u,%u,%u,%u,%p) and reference image (%u,%u,%u,%u,%p) "
17077
 
                                    "must have same dimensions",
17078
 
                                    pixel_type(),width,height,depth,dim,data,
17079
 
                                    reference.width,reference.height,reference.depth,reference.dim,reference.data);
17080
 
      const bool threed = depth>1;
17081
 
      CImg<ftype> u(width,height,depth,threed?3:2,0);
17082
 
 
17083
 
      const unsigned int nbs = nb_scale>0?nb_scale:(unsigned int)(2*std::log((double)(cimg::max(width,height,depth))));
17084
 
      for (int scale=nbs-1; scale>=0; --scale) {
17085
 
        const float fact = (float)std::pow(1.5f,-(float)scale);
17086
 
        const unsigned int
17087
 
          tnw = (unsigned int)(width*fact),  nw = tnw?tnw:1,
17088
 
          tnh = (unsigned int)(height*fact), nh = tnh?tnh:1,
17089
 
          tnd = (unsigned int)(depth*fact),  nd = tnd?tnd:1;
17090
 
        CImg<ftype>
17091
 
          I1 = get_resize(nw,nh,nd,1,3),
17092
 
          I2 = reference.get_resize(nw,nh,nd,1,3);
17093
 
        I1.norm_pointwise(1);
17094
 
        I2.norm_pointwise(2);
17095
 
        const CImgStats st1(I1,false), st2(I2,false);
17096
 
        const float M = cimg::max(cimg::abs(st1.min),cimg::abs(st1.max),cimg::abs(st2.min),cimg::abs(st2.max));
17097
 
        I1/=M; I2/=M;
17098
 
        u*=1.5;
17099
 
        u.resize(nw,nh,nd,threed?3:2,3);
17100
 
        float dt = 100, E = cimg::type<float>::max(), nprecision = nw*nh*nd*precision;
17101
 
        const CImgList<ftype> dI = threed?I2.get_gradientXYZ():I2.get_gradientXY();
17102
 
 
17103
 
        for (unsigned int iter=0; iter<itermax; ++iter) {
17104
 
          const float Eold = E;
17105
 
          E = 0;
17106
 
          if (threed)
17107
 
            cimg_for3XYZ(u,x,y,z) {
17108
 
            const ftype
17109
 
              X = x + u(x,y,z,0),
17110
 
              Y = y + u(x,y,z,1),
17111
 
              Z = z + u(x,y,z,2),
17112
 
              deltaI = (ftype)(I2.linear_pix3d(X,Y,Z) - I1(x,y,z));
17113
 
            float tmpf = 0;
17114
 
            cimg_forV(u,k) {
17115
 
              const ftype
17116
 
                ux  = 0.5f*(u(_nx,y,z,k) - u(_px,y,z,k)),
17117
 
                uy  = 0.5f*(u(x,_ny,z,k) - u(x,_py,z,k)),
17118
 
                uz  = 0.5f*(u(x,y,_nz,k) - u(x,y,_pz,k));
17119
 
              u(x,y,z,k) = (ftype)( u(x,y,z,k) +
17120
 
                                    dt*(-deltaI*dI[k].linear_pix3d(X,Y,Z) +
17121
 
                                        smooth* ( u(_nx,y,z,k) + u(_px,y,z,k) + u(x,_ny,z,k) + u(x,_py,z,k) + u(x,y,_nz,k) + u(x,y,_pz,k)))
17122
 
                                    )/(1 + 6*smooth*dt);
17123
 
              tmpf += (float)(ux*ux + uy*uy + uz*uz);
17124
 
            }
17125
 
            E += deltaI*deltaI + smooth * tmpf;
17126
 
          }
17127
 
          else cimg_for3XY(u,x,y) {
17128
 
            const ftype
17129
 
              X = x + u(x,y,0),
17130
 
              Y = y + u(x,y,1),
17131
 
              deltaI = (ftype)(I2.linear_pix2d(X,Y) - I1(x,y));
17132
 
            float tmpf = 0;
17133
 
            cimg_forV(u,k) {
17134
 
              const ftype
17135
 
                ux  = 0.5f*(u(_nx,y,k) - u(_px,y,k)),
17136
 
                uy  = 0.5f*(u(x,_ny,k) - u(x,_py,k));
17137
 
              u(x,y,k) = (ftype)( u(x,y,k) +
17138
 
                                  dt*(-deltaI*dI[k].linear_pix2d(X,Y) + smooth* ( u(_nx,y,k) + u(_px,y,k) + u(x,_ny,k) + u(x,_py,k) ))
17139
 
                                  )/(1 + 4*smooth*dt);
17140
 
              tmpf += (float)(ux*ux + uy*uy);
17141
 
            }
17142
 
            E += deltaI*deltaI + smooth * tmpf;
17143
 
          }
17144
 
          if (cimg::abs(Eold-E)<nprecision) break;
17145
 
          if (Eold<E) { dt/=2; if (dt<0.1) break; }
17146
 
        }
17147
 
      }
17148
 
      return u;
17149
 
    }
17150
 
 
17151
 
    //! Estimate displacement field between instance image and given reference image.
17152
 
    CImg& displacement_field(const CImg<T>& reference, const float smooth=0.1f, const float precision=1e-6f,
17153
 
                             const unsigned int nb_scale=0, const unsigned int itermax=10000) {
17154
 
      return assign(get_displacement_field(reference,smooth,precision,nb_scale,itermax));
 
23992
    //! Compute the Haar multiscale wavelet transform (monodimensional version).
 
23993
    /**
 
23994
       \param axis Axis considered for the transform.
 
23995
       \param invert Set inverse of direct transform.
 
23996
       \param nb_scales Number of scales used for the transform.
 
23997
    **/
 
23998
    CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const {
 
23999
      if (is_empty() || !nb_scales) return *this;
 
24000
      CImg<Tfloat> res;
 
24001
 
 
24002
      if (nb_scales==1) {
 
24003
        switch (cimg::uncase(axis)) { // Single scale transform
 
24004
        case 'x': {
 
24005
          const unsigned int w = width/2;
 
24006
          if (w) {
 
24007
            if (w%2) throw CImgInstanceException("CImg<%s>::haar() : Sub-image width = %u is not even at a particular scale (=%u).",pixel_type(),w);
 
24008
            res.assign(width,height,depth,dim);
 
24009
            if (invert) cimg_forYZV(*this,y,z,v) { // Inverse transform along X
 
24010
              for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
 
24011
                const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(xw,y,z,v);
 
24012
                res(x2++,y,z,v) = val0 - val1;
 
24013
                res(x2++,y,z,v) = val0 + val1;
 
24014
              }
 
24015
            } else cimg_forYZV(*this,y,z,v) { // Direct transform along X
 
24016
              for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
 
24017
                const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,v), val1 = (Tfloat)(*this)(x2++,y,z,v);
 
24018
                res(x,y,z,v) = (val0 + val1)/2;
 
24019
                res(xw,y,z,v) = (val1 - val0)/2;
 
24020
              }
 
24021
            }
 
24022
          } else return *this;
 
24023
        } break;
 
24024
        case 'y': {
 
24025
          const unsigned int h = height/2;
 
24026
          if (h) {
 
24027
            if (h%2) throw CImgInstanceException("CImg<%s>::haar() : Sub-image height = %u is not even at a particular scale.",pixel_type(),h);
 
24028
            res.assign(width,height,depth,dim);
 
24029
            if (invert) cimg_forXZV(*this,x,z,v) { // Inverse transform along Y
 
24030
              for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) {
 
24031
                const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,yh,z,v);
 
24032
                res(x,y2++,z,v) = val0 - val1;
 
24033
                res(x,y2++,z,v) = val0 + val1;
 
24034
              }
 
24035
            } else cimg_forXZV(*this,x,z,v) {
 
24036
              for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) { // Direct transform along Y
 
24037
                const Tfloat val0 = (Tfloat)(*this)(x,y2++,z,v), val1 = (Tfloat)(*this)(x,y2++,z,v);
 
24038
                res(x,y,z,v) = (val0 + val1)/2;
 
24039
                res(x,yh,z,v) = (val1 - val0)/2;
 
24040
              }
 
24041
            }
 
24042
          } else return *this;
 
24043
        } break;
 
24044
        case 'z': {
 
24045
          const unsigned int d = depth/2;
 
24046
          if (d) {
 
24047
            if (d%2) throw CImgInstanceException("CImg<%s>::haar() : Sub-image depth = %u is not even at a particular scale.",pixel_type(),d);
 
24048
            res.assign(width,height,depth,dim);
 
24049
            if (invert) cimg_forXYV(*this,x,y,v) { // Inverse transform along Z
 
24050
              for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) {
 
24051
                const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,y,zd,v);
 
24052
                res(x,y,z2++,v) = val0 - val1;
 
24053
                res(x,y,z2++,v) = val0 + val1;
 
24054
              }
 
24055
            } else cimg_forXYV(*this,x,y,v) {
 
24056
              for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) { // Direct transform along Z
 
24057
                const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,v), val1 = (Tfloat)(*this)(x,y,z2++,v);
 
24058
                res(x,y,z,v) = (val0 + val1)/2;
 
24059
                res(x,y,zd,v) = (val1 - val0)/2;
 
24060
              }
 
24061
            }
 
24062
          } else return *this;
 
24063
        } break;
 
24064
        default: throw CImgArgumentException("CImg<%s>::haar() : Unknown axis '%c'.",pixel_type(),axis); break;
 
24065
        }
 
24066
      } else { // Multi-scale version
 
24067
        if (invert) {
 
24068
          res.assign(*this);
 
24069
          switch (cimg::uncase(axis)) {
 
24070
          case 'x': {
 
24071
            unsigned int w = width;
 
24072
            for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
 
24073
            for (w=w?w:1; w<=width; w*=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',true,1),0);
 
24074
          } break;
 
24075
          case 'y': {
 
24076
            unsigned int h = width;
 
24077
            for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
 
24078
            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),0);
 
24079
          } break;
 
24080
          case 'z': {
 
24081
            unsigned int d = depth;
 
24082
            for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
 
24083
            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),0);
 
24084
          } break;
 
24085
          default: throw CImgArgumentException("CImg<%s>::haar() : Unknown axis '%c'.",pixel_type(),axis); break;
 
24086
          }
 
24087
        } else { // Direct transform
 
24088
          res = get_haar(axis,false,1);
 
24089
          switch (cimg::uncase(axis)) {
 
24090
          case 'x': {
 
24091
            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),0);
 
24092
          } break;
 
24093
          case 'y': {
 
24094
            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),0);
 
24095
          } break;
 
24096
          case 'z': {
 
24097
            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),0);
 
24098
          } break;
 
24099
          default: throw CImgArgumentException("CImg<%s>::haar() : Unknown axis '%c'.",pixel_type(),axis); break;
 
24100
          }
 
24101
        }
 
24102
      }
 
24103
      return res;
 
24104
    }
 
24105
 
 
24106
    //! Compute the Haar multiscale wavelet transform (monodimensional version) (in-place).
 
24107
    CImg<T>& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) {
 
24108
      return get_haar(axis,invert,nb_scales).transfer_to(*this);
 
24109
    }
 
24110
 
 
24111
    //! Compute the Haar multiscale wavelet transform.
 
24112
    /**
 
24113
       \param invert Set inverse of direct transform.
 
24114
       \param nb_scales Number of scales used for the transform.
 
24115
    **/
 
24116
    CImg<Tfloat> get_haar(const bool invert=false, const unsigned int nb_scales=1) const {
 
24117
      CImg<Tfloat> res;
 
24118
 
 
24119
      if (nb_scales==1) { // Single scale transform
 
24120
        if (width>1) get_haar('x',invert,1).transfer_to(res);
 
24121
        if (height>1) { if (res) res.get_haar('y',invert,1).transfer_to(res); else get_haar('y',invert,1).transfer_to(res); }
 
24122
        if (depth>1) { if (res) res.get_haar('z',invert,1).transfer_to(res); else get_haar('z',invert,1).transfer_to(res); }
 
24123
        if (res) return res;
 
24124
      } else { // Multi-scale transform
 
24125
        if (invert) { // Inverse transform
 
24126
          res.assign(*this);
 
24127
          if (width>1) {
 
24128
            if (height>1) {
 
24129
              if (depth>1) {
 
24130
                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; }
 
24131
                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)
 
24132
                  res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).get_haar(true,1),0,0,0);
 
24133
              } else {
 
24134
                unsigned int w = width, h = height; for (unsigned int s=1; w && h && s<nb_scales; ++s) { w/=2; h/=2; }
 
24135
                for (w=w?w:1, h=h?h:1; w<=width && h<=height; w*=2, h*=2)
 
24136
                  res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).get_haar(true,1),0,0,0);
 
24137
              }
 
24138
            } else {
 
24139
              if (depth>1) {
 
24140
                unsigned int w = width, d = depth; for (unsigned int s=1; w && d && s<nb_scales; ++s) { w/=2; d/=2; }
 
24141
                for (w=w?w:1, d=d?d:1; w<=width && d<=depth; w*=2, d*=2)
 
24142
                  res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).get_haar(true,1),0,0,0);
 
24143
              } else {
 
24144
                unsigned int w = width; for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
 
24145
                for (w=w?w:1; w<=width; w*=2)
 
24146
                  res.draw_image(res.get_crop(0,0,0,w-1,0,0).get_haar(true,1),0,0,0);
 
24147
              }
 
24148
            }
 
24149
          } else {
 
24150
            if (height>1) {
 
24151
              if (depth>1) {
 
24152
                unsigned int h = height, d = depth; for (unsigned int s=1; h && d && s<nb_scales; ++s) { h/=2; d/=2; }
 
24153
                for (h=h?h:1, d=d?d:1; h<=height && d<=depth; h*=2, d*=2)
 
24154
                  res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).get_haar(true,1),0,0,0);
 
24155
              } else {
 
24156
                unsigned int h = height; for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
 
24157
                for (h=h?h:1; h<=height; h*=2)
 
24158
                  res.draw_image(res.get_crop(0,0,0,0,h-1,0).get_haar(true,1),0,0,0);
 
24159
              }
 
24160
            } else {
 
24161
              if (depth>1) {
 
24162
                unsigned int d = depth; for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
 
24163
                for (d=d?d:1; d<=depth; d*=2)
 
24164
                  res.draw_image(res.get_crop(0,0,0,0,0,d-1).get_haar(true,1),0,0,0);
 
24165
              } else return *this;
 
24166
            }
 
24167
          }
 
24168
        } else { // Direct transform
 
24169
          res = get_haar(false,1);
 
24170
          if (width>1) {
 
24171
            if (height>1) {
 
24172
              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)
 
24173
                res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).haar(false,1),0,0,0);
 
24174
              else for (unsigned int s=1, w=width/2, h=height/2; w && h && s<nb_scales; ++s, w/=2, h/=2)
 
24175
                res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).haar(false,1),0,0,0);
 
24176
            } else {
 
24177
              if (depth>1) for (unsigned int s=1, w=width/2, d=depth/2; w && d && s<nb_scales; ++s, w/=2, d/=2)
 
24178
                res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).haar(false,1),0,0,0);
 
24179
              else for (unsigned int s=1, w=width/2; w && s<nb_scales; ++s, w/=2)
 
24180
                res.draw_image(res.get_crop(0,0,0,w-1,0,0).haar(false,1),0,0,0);
 
24181
            }
 
24182
          } else {
 
24183
            if (height>1) {
 
24184
              if (depth>1) for (unsigned int s=1, h=height/2, d=depth/2; h && d && s<nb_scales; ++s, h/=2, d/=2)
 
24185
                res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).haar(false,1),0,0,0);
 
24186
              else for (unsigned int s=1, h=height/2; h && s<nb_scales; ++s, h/=2)
 
24187
                res.draw_image(res.get_crop(0,0,0,0,h-1,0).haar(false,1),0,0,0);
 
24188
            } else {
 
24189
              if (depth>1) for (unsigned int s=1, d=depth/2; d && s<nb_scales; ++s, d/=2)
 
24190
                res.draw_image(res.get_crop(0,0,0,0,0,d-1).haar(false,1),0,0,0);
 
24191
              else return *this;
 
24192
            }
 
24193
          }
 
24194
        }
 
24195
        return res;
 
24196
      }
 
24197
      return *this;
 
24198
    }
 
24199
 
 
24200
    //! Compute the Haar multiscale wavelet transform (in-place).
 
24201
    CImg<T>& haar(const bool invert=false, const unsigned int nb_scales=1) {
 
24202
      return get_haar(invert,nb_scales).transfer_to(*this);
 
24203
    }
 
24204
 
 
24205
    //! Estimate a displacement field between instance image and given target image.
 
24206
    CImg<Tfloat> get_displacement_field(const CImg<T>& target,
 
24207
                                        const float smoothness=0.1f, const float precision=0.1f,
 
24208
                                        const unsigned int nb_scales=0, const unsigned int itermax=10000) const {
 
24209
      if (is_empty() || !target) return *this;
 
24210
      if (!is_sameXYZV(target))
 
24211
        throw CImgArgumentException("CImg<%s>::displacement_field() : Instance image (%u,%u,%u,%u,%p) and target image (%u,%u,%u,%u,%p) "
 
24212
                                    "have different size.",pixel_type(),width,height,depth,dim,data,
 
24213
                                    target.width,target.height,target.depth,target.dim,target.data);
 
24214
      if (smoothness<0)
 
24215
        throw CImgArgumentException("CImg<%s>::displacement_field() : Smoothness parameter %g is negative.",pixel_type(),smoothness);
 
24216
      if (precision<0)
 
24217
        throw CImgArgumentException("CImg<%s>::displacement_field() : Precision parameter %g is negative.",pixel_type(),precision);
 
24218
 
 
24219
      const unsigned int nscales = nb_scales>0?nb_scales:(unsigned int)(2*std::log((double)(cimg::max(width,height,depth))));
 
24220
      Tfloat m1, M1 = maxmin(m1), m2, M2 = target.maxmin(m2);
 
24221
      const Tfloat factor = cimg::max(cimg::abs(m1),cimg::abs(M1),cimg::abs(m2),cimg::abs(M2));
 
24222
      CImg<Tfloat> U0;
 
24223
      const bool threed = (depth>1);
 
24224
 
 
24225
      // Begin multi-scale motion estimation
 
24226
      for (int scale=(int)nscales-1; scale>=0; --scale) {
 
24227
        const float sfactor = (float)std::pow(1.5f,(float)scale), sprecision = (float)(precision/std::pow(2.25,1+scale));
 
24228
        const int
 
24229
          sw = (int)(width/sfactor), sh = (int)(height/sfactor), sd = (int)(depth/sfactor),
 
24230
          swidth = sw?sw:1, sheight = sh?sh:1, sdepth = sd?sd:1;
 
24231
        CImg<Tfloat>
 
24232
          I1 = get_resize(swidth,sheight,sdepth,-100,2),
 
24233
          I2 = target.get_resize(swidth,sheight,sdepth,-100,2);
 
24234
        I1/=factor; I2/=factor;
 
24235
        CImg<Tfloat> U;
 
24236
        if (U0) U = (U0*=1.5f).get_resize(I1.dimx(),I1.dimy(),I1.dimz(),-100,3);
 
24237
        else U.assign(I1.dimx(),I1.dimy(),I1.dimz(),threed?3:2,0);
 
24238
 
 
24239
        // Begin single-scale motion estimation
 
24240
        CImg<Tfloat> veloc(U);
 
24241
        float dt = 2.0f, Energy = cimg::type<float>::max();
 
24242
        const CImgList<Tfloat> dI = threed?I2.get_gradientXYZ():I2.get_gradientXY();
 
24243
        for (unsigned int iter=0; iter<itermax; iter++) {
 
24244
          veloc.fill(0);
 
24245
          float nEnergy = 0;
 
24246
          if (threed) {
 
24247
            CImg_3x3x3(I,Tfloat);
 
24248
            cimg_for3XYZ(U,x,y,z) {
 
24249
              const float X = x + U(x,y,z,0), Y = y + U(x,y,z,1), Z = z + U(x,y,z,2);
 
24250
              cimg_forV(U,k) {
 
24251
                const float
 
24252
                  Ux  = 0.5f*(U(_n1x,y,z,k) - U(_p1x,y,z,k)),
 
24253
                  Uy  = 0.5f*(U(x,_n1y,z,k) - U(x,_p1y,z,k)),
 
24254
                  Uz  = 0.5f*(U(x,y,_n1z,k) - U(x,y,_p1z,k)),
 
24255
                  Uxx = U(_n1x,y,z,k) + U(_p1x,y,z,k) - 2*U(x,y,z,k),
 
24256
                  Uyy = U(x,_n1y,z,k) + U(x,_p1y,z,k) - 2*U(x,y,z,k),
 
24257
                  Uzz = U(x,y,_n1z,k) + U(x,y,_n1z,k) - 2*U(x,y,z,k);
 
24258
                nEnergy += smoothness*(Ux*Ux + Uy*Uy + Uz*Uz);
 
24259
                float deltaIgrad = 0;
 
24260
                cimg_forV(I1,i) {
 
24261
                  const float deltaIi = (float)(I2.linear_at3(X,Y,Z,i) - I1(x,y,z,i));
 
24262
                  nEnergy += deltaIi*deltaIi/2;
 
24263
                  deltaIgrad+=-deltaIi*dI[k].linear_at3(X,Y,Z,i);
 
24264
                }
 
24265
                veloc(x,y,z,k) = deltaIgrad + smoothness*(Uxx + Uyy + Uzz);
 
24266
              }
 
24267
            }
 
24268
          } else {
 
24269
            CImg_3x3(I,Tfloat);
 
24270
            cimg_for3XY(U,x,y) {
 
24271
              const float X = x + U(x,y,0), Y = y + U(x,y,1);
 
24272
              cimg_forV(U,k) {
 
24273
                const float
 
24274
                  Ux  = 0.5f*(U(_n1x,y,k) - U(_p1x,y,k)),
 
24275
                  Uy  = 0.5f*(U(x,_n1y,k) - U(x,_p1y,k)),
 
24276
                  Uxx = U(_n1x,y,k) + U(_p1x,y,k) - 2*U(x,y,k),
 
24277
                  Uyy = U(x,_n1y,k) + U(x,_p1y,k) - 2*U(x,y,k);
 
24278
                nEnergy += smoothness*(Ux*Ux + Uy*Uy);
 
24279
                float deltaIgrad = 0;
 
24280
                cimg_forV(I1,i) {
 
24281
                  const float deltaIi = (float)(I2.linear_at2(X,Y,i) - I1(x,y,i));
 
24282
                  nEnergy += deltaIi*deltaIi/2;
 
24283
                  deltaIgrad+=-deltaIi*dI[k].linear_at2(X,Y,i);
 
24284
                }
 
24285
                veloc(x,y,k) = deltaIgrad + smoothness*(Uxx + Uyy);
 
24286
              }
 
24287
            }
 
24288
          }
 
24289
          const float vmax = cimg::max(cimg::abs(veloc.min()), cimg::abs(veloc.max()));
 
24290
          U+=(veloc*=dt/vmax);
 
24291
          if (cimg::abs(nEnergy-Energy)<sprecision) break;
 
24292
          if (nEnergy<Energy) dt*=0.5f;
 
24293
          Energy = nEnergy;
 
24294
        }
 
24295
        U.transfer_to(U0);
 
24296
      }
 
24297
      return U0;
 
24298
    }
 
24299
 
 
24300
    //! Estimate a displacement field between instance image and given target image (in-place).
 
24301
    CImg<T>& displacement_field(const CImg<T>& target, const float smooth=0.1f, const float precision=0.1f,
 
24302
                                const unsigned int nb_scales=0, const unsigned int itermax=10000) {
 
24303
      return get_displacement_field(target,smooth,precision,nb_scales,itermax).transfer_to(*this);
17155
24304
    }
17156
24305
 
17157
24306
    //@}
17161
24310
    //@{
17162
24311
    //-----------------------------
17163
24312
 
17164
 
    //! Return a vector with specified coefficients
17165
 
    static CImg vector(const T& a0) {
17166
 
      CImg<T> r(1,1); r[0] = a0;
 
24313
    //! Return a vector with specified coefficients.
 
24314
    static CImg<T> vector(const T& a0) {
 
24315
      static CImg<T> r(1,1); r[0] = a0;
17167
24316
      return r;
17168
24317
    }
17169
24318
 
17170
 
    //! Return a vector with specified coefficients
17171
 
    static CImg vector(const T& a0, const T& a1) {
17172
 
      CImg<T> r(1,2); T *ptr = r.data;
 
24319
    //! Return a vector with specified coefficients.
 
24320
    static CImg<T> vector(const T& a0, const T& a1) {
 
24321
      static CImg<T> r(1,2); T *ptr = r.data;
17173
24322
      *(ptr++) = a0; *(ptr++) = a1;
17174
24323
      return r;
17175
24324
    }
17176
24325
 
17177
 
    //! Return a vector with specified coefficients
17178
 
    static CImg vector(const T& a0, const T& a1, const T& a2) {
17179
 
      CImg<T> r(1,3); T *ptr = r.data;
 
24326
    //! Return a vector with specified coefficients.
 
24327
    static CImg<T> vector(const T& a0, const T& a1, const T& a2) {
 
24328
      static CImg<T> r(1,3); T *ptr = r.data;
17180
24329
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
17181
24330
      return r;
17182
24331
    }
17183
24332
 
17184
 
    //! Return a vector with specified coefficients
17185
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3) {
17186
 
      CImg<T> r(1,4); T *ptr = r.data;
 
24333
    //! Return a vector with specified coefficients.
 
24334
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3) {
 
24335
      static CImg<T> r(1,4); T *ptr = r.data;
17187
24336
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
17188
24337
      return r;
17189
24338
    }
17190
24339
 
17191
 
    //! Return a vector with specified coefficients
17192
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
17193
 
      CImg<T> r(1,5); T *ptr = r.data;
 
24340
    //! Return a vector with specified coefficients.
 
24341
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
 
24342
      static CImg<T> r(1,5); T *ptr = r.data;
17194
24343
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
17195
24344
      return r;
17196
24345
    }
17197
24346
 
17198
 
    //! Return a vector with specified coefficients
17199
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {
17200
 
      CImg<T> r(1,6); T *ptr = r.data;
 
24347
    //! Return a vector with specified coefficients.
 
24348
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {
 
24349
      static CImg<T> r(1,6); T *ptr = r.data;
17201
24350
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
17202
24351
      return r;
17203
24352
    }
17204
24353
 
17205
 
    //! Return a vector with specified coefficients
17206
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3,
17207
 
                       const T& a4, const T& a5, const T& a6) {
17208
 
      CImg<T> r(1,7); T *ptr = r.data;
17209
 
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6;
17210
 
      return r;
17211
 
    }
17212
 
 
17213
 
    //! Return a vector with specified coefficients
17214
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3,
17215
 
                       const T& a4, const T& a5, const T& a6, const T& a7) {
17216
 
      CImg<T> r(1,8); T *ptr = r.data;
17217
 
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
17218
 
      return r;
17219
 
    }
17220
 
 
17221
 
    //! Return a vector with specified coefficients
17222
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3,
17223
 
                       const T& a4, const T& a5, const T& a6, const T& a7, const T& a8) {
17224
 
      CImg<T> r(1,9); T *ptr = r.data;
17225
 
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 
24354
    //! Return a vector with specified coefficients.
 
24355
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 
24356
                          const T& a4, const T& a5, const T& a6) {
 
24357
      static CImg<T> r(1,7); T *ptr = r.data;
 
24358
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 
24359
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6;
 
24360
      return r;
 
24361
    }
 
24362
 
 
24363
    //! Return a vector with specified coefficients.
 
24364
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 
24365
                          const T& a4, const T& a5, const T& a6, const T& a7) {
 
24366
      static CImg<T> r(1,8); T *ptr = r.data;
 
24367
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 
24368
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 
24369
      return r;
 
24370
    }
 
24371
 
 
24372
    //! Return a vector with specified coefficients.
 
24373
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 
24374
                          const T& a4, const T& a5, const T& a6, const T& a7,
 
24375
                          const T& a8) {
 
24376
      static CImg<T> r(1,9); T *ptr = r.data;
 
24377
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 
24378
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
17226
24379
      *(ptr++) = a8;
17227
24380
      return r;
17228
24381
    }
17229
24382
 
17230
 
    //! Return a vector with specified coefficients
17231
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3,
17232
 
                       const T& a4, const T& a5, const T& a6, const T& a7,
17233
 
                       const T& a8, const T& a9) {
17234
 
      CImg<T> r(1,10); T *ptr = r.data;
17235
 
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 
24383
    //! Return a vector with specified coefficients.
 
24384
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 
24385
                          const T& a4, const T& a5, const T& a6, const T& a7,
 
24386
                          const T& a8, const T& a9) {
 
24387
      static CImg<T> r(1,10); T *ptr = r.data;
 
24388
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 
24389
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
17236
24390
      *(ptr++) = a8; *(ptr++) = a9;
17237
24391
      return r;
17238
24392
    }
17239
24393
 
17240
 
    //! Return a vector with specified coefficients
17241
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3,
17242
 
                       const T& a4, const T& a5, const T& a6, const T& a7,
17243
 
                       const T& a8, const T& a9, const T& a10) {
17244
 
      CImg<T> r(1,11); T *ptr = r.data;
17245
 
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 
24394
    //! Return a vector with specified coefficients.
 
24395
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 
24396
                          const T& a4, const T& a5, const T& a6, const T& a7,
 
24397
                          const T& a8, const T& a9, const T& a10) {
 
24398
      static CImg<T> r(1,11); T *ptr = r.data;
 
24399
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 
24400
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
17246
24401
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10;
17247
24402
      return r;
17248
24403
    }
17249
24404
 
17250
 
    //! Return a vector with specified coefficients
17251
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3,
17252
 
                       const T& a4, const T& a5, const T& a6, const T& a7,
17253
 
                       const T& a8, const T& a9, const T& a10, const T& a11) {
17254
 
      CImg<T> r(1,12); T *ptr = r.data;
17255
 
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
17256
 
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
17257
 
      return r;
17258
 
    }
17259
 
 
17260
 
    //! Return a vector with specified coefficients
17261
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3,
17262
 
                       const T& a4, const T& a5, const T& a6, const T& a7,
17263
 
                       const T& a8, const T& a9, const T& a10, const T& a11,
17264
 
                       const T& a12) {
17265
 
      CImg<T> r(1,13); T *ptr = r.data;
17266
 
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
17267
 
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12;
17268
 
      return r;
17269
 
    }
17270
 
 
17271
 
    //! Return a vector with specified coefficients
17272
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3,
17273
 
                       const T& a4, const T& a5, const T& a6, const T& a7,
17274
 
                       const T& a8, const T& a9, const T& a10, const T& a11,
17275
 
                       const T& a12, const T& a13) {
17276
 
      CImg<T> r(1,14); T *ptr = r.data;
17277
 
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
17278
 
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13;
17279
 
      return r;
17280
 
    }
17281
 
 
17282
 
    //! Return a vector with specified coefficients
17283
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3,
17284
 
                       const T& a4, const T& a5, const T& a6, const T& a7,
17285
 
                       const T& a8, const T& a9, const T& a10, const T& a11,
17286
 
                       const T& a12, const T& a13, const T& a14) {
17287
 
      CImg<T> r(1,15); T *ptr = r.data;
17288
 
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
17289
 
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
17290
 
      return r;
17291
 
    }
17292
 
 
17293
 
    //! Return a vector with specified coefficients
17294
 
    static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3,
17295
 
                       const T& a4, const T& a5, const T& a6, const T& a7,
17296
 
                       const T& a8, const T& a9, const T& a10, const T& a11,
17297
 
                       const T& a12, const T& a13, const T& a14, const T& a15) {
17298
 
      CImg<T> r(1,16); T *ptr = r.data;
17299
 
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
17300
 
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
17301
 
      return r;
17302
 
    }
17303
 
 
17304
 
    //! Return a vector with specified coefficients
17305
 
    template<int N> static CImg vector(const int a0, const int a1, ...) {
 
24405
    //! Return a vector with specified coefficients.
 
24406
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 
24407
                          const T& a4, const T& a5, const T& a6, const T& a7,
 
24408
                          const T& a8, const T& a9, const T& a10, const T& a11) {
 
24409
      static CImg<T> r(1,12); T *ptr = r.data;
 
24410
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 
24411
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 
24412
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 
24413
      return r;
 
24414
    }
 
24415
 
 
24416
    //! Return a vector with specified coefficients.
 
24417
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 
24418
                          const T& a4, const T& a5, const T& a6, const T& a7,
 
24419
                          const T& a8, const T& a9, const T& a10, const T& a11,
 
24420
                          const T& a12) {
 
24421
      static CImg<T> r(1,13); T *ptr = r.data;
 
24422
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 
24423
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 
24424
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 
24425
      *(ptr++) = a12;
 
24426
      return r;
 
24427
    }
 
24428
 
 
24429
    //! Return a vector with specified coefficients.
 
24430
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 
24431
                          const T& a4, const T& a5, const T& a6, const T& a7,
 
24432
                          const T& a8, const T& a9, const T& a10, const T& a11,
 
24433
                          const T& a12, const T& a13) {
 
24434
      static CImg<T> r(1,14); T *ptr = r.data;
 
24435
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 
24436
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 
24437
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 
24438
      *(ptr++) = a12; *(ptr++) = a13;
 
24439
      return r;
 
24440
    }
 
24441
 
 
24442
    //! Return a vector with specified coefficients.
 
24443
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 
24444
                          const T& a4, const T& a5, const T& a6, const T& a7,
 
24445
                          const T& a8, const T& a9, const T& a10, const T& a11,
 
24446
                          const T& a12, const T& a13, const T& a14) {
 
24447
      static CImg<T> r(1,15); T *ptr = r.data;
 
24448
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 
24449
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 
24450
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 
24451
      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
 
24452
      return r;
 
24453
    }
 
24454
 
 
24455
    //! Return a vector with specified coefficients.
 
24456
    static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
 
24457
                          const T& a4, const T& a5, const T& a6, const T& a7,
 
24458
                          const T& a8, const T& a9, const T& a10, const T& a11,
 
24459
                          const T& a12, const T& a13, const T& a14, const T& a15) {
 
24460
      static CImg<T> r(1,16); T *ptr = r.data;
 
24461
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
 
24462
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
 
24463
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
 
24464
      *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
 
24465
      return r;
 
24466
    }
 
24467
 
 
24468
    //! Return a vector with specified coefficients.
 
24469
    template<int N> static CImg<T> vector(const int a0, const int a1, ...) {
17306
24470
      CImg<T> res(1,N);
17307
24471
      _CImg_stdarg(res,a0,a1,N,int);
17308
24472
      return res;
17309
24473
    }
17310
24474
 
17311
 
    //! Return a vector with specified coefficients
17312
 
    template<int N> static CImg vector(const double a0, const double a1, ...) {
 
24475
    //! Return a vector with specified coefficients.
 
24476
    template<int N> static CImg<T> vector(const double a0, const double a1, ...) {
17313
24477
      CImg<T> res(1,N);
17314
24478
      _CImg_stdarg(res,a0,a1,N,double);
17315
24479
      return res;
17316
24480
    }
17317
24481
 
17318
 
    //! Return a 1x1 square matrix with specified coefficients
17319
 
    static CImg matrix(const T& a0) {
 
24482
    //! Return a 1x1 square matrix with specified coefficients.
 
24483
    static CImg<T> matrix(const T& a0) {
17320
24484
      return vector(a0);
17321
24485
    }
17322
24486
 
17323
 
    //! Return a 2x2 square matrix with specified coefficients
17324
 
    static CImg matrix(const T& a0, const T& a1,
17325
 
                       const T& a2, const T& a3) {
17326
 
      CImg<T> r(2,2); T *ptr = r.data;
 
24487
    //! Return a 2x2 square matrix with specified coefficients.
 
24488
    static CImg<T> matrix(const T& a0, const T& a1,
 
24489
                          const T& a2, const T& a3) {
 
24490
      static CImg<T> r(2,2); T *ptr = r.data;
17327
24491
      *(ptr++) = a0; *(ptr++) = a1;
17328
24492
      *(ptr++) = a2; *(ptr++) = a3;
17329
24493
      return r;
17330
24494
    }
17331
24495
 
17332
 
    //! Return a 3x3 square matrix with specified coefficients
17333
 
    static CImg matrix(const T& a0, const T& a1, const T& a2,
17334
 
                       const T& a3, const T& a4, const T& a5,
17335
 
                       const T& a6, const T& a7, const T& a8) {
17336
 
      CImg<T> r(3,3); T *ptr = r.data;
 
24496
    //! Return a 3x3 square matrix with specified coefficients.
 
24497
    static CImg<T> matrix(const T& a0, const T& a1, const T& a2,
 
24498
                          const T& a3, const T& a4, const T& a5,
 
24499
                          const T& a6, const T& a7, const T& a8) {
 
24500
      static CImg<T> r(3,3); T *ptr = r.data;
17337
24501
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
17338
24502
      *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
17339
24503
      *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8;
17340
24504
      return r;
17341
24505
    }
17342
24506
 
17343
 
    //! Return a 4x4 square matrix with specified coefficients
17344
 
    static CImg matrix(const T& a0, const T& a1, const T& a2, const T& a3,
17345
 
                       const T& a4, const T& a5, const T& a6, const T& a7,
17346
 
                       const T& a8, const T& a9, const T& a10, const T& a11,
17347
 
                       const T& a12, const T& a13, const T& a14, const T& a15) {
17348
 
      CImg<T> r(4,4); T *ptr = r.data;
 
24507
    //! Return a 4x4 square matrix with specified coefficients.
 
24508
    static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3,
 
24509
                          const T& a4, const T& a5, const T& a6, const T& a7,
 
24510
                          const T& a8, const T& a9, const T& a10, const T& a11,
 
24511
                          const T& a12, const T& a13, const T& a14, const T& a15) {
 
24512
      static CImg<T> r(4,4); T *ptr = r.data;
17349
24513
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
17350
24514
      *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
17351
24515
      *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
17353
24517
      return r;
17354
24518
    }
17355
24519
 
17356
 
    //! Return a 5x5 square matrix with specified coefficients
17357
 
    static CImg matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4,
17358
 
                       const T& a5, const T& a6, const T& a7, const T& a8, const T& a9,
17359
 
                       const T& a10, const T& a11, const T& a12, const T& a13, const T& a14,
17360
 
                       const T& a15, const T& a16, const T& a17, const T& a18, const T& a19,
17361
 
                       const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) {
17362
 
      CImg<T> r(5,5); T *ptr = r.data;
 
24520
    //! Return a 5x5 square matrix with specified coefficients.
 
24521
    static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4,
 
24522
                          const T& a5, const T& a6, const T& a7, const T& a8, const T& a9,
 
24523
                          const T& a10, const T& a11, const T& a12, const T& a13, const T& a14,
 
24524
                          const T& a15, const T& a16, const T& a17, const T& a18, const T& a19,
 
24525
                          const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) {
 
24526
      static CImg<T> r(5,5); T *ptr = r.data;
17363
24527
      *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
17364
24528
      *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9;
17365
24529
      *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
17368
24532
      return r;
17369
24533
    }
17370
24534
 
17371
 
    //! Return a MxN square matrix with specified coefficients
17372
 
    template<int M, int N> static CImg matrix(const int a0, const int a1, ...) {
 
24535
    //! Return a MxN square matrix with specified coefficients.
 
24536
    template<int M,int N> static CImg<T> matrix(const int a0, const int a1, ...) {
17373
24537
      CImg<T> res(M,N);
17374
24538
      _CImg_stdarg(res,a0,a1,M*N,int);
17375
24539
      return res;
17376
24540
    }
17377
24541
 
17378
 
    //! Return a NxN square matrix with specified coefficients
17379
 
    template<int M, int N> static CImg matrix(const double a0, const double a1, ...) {
 
24542
    //! Return a NxN square matrix with specified coefficients.
 
24543
    template<int M,int N> static CImg<T> matrix(const double a0, const double a1, ...) {
17380
24544
      CImg<T> res(M,N);
17381
24545
      _CImg_stdarg(res,a0,a1,M*N,double);
17382
24546
      return res;
17383
24547
    }
17384
24548
 
17385
 
    //! In-place version of get_matrix().
17386
 
    CImg& matrix() {
17387
 
      const unsigned int siz = size();
17388
 
      switch (siz) {
17389
 
      case 1: break;
17390
 
      case 4: width = height = 2; break;
17391
 
      case 9: width = height = 3; break;
17392
 
      case 16: width = height = 4; break;
17393
 
      case 25: width = height = 5; break;
17394
 
      case 36: width = height = 6; break;
17395
 
      case 49: width = height = 7; break;
17396
 
      case 64: width = height = 8; break;
17397
 
      case 81: width = height = 9; break;
17398
 
      case 100: width = height = 10; break;
17399
 
      default: {
17400
 
        unsigned int i=11, i2=i*i;
17401
 
        while (i2<siz) { i2+=2*i+1; ++i; }
17402
 
        if (i2==siz) width = height = i;
17403
 
        else throw CImgInstanceException("CImg<%s>::matrix() : Image size = %u is not a square number",pixel_type(),siz);
17404
 
      } break;
17405
 
      }
17406
 
      return *this;
17407
 
    }
17408
 
 
17409
 
    //! Realign pixel values of the instance image as a square matrix
17410
 
    CImg get_matrix() const {
17411
 
      return (+*this).matrix();
17412
 
    }
17413
 
 
17414
 
    //! Return a 1x1 symmetric matrix with specified coefficients
17415
 
    static CImg tensor(const T& a1) {
 
24549
    //! Return a 1x1 symmetric matrix with specified coefficients.
 
24550
    static CImg<T> tensor(const T& a1) {
17416
24551
      return matrix(a1);
17417
24552
    }
17418
24553
 
17419
 
    //! Return a 2x2 symmetric matrix tensor with specified coefficients
17420
 
    static CImg tensor(const T& a1, const T& a2, const T& a3) {
 
24554
    //! Return a 2x2 symmetric matrix tensor with specified coefficients.
 
24555
    static CImg<T> tensor(const T& a1, const T& a2, const T& a3) {
17421
24556
      return matrix(a1,a2,a2,a3);
17422
24557
    }
17423
24558
 
17424
 
    //! Return a 3x3 symmetric matrix with specified coefficients
17425
 
    static CImg tensor(const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) {
 
24559
    //! Return a 3x3 symmetric matrix with specified coefficients.
 
24560
    static CImg<T> tensor(const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) {
17426
24561
      return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6);
17427
24562
    }
17428
24563
 
17429
 
    CImg get_tensor() const {
17430
 
      CImg<T> res;
17431
 
      const unsigned int siz = size();
17432
 
      switch (siz) {
17433
 
      case 1: break;
17434
 
      case 3:
17435
 
        res.assign(2,2);
17436
 
        res(0,0) = (*this)(0);
17437
 
        res(1,0) = res(0,1) = (*this)(1);
17438
 
        res(1,1) = (*this)(2);
17439
 
        break;
17440
 
      case 6:
17441
 
        res.assign(3,3);
17442
 
        res(0,0) = (*this)(0);
17443
 
        res(1,0) = res(0,1) = (*this)(1);
17444
 
        res(2,0) = res(0,2) = (*this)(2);
17445
 
        res(1,1) = (*this)(3);
17446
 
        res(2,1) = res(1,2) = (*this)(4);
17447
 
        res(2,2) = (*this)(5);
17448
 
        break;
17449
 
      default:
17450
 
        throw CImgInstanceException("CImg<%s>::tensor() : Wrong vector dimension = %u in instance image.",
17451
 
                                    pixel_type(), dim);
17452
 
        break;
17453
 
      }
17454
 
      return res;
17455
 
    }
17456
 
 
17457
 
    //! In-place version of get_tensor().
17458
 
    CImg& tensor() {
17459
 
      return get_tensor().swap(*this);
17460
 
    }
17461
 
 
17462
 
    //! Return a 1x1 diagonal matrix with specified coefficients
17463
 
    static CImg diagonal(const T& a0) {
 
24564
    //! Return a 1x1 diagonal matrix with specified coefficients.
 
24565
    static CImg<T> diagonal(const T& a0) {
17464
24566
      return matrix(a0);
17465
24567
    }
17466
24568
 
17467
 
    //! Return a 2x2 diagonal matrix with specified coefficients
17468
 
    static CImg diagonal(const T& a0, const T& a1) {
17469
 
      return matrix(a0,0,
17470
 
                    0,a1);
17471
 
    }
17472
 
 
17473
 
    //! Return a 3x3 diagonal matrix with specified coefficients
17474
 
    static CImg diagonal(const T& a0, const T& a1, const T& a2) {
17475
 
      return matrix(a0,0,0,
17476
 
                    0,a1,0,
17477
 
                    0,0,a2);
17478
 
    }
17479
 
 
17480
 
    //! Return a 4x4 diagonal matrix with specified coefficients
17481
 
    static CImg diagonal(const T& a0, const T& a1, const T& a2, const T& a3) {
17482
 
      return matrix(a0,0,0,0,
17483
 
                    0,a1,0,0,
17484
 
                    0,0,a2,0,
17485
 
                    0,0,0,a3);
17486
 
    }
17487
 
 
17488
 
    //! Return a 5x5 diagonal matrix with specified coefficients
17489
 
    static CImg diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
17490
 
      return matrix(a0,0,0,0,0,
17491
 
                    0,a1,0,0,0,
17492
 
                    0,0,a2,0,0,
17493
 
                    0,0,0,a3,0,
17494
 
                    0,0,0,0,a4);
17495
 
    }
17496
 
 
17497
 
    //! Return a NxN diagonal matrix with specified coefficients
17498
 
    template<int N> static CImg diagonal(const int a0, ...) {
17499
 
      CImg res;
 
24569
    //! Return a 2x2 diagonal matrix with specified coefficients.
 
24570
    static CImg<T> diagonal(const T& a0, const T& a1) {
 
24571
      return matrix(a0,0,0,a1);
 
24572
    }
 
24573
 
 
24574
    //! Return a 3x3 diagonal matrix with specified coefficients.
 
24575
    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2) {
 
24576
      return matrix(a0,0,0,0,a1,0,0,0,a2);
 
24577
    }
 
24578
 
 
24579
    //! Return a 4x4 diagonal matrix with specified coefficients.
 
24580
    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3) {
 
24581
      return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3);
 
24582
    }
 
24583
 
 
24584
    //! Return a 5x5 diagonal matrix with specified coefficients.
 
24585
    static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
 
24586
      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);
 
24587
    }
 
24588
 
 
24589
    //! Return a NxN diagonal matrix with specified coefficients.
 
24590
    template<int N> static CImg<T> diagonal(const int a0, ...) {
 
24591
      CImg<T> res;
17500
24592
      if (N>0) {
17501
24593
        res.assign(N,N,1,1,0);
17502
24594
        va_list ap;
17508
24600
      return res;
17509
24601
    }
17510
24602
 
17511
 
    //! Return a NxN diagonal matrix with specified coefficients
17512
 
    template<int N> static CImg diagonal(const double a0, ...) {
17513
 
      CImg res;
 
24603
    //! Return a NxN diagonal matrix with specified coefficients.
 
24604
    template<int N> static CImg<T> diagonal(const double a0, ...) {
 
24605
      CImg<T> res;
17514
24606
      if (N>0) {
17515
24607
        res.assign(N,N,1,1,0);
17516
24608
        va_list ap;
17522
24614
      return res;
17523
24615
    }
17524
24616
 
17525
 
    //! Unroll all images values into specified axis.
17526
 
    CImg& unroll(const char axe='x') {
17527
 
      const unsigned int siz = size();
17528
 
      if (siz) switch (axe) {
17529
 
      case 'x': width = siz; height=depth=dim=1; break;
17530
 
      case 'y': height = siz; width=depth=dim=1; break;
17531
 
      case 'z': depth = siz; width=height=dim=1; break;
17532
 
      case 'v': dim = siz; width=height=depth=1; break;
17533
 
      default: throw CImgArgumentException("CImg<%s>::unroll() : Given axe is '%c' which is not 'x','y','z' or 'v'",
17534
 
                                           pixel_type(),axe);
17535
 
      }
17536
 
      return *this;
17537
 
    }
17538
 
 
17539
 
    CImg get_unroll(const char axe='x') const {
17540
 
      return (+*this).unroll(axe);
17541
 
    }
17542
 
 
17543
 
    CImg& vector() {
17544
 
      return unroll('y');
17545
 
    }
17546
 
 
17547
 
    CImg get_vector() const {
17548
 
      return get_unroll('y');
17549
 
    }
17550
 
 
17551
 
    //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image
17552
 
    CImg get_diagonal() const {
17553
 
      if (is_empty()) return CImg<T>();
17554
 
      CImg res(size(),size(),1,1,0);
17555
 
      cimg_foroff(*this,off) res(off,off) = (*this)(off);
17556
 
      return res;
17557
 
    }
17558
 
 
17559
 
    //! Replace a vector by a diagonal matrix containing the original vector coefficients.
17560
 
    CImg& diagonal() {
17561
 
      return get_diagonal().swap(*this);
17562
 
    }
17563
 
 
17564
 
    //! Return a NxN identity matrix
17565
 
    static CImg identity_matrix(const unsigned int N) {
 
24617
    //! Return a NxN identity matrix.
 
24618
    static CImg<T> identity_matrix(const unsigned int N) {
17566
24619
      CImg<T> res(N,N,1,1,0);
17567
24620
      cimg_forX(res,x) res(x,x) = 1;
17568
24621
      return res;
17569
24622
    }
17570
24623
 
17571
 
    CImg& identity_matrix() {
17572
 
      return identity_matrix(cimg::max(width,height)).swap(*this);
17573
 
    }
17574
 
 
17575
 
    CImg get_identity_matrix() const {
17576
 
      return identity_matrix(cimg::max(width,height));
17577
 
    }
17578
 
 
17579
 
    //! Return a N-numbered sequence vector from \p a0 to \p a1
17580
 
    CImg& sequence(const T& a0, const T& a1) {
17581
 
      if (!is_empty()) {
17582
 
        const unsigned int siz = size()-1;
17583
 
        const float delta = (float)((float)a1-a0);
17584
 
        T* ptr = data;
17585
 
        cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);
17586
 
      }
17587
 
      return *this;
17588
 
    }
17589
 
 
17590
 
    CImg get_sequence(const T& a0, const T& a1) const {
17591
 
      return (+*this).sequence(a0,a1);
17592
 
    }
17593
 
 
17594
 
    static CImg sequence(const unsigned int N, const T& a0, const T& a1) {
 
24624
    //! Return a N-numbered sequence vector from \p a0 to \p a1.
 
24625
    static CImg<T> sequence(const unsigned int N, const T a0, const T a1) {
17595
24626
      if (N) return CImg<T>(1,N).sequence(a0,a1);
17596
24627
      return CImg<T>();
17597
24628
    }
17598
24629
 
17599
24630
    //! Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w.
17600
 
    static CImg rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) {
 
24631
    static CImg<T> rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) {
17601
24632
      float X,Y,Z,W;
17602
24633
      if (!quaternion_data) {
17603
24634
        const float norm = (float)std::sqrt(x*x + y*y + z*z),
17616
24647
        if (norm>0) { X = x/norm; Y = y/norm; Z = z/norm; W = w/norm; }
17617
24648
        else { X = Y = Z = 0; W = 1; }
17618
24649
      }
17619
 
      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;
 
24650
      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;
17620
24651
      return CImg<T>::matrix((T)(1-2*(yy+zz)), (T)(2*(xy+zw)),   (T)(2*(xz-yw)),
17621
24652
                             (T)(2*(xy-zw)),   (T)(1-2*(xx+zz)), (T)(2*(yz+xw)),
17622
24653
                             (T)(2*(xz+yw)),   (T)(2*(yz-xw)),   (T)(1-2*(xx+yy)));
17623
24654
    }
17624
24655
 
17625
24656
    //! Return a new image corresponding to the vector located at (\p x,\p y,\p z) of the current vector-valued image.
17626
 
    CImg get_vector_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
17627
 
      CImg dest(1,dim);
17628
 
      cimg_forV(*this,k) dest[k]=(*this)(x,y,z,k);
 
24657
    CImg<T> get_vector_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
 
24658
      static CImg<T> dest;
 
24659
      if (dest.height!=dim) dest.assign(1,dim);
 
24660
      const unsigned int whz = width*height*depth;
 
24661
      const T *ptrs = ptr(x,y,z);
 
24662
      T *ptrd = dest.data;
 
24663
      cimg_forV(*this,k) { *(ptrd++) = *ptrs; ptrs+=whz; }
17629
24664
      return dest;
17630
24665
    }
17631
24666
 
 
24667
    //! 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.
 
24668
    template<typename t> CImg<T>& set_vector_at(const CImg<t>& vec, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
 
24669
      if (x<width && y<height && z<depth) {
 
24670
        const unsigned int whz = width*height*depth;
 
24671
        const t *ptrs = vec.data;
 
24672
        T *ptrd = ptr(x,y,z);
 
24673
        for (unsigned int k=cimg::min((unsigned int)vec.size(),dim); k; --k) { *ptrd = (T)*(ptrs++); ptrd+=whz; }
 
24674
      }
 
24675
      return *this;
 
24676
    }
 
24677
 
17632
24678
    //! 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.
17633
 
    CImg get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
 
24679
    CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
17634
24680
      const int n = (int)std::sqrt((double)dim);
17635
 
      CImg dest(n,n);
 
24681
      CImg<T> dest(n,n);
17636
24682
      cimg_forV(*this,k) dest[k]=(*this)(x,y,z,k);
17637
24683
      return dest;
17638
24684
    }
17639
24685
 
 
24686
    //! 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.
 
24687
    template<typename t> CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
 
24688
      return set_vector_at(mat,x,y,z);
 
24689
    }
 
24690
 
17640
24691
    //! 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.
17641
 
    CImg get_tensor_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
 
24692
    CImg<T> get_tensor_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
17642
24693
      if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2),
17643
 
                                          (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5));
 
24694
                                (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5));
17644
24695
      if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2));
17645
24696
      return tensor((*this)(x,y,z,0));
17646
24697
    }
17647
24698
 
17648
 
    //! 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.
17649
 
    CImg& set_vector_at(const CImg& vec, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
17650
 
      return draw_point(x,y,z,vec.data,1);
17651
 
    }
17652
 
 
17653
 
    //! 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.
17654
 
    CImg& set_matrix_at(const CImg& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
17655
 
      return set_vector_at(mat,x,y,z);
17656
 
    }
17657
 
 
17658
24699
    //! 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.
17659
 
    CImg& set_tensor_at(const CImg& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
 
24700
    template<typename t> CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
17660
24701
      if (ten.height==2) {
17661
 
        (*this)(x,y,z,0) = ten[0];
17662
 
        (*this)(x,y,z,1) = ten[1];
17663
 
        (*this)(x,y,z,2) = ten[3];
 
24702
        (*this)(x,y,z,0) = (T)ten[0];
 
24703
        (*this)(x,y,z,1) = (T)ten[1];
 
24704
        (*this)(x,y,z,2) = (T)ten[3];
17664
24705
      }
17665
24706
      else {
17666
 
        (*this)(x,y,z,0) = ten[0];
17667
 
        (*this)(x,y,z,1) = ten[1];
17668
 
        (*this)(x,y,z,2) = ten[2];
17669
 
        (*this)(x,y,z,3) = ten[4];
17670
 
        (*this)(x,y,z,4) = ten[5];
17671
 
        (*this)(x,y,z,5) = ten[8];
17672
 
      }
17673
 
      return *this;
17674
 
    }
17675
 
 
17676
 
    //! Return the transpose version of the current matrix.
17677
 
    CImg get_transpose() const {
 
24707
        (*this)(x,y,z,0) = (T)ten[0];
 
24708
        (*this)(x,y,z,1) = (T)ten[1];
 
24709
        (*this)(x,y,z,2) = (T)ten[2];
 
24710
        (*this)(x,y,z,3) = (T)ten[4];
 
24711
        (*this)(x,y,z,4) = (T)ten[5];
 
24712
        (*this)(x,y,z,5) = (T)ten[8];
 
24713
      }
 
24714
      return *this;
 
24715
    }
 
24716
 
 
24717
    //! Unroll all images values into a one-column vector.
 
24718
    CImg<T> get_vector() const {
 
24719
      return get_unroll('y');
 
24720
    }
 
24721
 
 
24722
    //! Unroll all images values into a one-column vector (in-place).
 
24723
    CImg<T>& vector() {
 
24724
      return unroll('y');
 
24725
    }
 
24726
 
 
24727
    //! Realign pixel values of the instance image as a square matrix
 
24728
    CImg<T> get_matrix() const {
 
24729
      return (+*this).matrix();
 
24730
    }
 
24731
 
 
24732
    //! Realign pixel values of the instance image as a square matrix (in-place).
 
24733
    CImg<T>& matrix() {
 
24734
      const unsigned int siz = size();
 
24735
      switch (siz) {
 
24736
      case 1: break;
 
24737
      case 4: width = height = 2; break;
 
24738
      case 9: width = height = 3; break;
 
24739
      case 16: width = height = 4; break;
 
24740
      case 25: width = height = 5; break;
 
24741
      case 36: width = height = 6; break;
 
24742
      case 49: width = height = 7; break;
 
24743
      case 64: width = height = 8; break;
 
24744
      case 81: width = height = 9; break;
 
24745
      case 100: width = height = 10; break;
 
24746
      default: {
 
24747
        unsigned int i = 11, i2 = i*i;
 
24748
        while (i2<siz) { i2+=2*i+1; ++i; }
 
24749
        if (i2==siz) width = height = i;
 
24750
        else throw CImgInstanceException("CImg<%s>::matrix() : Image size = %u is not a square number",pixel_type(),siz);
 
24751
      } break;
 
24752
      }
 
24753
      return *this;
 
24754
    }
 
24755
 
 
24756
    //! Realign pixel values of the instance image as a symmetric tensor.
 
24757
    CImg<T> get_tensor() const {
 
24758
      CImg<T> res;
 
24759
      const unsigned int siz = size();
 
24760
      switch (siz) {
 
24761
      case 1: break;
 
24762
      case 3:
 
24763
        res.assign(2,2);
 
24764
        res(0,0) = (*this)(0);
 
24765
        res(1,0) = res(0,1) = (*this)(1);
 
24766
        res(1,1) = (*this)(2);
 
24767
        break;
 
24768
      case 6:
 
24769
        res.assign(3,3);
 
24770
        res(0,0) = (*this)(0);
 
24771
        res(1,0) = res(0,1) = (*this)(1);
 
24772
        res(2,0) = res(0,2) = (*this)(2);
 
24773
        res(1,1) = (*this)(3);
 
24774
        res(2,1) = res(1,2) = (*this)(4);
 
24775
        res(2,2) = (*this)(5);
 
24776
        break;
 
24777
      default:
 
24778
        throw CImgInstanceException("CImg<%s>::tensor() : Wrong vector dimension = %u in instance image.",
 
24779
                                    pixel_type(), dim);
 
24780
        break;
 
24781
      }
 
24782
      return res;
 
24783
    }
 
24784
 
 
24785
    //! Realign pixel values of the instance image as a symmetric tensor (in-place).
 
24786
    CImg<T>& tensor() {
 
24787
      return get_tensor().transfer_to(*this);
 
24788
    }
 
24789
 
 
24790
    //! Unroll all images values into specified axis.
 
24791
    CImg<T> get_unroll(const char axe='x') const {
 
24792
      return (+*this).unroll(axe);
 
24793
    }
 
24794
 
 
24795
    //! Unroll all images values into specified axis (in-place).
 
24796
    CImg<T>& unroll(const char axe='x') {
 
24797
      const unsigned int siz = size();
 
24798
      if (siz) switch (axe) {
 
24799
      case 'x': width = siz; height=depth=dim=1; break;
 
24800
      case 'y': height = siz; width=depth=dim=1; break;
 
24801
      case 'z': depth = siz; width=height=dim=1; break;
 
24802
      case 'v': dim = siz; width=height=depth=1; break;
 
24803
      default: throw CImgArgumentException("CImg<%s>::unroll() : Given axe is '%c' which is not 'x','y','z' or 'v'",
 
24804
                                           pixel_type(),axe);
 
24805
      }
 
24806
      return *this;
 
24807
    }
 
24808
 
 
24809
    //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image.
 
24810
    CImg<T> get_diagonal() const {
 
24811
      if (is_empty()) return CImg<T>();
 
24812
      CImg<T> res(size(),size(),1,1,0);
 
24813
      cimg_foroff(*this,off) res(off,off) = (*this)(off);
 
24814
      return res;
 
24815
    }
 
24816
 
 
24817
    //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image (in-place).
 
24818
    CImg<T>& diagonal() {
 
24819
      return get_diagonal().transfer_to(*this);
 
24820
    }
 
24821
 
 
24822
    //! Get an identity matrix having same dimension than instance image.
 
24823
    CImg<T> get_identity_matrix() const {
 
24824
      return identity_matrix(cimg::max(width,height));
 
24825
    }
 
24826
 
 
24827
    //! Get an identity matrix having same dimension than instance image (in-place).
 
24828
    CImg<T>& identity_matrix() {
 
24829
      return identity_matrix(cimg::max(width,height)).transfer_to(*this);
 
24830
    }
 
24831
 
 
24832
    //! Return a N-numbered sequence vector from \p a0 to \p a1.
 
24833
    CImg<T> get_sequence(const T a0, const T a1) const {
 
24834
      return (+*this).sequence(a0,a1);
 
24835
    }
 
24836
 
 
24837
    //! Return a N-numbered sequence vector from \p a0 to \p a1 (in-place).
 
24838
    CImg<T>& sequence(const T a0, const T a1) {
 
24839
      if (!is_empty()) {
 
24840
        const unsigned int siz = size()-1;
 
24841
        const float delta = (float)((float)a1-a0);
 
24842
        T* ptr = data;
 
24843
        cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);
 
24844
      }
 
24845
      return *this;
 
24846
    }
 
24847
 
 
24848
    //! Transpose the current matrix.
 
24849
    CImg<T> get_transpose() const {
17678
24850
      return get_permute_axes("yxzv");
17679
24851
    }
17680
24852
 
17681
 
    //! Replace the current matrix by its transpose.
17682
 
    CImg& transpose() {
 
24853
    //! Transpose the current matrix (in-place).
 
24854
    CImg<T>& transpose() {
17683
24855
      if (width==1) { width=height; height=1; return *this; }
17684
24856
      if (height==1) { height=width; width=1; return *this; }
17685
24857
      if (width==height) {
17686
 
        cimg_forYZV(*this,y,z,v) for (int x=y; x<(int)width; ++x) cimg::swap((*this)(x,y,z,v),(*this)(y,x,z,v));
 
24858
        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));
17687
24859
        return *this;
17688
24860
      }
17689
 
      return get_transpose().swap(*this);
17690
 
    }
17691
 
 
17692
 
    //! Inverse the current matrix.
17693
 
    CImg& inverse(const bool use_LU=true) {
 
24861
      return get_transpose().transfer_to(*this);
 
24862
    }
 
24863
 
 
24864
    //! Invert the current matrix.
 
24865
    CImg<Tfloat> get_invert(const bool use_LU=true) const {
 
24866
      return CImg<Tfloat>(*this,false).invert(use_LU);
 
24867
    }
 
24868
 
 
24869
    //! Invert the current matrix (in-place).
 
24870
    CImg<T>& invert(const bool use_LU=true) {
17694
24871
      if (!is_empty()) {
17695
24872
        if (width!=height || depth!=1 || dim!=1)
17696
 
          throw CImgInstanceException("CImg<%s>::inverse() : Instance matrix (%u,%u,%u,%u,%p) is not square.",
 
24873
          throw CImgInstanceException("CImg<%s>::invert() : Instance matrix (%u,%u,%u,%u,%p) is not square.",
17697
24874
                                      pixel_type(),width,height,depth,dim,data);
17698
24875
#ifdef cimg_use_lapack
17699
 
        typedef typename cimg::largest<T,float>::type ftype;
17700
24876
        int INFO = (int)use_LU, N = width, LWORK = 4*N, *IPIV = new int[N];
17701
 
        ftype
17702
 
          *lapA = new ftype[N*N],
17703
 
          *WORK = new ftype[LWORK];
17704
 
        cimg_forXY(*this,k,l) lapA[k*N+l] = (ftype)((*this)(k,l));
 
24877
        Tfloat
 
24878
          *lapA = new Tfloat[N*N],
 
24879
          *WORK = new Tfloat[LWORK];
 
24880
        cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
17705
24881
        cimg::getrf(N,lapA,IPIV,INFO);
17706
 
        if (INFO) cimg::warn("CImg<%s>::inverse() : LAPACK library function dgetrf_() returned error code %d.",pixel_type(),INFO);
 
24882
        if (INFO) cimg::warn("CImg<%s>::invert() : LAPACK library function dgetrf_() returned error code %d.",pixel_type(),INFO);
17707
24883
        else {
17708
24884
          cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
17709
 
          if (INFO) cimg::warn("CImg<%s>::inverse() : LAPACK library function dgetri_() returned Error code %d",pixel_type(),INFO);
 
24885
          if (INFO) cimg::warn("CImg<%s>::invert() : LAPACK library function dgetri_() returned Error code %d",pixel_type(),INFO);
17710
24886
        }
17711
24887
        if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N+l]); else fill(0);
17712
24888
        delete[] IPIV; delete[] lapA; delete[] WORK;
17727
24903
          data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete);
17728
24904
          data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete);
17729
24905
        } else {
17730
 
          typedef typename cimg::largest<float,T>::type ftype;
17731
24906
          if (use_LU) { // LU-based inverse computation
17732
 
            CImg<ftype> A(*this), indx, col(1,width);
 
24907
            CImg<Tfloat> A(*this), indx, col(1,width);
17733
24908
            bool d;
17734
24909
            A._LU(indx,d);
17735
24910
            cimg_forX(*this,j) {
17739
24914
              cimg_forX(*this,i) (*this)(j,i) = (T)col(i);
17740
24915
            }
17741
24916
          } else { // SVD-based inverse computation
17742
 
            CImg<ftype> U(width,width), S(1,width), V(width,width);
 
24917
            CImg<Tfloat> U(width,width), S(1,width), V(width,width);
17743
24918
            SVD(U,S,V,false);
17744
24919
            U.transpose();
17745
24920
            cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k];
17752
24927
      return *this;
17753
24928
    }
17754
24929
 
17755
 
    //! Return the inverse of the current matrix.
17756
 
    CImg<typename cimg::largest<T,float>::type> get_inverse(const bool use_LU=true) const {
17757
 
      typedef typename cimg::largest<T,float>::type restype;
17758
 
      return CImg<restype>(*this,false).inverse(use_LU);
17759
 
    }
17760
 
 
17761
 
    //! Return the pseudo-inverse (Moore-Penrose) of the matrix
17762
 
    CImg<typename cimg::largest<T,float>::type> get_pseudoinverse() const {
17763
 
      typedef typename cimg::largest<T,float>::type restype;
17764
 
      CImg<restype> At = get_transpose(), At2(At);
17765
 
      return (((At*=*this).inverse())*=At2);
17766
 
    }
17767
 
 
17768
 
    //! Replace the matrix by its pseudo-inverse
17769
 
    CImg& pseudoinverse() {
17770
 
      typedef typename cimg::largest<T,float>::type restype;
17771
 
      CImg<restype> At = get_transpose(), At2(At);
17772
 
      ((At*=*this).inverse())*=At2;
17773
 
      return ((*this) = At);
17774
 
    }
17775
 
 
17776
 
    //! Return the trace of the current matrix.
17777
 
    double trace() const {
17778
 
      if (is_empty())
17779
 
        throw CImgInstanceException("CImg<%s>::trace() : Instance matrix (%u,%u,%u,%u,%p) is empty.",
17780
 
                                    pixel_type(),width,height,depth,dim,data);
17781
 
      double res = 0;
17782
 
      cimg_forX(*this,k) res+=(*this)(k,k);
17783
 
      return res;
17784
 
    }
17785
 
 
17786
 
    //! Return the kth smallest element of the image
17787
 
    // (Adapted from the numerical recipies for CImg)
17788
 
    const T kth_smallest(const unsigned int k) const {
17789
 
      if (is_empty())
17790
 
        throw CImgInstanceException("CImg<%s>::kth_smallest() : Instance image (%u,%u,%u,%u,%p) is empty.",
17791
 
                                    pixel_type(),width,height,depth,dim,data);
17792
 
      CImg<T> arr(*this);
17793
 
      unsigned long l = 0, ir = size()-1;
17794
 
      for (;;) {
17795
 
        if (ir<=l+1) {
17796
 
          if (ir==l+1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
17797
 
          return arr[k];
17798
 
        } else {
17799
 
          const unsigned long mid = (l+ir)>>1;
17800
 
          cimg::swap(arr[mid],arr[l+1]);
17801
 
          if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);
17802
 
          if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]);
17803
 
          if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]);
17804
 
          unsigned long i = l+1, j = ir;
17805
 
          const T pivot = arr[l+1];
17806
 
          for (;;) {
17807
 
            do ++i; while (arr[i]<pivot);
17808
 
            do --j; while (arr[j]>pivot);
17809
 
            if (j<i) break;
17810
 
            cimg::swap(arr[i],arr[j]);
17811
 
          }
17812
 
          arr[l+1] = arr[j];
17813
 
          arr[j] = pivot;
17814
 
          if (j>=k) ir=j-1;
17815
 
          if (j<=k) l=i;
17816
 
        }
 
24930
    //! Compute the pseudo-inverse (Moore-Penrose) of the matrix.
 
24931
    CImg<Tfloat> get_pseudoinvert() const {
 
24932
      CImg<Tfloat> U, S, V;
 
24933
      SVD(U,S,V);
 
24934
      cimg_forX(V,x) {
 
24935
        const float s = S(x), invs = s!=0.0f?1.0f/s:0.0f;
 
24936
        cimg_forY(V,y) V(x,y)*=invs;
17817
24937
      }
17818
 
      return 0;
17819
 
    }
17820
 
 
17821
 
    //! Return the median of the image
17822
 
    const T median() const {
17823
 
      const unsigned int s = size();
17824
 
      const T res = kth_smallest(s>>1);
17825
 
      return (s%2)?res:((res+kth_smallest((s>>1)-1))/2);
17826
 
    }
17827
 
 
17828
 
    //! Return the dot product of the current vector/matrix with the vector/matrix \p img.
17829
 
    double dot(const CImg& img) const {
17830
 
      if (is_empty())
17831
 
        throw CImgInstanceException("CImg<%s>::dot() : Instance object (%u,%u,%u,%u,%p) is empty.",
17832
 
                                    pixel_type(),width,height,depth,dim,data);
17833
 
      if (!img)
17834
 
        throw CImgArgumentException("CImg<%s>::trace() : Specified argument (%u,%u,%u,%u,%p) is empty.",
17835
 
                                    pixel_type(),img.width,img.height,img.depth,img.dim,img.data);
17836
 
      const unsigned long nb = cimg::min(size(),img.size());
17837
 
      double res = 0;
17838
 
      for (unsigned long off=0; off<nb; ++off) res+=data[off]*img[off];
17839
 
      return res;
17840
 
    }
17841
 
 
17842
 
    //! Return the cross product between two 3d vectors
17843
 
    CImg& cross(const CImg& img) {
 
24938
      return V*U.transpose();
 
24939
    }
 
24940
 
 
24941
    //! Compute the pseudo-inverse (Moore-Penrose) of the matrix (in-place).
 
24942
    CImg<T>& pseudoinvert() {
 
24943
      return get_pseudoinvert().transfer_to(*this);
 
24944
    }
 
24945
 
 
24946
    //! Compute the cross product between two 3d vectors.
 
24947
    template<typename t> CImg<typename cimg::superset<T,t>::type> get_cross(const CImg<t>& img) const {
 
24948
      typedef typename cimg::superset<T,t>::type Tt;
 
24949
      return CImg<Tt>(*this).cross(img);
 
24950
    }
 
24951
 
 
24952
    //! Compute the cross product between two 3d vectors (in-place).
 
24953
    template<typename t> CImg<T>& cross(const CImg<t>& img) {
17844
24954
      if (width!=1 || height<3 || img.width!=1 || img.height<3)
17845
24955
        throw CImgInstanceException("CImg<%s>::cross() : Arguments (%u,%u,%u,%u,%p) and (%u,%u,%u,%u,%p) must be both 3d vectors.",
17846
24956
                                    pixel_type(),width,height,depth,dim,data,img.width,img.height,img.depth,img.dim,img.data);
17847
24957
      const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
17848
 
      (*this)[0] = y*img[2]-z*img[1];
17849
 
      (*this)[1] = z*img[0]-x*img[2];
17850
 
      (*this)[2] = x*img[1]-y*img[0];
 
24958
      (*this)[0] = (T)(y*img[2]-z*img[1]);
 
24959
      (*this)[1] = (T)(z*img[0]-x*img[2]);
 
24960
      (*this)[2] = (T)(x*img[1]-y*img[0]);
17851
24961
      return *this;
17852
24962
    }
17853
24963
 
17854
 
    //! Return the cross product between two 3d vectors
17855
 
    CImg get_cross(const CImg& img) const {
17856
 
      return (+*this).cross(img);
 
24964
    //! Solve a linear system AX=B where B=*this.
 
24965
    template<typename t> CImg<typename cimg::superset2<T,t,float>::type> get_solve(const CImg<t>& A) const {
 
24966
      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 
24967
      return CImg<Ttfloat>(*this,false).solve(A);
17857
24968
    }
17858
24969
 
17859
 
    //! Return the determinant of the current matrix.
17860
 
    double det() const {
17861
 
      if (is_empty() || width!=height || depth!=1 || dim!=1)
17862
 
        throw CImgInstanceException("CImg<%s>::det() : Instance matrix (%u,%u,%u,%u,%p) is not square or is empty.",
17863
 
                                    pixel_type(),width,height,depth,dim,data);
17864
 
      switch (width) {
17865
 
      case 1: return (*this)(0,0);
17866
 
      case 2: return (*this)(0,0)*(*this)(1,1)-(*this)(0,1)*(*this)(1,0);
17867
 
      case 3: {
17868
 
        const double
17869
 
          a = data[0], d = data[1], g = data[2],
17870
 
          b = data[3], e = data[4], h = data[5],
17871
 
          c = data[6], f = data[7], i = data[8];
17872
 
        return i*a*e-a*h*f-i*b*d+b*g*f+c*d*h-c*g*e;
17873
 
      }
17874
 
      default: {
17875
 
        typedef typename cimg::largest<T,float>::type ftype;
17876
 
        CImg<ftype> lu(*this);
17877
 
        CImg<unsigned int> indx;
 
24970
    //! Solve a linear system AX=B where B=*this (in-place).
 
24971
    template<typename t> CImg<T>& solve(const CImg<t>& A) {
 
24972
      if (width!=1 || depth!=1 || dim!=1 || height!=A.height || A.depth!=1 || A.dim!=1)
 
24973
        throw CImgArgumentException("CImg<%s>::solve() : Instance matrix size is (%u,%u,%u,%u) while "
 
24974
                                    "size of given matrix A is (%u,%u,%u,%u).",
 
24975
                                    pixel_type(),width,height,depth,dim,A.width,A.height,A.depth,A.dim);
 
24976
 
 
24977
      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 
24978
      if (A.width==A.height) {
 
24979
#ifdef cimg_use_lapack
 
24980
        char TRANS='N';
 
24981
        int INFO, N = height, LWORK = 4*N, one = 1, *IPIV = new int[N];
 
24982
        Ttfloat
 
24983
          *lapA = new Ttfloat[N*N],
 
24984
          *lapB = new Ttfloat[N],
 
24985
          *WORK = new Ttfloat[LWORK];
 
24986
        cimg_forXY(A,k,l) lapA[k*N+l] = (Ttfloat)(A(k,l));
 
24987
        cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));
 
24988
        cimg::getrf(N,lapA,IPIV,INFO);
 
24989
        if (INFO) cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrf_() returned error code %d.",pixel_type(),INFO);
 
24990
        if (!INFO) {
 
24991
          cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
 
24992
          if (INFO) cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrs_() returned Error code %d",pixel_type(),INFO);
 
24993
        }
 
24994
        if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
 
24995
        delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
 
24996
#else
 
24997
        CImg<Ttfloat> lu(A);
 
24998
        CImg<Ttfloat> indx;
17878
24999
        bool d;
17879
25000
        lu._LU(indx,d);
17880
 
        double res = d?1.0:-1.0;
17881
 
        cimg_forX(lu,i) res*=lu(i,i);
17882
 
        return res;
17883
 
      }
17884
 
      }
17885
 
      return 0;
17886
 
    }
17887
 
 
17888
 
    //! Return the norm of the current vector/matrix. \p ntype = norm type (0=L2, 1=L1, -1=Linf).
17889
 
    double norm(const int norm_type=2) const {
17890
 
      if (is_empty())
17891
 
        throw CImgInstanceException("CImg<%s>::norm() : Instance object (%u,%u,%u,%u,%p) is empty.",
17892
 
                                    pixel_type(),width,height,depth,dim,data);
17893
 
      double res = 0;
17894
 
      switch (norm_type) {
17895
 
      case -1: {
17896
 
        cimg_foroff(*this,off) {
17897
 
          const double tmp = cimg::abs((double)data[off]);
17898
 
          if (tmp>res) res = tmp;
17899
 
        }
17900
 
        return res;
17901
 
      } break;
17902
 
      case 1 : {
17903
 
        cimg_foroff(*this,off) res+=cimg::abs((double)data[off]);
17904
 
        return res;
17905
 
      } break;
17906
 
      default: { return std::sqrt(dot(*this)); }
17907
 
      }
17908
 
      return 0;
17909
 
    }
17910
 
 
17911
 
    //! Return the sum of all the pixel values in an image.
17912
 
    double sum() const {
17913
 
      if (is_empty())
17914
 
        throw CImgInstanceException("CImg<%s>::sum() : Instance object (%u,%u,%u,%u,%p) is empty.",
17915
 
                                    pixel_type(),width,height,depth,dim,data);
17916
 
      double res = 0;
17917
 
      cimg_for(*this,ptr,T) res+=*ptr;
 
25001
        _solve(lu,indx);
 
25002
#endif
 
25003
      } else assign(A.get_pseudoinvert()*(*this));
 
25004
      return *this;
 
25005
    }
 
25006
 
 
25007
    template<typename t, typename ti> CImg<T>& _solve(const CImg<t>& A, const CImg<ti>& indx) {
 
25008
      typedef typename cimg::superset2<T,t,float>::type Ttfloat;
 
25009
      const int N = size();
 
25010
      int ii = -1;
 
25011
      Ttfloat sum;
 
25012
      for (int i=0; i<N; ++i) {
 
25013
        const int ip = (int)indx[i];
 
25014
        Ttfloat sum = (*this)(ip);
 
25015
        (*this)(ip) = (*this)(i);
 
25016
        if (ii>=0) for (int j=ii; j<=i-1; ++j) sum-=A(j,i)*(*this)(j);
 
25017
        else if (sum!=0) ii=i;
 
25018
        (*this)(i) = (T)sum;
 
25019
      }
 
25020
      { for (int i=N-1; i>=0; --i) {
 
25021
        sum = (*this)(i);
 
25022
        for (int j=i+1; j<N; ++j) sum-=A(j,i)*(*this)(j);
 
25023
        (*this)(i) = (T)(sum/A(i,i));
 
25024
      }}
 
25025
      return *this;
 
25026
    }
 
25027
 
 
25028
    //! Sort values of a vector and get permutations.
 
25029
    template<typename t> CImg<T> get_sort(CImg<t>& permutations, const bool increasing=true) const {
 
25030
      return (+*this).sort(permutations,increasing);
 
25031
    }
 
25032
 
 
25033
    //! Sort values of a vector and get permutations (in-place).
 
25034
    template<typename t>
 
25035
    CImg<T>& sort(CImg<t>& permutations, const bool increasing=true) {
 
25036
      if (is_empty()) permutations.assign();
 
25037
      else {
 
25038
        if (permutations.size()!=size()) permutations.assign(size());
 
25039
        cimg_foroff(permutations,off) permutations[off] = (t)off;
 
25040
        _quicksort(0,size()-1,permutations,increasing);
 
25041
      }
 
25042
      return *this;
 
25043
    }
 
25044
 
 
25045
    // Sort image values.
 
25046
    CImg<T> get_sort(const bool increasing=true) const {
 
25047
      return (+*this).sort(increasing);
 
25048
    }
 
25049
 
 
25050
    // Sort image values (in-place).
 
25051
    CImg<T>& sort(const bool increasing=true) {
 
25052
      CImg<T> foo;
 
25053
      return sort(foo,increasing);
 
25054
    }
 
25055
 
 
25056
    template<typename t> CImg<T>& _quicksort(const int min, const int max, CImg<t>& permutations, const bool increasing) {
 
25057
      if (min<max) {
 
25058
        const int mid = (min+max)/2;
 
25059
        if (increasing) {
 
25060
          if ((*this)[min]>(*this)[mid]) {
 
25061
            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 
25062
          if ((*this)[mid]>(*this)[max]) {
 
25063
            cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
 
25064
          if ((*this)[min]>(*this)[mid]) {
 
25065
            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 
25066
        } else {
 
25067
          if ((*this)[min]<(*this)[mid]) {
 
25068
            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 
25069
          if ((*this)[mid]<(*this)[max]) {
 
25070
            cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
 
25071
          if ((*this)[min]<(*this)[mid]) {
 
25072
            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
 
25073
        }
 
25074
        if (max-min>=3) {
 
25075
          const T pivot = (*this)[mid];
 
25076
          int i = min, j = max;
 
25077
          if (increasing) {
 
25078
            do {
 
25079
              while ((*this)[i]<pivot) ++i;
 
25080
              while ((*this)[j]>pivot) --j;
 
25081
              if (i<=j) {
 
25082
                cimg::swap((*this)[i],(*this)[j]);
 
25083
                cimg::swap(permutations[i++],permutations[j--]);
 
25084
              }
 
25085
            } while (i<=j);
 
25086
          } else {
 
25087
            do {
 
25088
              while ((*this)[i]>pivot) ++i;
 
25089
              while ((*this)[j]<pivot) --j;
 
25090
              if (i<=j) {
 
25091
                cimg::swap((*this)[i],(*this)[j]);
 
25092
                cimg::swap(permutations[i++],permutations[j--]);
 
25093
              }
 
25094
            } while (i<=j);
 
25095
          }
 
25096
          if (min<j) _quicksort(min,j,permutations,increasing);
 
25097
          if (i<max) _quicksort(i,max,permutations,increasing);
 
25098
        }
 
25099
      }
 
25100
      return *this;
 
25101
    }
 
25102
 
 
25103
    //! Get a permutation of the pixels.
 
25104
    template<typename t> CImg<T> get_permute(const CImg<t>& permutation) const {
 
25105
      if (permutation.size()!=size())
 
25106
        throw CImgArgumentException("CImg<%s>::permute() : Instance image (%u,%u,%u,%u,%p) and permutation (%u,%u,%u,%u,%p)"
 
25107
                                    "have different sizes.",pixel_type(),
 
25108
                                    width,height,depth,dim,data,
 
25109
                                    permutation.width,permutation.height,permutation.depth,permutation.dim,permutation.data);
 
25110
      CImg<T> res(width,height,depth,dim);
 
25111
      const t *p = permutation.ptr(permutation.size());
 
25112
      cimg_for(res,ptr,T) *ptr = (*this)[*(--p)];
17918
25113
      return res;
17919
25114
    }
17920
25115
 
 
25116
    //! Get a permutation of the pixels (in-place).
 
25117
    template<typename t> CImg<T>& permute(const CImg<t>& permutation) {
 
25118
      return get_permute(permutation).transfer_to(*this);
 
25119
    }
 
25120
 
17921
25121
    //! Compute the SVD of a general matrix.
17922
 
    template<typename t> const CImg& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V,
17923
 
                                         const bool sorting=true, const unsigned int max_iter=40, const float lambda=0) const {
 
25122
    template<typename t> const CImg<T>& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V,
 
25123
                                            const bool sorting=true, const unsigned int max_iter=40, const float lambda=0) const {
17924
25124
      if (is_empty()) { U.assign(); S.assign(); V.assign(); }
17925
25125
      else {
17926
25126
#ifdef cimg_use_lapack
17927
 
        typedef typename cimg::largest<T,float>::type ftype;
17928
25127
        int M = height, N = width, mn = cimg::min(M,N), MN = cimg::max(M,N), LWORK = 4*mn+2*MN, INFO;
17929
25128
        char JOB='A';
17930
 
        ftype
17931
 
          *lapA = new ftype[M*N],
17932
 
          *lapS = new ftype[mn],
17933
 
          *lapU = new ftype[M*M],
17934
 
          *lapV = new ftype[N*N],
17935
 
          *WORK = new ftype[LWORK];
17936
 
        cimg_forXY(*this,k,l) lapA[k*N+l] = (ftype)((*this)(k,l));
 
25129
        Tfloat
 
25130
          *lapA = new Tfloat[M*N],
 
25131
          *lapS = new Tfloat[mn],
 
25132
          *lapU = new Tfloat[M*M],
 
25133
          *lapV = new Tfloat[N*N],
 
25134
          *WORK = new Tfloat[LWORK];
 
25135
        cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
17937
25136
        cimg::gesvd(JOB,M,N,lapA,MN,lapS,lapU,lapV,WORK,LWORK,INFO);
17938
25137
        if (INFO) cimg::warn("CImg<%s>::SVD() : LAPACK library function gesvd_() returned error code %d.",pixel_type(),INFO);
17939
25138
        U.assign(M,M);
18035
25234
              for (int i=l; i<=k; ++i) {
18036
25235
                f = s*rv1[i]; rv1[i] = c*rv1[i];
18037
25236
                if ((cimg::abs(f)+anorm)==anorm) break;
18038
 
                g = S[i]; h = (t)cimg::pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;
 
25237
                g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;
18039
25238
                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; }
18040
25239
              }
18041
25240
            }
18042
 
            const t& z = S[k];
 
25241
            const t z = S[k];
18043
25242
            if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; }
18044
25243
            nm = k-1;
18045
25244
            t x = S[l], y = S[nm];
18046
25245
            g = rv1[nm]; h = rv1[k];
18047
25246
            f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y);
18048
 
            g = (t)cimg::pythagore(f,1.0);
 
25247
            g = (t)cimg::_pythagore(f,1.0);
18049
25248
            f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x;
18050
25249
            c = s = 1;
18051
25250
            for (int j=l; j<=nm; ++j) {
18052
25251
              const int i = j+1;
18053
25252
              g = rv1[i]; h = s*g; g = c*g;
18054
25253
              t y = S[i];
18055
 
              t z = (t)cimg::pythagore(f,h);
 
25254
              t z = (t)cimg::_pythagore(f,h);
18056
25255
              rv1[j] = z; c = f/z; s = h/z;
18057
25256
              f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c;
18058
25257
              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; }
18059
 
              z = (t)cimg::pythagore(f,h); S[j] = z;
 
25258
              z = (t)cimg::_pythagore(f,h); S[j] = z;
18060
25259
              if (z) { z = 1/z; c = f*z; s = h*z; }
18061
25260
              f = c*g+s*y; x = c*y-s*g;
18062
25261
              { 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; }}
18084
25283
    }
18085
25284
 
18086
25285
    //! Compute the SVD of a general matrix.
18087
 
    template<typename t> const CImg& SVD(CImgList<t>& USV) const {
 
25286
    template<typename t> const CImg<T>& SVD(CImgList<t>& USV) const {
18088
25287
      if (USV.size<3) USV.assign(3);
18089
25288
      return SVD(USV[0],USV[1],USV[2]);
18090
25289
    }
18091
25290
 
18092
25291
    //! Compute the SVD of a general matrix.
18093
 
    CImgList<typename cimg::largest<T,float>::type> get_SVD(const bool sorting=true) const {
18094
 
      typedef typename cimg::largest<T,float>::type restype;
18095
 
      CImgList<restype> res(3);
 
25292
    CImgList<Tfloat> get_SVD(const bool sorting=true) const {
 
25293
      CImgList<Tfloat> res(3);
18096
25294
      SVD(res[0],res[1],res[2],sorting);
18097
25295
      return res;
18098
25296
    }
18099
25297
 
18100
25298
    // INNER ROUTINE : Compute the LU decomposition of a permuted matrix (c.f. numerical recipies)
18101
 
    template<typename t> CImg& _LU(CImg<t>& indx, bool& d) {
18102
 
      typedef typename cimg::largest<T,float>::type ftype;
 
25299
    template<typename t> CImg<T>& _LU(CImg<t>& indx, bool& d) {
18103
25300
      const int N = dimx();
18104
25301
      int imax = 0;
18105
 
      CImg<ftype> vv(N);
 
25302
      CImg<Tfloat> vv(N);
18106
25303
      indx.assign(N);
18107
25304
      d = true;
18108
25305
      cimg_forX(*this,i) {
18109
 
        ftype vmax = 0;
 
25306
        Tfloat vmax = 0;
18110
25307
        cimg_forX(*this,j) {
18111
 
          const ftype tmp = cimg::abs((*this)(j,i));
 
25308
          const Tfloat tmp = cimg::abs((*this)(j,i));
18112
25309
          if (tmp>vmax) vmax = tmp;
18113
25310
        }
18114
25311
        if (vmax==0) { indx.fill(0); return fill(0); }
18116
25313
      }
18117
25314
      cimg_forX(*this,j) {
18118
25315
        for (int i=0; i<j; ++i) {
18119
 
          ftype sum=(*this)(j,i);
 
25316
          Tfloat sum=(*this)(j,i);
18120
25317
          for (int k=0; k<i; ++k) sum-=(*this)(k,i)*(*this)(j,k);
18121
25318
          (*this)(j,i) = (T)sum;
18122
25319
        }
18123
 
        ftype vmax = 0;
 
25320
        Tfloat vmax = 0;
18124
25321
        { for (int i=j; i<dimx(); ++i) {
18125
 
          ftype sum=(*this)(j,i);
 
25322
          Tfloat sum=(*this)(j,i);
18126
25323
          for (int k=0; k<j; ++k) sum-=(*this)(k,i)*(*this)(j,k);
18127
25324
          (*this)(j,i) = (T)sum;
18128
 
          const ftype tmp = vv[i]*cimg::abs(sum);
 
25325
          const Tfloat tmp = vv[i]*cimg::abs(sum);
18129
25326
          if (tmp>=vmax) { vmax=tmp; imax=i; }
18130
25327
        }}
18131
25328
        if (j!=imax) {
18136
25333
        indx[j] = (t)imax;
18137
25334
        if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20;
18138
25335
        if (j<N) {
18139
 
          const ftype tmp = 1/(ftype)(*this)(j,j);
 
25336
          const Tfloat tmp = 1/(Tfloat)(*this)(j,j);
18140
25337
          for (int i=j+1; i<N; ++i) (*this)(j,i) = (T)((*this)(j,i)*tmp);
18141
25338
        }
18142
25339
      }
18143
25340
      return *this;
18144
25341
    }
18145
25342
 
18146
 
    // INNER ROUTINE : Solve a linear system, using the LU decomposition
18147
 
    template<typename t, typename ti> CImg& _solve(const CImg<t>& A, const CImg<ti>& indx) {
18148
 
      typedef typename cimg::largest2<T,t,float>::type ftype;
18149
 
      const int N = size();
18150
 
      int ii = -1;
18151
 
      ftype sum;
18152
 
      for (int i=0; i<N; ++i) {
18153
 
        const int ip = (int)indx[i];
18154
 
        ftype sum = (*this)(ip);
18155
 
        (*this)(ip) = (*this)(i);
18156
 
        if (ii>=0) for (int j=ii; j<=i-1; ++j) sum-=A(j,i)*(*this)(j);
18157
 
        else if (sum!=0) ii=i;
18158
 
        (*this)(i) = (T)sum;
18159
 
      }
18160
 
      { for (int i=N-1; i>=0; --i) {
18161
 
        sum = (*this)(i);
18162
 
        for (int j=i+1; j<N; ++j) sum-=A(j,i)*(*this)(j);
18163
 
        (*this)(i) = (T)(sum/A(i,i));
18164
 
      }}
18165
 
      return *this;
18166
 
    }
18167
 
 
18168
 
    //! Solve a linear system AX=B where B=*this. (in-place version)
18169
 
    template<typename t> CImg& solve(const CImg<t>& A) {
18170
 
      if (width!=1 || depth!=1 || dim!=1 || height!=A.height || A.depth!=1 || A.dim!=1)
18171
 
        throw CImgArgumentException("CImg<%s>::solve() : Instance matrix size is (%u,%u,%u,%u) while "
18172
 
                                    "size of given matrix A is (%u,%u,%u,%u).",
18173
 
                                    pixel_type(),width,height,depth,dim,A.width,A.height,A.depth,A.dim);
18174
 
 
18175
 
      typedef typename cimg::largest2<T,t,float>::type ftype;
18176
 
      if (A.width==A.height) {
18177
 
#ifdef cimg_use_lapack
18178
 
        char TRANS='N';
18179
 
        int INFO, N = height, LWORK = 4*N, one = 1, *IPIV = new int[N];
18180
 
        ftype
18181
 
          *lapA = new ftype[N*N],
18182
 
          *lapB = new ftype[N],
18183
 
          *WORK = new ftype[LWORK];
18184
 
        cimg_forXY(A,k,l) lapA[k*N+l] = (ftype)(A(k,l));
18185
 
        cimg_forY(*this,i) lapB[i] = (ftype)((*this)(i));
18186
 
        cimg::getrf(N,lapA,IPIV,INFO);
18187
 
        if (INFO) cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrf_() returned error code %d.",pixel_type(),INFO);
18188
 
        if (!INFO) {
18189
 
          cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
18190
 
          if (INFO) cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrs_() returned Error code %d",pixel_type(),INFO);
18191
 
        }
18192
 
        if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
18193
 
        delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
18194
 
#else
18195
 
        CImg<ftype> lu(A);
18196
 
        CImg<ftype> indx;
18197
 
        bool d;
18198
 
        lu._LU(indx,d);
18199
 
        _solve(lu,indx);
18200
 
#endif
18201
 
      } else assign(A.get_pseudoinverse()*(*this));
18202
 
      return *this;
18203
 
    }
18204
 
 
18205
 
    //! Solve a linear system AX=B where B=*this.
18206
 
    template<typename t> CImg<typename cimg::largest2<T,t,float>::type> get_solve(const CImg<t>& A) const {
18207
 
      typedef typename cimg::largest2<T,t,float>::type restype;
18208
 
      return CImg<restype>(*this,false).solve(A);
 
25343
    //! Compute the eigenvalues and eigenvectors of a matrix.
 
25344
    CImgList<Tfloat> get_eigen() const {
 
25345
      CImgList<Tfloat> res(2);
 
25346
      eigen(res[0],res[1]);
 
25347
      return res;
18209
25348
    }
18210
25349
 
18211
25350
    //! Compute the eigenvalues and eigenvectors of a matrix.
18217
25356
                                      pixel_type(),width,height,depth,dim,data);
18218
25357
        if (val.size()<width) val.assign(1,width);
18219
25358
        if (vec.size()<width*width) vec.assign(width,width);
18220
 
        switch(width) {
 
25359
        switch (width) {
18221
25360
        case 1: { val[0]=(t)(*this)[0]; vec[0]=(t)1; } break;
18222
25361
        case 2: {
18223
25362
          const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a+d;
18241
25380
      return *this;
18242
25381
    }
18243
25382
 
18244
 
    //! Return the eigenvalues and eigenvectors of a matrix.
18245
 
    CImgList<typename cimg::largest<T,float>::type> get_eigen() const {
18246
 
      typedef typename cimg::largest<T,float>::type restype;
18247
 
      CImgList<restype> res(2);
18248
 
      eigen(res[0],res[1]);
 
25383
    //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
 
25384
    CImgList<Tfloat> get_symmetric_eigen() const {
 
25385
      CImgList<Tfloat> res(2);
 
25386
      symmetric_eigen(res[0],res[1]);
18249
25387
      return res;
18250
25388
    }
18251
25389
 
18252
 
    //! Compute the eigenvalues and eigenvectors of a matrix.
18253
 
    template<typename t> const CImg<T>& eigen(CImgList<t>& eig) const {
18254
 
      if (eig.size<2) eig.assign(2);
18255
 
      eigen(eig[0],eig[1]);
18256
 
      return *this;
18257
 
    }
18258
 
 
18259
25390
    //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
18260
25391
    template<typename t> const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& vec) const {
18261
25392
      if (is_empty()) { val.assign(); vec.assign(); }
18262
25393
      else {
18263
25394
#ifdef cimg_use_lapack
18264
 
        typedef typename cimg::largest<T,float>::type ftype;
18265
25395
        char JOB = 'V', UPLO = 'U';
18266
25396
        int N = width, LWORK = 4*N, INFO;
18267
 
        ftype
18268
 
          *lapA = new ftype[N*N],
18269
 
          *lapW = new ftype[N],
18270
 
          *WORK = new ftype[LWORK];
18271
 
        cimg_forXY(*this,k,l) lapA[k*N+l] = (ftype)((*this)(k,l));
 
25397
        Tfloat
 
25398
          *lapA = new Tfloat[N*N],
 
25399
          *lapW = new Tfloat[N],
 
25400
          *WORK = new Tfloat[LWORK];
 
25401
        cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
18272
25402
        cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO);
18273
25403
        if (INFO) cimg::warn("CImg<%s>::symmetric_eigen() : LAPACK library function dsyev_() returned error code %d.",pixel_type(),INFO);
18274
 
        val.assign(1,N); vec.assign(N,N);
 
25404
        val.assign(1,N);
 
25405
        vec.assign(N,N);
18275
25406
        if (!INFO) {
18276
25407
          cimg_forY(val,i) val(i) = (T)lapW[N-1-i];
18277
25408
          cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N-1-k)*N+l]);
18281
25412
        if (width!=height || depth>1 || dim>1)
18282
25413
          throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
18283
25414
                                      pixel_type(),width,height,depth,dim,data);
18284
 
        if (val.size()<width) val.assign(1,width);
18285
 
        if (vec.data && vec.size()<width*width) vec.assign(width,width);
 
25415
        val.assign(1,width);
 
25416
        if (vec.data) vec.assign(width,width);
18286
25417
        if (width<3) return eigen(val,vec);
18287
25418
        CImg<t> V(width,width);
18288
25419
        SVD(vec,val,V,false);
18289
25420
        bool ambiguous = false;
18290
25421
        float eig = 0;
18291
25422
        cimg_forY(val,p) {       // check for ambiguous cases.
18292
 
          if (val[p]>eig) eig = val[p];
 
25423
          if (val[p]>eig) eig = (float)val[p];
18293
25424
          t scal = 0;
18294
25425
          cimg_forY(vec,y) scal+=vec(p,y)*V(p,y);
18295
25426
          if (cimg::abs(scal)<0.9f) ambiguous = true;
18312
25443
      return *this;
18313
25444
    }
18314
25445
 
18315
 
    //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
18316
 
    CImgList<typename cimg::largest<T,float>::type> get_symmetric_eigen() const {
18317
 
      typedef typename cimg::largest<T,float>::type restype;
18318
 
      CImgList<restype> res(2);
18319
 
      symmetric_eigen(res[0],res[1]);
18320
 
      return res;
18321
 
    }
18322
 
 
18323
 
    //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
18324
 
    template<typename t> const CImg<T>& symmetric_eigen(CImgList<t>& eig) const {
18325
 
      if (eig.size<2) eig.assign(2);
18326
 
      symmetric_eigen(eig[0],eig[1]);
18327
 
      return *this;
18328
 
    }
18329
 
 
18330
 
    template<typename t> CImg<T>& _quicksort(const int min, const int max, CImg<t>& permutations, const bool increasing) {
18331
 
      if (min<max) {
18332
 
        const int mid = (min+max)/2;
18333
 
        if (increasing) {
18334
 
          if ((*this)[min]>(*this)[mid]) {
18335
 
            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
18336
 
          if ((*this)[mid]>(*this)[max]) {
18337
 
            cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
18338
 
          if ((*this)[min]>(*this)[mid]) {
18339
 
            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
18340
 
        } else {
18341
 
          if ((*this)[min]<(*this)[mid]) {
18342
 
            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
18343
 
          if ((*this)[mid]<(*this)[max]) {
18344
 
            cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
18345
 
          if ((*this)[min]<(*this)[mid]) {
18346
 
            cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
18347
 
        }
18348
 
        if (max-min>=3) {
18349
 
          const T pivot = (*this)[mid];
18350
 
          int i = min, j = max;
18351
 
          if (increasing) {
18352
 
            do {
18353
 
              while ((*this)[i]<pivot) ++i;
18354
 
              while ((*this)[j]>pivot) --j;
18355
 
              if (i<=j) {
18356
 
                cimg::swap((*this)[i],(*this)[j]);
18357
 
                cimg::swap(permutations[i++],permutations[j--]);
18358
 
              }
18359
 
            } while (i<=j);
18360
 
          } else {
18361
 
            do {
18362
 
              while ((*this)[i]>pivot) ++i;
18363
 
              while ((*this)[j]<pivot) --j;
18364
 
              if (i<=j) {
18365
 
                cimg::swap((*this)[i],(*this)[j]);
18366
 
                cimg::swap(permutations[i++],permutations[j--]);
18367
 
              }
18368
 
            } while (i<=j);
18369
 
          }
18370
 
          if (min<j) _quicksort(min,j,permutations,increasing);
18371
 
          if (i<max) _quicksort(i,max,permutations,increasing);
18372
 
        }
18373
 
      }
18374
 
      return *this;
18375
 
    }
18376
 
 
18377
 
    //! Sort values of a vector and get permutations.
18378
 
    template<typename t>
18379
 
    CImg<T>& sort(CImg<t>& permutations, const bool increasing=true) {
18380
 
      if (is_empty()) permutations.assign();
18381
 
      else {
18382
 
        if (permutations.size()!=size()) permutations.assign(size());
18383
 
        cimg_foroff(permutations,off) permutations[off] = (t)off;
18384
 
        _quicksort(0,size()-1,permutations,increasing);
18385
 
      }
18386
 
      return *this;
18387
 
    }
18388
 
 
18389
 
    //! Sort values of a vector.
18390
 
    CImg<T>& sort(const bool increasing=true) { CImg<T> foo; return sort(foo,increasing); }
18391
 
 
18392
 
    //! Get a sorted version a of vector, with permutations.
18393
 
    template<typename t> CImg<T> get_sort(CImg<t>& permutations, const bool increasing=true) {
18394
 
      return (+*this).sort(permutations,increasing);
18395
 
    }
18396
 
 
18397
 
    //! Get a sorted version of a vector.
18398
 
    CImg<T> get_sort(const bool increasing=true) {
18399
 
      return (+*this).sort(increasing);
18400
 
    }
18401
 
 
18402
 
    //! Get a permutation of the pixels
18403
 
    template<typename t> CImg<T> get_permute(const CImg<t>& permutation) const {
18404
 
      if (permutation.size()!=size())
18405
 
        throw CImgArgumentException("CImg<%s>::permute() : Instance image (%u,%u,%u,%u,%p) and permutation (%u,%u,%u,%u,%p)"
18406
 
                                    "have different sizes.",pixel_type(),
18407
 
                                    width,height,depth,dim,data,
18408
 
                                    permutation.width,permutation.height,permutation.depth,permutation.dim,permutation.data);
18409
 
      CImg<T> res(width,height,depth,dim);
18410
 
      const t *p = permutation.ptr(permutation.size());
18411
 
      cimg_for(res,ptr,T) *ptr = (*this)[*(--p)];
18412
 
      return res;
18413
 
    }
18414
 
 
18415
 
    //! In-place version of the previous function
18416
 
    template<typename t> CImg<T>& permute(const CImg<t>& permutation) {
18417
 
      return get_permute(permutation).swap(*this);
18418
 
    }
18419
 
 
18420
25446
    //@}
18421
25447
    //-------------------
18422
25448
    //
18425
25451
    //-------------------
18426
25452
 
18427
25453
    //! Display an image into a CImgDisplay window.
18428
 
    const CImg& display(CImgDisplay& disp) const {
 
25454
    const CImg<T>& display(CImgDisplay& disp) const {
18429
25455
      disp.display(*this);
18430
25456
      return *this;
18431
25457
    }
18432
25458
 
18433
25459
    //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n
18434
 
    //! Parameters \p min_size and \p max_size set the minimum and maximum dimensions of the display window.
18435
 
    //! If negative, they corresponds to a percentage of the original image size.
18436
 
    const CImg& display(const char *const title, const int min_size=128, const int max_size=1024,
18437
 
                        const int print_flag=1) const {
18438
 
      if (is_empty())
18439
 
        throw CImgInstanceException("CImg<%s>::display() : Instance image (%u,%u,%u,%u,%p) is empty.",
18440
 
                                    pixel_type(),width,height,depth,dim,data);
18441
 
      CImgDisplay disp;
18442
 
      unsigned int w = width+(depth>1?depth:0), h = height+(depth>1?depth:0), XYZ[3];
18443
 
      print(title,print_flag);
18444
 
      const unsigned int dmin = cimg::min(w,h), minsiz = min_size>=0?min_size:(-min_size)*dmin/100;
18445
 
      if (dmin<minsiz) { w=w*minsiz/dmin; w+=(w==0); h=h*minsiz/dmin; h+=(h==0); }
18446
 
      const unsigned int dmax = cimg::max(w,h), maxsiz = max_size>=0?max_size:(-max_size)*dmax/100;
18447
 
      if (dmax>maxsiz) { w=w*maxsiz/dmax; w+=(w==0); h=h*maxsiz/dmax; h+=(h==0); }
18448
 
      disp.assign(w,h,title,1,3);
18449
 
      XYZ[0] = width/2; XYZ[1] = height/2; XYZ[2] = depth/2;
18450
 
      while (!disp.is_closed && !disp.key) get_coordinates(1,disp,XYZ);
 
25460
    const CImg<T>& display(const char *const title=0, const unsigned int normalization_type=1, const bool display_info=true) const {
 
25461
      if (is_empty()) throw CImgInstanceException("CImg<%s>::display() : Instance image (%u,%u,%u,%u,%p) is empty.",
 
25462
                                                  pixel_type(),width,height,depth,dim,data);
 
25463
      unsigned int oldw = 0, oldh = 0, XYZ[3], frametiming = 5, key = 0;
 
25464
      int x0 = 0, y0 = 0, z0 = 0, x1 = dimx()-1, y1 = dimy()-1, z1 = dimz()-1;
 
25465
      char ntitle[64] = { 0 }; if (!title) std::sprintf(ntitle,"CImg<%s>",pixel_type());
 
25466
      if (display_info) print(title?title:ntitle);
 
25467
      CImgDisplay disp(cimg_fitscreen(width,height,depth),title?title:ntitle,normalization_type);
 
25468
      CImg<T> zoom;
 
25469
      for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
 
25470
        if (reset_view) {
 
25471
          XYZ[0] = (x0+x1)/2; XYZ[1] = (y0+y1)/2; XYZ[2] = (z0+z1)/2;
 
25472
          x0 = 0; y0 = 0; z0 = 0; x1 = width-1; y1 = height-1; z1 = depth-1;
 
25473
          oldw = disp.width; oldh = disp.height;
 
25474
          reset_view = false;
 
25475
        }
 
25476
        if (!x0 && !y0 && !z0 && x1==dimx()-1 && y1==dimy()-1 && z1==dimz()-1) zoom.assign();
 
25477
        else zoom = get_crop(x0,y0,z0,x1,y1,z1);
 
25478
 
 
25479
        const unsigned int
 
25480
          dx = 1 + x1 - x0, dy = 1 + y1 - y0, dz = 1 + z1 - z0,
 
25481
          tw = dx + (dz>1?dz:0), th = dy + (dz>1?dz:0);
 
25482
        if (resize_disp) {
 
25483
          const unsigned int
 
25484
            ttw = tw*disp.width/oldw, tth = th*disp.height/oldh,
 
25485
            dM = cimg::max(ttw,tth), diM = cimg::max(disp.width,disp.height),
 
25486
            imgw = cimg::max(16U,ttw*diM/dM), imgh = cimg::max(16U,tth*diM/dM);
 
25487
          disp.normalscreen().resize(cimg_fitscreen(imgw,imgh,1),false);
 
25488
          resize_disp = false;
 
25489
        }
 
25490
        oldw = tw; oldh = th;
 
25491
 
 
25492
        const CImg<T>& visu = zoom?zoom:*this;
 
25493
        const CImg<int> selection = visu.get_coordinates(2,disp,XYZ,0);
 
25494
        bool go_up = false, go_down = false, go_left = false, go_right = false;
 
25495
        const int
 
25496
          sx0 = selection(0), sy0 = selection(1), sz0 = selection(2),
 
25497
          sx1 = selection(3), sy1 = selection(4), sz1 = selection(5);
 
25498
        if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) {
 
25499
          x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1; x0+=sx0; y0+=sy0; z0+=sz0;
 
25500
          if (sx0==sx1 && sy0==sy1 && sz0==sz1) reset_view = true;
 
25501
          resize_disp = true;
 
25502
        } else switch (key = disp.key) {
 
25503
        case 0: case cimg::keyCTRLLEFT: case cimg::keyPAD5: disp.key = key = 0; break;
 
25504
        case cimg::keyP: if (visu.depth>1 && disp.is_keyCTRLLEFT) { // Special mode : play stack of frames
 
25505
          const unsigned int
 
25506
            w1 = visu.width*disp.width/(visu.width+(visu.depth>1?visu.depth:0)),
 
25507
            h1 = visu.height*disp.height/(visu.height+(visu.depth>1?visu.depth:0));
 
25508
          disp.resize(cimg_fitscreen(w1,h1,1),false).key = key = 0;
 
25509
          for (unsigned int timer = 0; !key && !disp.is_closed && !disp.button; ) {
 
25510
            if (disp.is_resized) disp.resize();
 
25511
            if (!timer) {
 
25512
              visu.get_slice(XYZ[2]).display(disp.set_title("%s | z=%d",title?title:ntitle,XYZ[2]));
 
25513
              if (++XYZ[2]>=visu.depth) XYZ[2] = 0;
 
25514
            }
 
25515
            if (++timer>frametiming) timer = 0;
 
25516
            if (disp.wheel) { frametiming-=disp.wheel; disp.wheel = 0; }
 
25517
            switch (key = disp.key) {
 
25518
            case 0: case cimg::keyCTRLLEFT: disp.key = key = 0; break;
 
25519
            case cimg::keyPAGEUP: --frametiming; key = 0; break;
 
25520
            case cimg::keyPAGEDOWN: ++frametiming; key = 0; break;
 
25521
            case cimg::keyD: if (disp.is_keyCTRLLEFT) {
 
25522
              disp.normalscreen().resize(cimg_fitscreen(3*disp.width/2,3*disp.height/2,1),false);
 
25523
              disp.key = key = 0;
 
25524
            } break;
 
25525
            case cimg::keyC: if (disp.is_keyCTRLLEFT) {
 
25526
              disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false);
 
25527
              disp.key = key = 0;
 
25528
            } break;
 
25529
            case cimg::keyR: if (disp.is_keyCTRLLEFT) {
 
25530
              disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false);
 
25531
              disp.key = key = 0;
 
25532
            } break;
 
25533
            case cimg::keyF: if (disp.is_keyCTRLLEFT) {
 
25534
              disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen();
 
25535
              disp.key = key = 0;
 
25536
            } break;
 
25537
            }
 
25538
            frametiming = frametiming<1?1:(frametiming>39?39:frametiming);
 
25539
            disp.wait(20);
 
25540
          }
 
25541
          const unsigned int
 
25542
            w2 = (visu.width + (visu.depth>1?visu.depth:0))*disp.width/visu.width,
 
25543
            h2 = (visu.height + (visu.depth>1?visu.depth:0))*disp.height/visu.height;
 
25544
          disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(title?title:ntitle);
 
25545
          key = disp.key = disp.button = disp.wheel = 0;
 
25546
        } break;
 
25547
        case cimg::keyHOME: case cimg::keyBACKSPACE: reset_view = resize_disp = true; key = 0; break;
 
25548
        case cimg::keyPADADD: {
 
25549
          const int deltax = (x1-x0)/8, deltay = (y1-y0)/8, deltaz = (z1-z0)/8;
 
25550
          x0+=deltax; y0+=deltay; z0+=deltaz;
 
25551
          x1-=deltax; y1-=deltay; z1-=deltaz;
 
25552
          key = 0;
 
25553
        } break;
 
25554
        case cimg::keyPADSUB: {
 
25555
          const int
 
25556
            deltax = (x1-x0)/8, deltay = (y1-y0)/8, deltaz = (z1-z0)/8,
 
25557
            ndeltax = deltax?deltax:(width>1?1:0),
 
25558
            ndeltay = deltay?deltay:(height>1?1:0),
 
25559
            ndeltaz = deltaz?deltaz:(depth>1?1:0);
 
25560
          x0-=ndeltax; y0-=ndeltay; z0-=ndeltaz;
 
25561
          x1+=ndeltax; y1+=ndeltay; z1+=ndeltaz;
 
25562
          if (x0<0) { x1-=x0; x0 = 0; if (x1>=dimx()) x1 = dimx()-1; }
 
25563
          if (y0<0) { y1-=y0; y0 = 0; if (y1>=dimy()) y1 = dimy()-1; }
 
25564
          if (z0<0) { z1-=z0; z0 = 0; if (z1>=dimz()) z1 = dimz()-1; }
 
25565
          if (x1>=dimx()) { x0-=(x1-dimx()+1); x1 = dimx()-1; if (x0<0) x0 = 0; }
 
25566
          if (y1>=dimy()) { y0-=(y1-dimy()+1); y1 = dimy()-1; if (y0<0) y0 = 0; }
 
25567
          if (z1>=dimz()) { z0-=(z1-dimz()+1); z1 = dimz()-1; if (z0<0) z0 = 0; }
 
25568
          key = 0;
 
25569
        } break;
 
25570
        case cimg::keyARROWLEFT: case cimg::keyPAD4: go_left = true; key = 0; break;
 
25571
        case cimg::keyARROWRIGHT: case cimg::keyPAD6: go_right = true; key = 0; break;
 
25572
        case cimg::keyARROWUP: case cimg::keyPAD8: go_up = true; key = 0; break;
 
25573
        case cimg::keyARROWDOWN: case cimg::keyPAD2: go_down = true; key = 0; break;
 
25574
        case cimg::keyPAD7: go_up = go_left = true; key = 0; break;
 
25575
        case cimg::keyPAD9: go_up = go_right = true; key = 0; break;
 
25576
        case cimg::keyPAD1: go_down = go_left = true; key = 0; break;
 
25577
        case cimg::keyPAD3: go_down = go_right = true; key = 0; break;
 
25578
        case cimg::keyPAGEUP: {
 
25579
          const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
 
25580
          if (z0-ndelta>=0) { z0-=ndelta; z1-=ndelta; }
 
25581
          else { z1-=z0; z0 = 0; }
 
25582
          key = 0;
 
25583
        } break;
 
25584
        case cimg::keyPAGEDOWN: {
 
25585
          const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
 
25586
          if (z1+ndelta<dimz()) { z0+=ndelta; z1+=ndelta; }
 
25587
          else { z0+=(depth-1-z1); z1 = depth-1; }
 
25588
          key = 0;
 
25589
        } break;
 
25590
        }
 
25591
        if (go_left) {
 
25592
          const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
 
25593
          if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
 
25594
          else { x1-=x0; x0 = 0; }
 
25595
        }
 
25596
        if (go_right) {
 
25597
          const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
 
25598
          if (x1+ndelta<dimx()) { x0+=ndelta; x1+=ndelta; }
 
25599
          else { x0+=(dimx()-1-x1); x1 = dimx()-1; }
 
25600
        }
 
25601
        if (go_up) {
 
25602
          const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
 
25603
          if (y0-ndelta>=0) { y0-=ndelta; y1-=ndelta; }
 
25604
          else { y1-=y0; y0 = 0; }
 
25605
        }
 
25606
        if (go_down) {
 
25607
          const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
 
25608
          if (y1+ndelta<dimy()) { y0+=ndelta; y1+=ndelta; }
 
25609
          else { y0+=(dimy()-1-y1); y1 = dimy()-1; }
 
25610
        }
 
25611
      }
 
25612
      disp.key = key;
18451
25613
      return *this;
18452
25614
    }
18453
25615
 
18454
 
    //! Display an image in a window, with a default title. See also \see display() for details on parameters.
18455
 
    const CImg& display(const int min_size=128, const int max_size=1024, const int print_flag=1) const {
18456
 
      char title[256] = { 0 };
18457
 
      std::sprintf(title,"CImg<%s>",pixel_type());
18458
 
      return display(title,min_size,max_size,print_flag);
18459
 
    }
18460
 
 
18461
 
    //! Simple interface to select shaped from an image
 
25616
    //! Simple interface to select shaped from an image.
18462
25617
    /**
18463
25618
       \param selection  Array of 6 values containing the selection result
18464
25619
       \param coords_type Determine shape type to select (0=point, 1=vector, 2=rectangle, 3=circle)
18469
25624
    CImg<typename cimg::last<T,int>::type> get_coordinates(const int coords_type, CImgDisplay &disp,
18470
25625
                                                           unsigned int *const XYZ=0, const unsigned char *const color=0) const {
18471
25626
 
 
25627
      typedef typename cimg::last<T,unsigned char>::type uchar;
18472
25628
      if (is_empty()) throw CImgInstanceException("CImg<%s>::get_coordinates() : Instance image (%u,%u,%u,%u,%p) is empty.",
18473
25629
                                                  pixel_type(),width,height,depth,dim,data);
 
25630
      if (!disp) throw CImgArgumentException("CImg<%s>::get_coordinates() : Specified display is empty.",pixel_type());
 
25631
 
18474
25632
      const unsigned int
18475
 
        old_events = disp.events,
18476
25633
        old_normalization = disp.normalization,
18477
25634
        hatch = 0x55555555;
18478
25635
 
18479
25636
      bool old_is_resized = disp.is_resized;
18480
 
      disp.events = 3;
18481
25637
      disp.normalization = 0;
18482
25638
      disp.show().key = 0;
18483
25639
 
18484
 
      unsigned char fgcolor[] = { 255,255,105 }, bgcolor[] = { 0,0,0 };
18485
 
      if (color) std::memcpy(fgcolor,color,sizeof(unsigned char)*cimg::min(3,dimv()));
 
25640
      unsigned char foreground_color[] = { 255,255,105 }, background_color[] = { 0,0,0 };
 
25641
      if (color) std::memcpy(foreground_color,color,sizeof(unsigned char)*cimg::min(3,dimv()));
18486
25642
 
18487
25643
      int area = 0, clicked_area = 0, phase = 0,
18488
25644
        X0 = (int)((XYZ?XYZ[0]:width/2)%width), Y0 = (int)((XYZ?XYZ[1]:height/2)%height), Z0 = (int)((XYZ?XYZ[2]:depth/2)%depth),
18492
25648
      unsigned int old_button = 0, key = 0;
18493
25649
 
18494
25650
      bool shape_selected = false, text_down = false;
18495
 
      CImg<unsigned char> visu, visu0;
 
25651
      CImg<uchar> visu, visu0;
18496
25652
      char text[1024] = { 0 };
18497
25653
 
18498
25654
      while (!key && !disp.is_closed && !shape_selected) {
18507
25663
        if (mX<dimx() && mY>=dimy()) { area = 2; X = mX; Z = mY-height; Y = phase?Y1:Y0; }
18508
25664
        if (mX>=dimx() && mY<dimy()) { area = 3; Y = mY; Z = mX-width; X = phase?X1:X0; }
18509
25665
 
18510
 
        key = disp.key;
18511
 
        if (key && key!=cimg::keyCTRLLEFT) {
18512
 
          if (disp.is_key(cimg::keyCTRLLEFT,true)) {
18513
 
            switch (key) {
18514
 
            case cimg::keyARROWLEFT:
18515
 
            case cimg::keyARROWDOWN: --disp.wheel; break;
18516
 
            case cimg::keyARROWRIGHT:
18517
 
            case cimg::keyARROWUP: ++disp.wheel; break;
18518
 
            case cimg::keyD: if (disp.is_fullscreen) disp.toggle_fullscreen(); disp.resize(-200,-200); disp.is_resized = true; break;
18519
 
            case cimg::keyC: if (disp.is_fullscreen) disp.toggle_fullscreen(); disp.resize(-50,-50); disp.is_resized = true; break;
18520
 
            case cimg::keyR: if (disp.is_fullscreen) disp.toggle_fullscreen(); disp.resize(*this); disp.is_resized = true; break;
18521
 
            case cimg::keyF:
18522
 
              disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen();
18523
 
              disp.is_resized = true;
18524
 
              break;
18525
 
            case cimg::keyS: {
18526
 
              static unsigned int snap_number = 0;
18527
 
              char filename[32] = { 0 };
18528
 
              std::FILE *file;
18529
 
              do {
18530
 
                std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
18531
 
                if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
18532
 
              } while (file);
18533
 
              if (visu0) {
18534
 
                visu.draw_text(2,2,fgcolor,bgcolor,11,0.8f,"Saving snapshot...").display(disp);
18535
 
                visu0.save(filename);
18536
 
                visu.draw_text(2,2,fgcolor,bgcolor,11,0.8f,"Snapshot '%s' saved.",filename).display(disp);
18537
 
              }
18538
 
            } break;
18539
 
            default: break;
18540
 
            }
18541
 
            key = disp.key = 0;
 
25666
        switch (key = disp.key) {
 
25667
        case 0: case cimg::keyCTRLLEFT: disp.key = key = 0; break;
 
25668
        case cimg::keyPAGEUP: if (disp.is_keyCTRLLEFT) { ++disp.wheel; key = 0; } break;
 
25669
        case cimg::keyPAGEDOWN: if (disp.is_keyCTRLLEFT) { --disp.wheel; key = 0; } break;
 
25670
        case cimg::keyD: if (disp.is_keyCTRLLEFT) {
 
25671
          disp.normalscreen().resize(cimg_fitscreen(3*disp.width/2,3*disp.height/2,1)).is_resized = true;
 
25672
          disp.key = key = 0;
 
25673
        } break;
 
25674
        case cimg::keyC: if (disp.is_keyCTRLLEFT) {
 
25675
          disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1)).is_resized = true;
 
25676
          disp.key = key = 0;
 
25677
        } break;
 
25678
        case cimg::keyR: if (disp.is_keyCTRLLEFT) {
 
25679
          disp.normalscreen().resize(cimg_fitscreen(width,height,depth)).is_resized = true;
 
25680
          disp.key = key = 0;
 
25681
        } break;
 
25682
        case cimg::keyF: if (disp.is_keyCTRLLEFT) {
 
25683
          disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
 
25684
          disp.key = key = 0;
 
25685
        } break;
 
25686
        case cimg::keyS: if (disp.is_keyCTRLLEFT) {
 
25687
          static unsigned int snap_number = 0;
 
25688
          char filename[32] = { 0 };
 
25689
          std::FILE *file;
 
25690
          do {
 
25691
            std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
 
25692
            if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
 
25693
          } while (file);
 
25694
          if (visu0) {
 
25695
            visu.draw_text(2,2,foreground_color,background_color,11,0.8f,"Saving snapshot...").display(disp);
 
25696
            visu0.save(filename);
 
25697
            visu.draw_text(2,2,foreground_color,background_color,11,0.8f,"Snapshot '%s' saved.",filename).display(disp);
18542
25698
          }
18543
 
        } else key = 0;
 
25699
          disp.key = key = 0;
 
25700
        } break;
 
25701
        case cimg::keyO: if (disp.is_keyCTRLLEFT) {
 
25702
          static unsigned int snap_number = 0;
 
25703
          char filename[32] = { 0 };
 
25704
          std::FILE *file;
 
25705
          do {
 
25706
            std::sprintf(filename,"CImg_%.4u.cimg",snap_number++);
 
25707
            if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
 
25708
          } while (file);
 
25709
          visu.draw_text(2,2,foreground_color,background_color,11,0.8f,"Saving instance...").display(disp);
 
25710
          save(filename);
 
25711
          visu.draw_text(2,2,foreground_color,background_color,11,0.8f,"Instance '%s' saved.",filename).display(disp);
 
25712
          disp.key = key = 0;
 
25713
        } break;
 
25714
        }
18544
25715
 
18545
25716
        if (!area) mx = my = X = Y = Z = -1;
18546
25717
        else {
18582
25753
          }
18583
25754
        }
18584
25755
 
18585
 
        if (X0<0) X0 = 0; if (X0>=(int)width) X0 = (int)width-1; if (Y0<0) Y0 = 0; if (Y0>=(int)height) Y0 = (int)height-1;
18586
 
        if (Z0<0) Z0 = 0; if (Z0>=(int)depth) Z0 = (int)depth-1;
18587
 
        if (X1<1) X1 = 0; if (X1>=(int)width) X1 = (int)width-1; if (Y1<0) Y1 = 0; if (Y1>=(int)height) Y1 = (int)height-1;
18588
 
        if (Z1<0) Z1 = 0; if (Z1>=(int)depth) Z1 = (int)depth-1;
 
25756
        if (X0<0) X0 = 0; if (X0>=dimx()) X0 = dimx()-1; if (Y0<0) Y0 = 0; if (Y0>=dimy()) Y0 = dimy()-1;
 
25757
        if (Z0<0) Z0 = 0; if (Z0>=dimz()) Z0 = dimz()-1;
 
25758
        if (X1<1) X1 = 0; if (X1>=dimx()) X1 = dimx()-1; if (Y1<0) Y1 = 0; if (Y1>=dimy()) Y1 = dimy()-1;
 
25759
        if (Z1<0) Z1 = 0; if (Z1>=dimz()) Z1 = dimz()-1;
18589
25760
 
18590
25761
        // Draw visualization image on the display
18591
25762
        if (oX!=X || oY!=Y || oZ!=Z || !visu0) {
18592
25763
          if (!visu0) {
18593
 
            CImg<T> tmp0 = get_shared_channels(0,cimg::min(2U,dim-1)), tmp;
18594
 
            if (depth!=1) tmp = (!phase?tmp0.get_projections2d(X0,Y0,Z0):tmp0.get_projections2d(X1,Y1,Z1)).resize(disp.width,disp.height,1,3);
18595
 
            else tmp = tmp0.get_resize(disp.width,disp.height,1,3);
18596
 
            if (old_normalization) {
18597
 
              if (old_normalization<3 || cimg::type<T>::is_float()) {
18598
 
                if (sizeof(T)>1) visu0.assign(tmp.normalize(0,255));
18599
 
                else visu0.assign(tmp).normalize(0,255);
18600
 
              } else {
18601
 
                if (cimg::type<T>::id()!=cimg::type<unsigned char>::id()) {
18602
 
                  const float m = cimg::type<T>::min(), M = cimg::type<T>::max();
18603
 
                  visu0.assign((CImg<float>(tmp)-=m)*=255.0f/(M-m));
18604
 
                } else visu0.assign(tmp);
18605
 
              }
18606
 
            } else visu0.assign(tmp);
 
25764
            CImg<Tuchar> tmp, tmp0;
 
25765
            if (depth!=1) {
 
25766
              tmp0 = (!phase)?get_projections2d(X0,Y0,Z0):get_projections2d(X1,Y1,Z1);
 
25767
              tmp = tmp0.get_channels(0,cimg::min(2U,dim-1));
 
25768
            } else tmp = get_channels(0,cimg::min(2U,dim-1));
 
25769
            switch (old_normalization) {
 
25770
            case 0: visu0 = tmp; break;
 
25771
            case 3:
 
25772
              if (cimg::type<T>::is_float()) visu0 = tmp.normalize(0,(T)255);
 
25773
              else {
 
25774
                const float m = (float)cimg::type<T>::min(), M = (float)cimg::type<T>::max();
 
25775
                visu0.assign(tmp.width,tmp.height,1,tmp.dim);
 
25776
                unsigned char *ptrd = visu0.end();
 
25777
                cimg_for(tmp,ptrs,Tuchar) *(--ptrd) = (unsigned char)((*ptrs-m)*255.0f/(M-m));
 
25778
              } break;
 
25779
            default: visu0 = tmp.normalize(0,255); break;
 
25780
            }
 
25781
            visu0.resize(disp);
18607
25782
          }
18608
25783
          visu = visu0;
18609
25784
          if (!color) {
18610
 
            const CImgStats st(visu,false);
18611
 
            if (st.mean<200) { fgcolor[0] = fgcolor[1] = fgcolor[2] = 255; bgcolor[0] = bgcolor[1] = bgcolor[2] = 0; }
18612
 
            else { fgcolor[0] = fgcolor[1] = fgcolor[2] = 0; bgcolor[0] = bgcolor[1] = bgcolor[2] = 255; }
 
25785
            if (visu.mean()<200) {
 
25786
              foreground_color[0] = foreground_color[1] = foreground_color[2] = 255;
 
25787
              background_color[0] = background_color[1] = background_color[2] = 0;
 
25788
            } else {
 
25789
              foreground_color[0] = foreground_color[1] = foreground_color[2] = 0;
 
25790
              background_color[0] = background_color[1] = background_color[2] = 255;
 
25791
            }
18613
25792
          }
18614
25793
 
18615
 
          const int d=(depth>1)?depth:0;
 
25794
          const int d = (depth>1)?depth:0;
18616
25795
          if (phase) switch (coords_type) {
18617
25796
          case 1: {
18618
25797
            const int
18619
 
              x0=(int)((X0+0.5f)*disp.width/(width+d)), y0=(int)((Y0+0.5f)*disp.height/(height+d)),
18620
 
              x1=(int)((X1+0.5f)*disp.width/(width+d)), y1=(int)((Y1+0.5f)*disp.height/(height+d));
18621
 
            visu.draw_arrow(x0,y0,x1,y1,fgcolor,30.0f,5.0f,1.0f,hatch);
 
25798
              x0 =(int)((X0+0.5f)*disp.width/(width+d)), y0 = (int)((Y0+0.5f)*disp.height/(height+d)),
 
25799
              x1 =(int)((X1+0.5f)*disp.width/(width+d)), y1 = (int)((Y1+0.5f)*disp.height/(height+d));
 
25800
            visu.draw_arrow(x0,y0,x1,y1,foreground_color,30.0f,5.0f,1.0f,hatch);
18622
25801
            if (d) {
18623
 
              const int zx0=(int)((width+Z0+0.5f)*disp.width/(width+d)), zx1=(int)((width+Z1+0.5f)*disp.width/(width+d)),
18624
 
                zy0=(int)((height+Z0+0.5f)*disp.height/(height+d)), zy1=(int)((height+Z1+0.5f)*disp.height/(height+d));
18625
 
              visu.draw_arrow(zx0,y0,zx1,y1,fgcolor,30.0f,5.0f,1.0f,hatch).draw_arrow(x0,zy0,x1,zy1,fgcolor,30.0f,5.0f,1.0f,hatch);
 
25802
              const int
 
25803
                zx0 = (int)((width+Z0+0.5f)*disp.width/(width+d)), zx1 = (int)((width+Z1+0.5f)*disp.width/(width+d)),
 
25804
                zy0 = (int)((height+Z0+0.5f)*disp.height/(height+d)), zy1 = (int)((height+Z1+0.5f)*disp.height/(height+d));
 
25805
              visu.draw_arrow(zx0,y0,zx1,y1,foreground_color,30.0f,5.0f,1.0f,hatch).
 
25806
                draw_arrow(x0,zy0,x1,zy1,foreground_color,30.0f,5.0f,1.0f,hatch);
18626
25807
            }
18627
25808
          } break;
18628
25809
          case 2: {
18631
25812
              y0=(Y0<Y1?Y0:Y1)*disp.height/(height+d),
18632
25813
              x1=((X0<X1?X1:X0)+1)*disp.width/(width+d)-1,
18633
25814
              y1=((Y0<Y1?Y1:Y0)+1)*disp.height/(height+d)-1;
18634
 
            visu.draw_rectangle(x0,y0,x1,y1,fgcolor,0.2f).draw_line(x0,y0,x1,y0,fgcolor,1.0f,hatch).
18635
 
              draw_line(x1,y0,x1,y1,fgcolor,1.0f,hatch).draw_line(x1,y1,x0,y1,fgcolor,1.0f,hatch).
18636
 
              draw_line(x0,y1,x0,y0,fgcolor,1.0f,hatch);
 
25815
            visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.2f).draw_line(x0,y0,x1,y0,foreground_color,1.0f,hatch).
 
25816
              draw_line(x1,y0,x1,y1,foreground_color,1.0f,hatch).draw_line(x1,y1,x0,y1,foreground_color,1.0f,hatch).
 
25817
              draw_line(x0,y1,x0,y0,foreground_color,1.0f,hatch);
18637
25818
            if (d) {
18638
25819
              const int
18639
25820
                zx0=(int)((width+(Z0<Z1?Z0:Z1))*disp.width/(width+d)),
18640
25821
                zy0=(int)((height+(Z0<Z1?Z0:Z1))*disp.height/(height+d)),
18641
25822
                zx1=(int)((width+(Z0<Z1?Z1:Z0)+1)*disp.width/(width+d))-1,
18642
25823
                zy1=(int)((height+(Z0<Z1?Z1:Z0)+1)*disp.height/(height+d))-1;
18643
 
              visu.draw_rectangle(zx0,y0,zx1,y1,fgcolor,0.2f).draw_line(zx0,y0,zx1,y0,fgcolor,1.0f,hatch).
18644
 
                draw_line(zx1,y0,zx1,y1,fgcolor,1.0f,hatch).draw_line(zx1,y1,zx0,y1,fgcolor,1.0f,hatch).
18645
 
                draw_line(zx0,y1,zx0,y0,fgcolor,1.0f,hatch);
18646
 
              visu.draw_rectangle(x0,zy0,x1,zy1,fgcolor,0.2f).draw_line(x0,zy0,x1,zy0,fgcolor,1.0f,hatch).
18647
 
                draw_line(x1,zy0,x1,zy1,fgcolor,1.0f,hatch).draw_line(x1,zy1,x0,zy1,fgcolor,1.0f,hatch).
18648
 
                draw_line(x0,zy1,x0,zy0,fgcolor,1.0f,hatch);
 
25824
              visu.draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.2f).draw_line(zx0,y0,zx1,y0,foreground_color,1.0f,hatch).
 
25825
                draw_line(zx1,y0,zx1,y1,foreground_color,1.0f,hatch).draw_line(zx1,y1,zx0,y1,foreground_color,1.0f,hatch).
 
25826
                draw_line(zx0,y1,zx0,y0,foreground_color,1.0f,hatch);
 
25827
              visu.draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.2f).draw_line(x0,zy0,x1,zy0,foreground_color,1.0f,hatch).
 
25828
                draw_line(x1,zy0,x1,zy1,foreground_color,1.0f,hatch).draw_line(x1,zy1,x0,zy1,foreground_color,1.0f,hatch).
 
25829
                draw_line(x0,zy1,x0,zy0,foreground_color,1.0f,hatch);
18649
25830
            }
18650
25831
          } break;
18651
25832
          case 3: {
18654
25835
              y0=Y0*disp.height/(height+d),
18655
25836
              x1=X1*disp.width/(width+d)-1,
18656
25837
              y1=Y1*disp.height/(height+d)-1;
18657
 
            visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,fgcolor,0.2f).
18658
 
              draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,fgcolor,1.0f,hatch);
 
25838
            visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,foreground_color,0.2f).
 
25839
              draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,foreground_color,1.0f,hatch);
18659
25840
            if (d) {
18660
25841
              const int
18661
25842
                zx0=(int)((width+Z0)*disp.width/(width+d)),
18662
25843
                zy0=(int)((height+Z0)*disp.height/(height+d)),
18663
25844
                zx1=(int)((width+Z1+1)*disp.width/(width+d))-1,
18664
25845
                zy1=(int)((height+Z1+1)*disp.height/(height+d))-1;
18665
 
              visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,fgcolor,0.2f).
18666
 
                draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,fgcolor,1.0f,hatch).
18667
 
                draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,fgcolor,0.2f).
18668
 
                draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,fgcolor,1.0f,hatch);
 
25846
              visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,foreground_color,0.2f).
 
25847
                draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,foreground_color,1.0f,hatch).
 
25848
                draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,foreground_color,0.2f).
 
25849
                draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,foreground_color,1.0f,hatch);
18669
25850
            }
18670
25851
          } break;
18671
25852
          }
18673
25854
          if (my<12) text_down = true;
18674
25855
          if (my>=visu.dimy()-11) text_down = false;
18675
25856
          if (!coords_type || !phase) {
18676
 
            if (X>=0 && Y>=0 && Z>=0 && X<(int)width && Y<(int)height && Z<(int)depth) {
 
25857
            if (X>=0 && Y>=0 && Z>=0 && X<dimx() && Y<dimy() && Z<dimz()) {
18677
25858
              if (depth>1) std::sprintf(text,"Point (%d,%d,%d)={ ",X,Y,Z); else std::sprintf(text,"Point (%d,%d)={ ",X,Y);
18678
 
              char *ctext = text + cimg::strlen(text), *const ltext = text+512;
 
25859
              char *ctext = text + cimg::strlen(text), *const ltext = text + 512;
18679
25860
              for (unsigned int k=0; k<dim && ctext<ltext; ++k) {
18680
 
                std::sprintf(ctext,"%g ",(double)(*this)(X,Y,Z,k));
 
25861
                std::sprintf(ctext,cimg::type<T>::format(),cimg::type<T>::format((*this)(X,Y,Z,k)));
18681
25862
                ctext = text + cimg::strlen(text);
 
25863
                *(ctext++) = ' '; *ctext = '\0';
18682
25864
              }
18683
 
              std::sprintf(text+cimg::strlen(text),"}");
 
25865
              std::sprintf(text + cimg::strlen(text),"}");
18684
25866
            }
18685
25867
          } else switch (coords_type) {
18686
25868
          case 1: {
18687
 
            const double dX=(double)(X0-X1), dY=(double)(Y0-Y1), dZ=(double)(Z0-Z1), norm = std::sqrt(dX*dX+dY*dY+dZ*dZ);
 
25869
            const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), norm = std::sqrt(dX*dX+dY*dY+dZ*dZ);
18688
25870
            if (depth>1) std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), norm=%g",X0,Y0,Z0,X1,Y1,Z1,norm);
18689
25871
            else std::sprintf(text,"Vect (%d,%d)-(%d,%d), norm=%g",X0,Y0,X1,Y1,norm);
18690
25872
          } break;
18704
25886
 
18705
25887
            break;
18706
25888
          }
18707
 
          if (phase || (mx>=0 && my>=0)) visu.draw_text(text,0,text_down?visu.dimy()-11:0,fgcolor,bgcolor,11,0.7f);
 
25889
          if (phase || (mx>=0 && my>=0)) visu.draw_text(text,0,text_down?visu.dimy()-11:0,foreground_color,background_color,11,0.7f);
18708
25890
          disp.display(visu).wait(25);
18709
 
        } else disp.wait();
 
25891
        } else if (!shape_selected) disp.wait();
18710
25892
 
18711
25893
        if (disp.is_resized) { disp.resize(false); old_is_resized = true; disp.is_resized = false; visu0.assign(); }
18712
25894
      }
18713
25895
 
18714
25896
      // Return result
18715
 
      typedef typename cimg::last<T,int>::type restype;
18716
 
      CImg<restype> res(1,6,1,1,(restype)-1);
 
25897
      typedef typename cimg::last<T,int>::type type_int;
 
25898
      CImg<type_int> res(1,6,1,1,-1);
18717
25899
      if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; }
18718
25900
      if (shape_selected) {
18719
25901
        if (coords_type==2) {
18722
25904
          if (Z0>Z1) cimg::swap(Z0,Z1);
18723
25905
        }
18724
25906
        if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1;
18725
 
        switch(coords_type) {
 
25907
        switch (coords_type) {
18726
25908
        case 1:
18727
 
        case 2:  res[3] = (restype)X1; res[4] = (restype)Y1; res[5] = (restype)Z1;
18728
 
        default: res[0] = (restype)X0; res[1] = (restype)Y0; res[2] = (restype)Z0;
 
25909
        case 2:  res[3] = X1; res[4] = Y1; res[5] = Z1;
 
25910
        default: res[0] = X0; res[1] = Y0; res[2] = Z0;
18729
25911
        }
18730
25912
      }
18731
25913
      disp.button = 0;
18732
 
      disp.events = old_events;
18733
25914
      disp.normalization = old_normalization;
18734
25915
      disp.is_resized = old_is_resized;
18735
25916
      disp.key = key;
18736
25917
      return res;
18737
25918
    }
18738
25919
 
18739
 
    //! High-level interface to select features in images
 
25920
    //! High-level interface to select features in images.
18740
25921
    CImg<typename cimg::last<T,int>::type> get_coordinates(const int coords_type=0,
18741
25922
                                                           unsigned int *const XYZ=0, const unsigned char *const color=0) const {
18742
 
      unsigned int w = width + (depth>1?depth:0), h = height + (depth>1?depth:0);
18743
 
      const unsigned int dmin = cimg::min(w,h), minsiz = 256;
18744
 
      if (dmin<minsiz) { w=w*minsiz/dmin; h=h*minsiz/dmin; }
18745
 
      const unsigned int dmax = cimg::max(w,h), maxsiz = 1024;
18746
 
      if (dmax>maxsiz) { w=w*maxsiz/dmax; h=h*maxsiz/dmax; }
18747
 
      CImgDisplay disp(w,h," ",1,3);
 
25923
      CImgDisplay disp(cimg_fitscreen(width,height,depth),"");
18748
25924
      return get_coordinates(coords_type,disp,XYZ,color);
18749
25925
    }
18750
25926
 
18751
 
    //! High-level interface for displaying a 3d object
18752
 
    template<typename tp, typename tf, typename to>
18753
 
    const CImg& display_object3d(const CImg<tp>& points, const CImgList<tf>& primitives,
18754
 
                                 const CImgList<T>& colors, const CImgList<to>& opacities, CImgDisplay& disp,
18755
 
                                 const bool centering=true,
18756
 
                                 const int render_static=4, const int render_motion=1,
18757
 
                                 const bool double_sided=false,
18758
 
                                 const float focale=500.0f, const float ambient_light=0.05f,
18759
 
                                 const bool display_axes=true, float *const pose_matrix=0) const {
 
25927
    CImg<T>& coordinates(const int coords_type=0, unsigned int *const XYZ=0, const unsigned char *const color=0) {
 
25928
      return get_coordinates(coords_type,XYZ,color).transfer_to(*this);
 
25929
    }
 
25930
 
 
25931
    //! High-level interface for displaying a 3d object.
 
25932
    template<typename tp, typename tf, typename tc, typename to>
 
25933
    const CImg<T>& display_object3d(const CImg<tp>& points, const CImgList<tf>& primitives,
 
25934
                                    const CImgList<tc>& colors, const CImgList<to>& opacities, CImgDisplay& disp,
 
25935
                                    const bool centering=true,
 
25936
                                    const int render_static=4, const int render_motion=1,
 
25937
                                    const bool double_sided=false, const float focale=500.0f,
 
25938
                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 
25939
                                    const bool display_axes=true, float *const pose_matrix=0) const {
18760
25940
 
18761
25941
      // Check input arguments
18762
25942
      if (!points || !primitives || !opacities)
18765
25945
      if (is_empty())
18766
25946
        return CImg<T>(disp.width,disp.height,1,colors[0].size(),0).
18767
25947
          display_object3d(points,primitives,colors,opacities,disp,centering,
18768
 
                           render_static,render_motion,double_sided,focale,ambient_light,
 
25948
                           render_static,render_motion,double_sided,focale,specular_light,specular_shine,
18769
25949
                           display_axes,pose_matrix);
18770
25950
      if (points.height<3)
18771
25951
        return display_object3d(points.get_resize(-100,3,1,1,0),primitives,colors,opacities,disp,
18772
 
                                centering,render_static,render_motion,double_sided,focale,ambient_light,
 
25952
                                centering,render_static,render_motion,double_sided,focale,specular_light,specular_shine,
18773
25953
                                display_axes,pose_matrix);
18774
25954
 
 
25955
      const CImgList<tc> tcolors(CImg<tc>::vector(200,200,200)), &ncolors = colors?colors:tcolors;
 
25956
 
18775
25957
      // Init 3D objects and compute object statistics
18776
25958
      CImg<float> pose, rot_mat,
18777
25959
        centered_points = centering?CImg<float>(points.width,3):CImg<float>(),
18781
25963
      CImgList<to> bbox_opacities, axes_opacities;
18782
25964
      CImgList<T> bbox_colors, axes_colors;
18783
25965
      CImgList<tf> bbox_primitives, axes_primitives;
18784
 
      float nambient = ambient_light, dx = 0, dy = 0, dz = 0, ratio = 1;
 
25966
      float dx = 0, dy = 0, dz = 0, ratio = 1;
18785
25967
 
18786
25968
      T minval = (T)0, maxval = (T)255;
18787
 
      if (disp.normalization) {
18788
 
        const CImgStats st(colors,false);
18789
 
        minval = (T)st.min;
18790
 
        maxval = (T)st.max;
18791
 
      }
18792
 
      const CImgStats st(*this,false);
 
25969
      if (disp.normalization) minval = ncolors.minmax(maxval);
 
25970
      const float meanval = (float)mean();
18793
25971
      bool color_model = true;
18794
25972
 
18795
 
      if (cimg::abs(st.mean-minval)>cimg::abs(st.mean-maxval)) color_model = false;
 
25973
      if (cimg::abs(meanval-minval)>cimg::abs(meanval-maxval)) color_model = false;
18796
25974
      const CImg<T>
18797
 
        bgcolor(1,1,1,dim,color_model?minval:maxval),
18798
 
        fgcolor(1,1,1,dim,color_model?maxval:minval);
18799
 
      const CImgStats
18800
 
        sx(points.get_shared_line(0),false),
18801
 
        sy(points.get_shared_line(1),false),
18802
 
        sz(points.get_shared_line(2),false);
18803
 
      const float
18804
 
        xm = (float)sx.min, xM = (float)sx.max,
18805
 
        ym = (float)sy.min, yM = (float)sy.max,
18806
 
        zm = (float)sz.min, zM = (float)sz.max,
 
25975
        background_color(1,1,1,dim,color_model?minval:maxval),
 
25976
        foreground_color(1,1,1,dim,color_model?maxval:minval);
 
25977
      float
 
25978
        xm, xM = (float)points.get_shared_line(0).maxmin(xm),
 
25979
        ym, yM = (float)points.get_shared_line(1).maxmin(ym),
 
25980
        zm, zM = (float)points.get_shared_line(2).maxmin(zm),
18807
25981
        delta = cimg::max(xM-xm,yM-ym,zM-zm);
18808
25982
 
18809
25983
      if (display_axes) {
18810
25984
        axes_points.assign(7,3);
18811
25985
        rotated_axes_points.assign(7,3);
18812
25986
        axes_opacities.assign(3,1,1,1,1,1.0f);
18813
 
        axes_colors.assign(3,dim,1,1,1,fgcolor[0]);
 
25987
        axes_colors.assign(3,dim,1,1,1,foreground_color[0]);
18814
25988
        axes_points(0,0) = 0; axes_points(0,1) = 0; axes_points(0,2) = 0;
18815
25989
        axes_points(1,0) = 20; axes_points(1,1) = 0; axes_points(1,2) = 0;
18816
25990
        axes_points(2,0) = 0; axes_points(2,1) = 20; axes_points(2,2) = 0;
18828
26002
      bool init = true, clicked = false, redraw = true;
18829
26003
      unsigned int key = 0;
18830
26004
      int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
18831
 
      const unsigned int old_events = disp.events;
18832
26005
      disp.show().button = disp.key = 0;
18833
 
      disp.events = 3;
18834
26006
 
18835
26007
      while (!disp.is_closed && !key) {
18836
26008
 
18847
26019
          }
18848
26020
 
18849
26021
          if (render_static<0 || render_motion<0) {
18850
 
            bbox_colors.assign(12,dim,1,1,1,fgcolor[0]);
 
26022
            bbox_colors.assign(12,dim,1,1,1,foreground_color[0]);
18851
26023
            bbox_primitives.assign(12,1,2);
18852
26024
            bbox_points.assign(8,3);
18853
26025
            rotated_bbox_points.assign(8,3);
18859
26031
            bbox_points(5,0) = xM; bbox_points(5,1) = ym; bbox_points(5,2) = zM;
18860
26032
            bbox_points(6,0) = xM; bbox_points(6,1) = yM; bbox_points(6,2) = zM;
18861
26033
            bbox_points(7,0) = xm; bbox_points(7,1) = yM; bbox_points(7,2) = zM;
18862
 
            bbox_primitives[0].fill(0,1); bbox_primitives[1].fill(1,2); bbox_primitives[2].fill(2,3); bbox_primitives[3].fill(3,0);
 
26034
            bbox_primitives[0].fill(0U,1); bbox_primitives[1].fill(1,2); bbox_primitives[2].fill(2,3); bbox_primitives[3].fill(3,0);
18863
26035
            bbox_primitives[4].fill(4,5); bbox_primitives[5].fill(5,6); bbox_primitives[6].fill(6,7); bbox_primitives[7].fill(7,4);
18864
 
            bbox_primitives[8].fill(0,4); bbox_primitives[9].fill(1,5); bbox_primitives[10].fill(2,6); bbox_primitives[11].fill(3,7);
 
26036
            bbox_primitives[8].fill(0U,4); bbox_primitives[9].fill(1,5); bbox_primitives[10].fill(2,6); bbox_primitives[11].fill(3,7);
18865
26037
            bbox_opacities.assign(bbox_primitives.size,1,1,1,1,1.0f);
18866
26038
          }
18867
26039
 
18910
26082
          if ((clicked && render_motion<0) || (!clicked && render_static<0))
18911
26083
            visu.draw_object3d(visu.width/2.0f, visu.height/2.0f, 0,
18912
26084
                               rotated_bbox_points,bbox_primitives,bbox_colors,bbox_opacities,1,
18913
 
                               false,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000.0f,0.2f);
 
26085
                               false,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000.0f,specular_light,0.2f);
18914
26086
          else visu.draw_object3d(visu.width/2.0f, visu.height/2.0f, 0,
18915
 
                                  rotated_points,primitives,colors,opacities,clicked?render_motion:render_static,
18916
 
                                  double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000.0f,nambient);
 
26087
                                  rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
 
26088
                                  double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000.0f,specular_light,specular_shine);
18917
26089
 
18918
26090
          // Draw axes
18919
26091
          if (display_axes) {
18928
26100
            axes_opacities(1,0) = (rotated_axes_points(2,2)>0)?0.5f:1.0f;
18929
26101
            axes_opacities(2,0) = (rotated_axes_points(3,2)>0)?0.5f:1.0f;
18930
26102
            visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_points,axes_primitives,axes_colors,axes_opacities,1,false,focale,0,0,0,0).
18931
 
              draw_text("X",(int)(Xaxes+rotated_axes_points(4,0)), (int)(Yaxes+rotated_axes_points(4,1)), axes_colors[0].ptr(), 0, 11, axes_opacities(0,0)).
18932
 
              draw_text("Y",(int)(Xaxes+rotated_axes_points(5,0)), (int)(Yaxes+rotated_axes_points(5,1)), axes_colors[1].ptr(), 0, 11, axes_opacities(1,0)).
18933
 
              draw_text("Z",(int)(Xaxes+rotated_axes_points(6,0)), (int)(Yaxes+rotated_axes_points(6,1)), axes_colors[2].ptr(), 0, 11, axes_opacities(2,0));
 
26103
              draw_text("X",(int)(Xaxes+rotated_axes_points(4,0)), (int)(Yaxes+rotated_axes_points(4,1)), axes_colors[0].data, (T*)0, 11, axes_opacities(0,0)).
 
26104
              draw_text("Y",(int)(Xaxes+rotated_axes_points(5,0)), (int)(Yaxes+rotated_axes_points(5,1)), axes_colors[1].data, (T*)0, 11, axes_opacities(1,0)).
 
26105
              draw_text("Z",(int)(Xaxes+rotated_axes_points(6,0)), (int)(Yaxes+rotated_axes_points(6,1)), axes_colors[2].data, (T*)0, 11, axes_opacities(2,0));
18934
26106
          }
18935
26107
          visu.display(disp);
18936
26108
          if (!clicked || render_motion==render_static) redraw = false;
18974
26146
          if ((disp.button&1) && (disp.button&2)) { init = true; disp.button = 0; x0 = x1; y0 = y1; pose = CImg<float>::identity_matrix(4); }
18975
26147
        } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; }
18976
26148
 
18977
 
        key = disp.key;
18978
 
        if (key && key!=cimg::keyCTRLLEFT && key!=cimg::keyCTRLRIGHT) {
18979
 
          if (disp.is_key(cimg::keyCTRLLEFT,true) || disp.is_key(cimg::keyCTRLRIGHT,true)) {
18980
 
            switch (key) {
18981
 
            case cimg::keyPAGEDOWN: nambient-=0.1f; if (nambient<-2) nambient = -2; redraw = true; break;
18982
 
            case cimg::keyPAGEUP:   nambient+=0.1f; if (nambient>2) nambient = 2; redraw = true; break;
18983
 
            case cimg::keyD: if (disp.is_fullscreen) disp.toggle_fullscreen(); disp.resize(-200,-200); disp.is_resized = true; break;
18984
 
            case cimg::keyC: if (disp.is_fullscreen) disp.toggle_fullscreen(); disp.resize(-50,-50); disp.is_resized = true; break;
18985
 
            case cimg::keyR: if (disp.is_fullscreen) disp.toggle_fullscreen(); disp.resize(*this); disp.is_resized = true; break;
18986
 
            case cimg::keyF: disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true; break;
18987
 
            case cimg::keyS: { // Save snapshot
18988
 
              static unsigned int snap_number = 0;
18989
 
              char filename[32] = { 0 };
18990
 
              std::FILE *file;
18991
 
              do {
18992
 
                std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
18993
 
                if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
18994
 
              } while (file);
18995
 
              (+visu).draw_text(2,2,fgcolor.ptr(),bgcolor.ptr(),11,1.0f,"Saving snapshot...",filename).display(disp);
18996
 
              visu.save(filename);
18997
 
              visu.draw_text(2,2,fgcolor.ptr(),bgcolor.ptr(),11,1.0f,"Snapshot '%s' saved.",filename).display(disp);
18998
 
            } break;
18999
 
            case cimg::keyO: { // Save object as an .OFF file
19000
 
              static unsigned int snap_number = 0;
19001
 
              char filename[32] = { 0 };
19002
 
              std::FILE *file;
19003
 
              do {
19004
 
                std::sprintf(filename,"CImg_%.4u.off",snap_number++);
19005
 
                if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
19006
 
              } while (file);
19007
 
              visu.draw_text(2,2,fgcolor.ptr(),bgcolor.ptr(),11,1.0f,"Saving object...",filename).display(disp);
19008
 
              points.save_off(filename,primitives,colors);
19009
 
              visu.draw_text(2,2,fgcolor.ptr(),bgcolor.ptr(),11,1.0f,"Object '%s' saved.",filename).display(disp);
19010
 
            } break;
19011
 
            }
19012
 
            disp.key = key = 0;
19013
 
          }
19014
 
        } else key = 0;
 
26149
        switch (key = disp.key) {
 
26150
        case 0: case cimg::keyCTRLLEFT: disp.key = key = 0; break;
 
26151
        case cimg::keyD: if (disp.is_keyCTRLLEFT) {
 
26152
          disp.normalscreen().resize(cimg_fitscreen(3*disp.width/2,3*disp.height/2,1),false).is_resized = true;
 
26153
          disp.key = key = 0;
 
26154
        } break;
 
26155
        case cimg::keyC: if (disp.is_keyCTRLLEFT) {
 
26156
          disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
 
26157
          disp.key = key = 0;
 
26158
        } break;
 
26159
        case cimg::keyR: if (disp.is_keyCTRLLEFT) {
 
26160
          disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false).is_resized = true;
 
26161
          disp.key = key = 0;
 
26162
        } break;
 
26163
        case cimg::keyF: if (disp.is_keyCTRLLEFT) {
 
26164
          disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
 
26165
          disp.key = key = 0;
 
26166
        } break;
 
26167
        case cimg::keyS: if (disp.is_keyCTRLLEFT) { // Save snapshot
 
26168
          static unsigned int snap_number = 0;
 
26169
          char filename[32] = { 0 };
 
26170
          std::FILE *file;
 
26171
          do {
 
26172
            std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
 
26173
            if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
 
26174
          } while (file);
 
26175
          (+visu).draw_text(2,2,foreground_color,background_color,11,1.0f,"Saving BMP snapshot...").display(disp);
 
26176
          visu.save(filename);
 
26177
          visu.draw_text(2,2,foreground_color,background_color,11,1.0f,"Snapshot '%s' saved.",filename).display(disp);
 
26178
          disp.key = key = 0;
 
26179
        } break;
 
26180
        case cimg::keyO: if (disp.is_keyCTRLLEFT) { // Save object as an .OFF file
 
26181
          static unsigned int snap_number = 0;
 
26182
          char filename[32] = { 0 };
 
26183
          std::FILE *file;
 
26184
          do {
 
26185
            std::sprintf(filename,"CImg_%.4u.off",snap_number++);
 
26186
            if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
 
26187
          } while (file);
 
26188
          visu.draw_text(2,2,foreground_color,background_color,11,1.0f,"Saving object...").display(disp);
 
26189
          points.save_off(filename,primitives,ncolors);
 
26190
          visu.draw_text(2,2,foreground_color,background_color,11,1.0f,"Object '%s' saved.",filename).display(disp);
 
26191
          disp.key = key = 0;
 
26192
        } break;
 
26193
#ifdef cimg_use_board
 
26194
        case cimg::keyP: if (disp.is_keyCTRLLEFT) { // Save object as a .EPS file
 
26195
          static unsigned int snap_number = 0;
 
26196
          char filename[32] = { 0 };
 
26197
          std::FILE *file;
 
26198
          do {
 
26199
            std::sprintf(filename,"CImg_%.4u.eps",snap_number++);
 
26200
            if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
 
26201
          } while (file);
 
26202
          visu.draw_text(2,2,foreground_color,background_color,11,1.0f,"Saving EPS snapshot...").display(disp);
 
26203
          BoardLib::Board board;
 
26204
          (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
 
26205
                                rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
 
26206
                                double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000.0f,specular_light,specular_shine);
 
26207
          board.saveEPS(filename);
 
26208
          visu.draw_text(2,2,foreground_color,background_color,11,1.0f,"Object '%s' saved.",filename).display(disp);
 
26209
          disp.key = key = 0;
 
26210
        } break;
 
26211
        case cimg::keyV: if (disp.is_keyCTRLLEFT) { // Save object as a .SVG file
 
26212
          static unsigned int snap_number = 0;
 
26213
          char filename[32] = { 0 };
 
26214
          std::FILE *file;
 
26215
          do {
 
26216
            std::sprintf(filename,"CImg_%.4u.svg",snap_number++);
 
26217
            if ((file=std::fopen(filename,"r"))!=0) std::fclose(file);
 
26218
          } while (file);
 
26219
          visu.draw_text(2,2,foreground_color,background_color,11,1.0f,"Saving SVG snapshot...").display(disp);
 
26220
          BoardLib::Board board;
 
26221
          (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
 
26222
                                rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
 
26223
                                double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000.0f,specular_light,specular_shine);
 
26224
          board.saveSVG(filename);
 
26225
          visu.draw_text(2,2,foreground_color,background_color,11,1.0f,"Object '%s' saved.",filename).display(disp);
 
26226
          disp.key = key = 0;
 
26227
        } break;
 
26228
#endif
 
26229
        }
19015
26230
        if (disp.is_resized) { disp.resize(false); visu0 = get_resize(disp,1); redraw = true; }
19016
26231
      }
19017
26232
      if (pose_matrix) std::memcpy(pose_matrix,pose.data,16*sizeof(float));
19018
 
      disp.events = old_events;
19019
26233
      disp.button = 0;
 
26234
      disp.key = key;
19020
26235
      return *this;
19021
26236
    }
19022
26237
 
19023
 
    //! High-level interface for displaying a 3d object
19024
 
    template<typename tp, typename tf, typename to>
19025
 
    const CImg& display_object3d(const CImgList<tp>& points, const CImgList<tf>& primitives,
19026
 
                                 const CImgList<T>& colors, const CImgList<to>& opacities, CImgDisplay &disp,
19027
 
                                 const bool centering=true,
19028
 
                                 const int render_static=4, const int render_motion=1,
19029
 
                                 const bool double_sided=false,
19030
 
                                 const float focale=500.0f, const float ambient_light=0.05f,
19031
 
                                 const bool display_axes=true, float *const pose_matrix=0) const {
 
26238
    //! High-level interface for displaying a 3d object.
 
26239
    template<typename tp, typename tf, typename tc, typename to>
 
26240
    const CImg<T>& display_object3d(const CImgList<tp>& points, const CImgList<tf>& primitives,
 
26241
                                    const CImgList<tc>& colors, const CImgList<to>& opacities, CImgDisplay &disp,
 
26242
                                    const bool centering=true,
 
26243
                                    const int render_static=4, const int render_motion=1,
 
26244
                                    const bool double_sided=false, const float focale=500.0f,
 
26245
                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 
26246
                                    const bool display_axes=true, float *const pose_matrix=0) const {
19032
26247
      CImg<tp> npoints(points.size,3,1,1,0);
19033
 
      tp *ptrX = npoints.ptr(), *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2);
 
26248
      tp *ptrX = npoints.data, *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2);
19034
26249
      cimg_forX(npoints,l) {
19035
26250
        const CImg<tp>& point = points[l];
19036
26251
        const unsigned int siz = point.size();
19042
26257
        *(ptrX++) = point(0);
19043
26258
      }
19044
26259
      return display_object3d(npoints,primitives,colors,opacities,disp,centering,
19045
 
                              render_static,render_motion,double_sided,focale,ambient_light,
 
26260
                              render_static,render_motion,double_sided,focale,specular_light,specular_shine,
19046
26261
                              display_axes,pose_matrix);
19047
26262
    }
19048
26263
 
19049
 
    //! High-level interface for displaying a 3d object
19050
 
    template<typename tp, typename tf, typename to>
19051
 
    const CImg& display_object3d(const CImg<tp>& points, const CImgList<tf>& primitives,
19052
 
                                 const CImgList<T>& colors, const CImg<to>& opacities, CImgDisplay& disp,
19053
 
                                 const bool centering=true,
19054
 
                                 const int render_static=4, const int render_motion=1,
19055
 
                                 const bool double_sided=false,
19056
 
                                 const float focale=500.0f, const float ambient_light=0.05f,
19057
 
                                 const bool display_axes=true, float *const pose_matrix=0) const {
 
26264
    //! High-level interface for displaying a 3d object.
 
26265
    template<typename tp, typename tf, typename tc, typename to>
 
26266
    const CImg<T>& display_object3d(const CImg<tp>& points, const CImgList<tf>& primitives,
 
26267
                                    const CImgList<tc>& colors, const CImg<to>& opacities, CImgDisplay& disp,
 
26268
                                    const bool centering=true,
 
26269
                                    const int render_static=4, const int render_motion=1,
 
26270
                                    const bool double_sided=false, const float focale=500.0f,
 
26271
                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 
26272
                                    const bool display_axes=true, float *const pose_matrix=0) const {
19058
26273
      CImgList<to> nopacities(opacities.size(),1);
19059
26274
      cimglist_for(nopacities,l) nopacities(l,0) = opacities(l);
19060
26275
      return display_object3d(points,primitives,colors,nopacities,disp,centering,
19061
 
                              render_static,render_motion,double_sided,focale,ambient_light,
 
26276
                              render_static,render_motion,double_sided,focale,specular_light,specular_shine,
19062
26277
                              display_axes,pose_matrix);
19063
26278
    }
19064
26279
 
19065
 
    //! High-level interface for displaying a 3d object
19066
 
    template<typename tp, typename tf, typename to>
19067
 
    const CImg& display_object3d(const CImgList<tp>& points, const CImgList<tf>& primitives,
19068
 
                                 const CImgList<T>& colors, const CImg<to>& opacities, CImgDisplay& disp,
19069
 
                                 const bool centering=true,
19070
 
                                 const int render_static=4, const int render_motion=1,
19071
 
                                 const bool double_sided=false,
19072
 
                                 const float focale=500.0f, const float ambient_light=0.05f,
19073
 
                                 const bool display_axes=true, float *const pose_matrix=0) const {
 
26280
    //! High-level interface for displaying a 3d object.
 
26281
    template<typename tp, typename tf, typename tc, typename to>
 
26282
    const CImg<T>& display_object3d(const CImgList<tp>& points, const CImgList<tf>& primitives,
 
26283
                                    const CImgList<tc>& colors, const CImg<to>& opacities, CImgDisplay& disp,
 
26284
                                    const bool centering=true,
 
26285
                                    const int render_static=4, const int render_motion=1,
 
26286
                                    const bool double_sided=false, const float focale=500.0f,
 
26287
                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 
26288
                                    const bool display_axes=true, float *const pose_matrix=0) const {
19074
26289
      CImgList<to> nopacities(opacities.size(),1);
19075
26290
      cimglist_for(nopacities,l) nopacities(l,0) = opacities(l);
19076
26291
      if (!points) throw CImgArgumentException("CImg<%s>::display_object3d() : Given points are empty.",
19077
26292
                                               pixel_type());
19078
26293
      CImg<tp> npoints(points.size,3,1,1,0);
19079
 
      tp *ptrX = npoints.ptr(), *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2);
 
26294
      tp *ptrX = npoints.data, *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2);
19080
26295
      { cimg_forX(npoints,l) {
19081
26296
        const CImg<tp>& point = points[l];
19082
26297
        const unsigned int siz = point.size();
19089
26304
      }
19090
26305
      }
19091
26306
      return display_object3d(npoints,primitives,colors,nopacities,disp,centering,
19092
 
                              render_static,render_motion,double_sided,focale,ambient_light,
 
26307
                              render_static,render_motion,double_sided,focale,specular_light,specular_shine,
19093
26308
                              display_axes,pose_matrix);
19094
26309
    }
19095
26310
 
19096
 
    //! High-level interface for displaying a 3d object
19097
 
    template<typename tp, typename tf, typename to>
19098
 
    const CImg& display_object3d(const tp& points, const CImgList<tf>& primitives,
19099
 
                                 const CImgList<T>& colors, const to& opacities,
19100
 
                                 const bool centering=true,
19101
 
                                 const int render_static=4, const int render_motion=1,
19102
 
                                 const bool double_sided=false,
19103
 
                                 const float focale=500.0f, const float ambient_light=0.05f,
19104
 
                                 const bool display_axes=true, float *const pose_matrix=0) const {
19105
 
      CImgDisplay disp(width,height,0,0);
 
26311
    //! High-level interface for displaying a 3d object.
 
26312
    template<typename tp, typename tf, typename tc, typename to>
 
26313
    const CImg<T>& display_object3d(const tp& points, const CImgList<tf>& primitives,
 
26314
                                    const CImgList<tc>& colors, const to& opacities,
 
26315
                                    const bool centering=true,
 
26316
                                    const int render_static=4, const int render_motion=1,
 
26317
                                    const bool double_sided=false, const float focale=500.0f,
 
26318
                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 
26319
                                    const bool display_axes=true, float *const pose_matrix=0) const {
 
26320
      CImgDisplay disp(width,height,"",0);
19106
26321
      return display_object3d(points,primitives,colors,opacities,disp,centering,
19107
 
                              render_static,render_motion,double_sided,focale,ambient_light,
 
26322
                              render_static,render_motion,double_sided,focale,specular_light,specular_shine,
19108
26323
                              display_axes,pose_matrix);
19109
26324
    }
19110
26325
 
19111
 
    //! High-level interface for displaying a 3d object
19112
 
    template<typename tp, typename tf>
19113
 
    const CImg& display_object3d(const tp& points, const CImgList<tf>& primitives,
19114
 
                                 const CImgList<T>& colors,
19115
 
                                 const bool centering=true,
19116
 
                                 const int render_static=4, const int render_motion=1,
19117
 
                                 const bool double_sided=false,
19118
 
                                 const float focale=500.0f, const float ambient_light=0.05f,
19119
 
                                 const bool display_axes=true, float *const pose_matrix=0,
19120
 
                                 const float opacity=1.0f) const {
19121
 
      CImgDisplay disp(width,height," ",0);
19122
 
      return display_object3d(points,primitives,colors,CImg<float>::vector(opacity),
19123
 
                              disp,centering,render_static,render_motion,double_sided,
19124
 
                              focale,ambient_light,display_axes,pose_matrix);
19125
 
    }
19126
 
 
19127
 
    //! High-level interface for displaying a 3d object
19128
 
    template<typename tp, typename tf>
19129
 
    const CImg& display_object3d(const tp& points, const CImgList<tf>& primitives,
19130
 
                                 const CImgList<T>& colors, CImgDisplay &disp,
19131
 
                                 const bool centering=true,
19132
 
                                 const int render_static=4, const int render_motion=1,
19133
 
                                 const bool double_sided=false,
19134
 
                                 const float focale=500.0f, const float ambient_light=0.05f,
19135
 
                                 const bool display_axes=true, float *const pose_matrix=0,
19136
 
                                 const float opacity=1.0f) const {
19137
 
      return display_object3d(points,primitives,colors,CImg<float>::vector(opacity),
19138
 
                              disp,centering,render_static,render_motion,double_sided,
19139
 
                              focale,ambient_light,display_axes,pose_matrix);
 
26326
    //! High-level interface for displaying a 3d object.
 
26327
    template<typename tp, typename tf, typename tc>
 
26328
    const CImg<T>& display_object3d(const tp& points, const CImgList<tf>& primitives,
 
26329
                                    const CImgList<tc>& colors,
 
26330
                                    const bool centering=true,
 
26331
                                    const int render_static=4, const int render_motion=1,
 
26332
                                    const bool double_sided=false, const float focale=500.0f,
 
26333
                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 
26334
                                    const bool display_axes=true, float *const pose_matrix=0,
 
26335
                                    const float opacity=1.0f) const {
 
26336
      CImgDisplay disp(width,height,"",0);
 
26337
      return display_object3d(points,primitives,colors,CImg<float>::vector(opacity),
 
26338
                              disp,centering,render_static,render_motion,double_sided,
 
26339
                              focale,specular_light,specular_shine,display_axes,pose_matrix);
 
26340
    }
 
26341
 
 
26342
    //! High-level interface for displaying a 3d object.
 
26343
    template<typename tp, typename tf>
 
26344
    const CImg<T>& display_object3d(const tp& points, const CImgList<tf>& primitives,
 
26345
                                    const bool centering=true,
 
26346
                                    const int render_static=4, const int render_motion=1,
 
26347
                                    const bool double_sided=false, const float focale=500.0f,
 
26348
                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 
26349
                                    const bool display_axes=true, float *const pose_matrix=0,
 
26350
                                    const float opacity=1.0f) const {
 
26351
      CImgDisplay disp(width,height,"",0);
 
26352
      return display_object3d(points,primitives,CImgList<T>(),CImg<float>::vector(opacity),
 
26353
                              disp,centering,render_static,render_motion,double_sided,
 
26354
                              focale,specular_light,specular_shine,display_axes,pose_matrix);
 
26355
    }
 
26356
 
 
26357
    //! High-level interface for displaying a 3d object.
 
26358
    template<typename tp, typename tf, typename tc>
 
26359
    const CImg<T>& display_object3d(const tp& points, const CImgList<tf>& primitives,
 
26360
                                    const CImgList<tc>& colors, CImgDisplay &disp,
 
26361
                                    const bool centering=true,
 
26362
                                    const int render_static=4, const int render_motion=1,
 
26363
                                    const bool double_sided=false, const float focale=500.0f,
 
26364
                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 
26365
                                    const bool display_axes=true, float *const pose_matrix=0,
 
26366
                                    const float opacity=1.0f) const {
 
26367
      return display_object3d(points,primitives,colors,CImg<float>::vector(opacity),
 
26368
                              disp,centering,render_static,render_motion,double_sided,
 
26369
                              focale,specular_light,specular_shine,display_axes,pose_matrix);
 
26370
    }
 
26371
 
 
26372
    //! High-level interface for displaying a 3d object.
 
26373
    template<typename tp, typename tf, typename tc>
 
26374
    const CImg<T>& display_object3d(const tp& points, const CImgList<tf>& primitives,
 
26375
                                    CImgDisplay &disp,
 
26376
                                    const bool centering=true,
 
26377
                                    const int render_static=4, const int render_motion=1,
 
26378
                                    const bool double_sided=false, const float focale=500.0f,
 
26379
                                    const float specular_light=0.2f, const float specular_shine=0.1f,
 
26380
                                    const bool display_axes=true, float *const pose_matrix=0,
 
26381
                                    const float opacity=1.0f) const {
 
26382
      return display_object3d(points,primitives,CImgList<T>(),CImg<float>::vector(opacity),
 
26383
                              disp,centering,render_static,render_motion,double_sided,
 
26384
                              focale,specular_light,specular_shine,display_axes,pose_matrix);
19140
26385
    }
19141
26386
 
19142
26387
    //@}
19143
 
    //----------------------
 
26388
    //---------------------------
19144
26389
    //
19145
 
    //! \name Input-Output
 
26390
    //! \name Image File Loading
19146
26391
    //@{
19147
 
    //----------------------
 
26392
    //---------------------------
19148
26393
 
19149
26394
    //! Load an image from a file.
19150
26395
    /**
19151
 
       \param filename = name of the image file to load.
 
26396
       \param filename is the name of the image file to load.
19152
26397
       \note The extension of \c filename defines the file format. If no filename
19153
 
       extension is provided, CImg<T>::get_load() will try to load a CRAW file (CImg Raw file).
 
26398
       extension is provided, CImg<T>::get_load() will try to load a .cimg file.
19154
26399
    **/
19155
 
    CImg& load(const char *const filename) {
19156
 
      const char *ext = cimg::filename_split(filename);
 
26400
    static CImg<T> get_load(const char *const filename) {
 
26401
      return CImg<T>().load(filename);
 
26402
    }
 
26403
 
 
26404
    //! Load an image from a file (in-place version).
 
26405
    CImg<T>& load(const char *const filename) {
 
26406
      if (!filename) throw CImgArgumentException("CImg<%s>::load() : Cannot load (null) filename.",pixel_type());
 
26407
      const char *ext = cimg::split_filename(filename);
19157
26408
#ifdef cimg_load_plugin
19158
26409
      cimg_load_plugin(filename);
19159
26410
#endif
19160
 
      if (!cimg::strncasecmp(ext,"asc",3))   return load_ascii(filename);
19161
 
      if (!cimg::strncasecmp(ext,"dlm",3) ||
19162
 
          !cimg::strncasecmp(ext,"txt",3))   return load_dlm(filename);
19163
 
      if (!cimg::strncasecmp(ext,"inr",3))   return load_inr(filename);
19164
 
      if (!cimg::strncasecmp(ext,"hdr",3) ||
19165
 
          !cimg::strncasecmp(ext,"nii",3))   return load_analyze(filename);
19166
 
      if (!cimg::strncasecmp(ext,"par",3) ||
19167
 
          !cimg::strncasecmp(ext,"rec",3))   return load_parrec(filename);
19168
 
      if (!cimg::strncasecmp(ext,"pan",3))   return load_pandore(filename);
19169
 
      if (!cimg::strncasecmp(ext,"bmp",3))   return load_bmp(filename);
19170
 
      if (!cimg::strncasecmp(ext,"png",3))   return load_png(filename);
19171
 
      if (!cimg::strncasecmp(ext,"tif",3))   return load_tiff(filename);
19172
 
      if (!cimg::strncasecmp(ext,"jpg",3) ||
19173
 
          !cimg::strncasecmp(ext,"jpeg",4))  return load_jpeg(filename);
19174
 
      if (!cimg::strncasecmp(ext,"ppm",3) ||
19175
 
          !cimg::strncasecmp(ext,"pgm",3) ||
19176
 
          !cimg::strncasecmp(ext,"pnm",3))   return load_pnm(filename);
19177
 
      if (!cimg::strncasecmp(ext,"cimg",4) ||
19178
 
          ext[0]=='\0')                      return load_cimg(filename);
19179
 
      if (!cimg::strncasecmp(ext,"dcm",3) ||
19180
 
          !cimg::strncasecmp(ext,"dicom",5)) return load_dicom(filename);
 
26411
#ifdef cimg_load_plugin1
 
26412
      cimg_load_plugin1(filename);
 
26413
#endif
 
26414
#ifdef cimg_load_plugin2
 
26415
      cimg_load_plugin2(filename);
 
26416
#endif
 
26417
#ifdef cimg_load_plugin3
 
26418
      cimg_load_plugin3(filename);
 
26419
#endif
 
26420
#ifdef cimg_load_plugin4
 
26421
      cimg_load_plugin4(filename);
 
26422
#endif
 
26423
#ifdef cimg_load_plugin5
 
26424
      cimg_load_plugin5(filename);
 
26425
#endif
 
26426
#ifdef cimg_load_plugin6
 
26427
      cimg_load_plugin6(filename);
 
26428
#endif
 
26429
#ifdef cimg_load_plugin7
 
26430
      cimg_load_plugin7(filename);
 
26431
#endif
 
26432
#ifdef cimg_load_plugin8
 
26433
      cimg_load_plugin8(filename);
 
26434
#endif
 
26435
      // ASCII formats
 
26436
      if (!cimg::strcasecmp(ext,"asc")) return load_ascii(filename);
 
26437
      if (!cimg::strcasecmp(ext,"dlm") ||
 
26438
          !cimg::strcasecmp(ext,"txt")) return load_dlm(filename);
 
26439
 
 
26440
      // 2D binary formats
 
26441
      if (!cimg::strcasecmp(ext,"bmp")) return load_bmp(filename);
 
26442
      if (!cimg::strcasecmp(ext,"jpg") ||
 
26443
          !cimg::strcasecmp(ext,"jpeg")) return load_jpeg(filename);
 
26444
      if (!cimg::strcasecmp(ext,"png")) return load_png(filename);
 
26445
      if (!cimg::strcasecmp(ext,"ppm") ||
 
26446
          !cimg::strcasecmp(ext,"pgm") ||
 
26447
          !cimg::strcasecmp(ext,"pnm")) return load_pnm(filename);
 
26448
      if (!cimg::strcasecmp(ext,"tif")) return load_tiff(filename);
 
26449
 
 
26450
      // 3D binary formats
 
26451
      if (!cimg::strcasecmp(ext,"dcm") ||
 
26452
          !cimg::strcasecmp(ext,"dicom")) return load_medcon_external(filename);
 
26453
      if (!cimg::strcasecmp(ext,"hdr") ||
 
26454
          !cimg::strcasecmp(ext,"nii")) return load_analyze(filename);
 
26455
      if (!cimg::strcasecmp(ext,"par") ||
 
26456
          !cimg::strcasecmp(ext,"rec")) return load_parrec(filename);
 
26457
      if (!cimg::strcasecmp(ext,"inr")) return load_inr(filename);
 
26458
      if (!cimg::strcasecmp(ext,"pan")) return load_pandore(filename);
 
26459
      if (!cimg::strcasecmp(ext,"cimg") ||
 
26460
          !cimg::strcasecmp(ext,"cimgz") ||
 
26461
          *ext=='\0') return load_cimg(filename);
 
26462
 
 
26463
      // Archive files
 
26464
      if (!cimg::strcasecmp(ext,"gz")) return load_gzip_external(filename);
 
26465
 
 
26466
      // Image sequences
 
26467
      if (!cimg::strcasecmp(ext,"avi") ||
 
26468
          !cimg::strcasecmp(ext,"mov") ||
 
26469
          !cimg::strcasecmp(ext,"mpg") ||
 
26470
          !cimg::strcasecmp(ext,"mpeg") ||
 
26471
          !cimg::strcasecmp(ext,"ogg") ||
 
26472
          !cimg::strcasecmp(ext,"flv")) return load_ffmpeg(filename);
19181
26473
      return load_other(filename);
19182
26474
    }
19183
26475
 
19184
 
    //! Load an image from a file.
19185
 
    static CImg get_load(const char *const filename) {
19186
 
      return CImg<T>().load(filename);
19187
 
    }
19188
 
 
19189
 
    //! Load an image from an ASCII file.
19190
 
    CImg& load_ascii(std::FILE *const file, const char *const filename=0) {
 
26476
    // Load an image from an ASCII file (internal function).
 
26477
    CImg<T>& _load_ascii(std::FILE *const file, const char *const filename) {
 
26478
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_ascii() : Cannot load (null) filename.",pixel_type());
19191
26479
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
19192
26480
      char line[256] = { 0 };
 
26481
      std::fscanf(nfile,"%*[^0-9]");
19193
26482
      std::fscanf(nfile,"%255[^\n]",line);
19194
26483
      unsigned int off, dx = 0, dy = 1, dz = 1, dv = 1;
19195
26484
      int err = 1;
19196
 
      std::sscanf(line,"%u %u %u %u",&dx,&dy,&dz,&dv);
 
26485
      std::sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dv);
 
26486
      std::fscanf(nfile,"%*[^0-9.+-]");
19197
26487
      if (!dx || !dy || !dz || !dv) {
19198
26488
        if (!file) cimg::fclose(nfile);
19199
26489
        throw CImgIOException("CImg<%s>::load_ascii() : File '%s' is not a valid .ASC file.\n"
19201
26491
                              pixel_type(),filename?filename:"(FILE*)",dx,dy,dz,dv);
19202
26492
      }
19203
26493
      assign(dx,dy,dz,dv);
19204
 
      const unsigned int siz = size();
 
26494
      const unsigned long siz = size();
19205
26495
      double val;
19206
26496
      T *ptr = data;
19207
26497
      for (off=0; off<siz && err==1; ++off) {
19208
 
        err = std::fscanf(nfile,"%lf%*[^0-9.eE+-]",&val);
 
26498
        err = std::fscanf(nfile,"%lf%*[^0-9.+-]",&val);
19209
26499
        *(ptr++) = (T)val;
19210
26500
      }
19211
 
      if (off<size()) cimg::warn("CImg<%s>::load_ascii() : File '%s', only %u/%u values read.",
19212
 
                                 pixel_type(),filename?filename:"(FILE*)",off,siz);
 
26501
      if (err!=1) cimg::warn("CImg<%s>::load_ascii() : File '%s', only %u/%lu values read.",
 
26502
                             pixel_type(),filename?filename:"(FILE*)",off-1,siz);
19213
26503
      if (!file) cimg::fclose(nfile);
19214
26504
      return *this;
19215
26505
    }
19216
26506
 
19217
26507
    //! Load an image from an ASCII file.
19218
 
    CImg& load_ascii(const char *const filename) {
19219
 
      return load_ascii(0,filename);
19220
 
    }
19221
 
 
19222
 
    //! Load an image from an ASCII file.
19223
 
    static CImg get_load_ascii(std::FILE *const file, const char *const filename=0) {
19224
 
      return CImg<T>().load_ascii(file,filename);
19225
 
    }
19226
 
 
19227
 
    //! Load an image from an ASCII file.
19228
 
    static CImg get_load_ascii(const char *const filename) {
19229
 
      return CImg<T>().load_ascii(0,filename);
19230
 
    }
19231
 
 
19232
 
    //! Load an image from a DLM file.
19233
 
    CImg& load_dlm(std::FILE *const file, const char *const filename=0) {
 
26508
    static CImg<T> get_load_ascii(const char *const filename) {
 
26509
      return CImg<T>().load_ascii(filename);
 
26510
    }
 
26511
 
 
26512
    //! Load an image from an ASCII file.
 
26513
    static CImg<T> get_load_ascii(std::FILE *const file) {
 
26514
      return CImg<T>().load_ascii(file);
 
26515
    }
 
26516
 
 
26517
    //! Load an image from an ASCII file (in-place).
 
26518
    CImg<T>& load_ascii(const char *const filename) {
 
26519
      return _load_ascii(0,filename);
 
26520
    }
 
26521
 
 
26522
    //! Load an image from an ASCII file (in-place).
 
26523
    CImg<T>& load_ascii(std::FILE *const file) {
 
26524
      return _load_ascii(file,0);
 
26525
    }
 
26526
 
 
26527
    // Load an image from a DLM file (internal function).
 
26528
    CImg<T>& _load_dlm(std::FILE *const file, const char *const filename) {
 
26529
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_dlm() : Cannot load (null) filename.",pixel_type());
19234
26530
      std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
19235
26531
      assign(256,256);
19236
26532
      char c, delimiter[256] = { 0 }, tmp[256];
19237
26533
      unsigned int cdx = 0, dx = 0, dy = 0;
19238
26534
      int oerr = 0, err;
19239
26535
      double val;
19240
 
      while ((err = std::fscanf(nfile,"%lf%255[^0-9.eE+-]",&val,delimiter))!=EOF) {
 
26536
      while ((err = std::fscanf(nfile,"%lf%255[^0-9.+-]",&val,delimiter))!=EOF) {
19241
26537
        oerr = err;
19242
26538
        if (err>0) (*this)(cdx++,dy) = (T)val;
19243
26539
        if (cdx>=width) resize(width+256,1,1,1,0);
19261
26557
    }
19262
26558
 
19263
26559
    //! Load an image from a DLM file.
19264
 
    CImg& load_dlm(const char *const filename) {
19265
 
      return load_dlm(0,filename);
19266
 
    }
19267
 
 
19268
 
    //! Load an image from a DLM file.
19269
 
    static CImg get_load_dlm(std::FILE *const file, const char *const filename=0) {
19270
 
      return CImg<T>().load_dlm(file,filename);
19271
 
    }
19272
 
 
19273
 
    //! Load an image from a DLM file.
19274
 
    static CImg get_load_dlm(const char *const filename) {
19275
 
      return CImg<T>().load_dlm(0,filename);
19276
 
    }
19277
 
 
19278
 
    //! Load an image from a PNM file.
19279
 
    CImg& load_pnm(std::FILE *const file, const char *const filename=0) {
19280
 
      std::FILE *const nfile=file?file:cimg::fopen(filename,"rb");
19281
 
      unsigned int ppm_type, W, H, colormax=255;
19282
 
      char item[1024] = { 0 };
19283
 
      int err, rval, gval, bval;
19284
 
      const int cimg_iobuffer = 12*1024*1024;
19285
 
      while ((err=std::fscanf(nfile,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile);
19286
 
      if(std::sscanf(item," P%u",&ppm_type)!=1) {
19287
 
        if (!file) cimg::fclose(nfile);
19288
 
        throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PNM header 'P?' not found.",
19289
 
                              pixel_type(),filename?filename:"(FILE*)");
19290
 
      }
19291
 
      while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile);
19292
 
      if ((err=std::sscanf(item," %u %u %u",&W,&H,&colormax))<2) {
19293
 
        if (!file) cimg::fclose(nfile);
19294
 
        throw CImgIOException("CImg<%s>::load_pnm() : File '%s', WIDTH and HEIGHT fields are not defined in PNM header.",
19295
 
                              pixel_type(),filename?filename:"(FILE*)");
19296
 
      }
19297
 
      if (err==2) {
19298
 
        while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile);
19299
 
        if (std::sscanf(item,"%u",&colormax)!=1)
19300
 
          cimg::warn("CImg<%s>::load_pnm() : File '%s', COLORMAX field is not defined in PNM header.",
19301
 
                     pixel_type(),filename?filename:"(FILE*)");
19302
 
      }
19303
 
      std::fgetc(nfile);
19304
 
      assign();
19305
 
 
19306
 
      switch (ppm_type) {
19307
 
      case 2: { // Grey Ascii
19308
 
        assign(W,H,1,1);
19309
 
        T* rdata = ptr();
19310
 
        cimg_foroff(*this,off) { std::fscanf(nfile,"%d",&rval); *(rdata++) = (T)rval; }
19311
 
      } break;
19312
 
      case 3: { // Color Ascii
19313
 
        assign(W,H,1,3);
19314
 
        T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
19315
 
        cimg_forXY(*this,x,y) {
19316
 
          std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval);
19317
 
          *(rdata++) = (T)rval;
19318
 
          *(gdata++) = (T)gval;
19319
 
          *(bdata++) = (T)bval; }
19320
 
      } break;
19321
 
      case 5: { // Grey Binary
19322
 
        if (colormax<256) { // 8 bits
19323
 
          CImg<unsigned char> raw;
19324
 
          assign(W,H,1,1);
19325
 
          T *ptrd = ptr(0,0,0,0);
19326
 
          for (int toread = (int)size(); toread>0; ) {
19327
 
            raw.assign(cimg::min(toread,cimg_iobuffer));
19328
 
            cimg::fread(raw.data,raw.width,nfile);
19329
 
            toread-=raw.width;
19330
 
            const unsigned char *ptrs = raw.ptr();
19331
 
            for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
19332
 
          }
19333
 
        } else { // 16 bits
19334
 
          CImg<unsigned short> raw;
19335
 
          assign(W,H,1,1);
19336
 
          T *ptrd = ptr(0,0,0,0);
19337
 
          for (int toread = (int)size(); toread>0; ) {
19338
 
            raw.assign(cimg::min(toread,cimg_iobuffer/2));
19339
 
            cimg::fread(raw.data,raw.width,nfile);
19340
 
            toread-=raw.width;
19341
 
            const unsigned short *ptrs = raw.ptr();
19342
 
            for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
19343
 
          }
19344
 
        }
19345
 
      } break;
19346
 
      case 6: { // Color Binary
19347
 
        if (colormax<256) { // 8 bits
19348
 
          CImg<unsigned char> raw;
19349
 
          assign(W,H,1,3);
19350
 
          T
19351
 
            *ptr_r = ptr(0,0,0,0),
19352
 
            *ptr_g = ptr(0,0,0,1),
19353
 
            *ptr_b = ptr(0,0,0,2);
19354
 
          for (int toread = (int)size(); toread>0; ) {
19355
 
            raw.assign(cimg::min(toread,cimg_iobuffer));
19356
 
            cimg::fread(raw.data,raw.width,nfile);
19357
 
            toread-=raw.width;
19358
 
            const unsigned char *ptrs = raw.ptr();
19359
 
            for (unsigned int off = raw.width/3; off; --off) {
19360
 
              *(ptr_r++) = (T)*(ptrs++);
19361
 
              *(ptr_g++) = (T)*(ptrs++);
19362
 
              *(ptr_b++) = (T)*(ptrs++);
19363
 
            }
19364
 
          }
19365
 
        } else { // 16 bits
19366
 
          CImg<unsigned short> raw;
19367
 
          assign(W,H,1,3);
19368
 
          T
19369
 
            *ptr_r = ptr(0,0,0,0),
19370
 
            *ptr_g = ptr(0,0,0,1),
19371
 
            *ptr_b = ptr(0,0,0,2);
19372
 
          for (int toread = (int)size(); toread>0; ) {
19373
 
            raw.assign(cimg::min(toread,cimg_iobuffer/2));
19374
 
            cimg::fread(raw.data,raw.width,nfile);
19375
 
            if (!cimg::endian()) cimg::endian_swap(raw.data,raw.width);
19376
 
            toread-=raw.width;
19377
 
            const unsigned short *ptrs = raw.ptr();
19378
 
            for (unsigned int off = raw.width/3; off; --off) {
19379
 
              *(ptr_r++) = (T)*(ptrs++);
19380
 
              *(ptr_g++) = (T)*(ptrs++);
19381
 
              *(ptr_b++) = (T)*(ptrs++);
19382
 
            }
19383
 
          }
19384
 
        }
19385
 
      } break;
19386
 
      default:
19387
 
        if (!file) cimg::fclose(nfile);
19388
 
        throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PPM type 'P%d' not supported.",
19389
 
                              pixel_type(),filename?filename:"(FILE*)",ppm_type);
19390
 
      }
19391
 
      if (!file) cimg::fclose(nfile);
19392
 
      return *this;
19393
 
    }
19394
 
 
19395
 
    //! Load an image from a PNM file.
19396
 
    CImg& load_pnm(const char *const filename) {
19397
 
      return load_pnm(0,filename);
19398
 
    }
19399
 
 
19400
 
    //! Load an image from a PNM file.
19401
 
    static CImg get_load_pnm(std::FILE *const file, const char *const filename=0) {
19402
 
      return CImg<T>().load_pnm(file, filename);
19403
 
    }
19404
 
 
19405
 
    //! Load an image from a PNM file.
19406
 
    static CImg get_load_pnm(const char *const filename) {
19407
 
      return get_load_pnm(0,filename);
19408
 
    }
19409
 
 
19410
 
    //! Load an image from a BMP file.
19411
 
    CImg& load_bmp(std::FILE *const file, const char *const filename=0) {
 
26560
    static CImg<T> get_load_dlm(const char *const filename) {
 
26561
      return CImg<T>().load_dlm(filename);
 
26562
    }
 
26563
 
 
26564
    //! Load an image from a DLM file.
 
26565
    static CImg<T> get_load_dlm(std::FILE *const file) {
 
26566
      return CImg<T>().load_dlm(file);
 
26567
    }
 
26568
 
 
26569
    //! Load an image from a DLM file (in-place).
 
26570
    CImg<T>& load_dlm(const char *const filename) {
 
26571
      return _load_dlm(0,filename);
 
26572
    }
 
26573
 
 
26574
    //! Load an image from a DLM file (in-place).
 
26575
    CImg<T>& load_dlm(std::FILE *const file) {
 
26576
      return _load_dlm(file,0);
 
26577
    }
 
26578
 
 
26579
    // Load an image from a BMP file (internal function).
 
26580
    CImg<T>& _load_bmp(std::FILE *const file, const char *const filename) {
 
26581
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_bmp() : Cannot load (null) filename.",pixel_type());
19412
26582
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
19413
26583
      unsigned char header[64];
19414
26584
      cimg::fread(header,54,nfile);
19518
26688
    }
19519
26689
 
19520
26690
    //! Load an image from a BMP file.
19521
 
    CImg& load_bmp(const char *const filename) {
19522
 
      return load_bmp(0,filename);
19523
 
    }
19524
 
 
19525
 
    //! Load an image from a BMP file.
19526
 
    static CImg get_load_bmp(std::FILE *const file, const char *const filename=0) {
19527
 
      return CImg<T>().load_bmp(file,filename);
19528
 
    }
19529
 
 
19530
 
    //! Load an image from a BMP file.
19531
 
    static CImg get_load_bmp(const char *const filename) {
19532
 
      return CImg<T>().load_bmp(0,filename);
19533
 
    }
19534
 
 
19535
 
    //! Load an image from a PNG file.
 
26691
    static CImg<T> get_load_bmp(const char *const filename) {
 
26692
      return CImg<T>().load_bmp(filename);
 
26693
    }
 
26694
 
 
26695
    //! Load an image from a BMP file.
 
26696
    static CImg<T> get_load_bmp(std::FILE *const file) {
 
26697
      return CImg<T>().load_bmp(file);
 
26698
    }
 
26699
 
 
26700
    //! Load an image from a BMP file (in-place).
 
26701
    CImg<T>& load_bmp(const char *const filename) {
 
26702
      return _load_bmp(0,filename);
 
26703
    }
 
26704
 
 
26705
    //! Load an image from a BMP file (in-place).
 
26706
    CImg<T>& load_bmp(std::FILE *const file) {
 
26707
      return _load_bmp(file,0);
 
26708
    }
 
26709
 
 
26710
    // Load an image from a JPEG file (internal).
 
26711
    CImg<T>& _load_jpeg(std::FILE *const file, const char *const filename) {
 
26712
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_jpeg() : Cannot load (null) filename.",pixel_type());
 
26713
#ifndef cimg_use_jpeg
 
26714
      if (file)
 
26715
        throw CImgIOException("CImg<%s>::load_jpeg() : File '(FILE*)' cannot be read without using libjpeg.",
 
26716
                              pixel_type());
 
26717
      else return load_other(filename);
 
26718
#else
 
26719
      struct jpeg_decompress_struct cinfo;
 
26720
      struct jpeg_error_mgr jerr;
 
26721
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 
26722
 
 
26723
      cinfo.err = jpeg_std_error(&jerr);
 
26724
      jpeg_create_decompress(&cinfo);
 
26725
      jpeg_stdio_src(&cinfo,nfile);
 
26726
      jpeg_read_header(&cinfo,TRUE);
 
26727
      jpeg_start_decompress(&cinfo);
 
26728
 
 
26729
      if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) {
 
26730
        cimg::warn("CImg<%s>::load_jpeg() : Don't know how to read image '%s' with libpeg, trying ImageMagick's convert",
 
26731
                   pixel_type(),filename?filename:"(unknown)");
 
26732
        if (!file) return load_other(filename);
 
26733
        else {
 
26734
          if (!file) cimg::fclose(nfile);
 
26735
          throw CImgIOException("CImg<%s>::load_jpeg() : Cannot read JPEG image '%s' using a *FILE input.",
 
26736
                                pixel_type(),filename?filename:"(FILE*)");
 
26737
        }
 
26738
      }
 
26739
 
 
26740
      const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
 
26741
      unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components], *buf2 = buf;
 
26742
      JSAMPROW row_pointer[1];
 
26743
      while (cinfo.output_scanline < cinfo.output_height) {
 
26744
        row_pointer[0] = &buf[cinfo.output_scanline*row_stride];
 
26745
        jpeg_read_scanlines(&cinfo,row_pointer,1);
 
26746
      }
 
26747
      jpeg_finish_decompress(&cinfo);
 
26748
      jpeg_destroy_decompress(&cinfo);
 
26749
      if (!file) cimg::fclose(nfile);
 
26750
 
 
26751
      assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components);
 
26752
      switch (dim) {
 
26753
      case 1: {
 
26754
        T *ptr_g = data;
 
26755
        cimg_forXY(*this,x,y) *(ptr_g++) = (T)*(buf2++);
 
26756
      } break;
 
26757
      case 3: {
 
26758
        T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
 
26759
        cimg_forXY(*this,x,y) {
 
26760
          *(ptr_r++) = (T)*(buf2++);
 
26761
          *(ptr_g++) = (T)*(buf2++);
 
26762
          *(ptr_b++) = (T)*(buf2++);
 
26763
        }
 
26764
      } break;
 
26765
      case 4: {
 
26766
        T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1),
 
26767
          *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3);
 
26768
        cimg_forXY(*this,x,y) {
 
26769
          *(ptr_r++) = (T)*(buf2++);
 
26770
          *(ptr_g++) = (T)*(buf2++);
 
26771
          *(ptr_b++) = (T)*(buf2++);
 
26772
          *(ptr_a++) = (T)*(buf2++);
 
26773
        }
 
26774
      } break;
 
26775
      }
 
26776
      delete[] buf;
 
26777
      return *this;
 
26778
#endif
 
26779
    }
 
26780
 
 
26781
    //! Load an image from a JPEG file.
 
26782
    static CImg<T> get_load_jpeg(const char *const filename) {
 
26783
      return CImg<T>().load_jpeg(filename);
 
26784
    }
 
26785
 
 
26786
    //! Load an image from a JPEG file.
 
26787
    static CImg<T> get_load_jpeg(std::FILE *const file) {
 
26788
      return CImg<T>().load_jpeg(file);
 
26789
    }
 
26790
 
 
26791
    //! Load an image from a JPEG file (in-place).
 
26792
    CImg<T>& load_jpeg(const char *const filename) {
 
26793
      return _load_jpeg(0,filename);
 
26794
    }
 
26795
 
 
26796
    //! Load an image from a JPEG file (in-place).
 
26797
    CImg<T>& load_jpeg(std::FILE *const file) {
 
26798
      return _load_jpeg(file,0);
 
26799
    }
 
26800
 
 
26801
    // Load an image from a file, using Magick++ lirary.
 
26802
    static CImg<T> get_load_magick(const char *const filename) {
 
26803
      return CImg<T>().load_magick(filename);
 
26804
    }
 
26805
 
 
26806
    //! Load an image from a file, using Magick++ library.
 
26807
    // Added April/may 2006 by Christoph Hormann <chris_hormann@gmx.de>
 
26808
    //   This is experimental code, not much tested, use with care.
 
26809
    CImg<T>& load_magick(const char *const filename) {
 
26810
      if (!filename) throw CImgArgumentException("CImg<%s>::load_magick() : Cannot load (null) filename.",pixel_type());
 
26811
#ifdef cimg_use_magick
 
26812
      Magick::Image image(filename);
 
26813
      const unsigned int W = image.size().width(), H = image.size().height();
 
26814
      switch (image.type()) {
 
26815
      case Magick::PaletteMatteType:
 
26816
      case Magick::TrueColorMatteType:
 
26817
      case Magick::ColorSeparationType: {
 
26818
        assign(W,H,1,4);
 
26819
        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);
 
26820
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 
26821
        for (unsigned int off = W*H; off; --off) {
 
26822
          *(rdata++) = (T)(pixels->red);
 
26823
          *(gdata++) = (T)(pixels->green);
 
26824
          *(bdata++) = (T)(pixels->blue);
 
26825
          *(adata++) = (T)(pixels->opacity);
 
26826
          ++pixels;
 
26827
        }
 
26828
      } break;
 
26829
      case Magick::PaletteType:
 
26830
      case Magick::TrueColorType: {
 
26831
        assign(W,H,1,3);
 
26832
        T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
 
26833
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 
26834
        for (unsigned int off = W*H; off; --off) {
 
26835
          *(rdata++) = (T)(pixels->red);
 
26836
          *(gdata++) = (T)(pixels->green);
 
26837
          *(bdata++) = (T)(pixels->blue);
 
26838
          ++pixels;
 
26839
        }
 
26840
      } break;
 
26841
      case Magick::GrayscaleMatteType: {
 
26842
        assign(W,H,1,2);
 
26843
        T *data = ptr(0,0,0,0), *adata = ptr(0,0,0,1);
 
26844
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 
26845
        for (unsigned int off = W*H; off; --off) {
 
26846
          *(data++) = (T)(pixels->red);
 
26847
          *(adata++) = (T)(pixels->opacity);
 
26848
          ++pixels;
 
26849
        }
 
26850
      } break;
 
26851
      default: {
 
26852
        assign(W,H,1,1);
 
26853
        T *data = ptr(0,0,0,0);
 
26854
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
 
26855
        for (unsigned int off = W*H; off; --off) {
 
26856
          *(data++) = (T)(pixels->red);
 
26857
          ++pixels;
 
26858
        }
 
26859
      } break;
 
26860
      }
 
26861
#else
 
26862
      throw CImgIOException("CImg<%s>::load_magick() : File '%s', Magick++ has not been linked during compilation.",
 
26863
                            pixel_type(),filename?filename:"(null)");
 
26864
#endif
 
26865
      return *this;
 
26866
    }
 
26867
 
 
26868
    // Load an image from a PNG file (internal).
19536
26869
    // (Note : Most of this function has been written by Eric Fausett)
19537
 
    CImg& load_png(std::FILE *const file, const char *const filename=0) {
 
26870
    CImg<T>& _load_png(std::FILE *const file, const char *const filename) {
 
26871
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_png() : Cannot load (null) filename.",pixel_type());
19538
26872
#ifndef cimg_use_png
19539
26873
      if (file)
19540
26874
        throw CImgIOException("CImg<%s>::load_png() : File '(FILE*)' cannot be read without using libpng.",pixel_type());
19541
26875
      else return load_other(filename);
19542
26876
#else
19543
26877
      // Open file and check for PNG validity
19544
 
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 
26878
      const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
 
26879
      std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb");
 
26880
 
19545
26881
      unsigned char pngCheck[8];
19546
 
      cimg::fread(pngCheck,8,nfile);
 
26882
      cimg::fread(pngCheck,8,(std::FILE*)nfile);
19547
26883
      if (png_sig_cmp(pngCheck,0,8)) {
19548
26884
        if (!file) cimg::fclose(nfile);
19549
26885
        throw CImgIOException("CImg<%s>::load_png() : File '%s' is not a valid PNG file.",
19550
 
                              pixel_type(),filename?filename:"(FILE*)");
 
26886
                              pixel_type(),nfilename?nfilename:"(FILE*)");
19551
26887
      }
19552
26888
 
19553
26889
      // Setup PNG structures for read
19554
26890
      png_voidp user_error_ptr = 0;
19555
26891
      png_error_ptr user_error_fn = 0, user_warning_fn = 0;
19556
 
      png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,       // Verifies libpng version correct
19557
 
                                                   user_error_ptr, user_error_fn, user_warning_fn);
19558
 
      if(!png_ptr){
 
26892
      png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn);
 
26893
      if (!png_ptr) {
19559
26894
        if (!file) cimg::fclose(nfile);
19560
26895
        throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'png_ptr' data structure.",
19561
 
                              pixel_type(),filename?filename:"(FILE*)");
 
26896
                              pixel_type(),nfilename?nfilename:"(FILE*)");
19562
26897
      }
19563
26898
      png_infop info_ptr = png_create_info_struct(png_ptr);
19564
 
      if(!info_ptr){
 
26899
      if (!info_ptr) {
19565
26900
        if (!file) cimg::fclose(nfile);
19566
 
        png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
 
26901
        png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0);
19567
26902
        throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'info_ptr' data structure.",
19568
 
                              pixel_type(),filename?filename:"(FILE*)");
 
26903
                              pixel_type(),nfilename?nfilename:"(FILE*)");
19569
26904
      }
19570
26905
      png_infop end_info = png_create_info_struct(png_ptr);
19571
 
      if(!end_info){
 
26906
      if (!end_info) {
19572
26907
        if (!file) cimg::fclose(nfile);
19573
 
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0);
 
26908
        png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0);
19574
26909
        throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'end_info' data structure.",
19575
 
                              pixel_type(),filename?filename:"(FILE*)");
 
26910
                              pixel_type(),nfilename?nfilename:"(FILE*)");
19576
26911
      }
19577
26912
 
19578
26913
      // Error handling callback for png file reading
19579
 
      if (setjmp(png_jmpbuf(png_ptr))){
19580
 
        if (!file) cimg::fclose(nfile);
 
26914
      if (setjmp(png_jmpbuf(png_ptr))) {
 
26915
        if (!file) cimg::fclose((std::FILE*)nfile);
19581
26916
        png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
19582
26917
        throw CImgIOException("CImg<%s>::load_png() : File '%s', unknown fatal error.",
19583
 
                              pixel_type(),filename?filename:"(FILE*)");
 
26918
                              pixel_type(),nfilename?nfilename:"(FILE*)");
19584
26919
      }
19585
26920
      png_init_io(png_ptr, nfile);
19586
26921
      png_set_sig_bytes(png_ptr, 8);
19587
26922
 
19588
26923
      // Get PNG Header Info up to data block
19589
 
      png_read_info(png_ptr, info_ptr);
 
26924
      png_read_info(png_ptr,info_ptr);
19590
26925
      png_uint_32 W, H;
19591
26926
      int bit_depth, color_type, interlace_type;
19592
 
      png_get_IHDR(png_ptr, info_ptr, &W, &H, &bit_depth, &color_type, &interlace_type,
19593
 
                   int_p_NULL, int_p_NULL);
 
26927
      png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,int_p_NULL,int_p_NULL);
19594
26928
      int new_bit_depth = bit_depth;
19595
26929
      int new_color_type = color_type;
19596
26930
 
19610
26944
        png_set_gray_to_rgb(png_ptr);
19611
26945
        new_color_type |= PNG_COLOR_MASK_COLOR;
19612
26946
      }
19613
 
      if (new_color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);
19614
 
      png_read_update_info(png_ptr, info_ptr);
 
26947
      if (new_color_type == PNG_COLOR_TYPE_RGB)
 
26948
        png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);
 
26949
      png_read_update_info(png_ptr,info_ptr);
19615
26950
      if (!(new_bit_depth==8 || new_bit_depth==16)) {
19616
26951
        if (!file) cimg::fclose(nfile);
19617
26952
        png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
19618
26953
        throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong bit coding (bit_depth=%u)",
19619
 
                              pixel_type(),filename?filename:"(FILE*)",new_bit_depth);
 
26954
                              pixel_type(),nfilename?nfilename:"(FILE*)",new_bit_depth);
19620
26955
      }
19621
26956
      const int byte_depth = new_bit_depth>>3;
19622
26957
 
19623
26958
      // Allocate Memory for Image Read
19624
26959
      png_bytep *imgData = new png_bytep[H];
19625
 
      for (unsigned int row=0; row < H; ++row) imgData[row] = new png_byte[byte_depth * 4 * W];
19626
 
      png_read_image(png_ptr, imgData);
19627
 
      png_read_end(png_ptr, end_info);
 
26960
      for (unsigned int row = 0; row<H; ++row) imgData[row] = new png_byte[byte_depth*4*W];
 
26961
      png_read_image(png_ptr,imgData);
 
26962
      png_read_end(png_ptr,end_info);
19628
26963
 
19629
26964
      // Read pixel data
19630
26965
      if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA)) {
19631
26966
        if (!file) cimg::fclose(nfile);
19632
 
        png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
 
26967
        png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);
19633
26968
        throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong color coding (new_color_type=%u)",
19634
 
                              pixel_type(),filename?filename:"(FILE*)",new_color_type);
 
26969
                              pixel_type(),nfilename?nfilename:"(FILE*)",new_color_type);
19635
26970
      }
19636
26971
      const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB);
19637
26972
      assign(W,H,1,no_alpha_channel?3:4);
19638
26973
      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);
19639
 
      switch(new_bit_depth) {
 
26974
      switch (new_bit_depth) {
19640
26975
      case 8: {
19641
26976
        cimg_forY(*this,y){
19642
26977
          const unsigned char *ptrs = (unsigned char*)imgData[y];
19651
26986
      case 16: {
19652
26987
        cimg_forY(*this,y){
19653
26988
          const unsigned short *ptrs = (unsigned short*)(imgData[y]);
 
26989
          if (!cimg::endianness()) cimg::invert_endianness(ptrs,4*width);
19654
26990
          cimg_forX(*this,x){
19655
26991
            *(ptr1++) = (T)*(ptrs++);
19656
26992
            *(ptr2++) = (T)*(ptrs++);
19663
26999
      png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
19664
27000
 
19665
27001
      // Deallocate Image Read Memory
19666
 
      for (unsigned int n=0; n<H; ++n) delete[] imgData[n];
 
27002
      cimg_forY(*this,n) delete[] imgData[n];
19667
27003
      delete[] imgData;
19668
27004
      if (!file) cimg::fclose(nfile);
19669
27005
      return *this;
19671
27007
    }
19672
27008
 
19673
27009
    //! Load an image from a PNG file.
19674
 
    CImg& load_png(const char *const filename) {
19675
 
      return load_png(0,filename);
19676
 
    }
19677
 
 
19678
 
    //! Load an image from a PNG file.
19679
 
    static CImg get_load_png(std::FILE *const file, const char *const filename=0) {
19680
 
      return CImg<T>().load_png(file,filename);
19681
 
    }
19682
 
 
19683
 
    //! Load an image from a PNG file.
19684
 
    static CImg get_load_png(const char *const filename) {
19685
 
      return CImg<T>().load_png(0,filename);
19686
 
    }
19687
 
 
19688
 
    //! Load an image from a TIFF file.
 
27010
    static CImg<T> get_load_png(const char *const filename) {
 
27011
      return CImg<T>().load_png(filename);
 
27012
    }
 
27013
 
 
27014
    //! Load an image from a PNG file.
 
27015
    static CImg<T> get_load_png(std::FILE *const file) {
 
27016
      return CImg<T>().load_png(file);
 
27017
    }
 
27018
 
 
27019
    //! Load an image from a PNG file (in-place).
 
27020
    CImg<T>& load_png(const char *const filename) {
 
27021
      return _load_png(0,filename);
 
27022
    }
 
27023
 
 
27024
    //! Load an image from a PNG file (in-place).
 
27025
    CImg<T>& load_png(std::FILE *const file) {
 
27026
      return _load_png(file,0);
 
27027
    }
 
27028
 
 
27029
    // Load an image from a PNM file (internal).
 
27030
    CImg<T>& _load_pnm(std::FILE *const file, const char *const filename) {
 
27031
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_pnm() : Cannot load (null) filename.",pixel_type());
 
27032
      std::FILE *const nfile=file?file:cimg::fopen(filename,"rb");
 
27033
      unsigned int ppm_type, W, H, colormax=255;
 
27034
      char item[1024] = { 0 };
 
27035
      int err, rval, gval, bval;
 
27036
      const int cimg_iobuffer = 12*1024*1024;
 
27037
      while ((err=std::fscanf(nfile,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile);
 
27038
      if(std::sscanf(item," P%u",&ppm_type)!=1) {
 
27039
        if (!file) cimg::fclose(nfile);
 
27040
        throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PNM header 'P?' not found.",
 
27041
                              pixel_type(),filename?filename:"(FILE*)");
 
27042
      }
 
27043
      while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile);
 
27044
      if ((err=std::sscanf(item," %u %u %u",&W,&H,&colormax))<2) {
 
27045
        if (!file) cimg::fclose(nfile);
 
27046
        throw CImgIOException("CImg<%s>::load_pnm() : File '%s', WIDTH and HEIGHT fields are not defined in PNM header.",
 
27047
                              pixel_type(),filename?filename:"(FILE*)");
 
27048
      }
 
27049
      if (err==2) {
 
27050
        while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile);
 
27051
        if (std::sscanf(item,"%u",&colormax)!=1)
 
27052
          cimg::warn("CImg<%s>::load_pnm() : File '%s', COLORMAX field is not defined in PNM header.",
 
27053
                     pixel_type(),filename?filename:"(FILE*)");
 
27054
      }
 
27055
      std::fgetc(nfile);
 
27056
      assign();
 
27057
 
 
27058
      switch (ppm_type) {
 
27059
      case 2: { // Grey Ascii
 
27060
        assign(W,H,1,1);
 
27061
        T* rdata = data;
 
27062
        cimg_foroff(*this,off) { std::fscanf(nfile,"%d",&rval); *(rdata++) = (T)rval; }
 
27063
      } break;
 
27064
      case 3: { // Color Ascii
 
27065
        assign(W,H,1,3);
 
27066
        T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
 
27067
        cimg_forXY(*this,x,y) {
 
27068
          std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval);
 
27069
          *(rdata++) = (T)rval;
 
27070
          *(gdata++) = (T)gval;
 
27071
          *(bdata++) = (T)bval; }
 
27072
      } break;
 
27073
      case 5: { // Grey Binary
 
27074
        if (colormax<256) { // 8 bits
 
27075
          CImg<unsigned char> raw;
 
27076
          assign(W,H,1,1);
 
27077
          T *ptrd = ptr(0,0,0,0);
 
27078
          for (int toread = (int)size(); toread>0; ) {
 
27079
            raw.assign(cimg::min(toread,cimg_iobuffer));
 
27080
            cimg::fread(raw.data,raw.width,nfile);
 
27081
            toread-=raw.width;
 
27082
            const unsigned char *ptrs = raw.data;
 
27083
            for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
 
27084
          }
 
27085
        } else { // 16 bits
 
27086
          CImg<unsigned short> raw;
 
27087
          assign(W,H,1,1);
 
27088
          T *ptrd = ptr(0,0,0,0);
 
27089
          for (int toread = (int)size(); toread>0; ) {
 
27090
            raw.assign(cimg::min(toread,cimg_iobuffer/2));
 
27091
            cimg::fread(raw.data,raw.width,nfile);
 
27092
            toread-=raw.width;
 
27093
            const unsigned short *ptrs = raw.data;
 
27094
            for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
 
27095
          }
 
27096
        }
 
27097
      } break;
 
27098
      case 6: { // Color Binary
 
27099
        if (colormax<256) { // 8 bits
 
27100
          CImg<unsigned char> raw;
 
27101
          assign(W,H,1,3);
 
27102
          T
 
27103
            *ptr_r = ptr(0,0,0,0),
 
27104
            *ptr_g = ptr(0,0,0,1),
 
27105
            *ptr_b = ptr(0,0,0,2);
 
27106
          for (int toread = (int)size(); toread>0; ) {
 
27107
            raw.assign(cimg::min(toread,cimg_iobuffer));
 
27108
            cimg::fread(raw.data,raw.width,nfile);
 
27109
            toread-=raw.width;
 
27110
            const unsigned char *ptrs = raw.data;
 
27111
            for (unsigned int off = raw.width/3; off; --off) {
 
27112
              *(ptr_r++) = (T)*(ptrs++);
 
27113
              *(ptr_g++) = (T)*(ptrs++);
 
27114
              *(ptr_b++) = (T)*(ptrs++);
 
27115
            }
 
27116
          }
 
27117
        } else { // 16 bits
 
27118
          CImg<unsigned short> raw;
 
27119
          assign(W,H,1,3);
 
27120
          T
 
27121
            *ptr_r = ptr(0,0,0,0),
 
27122
            *ptr_g = ptr(0,0,0,1),
 
27123
            *ptr_b = ptr(0,0,0,2);
 
27124
          for (int toread = (int)size(); toread>0; ) {
 
27125
            raw.assign(cimg::min(toread,cimg_iobuffer/2));
 
27126
            cimg::fread(raw.data,raw.width,nfile);
 
27127
            if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
 
27128
            toread-=raw.width;
 
27129
            const unsigned short *ptrs = raw.data;
 
27130
            for (unsigned int off = raw.width/3; off; --off) {
 
27131
              *(ptr_r++) = (T)*(ptrs++);
 
27132
              *(ptr_g++) = (T)*(ptrs++);
 
27133
              *(ptr_b++) = (T)*(ptrs++);
 
27134
            }
 
27135
          }
 
27136
        }
 
27137
      } break;
 
27138
      default:
 
27139
        if (!file) cimg::fclose(nfile);
 
27140
        throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PPM type 'P%d' not supported.",
 
27141
                              pixel_type(),filename?filename:"(FILE*)",ppm_type);
 
27142
      }
 
27143
      if (!file) cimg::fclose(nfile);
 
27144
      return *this;
 
27145
    }
 
27146
 
 
27147
    //! Load an image from a PNM file.
 
27148
    static CImg<T> get_load_pnm(const char *const filename) {
 
27149
      return CImg<T>().load_pnm(filename);
 
27150
    }
 
27151
 
 
27152
    //! Load an image from a PNM file.
 
27153
    static CImg<T> get_load_pnm(std::FILE *const file) {
 
27154
      return CImg<T>().load_pnm(file);
 
27155
    }
 
27156
 
 
27157
    //! Load an image from a PNM file (in-place).
 
27158
    CImg<T>& load_pnm(const char *const filename) {
 
27159
      return _load_pnm(0,filename);
 
27160
    }
 
27161
 
 
27162
    //! Load an image from a PNM file (in-place).
 
27163
    CImg<T>& load_pnm(std::FILE *const file) {
 
27164
      return _load_pnm(file,0);
 
27165
    }
 
27166
 
 
27167
    // Load an image from a RGB file (internal).
 
27168
    CImg<T>& _load_rgb(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
 
27169
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_rgb() : Cannot load (null) filename.",pixel_type());
 
27170
      if (!dimw || !dimh) return assign();
 
27171
      const int cimg_iobuffer = 12*1024*1024;
 
27172
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 
27173
      CImg<unsigned char> raw;
 
27174
      assign(dimw,dimh,1,3);
 
27175
      T
 
27176
        *ptr_r = ptr(0,0,0,0),
 
27177
        *ptr_g = ptr(0,0,0,1),
 
27178
        *ptr_b = ptr(0,0,0,2);
 
27179
      for (int toread = (int)size(); toread>0; ) {
 
27180
        raw.assign(cimg::min(toread,cimg_iobuffer));
 
27181
        cimg::fread(raw.data,raw.width,nfile);
 
27182
        toread-=raw.width;
 
27183
        const unsigned char *ptrs = raw.data;
 
27184
        for (unsigned int off = raw.width/3; off; --off) {
 
27185
          *(ptr_r++) = (T)*(ptrs++);
 
27186
          *(ptr_g++) = (T)*(ptrs++);
 
27187
          *(ptr_b++) = (T)*(ptrs++);
 
27188
        }
 
27189
      }
 
27190
      if (!file) cimg::fclose(nfile);
 
27191
      return *this;
 
27192
    }
 
27193
 
 
27194
    //! Load an image from a RGB file.
 
27195
    static CImg<T> get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 
27196
      return CImg<T>().load_rgb(filename,dimw,dimh);
 
27197
    }
 
27198
 
 
27199
    //! Load an image from a RGB file.
 
27200
    static CImg<T> get_load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 
27201
      return CImg<T>().load_rgb(file,dimw,dimh);
 
27202
    }
 
27203
 
 
27204
    //! Load an image from a RGB file (in-place).
 
27205
    CImg<T>& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 
27206
      return _load_rgb(0,filename,dimw,dimh);
 
27207
    }
 
27208
 
 
27209
    //! Load an image from a RGB file (in-place).
 
27210
    CImg<T>& load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 
27211
      return _load_rgb(file,0,dimw,dimh);
 
27212
    }
 
27213
 
 
27214
    // Load an image from a RGBA file (internal).
 
27215
    CImg<T>& _load_rgba(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
 
27216
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_rgba() : Cannot load (null) filename.",pixel_type());
 
27217
      if (!dimw || !dimh) return assign();
 
27218
      const int cimg_iobuffer = 12*1024*1024;
 
27219
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 
27220
      CImg<unsigned char> raw;
 
27221
      assign(dimw,dimh,1,4);
 
27222
      T
 
27223
        *ptr_r = ptr(0,0,0,0),
 
27224
        *ptr_g = ptr(0,0,0,1),
 
27225
        *ptr_b = ptr(0,0,0,2),
 
27226
        *ptr_a = ptr(0,0,0,3);
 
27227
      for (int toread = (int)size(); toread>0; ) {
 
27228
        raw.assign(cimg::min(toread,cimg_iobuffer));
 
27229
        cimg::fread(raw.data,raw.width,nfile);
 
27230
        toread-=raw.width;
 
27231
        const unsigned char *ptrs = raw.data;
 
27232
        for (unsigned int off = raw.width/4; off; --off) {
 
27233
          *(ptr_r++) = (T)*(ptrs++);
 
27234
          *(ptr_g++) = (T)*(ptrs++);
 
27235
          *(ptr_b++) = (T)*(ptrs++);
 
27236
          *(ptr_a++) = (T)*(ptrs++);
 
27237
        }
 
27238
      }
 
27239
      if (!file) cimg::fclose(nfile);
 
27240
      return *this;
 
27241
    }
 
27242
 
 
27243
    //! Load an image from a RGBA file.
 
27244
    static CImg<T> get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 
27245
      return CImg<T>().load_rgba(filename,dimw,dimh);
 
27246
    }
 
27247
 
 
27248
    //! Load an image from a RGBA file.
 
27249
    static CImg<T> get_load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 
27250
      return CImg<T>().load_rgba(file,dimw,dimh);
 
27251
    }
 
27252
 
 
27253
    //! Load an image from a RGBA file (in-place).
 
27254
    CImg<T>& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
 
27255
      return _load_rgba(0,filename,dimw,dimh);
 
27256
    }
 
27257
 
 
27258
    //! Load an image from a RGBA file (in-place).
 
27259
    CImg<T>& load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
 
27260
      return _load_rgba(file,0,dimw,dimh);
 
27261
    }
 
27262
 
 
27263
    // Load an image from a TIFF file (internal).
19689
27264
    // (Original contribution by Jerome Boulanger).
19690
 
    CImg& load_tiff(const char *const filename) {
19691
 
#ifndef cimg_use_tiff
19692
 
      return load_other(filename);
19693
 
#else
19694
 
      TIFF *tif = TIFFOpen(filename,"r");
19695
 
#if cimg_debug>=3
19696
 
      TIFFSetWarningHandler(0);
19697
 
      TIFFSetErrorHandler(0);
19698
 
#endif
19699
 
      if (tif) {
19700
 
        unsigned int number_of_directories = 0;
19701
 
        do ++number_of_directories; while (TIFFReadDirectory(tif));
19702
 
        uint16 samplesperpixel, bitspersample;
19703
 
        uint32 nx,ny;
19704
 
        TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx);
19705
 
        TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny);
19706
 
        TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel);
19707
 
        if (samplesperpixel!=1 && samplesperpixel!=3 && samplesperpixel!=4) {
19708
 
          cimg::warn("CImg<%s>::load_tiff() : File '%s', unknow value for tag : TIFFTAG_SAMPLESPERPIXEL, will force it to 1.",
19709
 
                     pixel_type(),filename?filename:"(FILE*)");
19710
 
          samplesperpixel=1;
19711
 
        }
19712
 
        TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
19713
 
        TIFFClose(tif);
19714
 
        tif = TIFFOpen(filename,"r");
19715
 
        assign(nx,ny,number_of_directories,samplesperpixel);
19716
 
        unsigned int dir = 0;
19717
 
        do {
19718
 
          if (bitspersample!=8 || !(samplesperpixel == 3 || samplesperpixel == 4)) {
19719
 
            uint16 photo, config;
19720
 
            TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config);
19721
 
            TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo);
19722
 
            if (TIFFIsTiled(tif)) {
19723
 
              uint32 tw, th;
19724
 
              TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
19725
 
              TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
19726
 
              if (config==PLANARCONFIG_CONTIG) switch(bitspersample) {
19727
 
              case 8: {
19728
 
                unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
19729
 
                if (buf) {
 
27265
#ifdef cimg_use_tiff
 
27266
    CImg<T>& _load_tiff(TIFF *tif, const unsigned int directory) {
 
27267
      if (!TIFFSetDirectory(tif,directory)) return assign();
 
27268
      uint16 samplesperpixel, bitspersample;
 
27269
      uint32 nx,ny;
 
27270
      const char *const filename = TIFFFileName(tif);
 
27271
      TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx);
 
27272
      TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny);
 
27273
      TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel);
 
27274
      if (samplesperpixel!=1 && samplesperpixel!=3 && samplesperpixel!=4) {
 
27275
        cimg::warn("CImg<%s>::load_tiff() : File '%s', unknow value for tag : TIFFTAG_SAMPLESPERPIXEL, will force it to 1.",
 
27276
                   pixel_type(),filename);
 
27277
        samplesperpixel = 1;
 
27278
      }
 
27279
      TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample);
 
27280
      assign(nx,ny,1,samplesperpixel);
 
27281
      if (bitspersample!=8 || !(samplesperpixel==3 || samplesperpixel==4)) {
 
27282
        uint16 photo, config;
 
27283
        TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config);
 
27284
        TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo);
 
27285
        if (TIFFIsTiled(tif)) {
 
27286
          uint32 tw, th;
 
27287
          TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw);
 
27288
          TIFFGetField(tif,TIFFTAG_TILELENGTH,&th);
 
27289
          if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
 
27290
            case 8: {
 
27291
              unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
 
27292
              if (buf) {
 
27293
                for (unsigned int row = 0; row<ny; row+=th)
 
27294
                  for (unsigned int col = 0; col<nx; col+=tw) {
 
27295
                    if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 
27296
                      _TIFFfree(buf); TIFFClose(tif);
 
27297
                      throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 
27298
                                          pixel_type(),filename);
 
27299
                    } else {
 
27300
                      unsigned char *ptr = buf;
 
27301
                      for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 
27302
                        for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 
27303
                          for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 
27304
                            (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
 
27305
                    }
 
27306
                  }
 
27307
                _TIFFfree(buf);
 
27308
              }
 
27309
            } break;
 
27310
            case 16: {
 
27311
              unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
 
27312
              if (buf) {
 
27313
                for (unsigned int row = 0; row<ny; row+=th)
 
27314
                  for (unsigned int col = 0; col<nx; col+=tw) {
 
27315
                    if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 
27316
                      _TIFFfree(buf); TIFFClose(tif);
 
27317
                      throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 
27318
                                          pixel_type(),filename);
 
27319
                    } else {
 
27320
                      unsigned short *ptr = buf;
 
27321
                      for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 
27322
                        for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 
27323
                          for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 
27324
                            (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
 
27325
                    }
 
27326
                  }
 
27327
                _TIFFfree(buf);
 
27328
              }
 
27329
            } break;
 
27330
            case 32: {
 
27331
              float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
 
27332
              if (buf) {
 
27333
                for (unsigned int row = 0; row<ny; row+=th)
 
27334
                  for (unsigned int col = 0; col<nx; col+=tw) {
 
27335
                    if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 
27336
                      _TIFFfree(buf); TIFFClose(tif);
 
27337
                      throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
 
27338
                                          pixel_type(),filename);
 
27339
                    } else {
 
27340
                      float *ptr = buf;
 
27341
                      for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 
27342
                        for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 
27343
                          for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
 
27344
                            (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
 
27345
                    }
 
27346
                  }
 
27347
                _TIFFfree(buf);
 
27348
              }
 
27349
            } break;
 
27350
            } else switch (bitspersample) {
 
27351
            case 8: {
 
27352
              unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
 
27353
              if (buf) {
 
27354
                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
19730
27355
                  for (unsigned int row = 0; row<ny; row+=th)
19731
27356
                    for (unsigned int col = 0; col<nx; col+=tw) {
19732
 
                      if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 
27357
                      if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
19733
27358
                        _TIFFfree(buf); TIFFClose(tif);
19734
27359
                        throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
19735
 
                                            pixel_type(),filename?filename:"(FILE*)");
 
27360
                                            pixel_type(),filename);
19736
27361
                      } else {
19737
27362
                        unsigned char *ptr = buf;
19738
 
                        for (unsigned int rr=row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
19739
 
                          for (unsigned int cc=col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
19740
 
                            for (unsigned int vv=0; vv<samplesperpixel; ++vv) (*this)(cc,rr,dir,vv) = (T)(float)*(ptr++);
 
27363
                        for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 
27364
                          for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 
27365
                            (*this)(cc,rr,vv) = (T)(float)*(ptr++);
19741
27366
                      }
19742
27367
                    }
19743
 
                  _TIFFfree(buf);
19744
 
                }
19745
 
              } break;
19746
 
              case 16: {
19747
 
                unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
19748
 
                if (buf) {
 
27368
                _TIFFfree(buf);
 
27369
              }
 
27370
            } break;
 
27371
            case 16: {
 
27372
              unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
 
27373
              if (buf) {
 
27374
                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
19749
27375
                  for (unsigned int row = 0; row<ny; row+=th)
19750
27376
                    for (unsigned int col = 0; col<nx; col+=tw) {
19751
 
                      if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 
27377
                      if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
19752
27378
                        _TIFFfree(buf); TIFFClose(tif);
19753
27379
                        throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
19754
 
                                            pixel_type(),filename?filename:"(FILE*)");
 
27380
                                            pixel_type(),filename);
19755
27381
                      } else {
19756
27382
                        unsigned short *ptr = buf;
19757
 
                        for (unsigned int rr=row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
19758
 
                          for (unsigned int cc=col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
19759
 
                            for (unsigned int vv=0; vv<samplesperpixel; ++vv) (*this)(cc,rr,dir,vv) = (T)(float)*(ptr++);
 
27383
                        for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 
27384
                          for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 
27385
                            (*this)(cc,rr,vv) = (T)(float)*(ptr++);
19760
27386
                      }
19761
27387
                    }
19762
 
                  _TIFFfree(buf);
19763
 
                }
19764
 
              } break;
19765
 
              case 32: {
19766
 
                float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
19767
 
                if (buf) {
 
27388
                _TIFFfree(buf);
 
27389
              }
 
27390
            } break;
 
27391
            case 32: {
 
27392
              float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
 
27393
              if (buf) {
 
27394
                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
19768
27395
                  for (unsigned int row = 0; row<ny; row+=th)
19769
27396
                    for (unsigned int col = 0; col<nx; col+=tw) {
19770
 
                      if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
 
27397
                      if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
19771
27398
                        _TIFFfree(buf); TIFFClose(tif);
19772
27399
                        throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
19773
 
                                            pixel_type(),filename?filename:"(FILE*)");
 
27400
                                            pixel_type(),filename);
19774
27401
                      } else {
19775
27402
                        float *ptr = buf;
19776
 
                        for (unsigned int rr=row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
19777
 
                          for (unsigned int cc=col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
19778
 
                            for (unsigned int vv=0; vv<samplesperpixel; ++vv) (*this)(cc,rr,dir,vv) = (T)(float)*(ptr++);
 
27403
                        for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
 
27404
                          for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
 
27405
                            (*this)(cc,rr,vv) = (T)(float)*(ptr++);
19779
27406
                      }
19780
27407
                    }
19781
 
                  _TIFFfree(buf);
19782
 
                }
19783
 
              } break;
19784
 
              } else switch (bitspersample) {
19785
 
              case 8: {
19786
 
                unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
19787
 
                if (buf) {
19788
 
                  for (unsigned int vv=0; vv<samplesperpixel; ++vv)
19789
 
                    for (unsigned int row = 0; row<ny; row+=th)
19790
 
                      for (unsigned int col = 0; col<nx; col+=tw) {
19791
 
                        if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
19792
 
                          _TIFFfree(buf); TIFFClose(tif);
19793
 
                          throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
19794
 
                                              pixel_type(),filename?filename:"(FILE*)");
19795
 
                        } else {
19796
 
                          unsigned char *ptr = buf;
19797
 
                          for (unsigned int rr=row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
19798
 
                            for (unsigned int cc=col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
19799
 
                              (*this)(cc,rr,dir,vv) = (T)(float)*(ptr++);
19800
 
                        }
19801
 
                      }
19802
 
                  _TIFFfree(buf);
19803
 
                }
19804
 
              } break;
19805
 
              case 16: {
19806
 
                unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
19807
 
                if (buf) {
19808
 
                  for (unsigned int vv=0; vv<samplesperpixel; ++vv)
19809
 
                    for (unsigned int row = 0; row<ny; row+=th)
19810
 
                      for (unsigned int col = 0; col<nx; col+=tw) {
19811
 
                        if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
19812
 
                          _TIFFfree(buf); TIFFClose(tif);
19813
 
                          throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
19814
 
                                              pixel_type(),filename?filename:"(FILE*)");
19815
 
                        } else {
19816
 
                          unsigned short *ptr = buf;
19817
 
                          for (unsigned int rr=row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
19818
 
                            for (unsigned int cc=col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
19819
 
                              (*this)(cc,rr,dir,vv) = (T)(float)*(ptr++);
19820
 
                        }
19821
 
                      }
19822
 
                  _TIFFfree(buf);
19823
 
                }
19824
 
              } break;
19825
 
              case 32: {
19826
 
                float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
19827
 
                if (buf) {
19828
 
                  for (unsigned int vv=0; vv<samplesperpixel; ++vv)
19829
 
                    for (unsigned int row = 0; row<ny; row+=th)
19830
 
                      for (unsigned int col = 0; col<nx; col+=tw) {
19831
 
                        if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
19832
 
                          _TIFFfree(buf); TIFFClose(tif);
19833
 
                          throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
19834
 
                                              pixel_type(),filename?filename:"(FILE*)");
19835
 
                        } else {
19836
 
                          float *ptr = buf;
19837
 
                          for (unsigned int rr=row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
19838
 
                            for (unsigned int cc=col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
19839
 
                              (*this)(cc,rr,dir,vv) = (T)(float)*(ptr++);
19840
 
                        }
19841
 
                      }
19842
 
                  _TIFFfree(buf);
19843
 
                }
19844
 
              } break;
19845
 
              }
19846
 
            } else {
19847
 
              if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
19848
 
              case 8: {
19849
 
                unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
19850
 
                if (buf) {
19851
 
                  uint32 row, rowsperstrip = (uint32)-1;
19852
 
                  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 
27408
                _TIFFfree(buf);
 
27409
              }
 
27410
            } break;
 
27411
            }
 
27412
        } else {
 
27413
          if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
 
27414
            case 8: {
 
27415
              unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
 
27416
              if (buf) {
 
27417
                uint32 row, rowsperstrip = (uint32)-1;
 
27418
                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 
27419
                for (row = 0; row<ny; row+= rowsperstrip) {
 
27420
                  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 
27421
                  tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 
27422
                  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 
27423
                    _TIFFfree(buf); TIFFClose(tif);
 
27424
                    throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
 
27425
                                        pixel_type(),filename);
 
27426
                  }
 
27427
                  unsigned char *ptr = buf;
 
27428
                  for (unsigned int rr = 0; rr<nrow; ++rr)
 
27429
                    for (unsigned int cc = 0; cc<nx; ++cc)
 
27430
                      for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 
27431
                }
 
27432
                _TIFFfree(buf);
 
27433
              }
 
27434
            } break;
 
27435
            case 16: {
 
27436
              unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
 
27437
              if (buf) {
 
27438
                uint32 row, rowsperstrip = (uint32)-1;
 
27439
                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 
27440
                for (row = 0; row<ny; row+= rowsperstrip) {
 
27441
                  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 
27442
                  tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 
27443
                  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 
27444
                    _TIFFfree(buf); TIFFClose(tif);
 
27445
                    throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
 
27446
                                        pixel_type(),filename);
 
27447
                  }
 
27448
                  unsigned short *ptr = buf;
 
27449
                  for (unsigned int rr = 0; rr<nrow; ++rr)
 
27450
                    for (unsigned int cc = 0; cc<nx; ++cc)
 
27451
                      for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 
27452
                }
 
27453
                _TIFFfree(buf);
 
27454
              }
 
27455
            } break;
 
27456
            case 32: {
 
27457
              float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
 
27458
              if (buf) {
 
27459
                uint32 row, rowsperstrip = (uint32)-1;
 
27460
                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 
27461
                for (row = 0; row<ny; row+= rowsperstrip) {
 
27462
                  uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
 
27463
                  tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 
27464
                  if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
 
27465
                    _TIFFfree(buf); TIFFClose(tif);
 
27466
                    throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
 
27467
                                        pixel_type(),filename);
 
27468
                  }
 
27469
                  float *ptr = buf;
 
27470
                  for (unsigned int rr = 0; rr<nrow; ++rr)
 
27471
                    for (unsigned int cc = 0; cc<nx; ++cc)
 
27472
                      for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
 
27473
                }
 
27474
                _TIFFfree(buf);
 
27475
              }
 
27476
            } break;
 
27477
            } else switch (bitspersample){
 
27478
            case 8: {
 
27479
              unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
 
27480
              if (buf) {
 
27481
                uint32 row, rowsperstrip = (uint32)-1;
 
27482
                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 
27483
                for (unsigned int vv=0; vv<samplesperpixel; ++vv)
19853
27484
                  for (row = 0; row<ny; row+= rowsperstrip) {
19854
27485
                    uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
19855
 
                    tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 
27486
                    tstrip_t strip = TIFFComputeStrip(tif, row, vv);
19856
27487
                    if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
19857
27488
                      _TIFFfree(buf); TIFFClose(tif);
19858
27489
                      throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
19859
 
                                          pixel_type(),filename?filename:"(FILE*)");
 
27490
                                          pixel_type(),filename);
19860
27491
                    }
19861
27492
                    unsigned char *ptr = buf;
19862
 
                    for (unsigned int rr=0; rr<nrow; ++rr) for (unsigned int cc=0; cc<nx; ++cc)
19863
 
                      for (unsigned int vv=0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,dir,vv) = (T)(float)*(ptr++);
 
27493
                    for (unsigned int rr = 0;rr<nrow; ++rr)
 
27494
                      for (unsigned int cc = 0; cc<nx; ++cc)
 
27495
                        (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
19864
27496
                  }
19865
 
                  _TIFFfree(buf);
19866
 
                }
19867
 
                } break;
19868
 
              case 16: {
19869
 
                unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
19870
 
                if (buf) {
19871
 
                  uint32 row, rowsperstrip = (uint32)-1;
19872
 
                  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 
27497
                _TIFFfree(buf);
 
27498
              }
 
27499
            } break;
 
27500
            case 16: {
 
27501
              unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
 
27502
              if (buf) {
 
27503
                uint32 row, rowsperstrip = (uint32)-1;
 
27504
                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 
27505
                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
19873
27506
                  for (row = 0; row<ny; row+= rowsperstrip) {
19874
27507
                    uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
19875
 
                    tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 
27508
                    tstrip_t strip = TIFFComputeStrip(tif, row, vv);
19876
27509
                    if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
19877
27510
                      _TIFFfree(buf); TIFFClose(tif);
19878
27511
                      throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
19879
 
                                          pixel_type(),filename?filename:"(FILE*)");
 
27512
                                          pixel_type(),filename);
19880
27513
                    }
19881
27514
                    unsigned short *ptr = buf;
19882
 
                    for (unsigned int rr=0; rr<nrow; ++rr) for (unsigned int cc=0; cc<nx; ++cc)
19883
 
                      for (unsigned int vv=0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,dir,vv) = (T)(float)*(ptr++);
 
27515
                    for (unsigned int rr = 0; rr<nrow; ++rr)
 
27516
                      for (unsigned int cc = 0; cc<nx; ++cc)
 
27517
                        (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
19884
27518
                  }
19885
 
                  _TIFFfree(buf);
19886
 
                }
19887
 
              } break;
19888
 
              case 32: {
19889
 
                float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
19890
 
                if (buf) {
19891
 
                  uint32 row, rowsperstrip = (uint32)-1;
19892
 
                  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 
27519
                _TIFFfree(buf);
 
27520
              }
 
27521
            } break;
 
27522
            case 32: {
 
27523
              float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
 
27524
              if (buf) {
 
27525
                uint32 row, rowsperstrip = (uint32)-1;
 
27526
                TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
 
27527
                for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
19893
27528
                  for (row = 0; row<ny; row+= rowsperstrip) {
19894
27529
                    uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
19895
 
                    tstrip_t strip = TIFFComputeStrip(tif, row, 0);
 
27530
                    tstrip_t strip = TIFFComputeStrip(tif, row, vv);
19896
27531
                    if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
19897
27532
                      _TIFFfree(buf); TIFFClose(tif);
19898
27533
                      throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
19899
 
                                          pixel_type(),filename?filename:"(FILE*)");
 
27534
                                          pixel_type(),filename);
19900
27535
                    }
19901
27536
                    float *ptr = buf;
19902
 
                    for (unsigned int rr=0; rr<nrow; ++rr) for (unsigned int cc=0; cc<nx; ++cc)
19903
 
                      for (unsigned int vv=0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,dir,vv) = (T)(float)*(ptr++);
 
27537
                    for (unsigned int rr = 0; rr<nrow; ++rr)  for (unsigned int cc = 0; cc<nx; ++cc)
 
27538
                        (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
19904
27539
                  }
19905
 
                  _TIFFfree(buf);
19906
 
                }
19907
 
              } break;
19908
 
              } else switch(bitspersample){
19909
 
              case 8: {
19910
 
                unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
19911
 
                if (buf) {
19912
 
                  uint32 row, rowsperstrip = (uint32)-1;
19913
 
                  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
19914
 
                  for (unsigned int vv=0; vv<samplesperpixel; ++vv)
19915
 
                    for (row = 0; row<ny; row+= rowsperstrip) {
19916
 
                      uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
19917
 
                      tstrip_t strip = TIFFComputeStrip(tif, row, vv);
19918
 
                      if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
19919
 
                        _TIFFfree(buf); TIFFClose(tif);
19920
 
                        throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
19921
 
                                            pixel_type(),filename?filename:"(FILE*)");
19922
 
                      }
19923
 
                      unsigned char *ptr = buf;
19924
 
                      for (unsigned int rr=0;rr<nrow; ++rr) for (unsigned int cc=0; cc<nx; ++cc)
19925
 
                        (*this)(cc,row+rr,dir,vv) = (T)(float)*(ptr++);
19926
 
                    }
19927
 
                  _TIFFfree(buf);
19928
 
                }
19929
 
              } break;
19930
 
              case 16: {
19931
 
                unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
19932
 
                if (buf) {
19933
 
                  uint32 row, rowsperstrip = (uint32)-1;
19934
 
                  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
19935
 
                  for (unsigned int vv=0; vv<samplesperpixel; ++vv)
19936
 
                    for (row = 0; row<ny; row+= rowsperstrip) {
19937
 
                      uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
19938
 
                      tstrip_t strip = TIFFComputeStrip(tif, row, vv);
19939
 
                      if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
19940
 
                        _TIFFfree(buf); TIFFClose(tif);
19941
 
                        throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
19942
 
                                            pixel_type(),filename?filename:"(FILE*)");
19943
 
                      }
19944
 
                      unsigned short *ptr = buf;
19945
 
                      for (unsigned int rr=0; rr<nrow; ++rr) for (unsigned int cc=0; cc<nx; ++cc)
19946
 
                          (*this)(cc,row+rr,dir,vv) = (T)(float)*(ptr++);
19947
 
                    }
19948
 
                  _TIFFfree(buf);
19949
 
                }
19950
 
              } break;
19951
 
              case 32: {
19952
 
                float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
19953
 
                if (buf) {
19954
 
                  uint32 row, rowsperstrip = (uint32)-1;
19955
 
                  TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
19956
 
                  for (unsigned int vv=0; vv<samplesperpixel; ++vv)
19957
 
                    for (row = 0; row<ny; row+= rowsperstrip) {
19958
 
                      uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
19959
 
                      tstrip_t strip = TIFFComputeStrip(tif, row, vv);
19960
 
                      if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
19961
 
                        _TIFFfree(buf); TIFFClose(tif);
19962
 
                        throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
19963
 
                                            pixel_type(),filename?filename:"(FILE*)");
19964
 
                      }
19965
 
                      float *ptr = buf;
19966
 
                      for (unsigned int rr=0; rr<nrow; ++rr) for (unsigned int cc=0; cc<nx; ++cc)
19967
 
                        (*this)(cc,row+rr,dir,vv) = (T)(float)*(ptr++);
19968
 
                    }
19969
 
                  _TIFFfree(buf);
19970
 
                }
19971
 
              } break;
19972
 
              }
19973
 
            }
19974
 
          } else {
19975
 
            uint32* raster = (uint32*)_TIFFmalloc(nx * ny * sizeof (uint32));
19976
 
            if (!raster) {
19977
 
              _TIFFfree(raster); TIFFClose(tif);
19978
 
              throw CImgException("CImg<%s>::load_tiff() : File '%s', not enough memory for buffer allocation.",
19979
 
                                  pixel_type(),filename?filename:"(FILE*)");
19980
 
            }
19981
 
            TIFFReadRGBAImage(tif,nx,ny,raster,0);
19982
 
            switch (samplesperpixel) {
19983
 
            case 1: {
19984
 
              cimg_forXY(*this,x,y) (*this)(x,y,dir) = (T)(float)((raster[nx*(ny-1-y)+x]+ 128) / 257);
19985
 
            } break;
19986
 
            case 3: {
19987
 
              cimg_forXY(*this,x,y) {
19988
 
                (*this)(x,y,dir,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
19989
 
                (*this)(x,y,dir,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
19990
 
                (*this)(x,y,dir,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
19991
 
              }
19992
 
            } break;
19993
 
            case 4: {
19994
 
              cimg_forXY(*this,x,y) {
19995
 
                (*this)(x,y,dir,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
19996
 
                (*this)(x,y,dir,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
19997
 
                (*this)(x,y,dir,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
19998
 
                (*this)(x,y,dir,3) = (T)(float)TIFFGetA(raster[nx*(ny-1-y)+x]);
19999
 
              }
20000
 
            } break;
20001
 
            }
20002
 
            _TIFFfree(raster);
20003
 
          }
20004
 
          ++dir;
20005
 
        } while (TIFFReadDirectory(tif));
 
27540
                _TIFFfree(buf);
 
27541
              }
 
27542
            } break;
 
27543
            }
 
27544
        }
 
27545
      } else {
 
27546
        uint32* raster = (uint32*)_TIFFmalloc(nx * ny * sizeof (uint32));
 
27547
        if (!raster) {
 
27548
          _TIFFfree(raster); TIFFClose(tif);
 
27549
          throw CImgException("CImg<%s>::load_tiff() : File '%s', not enough memory for buffer allocation.",
 
27550
                              pixel_type(),filename);
 
27551
        }
 
27552
        TIFFReadRGBAImage(tif,nx,ny,raster,0);
 
27553
        switch (samplesperpixel) {
 
27554
        case 1: {
 
27555
          cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny-1-y)+x]+ 128) / 257);
 
27556
        } break;
 
27557
        case 3: {
 
27558
          cimg_forXY(*this,x,y) {
 
27559
            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
 
27560
            (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
 
27561
            (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
 
27562
          }
 
27563
        } break;
 
27564
        case 4: {
 
27565
          cimg_forXY(*this,x,y) {
 
27566
            (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
 
27567
            (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
 
27568
            (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
 
27569
            (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny-1-y)+x]);
 
27570
          }
 
27571
        } break;
 
27572
        }
 
27573
        _TIFFfree(raster);
 
27574
      }
 
27575
      return *this;
 
27576
    }
 
27577
#endif
 
27578
 
 
27579
    //! Load an image from a TIFF file.
 
27580
    static CImg<T> get_load_tiff(const char *const filename,
 
27581
                                 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
27582
                                 const unsigned int step_frame=1) {
 
27583
      return CImg<T>().load_tiff(filename,first_frame,last_frame,step_frame);
 
27584
    }
 
27585
 
 
27586
    //! Load an image from a TIFF file (in-place).
 
27587
    CImg<T>& load_tiff(const char *const filename,
 
27588
                       const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
27589
                       const unsigned int step_frame=1) {
 
27590
      if (!filename) throw CImgArgumentException("CImg<%s>::load_tiff() : Cannot load (null) filename.",pixel_type());
 
27591
      const unsigned int
 
27592
        nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 
27593
        nstep_frame = step_frame?step_frame:1;
 
27594
      unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
 
27595
 
 
27596
#ifndef cimg_use_tiff
 
27597
      if (nfirst_frame || nlast_frame!=~0U || nstep_frame>1)
 
27598
        throw CImgArgumentException("CImg<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
 
27599
                                    "('cimg_use_tiff' must be defined).",pixel_type(),filename);
 
27600
      return load_other(filename);
 
27601
#else
 
27602
      TIFF *tif = TIFFOpen(filename,"r");
 
27603
      if (tif) {
 
27604
        unsigned int nb_images = 0;
 
27605
        do ++nb_images; while (TIFFReadDirectory(tif));
 
27606
        if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
 
27607
          cimg::warn("CImg<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
 
27608
                     pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
 
27609
        if (nfirst_frame>=nb_images) return assign();
 
27610
        if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
 
27611
        TIFFSetDirectory(tif,0);
 
27612
        CImg<T> frame;
 
27613
        for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) {
 
27614
          frame._load_tiff(tif,l);
 
27615
          if (l==nfirst_frame) assign(frame.width,frame.height,1+(nlast_frame-nfirst_frame)/nstep_frame,frame.dim);
 
27616
          if (frame.width>width || frame.height>height || frame.dim>dim)
 
27617
            resize(cimg::max(frame.width,width),cimg::max(frame.height,height),-100,cimg::max(frame.dim,dim),0);
 
27618
          draw_image(frame,0,0,(l-nfirst_frame)/nstep_frame,0);
 
27619
        }
20006
27620
        TIFFClose(tif);
20007
 
      } else throw CImgException("CImg<%s>::load_tiff() : File '%s', error while loading the image.",
20008
 
                                 pixel_type(),filename?filename:"(FILE*)");
 
27621
      } else throw CImgException("CImg<%s>::load_tiff() : File '%s', cannot open file.",pixel_type(),filename);
20009
27622
      return *this;
20010
27623
#endif
20011
27624
    }
20012
27625
 
20013
 
    //! Load an image from a TIFF file.
20014
 
    static CImg get_load_tiff(const char *const filename) {
20015
 
      return CImg<T>().load_tiff(filename);
 
27626
    //! Load an image from an ANALYZE7.5/NIFTI file.
 
27627
    static CImg<T> get_load_analyze(const char *const filename, float *const voxsize=0) {
 
27628
      return CImg<T>().load_analyze(filename,voxsize);
20016
27629
    }
20017
27630
 
20018
 
    //! Load an image from a JPEG file.
20019
 
    CImg& load_jpeg(std::FILE *const file, const char *const filename=0) {
20020
 
#ifndef cimg_use_jpeg
20021
 
      if (file)
20022
 
        throw CImgIOException("CImg<%s>::load_jpeg() : File '(FILE*)' cannot be read without using libjpeg.",
20023
 
                              pixel_type());
20024
 
      else return load_other(filename);
20025
 
#else
20026
 
      struct jpeg_decompress_struct cinfo;
20027
 
      struct jpeg_error_mgr jerr;
20028
 
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
20029
 
 
20030
 
      cinfo.err = jpeg_std_error(&jerr);
20031
 
      jpeg_create_decompress(&cinfo);
20032
 
      jpeg_stdio_src(&cinfo,nfile);
20033
 
      jpeg_read_header(&cinfo,TRUE);
20034
 
      jpeg_start_decompress(&cinfo);
20035
 
 
20036
 
      if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) {
20037
 
        cimg::warn("CImg<%s>::load_jpeg() : Don't know how to read image '%s' with libpeg, trying ImageMagick's convert",
20038
 
                   pixel_type(),filename?filename:"(unknown)");
20039
 
        if (!file) return load_other(filename);
20040
 
        else {
20041
 
          if (!file) cimg::fclose(nfile);
20042
 
          throw CImgIOException("CImg<%s>::load_jpeg() : Cannot read JPEG image '%s' using a *FILE input.",
20043
 
                                pixel_type(),filename?filename:"(FILE*)");
20044
 
        }
20045
 
      }
20046
 
 
20047
 
      const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
20048
 
      unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components], *buf2 = buf;
20049
 
      JSAMPROW row_pointer[1];
20050
 
      while (cinfo.output_scanline < cinfo.output_height) {
20051
 
        row_pointer[0] = &buf[cinfo.output_scanline*row_stride];
20052
 
        jpeg_read_scanlines(&cinfo,row_pointer,1);
20053
 
      }
20054
 
      jpeg_finish_decompress(&cinfo);
20055
 
      jpeg_destroy_decompress(&cinfo);
20056
 
      if (!file) cimg::fclose(nfile);
20057
 
 
20058
 
      assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components);
20059
 
      switch (dim) {
20060
 
      case 1: {
20061
 
        T *ptr_g = ptr();
20062
 
        cimg_forXY(*this,x,y) *(ptr_g++) = (T)*(buf2++);
20063
 
      } break;
20064
 
      case 3: {
20065
 
        T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
20066
 
        cimg_forXY(*this,x,y) {
20067
 
          *(ptr_r++) = (T)*(buf2++);
20068
 
          *(ptr_g++) = (T)*(buf2++);
20069
 
          *(ptr_b++) = (T)*(buf2++);
20070
 
        }
 
27631
    //! Load an image from an ANALYZE7.5/NIFTI file (in-place).
 
27632
    CImg<T>& load_analyze(const char *const filename, float *const voxsize=0) {
 
27633
      if (!filename) throw CImgArgumentException("CImg<%s>::load_analyze() : Cannot load (null) filename.",pixel_type());
 
27634
      std::FILE *file_header = 0, *file = 0;
 
27635
      bool error_file = false;
 
27636
      char body[1024];
 
27637
      const char *ext = cimg::split_filename(filename,body);
 
27638
      if (!cimg::strncasecmp(ext,"nii",3)) file_header = cimg::fopen(filename,"rb");
 
27639
      else {
 
27640
        if (!cimg::strncasecmp(ext,"hdr",3) ||
 
27641
            !cimg::strncasecmp(ext,"img",3)) {
 
27642
          std::sprintf(body+cimg::strlen(body),".hdr");
 
27643
          file_header = cimg::fopen(body,"rb");
 
27644
          if (!file_header) error_file = true;
 
27645
          else {
 
27646
            std::sprintf(body+cimg::strlen(body)-3,"img");
 
27647
            file = cimg::fopen(body,"rb");
 
27648
            if (!file) { cimg::fclose(file_header); error_file = true; }
 
27649
          }
 
27650
        }
 
27651
      }
 
27652
      if (error_file) throw CImgIOException("CImg<%s>::load_analyze() : Filename '%s', not recognized as an Analyze 7.5 or NIFTI file.",
 
27653
                                            pixel_type(),filename);
 
27654
 
 
27655
      // Read header
 
27656
      bool endian = false;
 
27657
      unsigned int header_size;
 
27658
      cimg::fread(&header_size,1,file_header);
 
27659
      if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); }
 
27660
      unsigned char *header = new unsigned char[header_size];
 
27661
      cimg::fread(header+4,header_size-4,file_header);
 
27662
      if (file) cimg::fclose(file_header);
 
27663
      if (endian) {
 
27664
        cimg::invert_endianness((short*)(header+40),5);
 
27665
        cimg::invert_endianness((short*)(header+70),1);
 
27666
        cimg::invert_endianness((short*)(header+72),1);
 
27667
        cimg::invert_endianness((float*)(header+76),4);
 
27668
        cimg::invert_endianness((float*)(header+112),1);
 
27669
      }
 
27670
      unsigned short *dim = (unsigned short*)(header+40), dimx=1, dimy=1, dimz=1, dimv=1;
 
27671
      if (!dim[0]) cimg::warn("CImg<%s>::load_analyze() : Specified image has zero dimensions.",pixel_type());
 
27672
      if (dim[0]>4) cimg::warn("CImg<%s>::load_analyze() : Number of image dimension is %d, reading only the 4 first dimensions",
 
27673
                               pixel_type(),dim[0]);
 
27674
      if (dim[0]>=1) dimx = dim[1];
 
27675
      if (dim[0]>=2) dimy = dim[2];
 
27676
      if (dim[0]>=3) dimz = dim[3];
 
27677
      if (dim[0]>=4) dimv = dim[4];
 
27678
 
 
27679
      float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
 
27680
      const unsigned short datatype = *(short*)(header+70);
 
27681
      if (voxsize) { const float *vsize = (float*)(header+76); voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3]; }
 
27682
      delete[] header;
 
27683
 
 
27684
      // Read pixel data
 
27685
      std::FILE *nfile = file?file:file_header;
 
27686
      assign(dimx,dimy,dimz,dimv);
 
27687
      switch (datatype) {
 
27688
      case 2: {
 
27689
        unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
 
27690
        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 
27691
        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 
27692
        delete[] buffer;
20071
27693
      } break;
20072
27694
      case 4: {
20073
 
        T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1),
20074
 
          *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3);
20075
 
        cimg_forXY(*this,x,y) {
20076
 
          *(ptr_r++) = (T)*(buf2++);
20077
 
          *(ptr_g++) = (T)*(buf2++);
20078
 
          *(ptr_b++) = (T)*(buf2++);
20079
 
          *(ptr_a++) = (T)*(buf2++);
20080
 
        }
20081
 
      } break;
20082
 
      }
20083
 
      delete[] buf;
20084
 
      return *this;
20085
 
#endif
20086
 
    }
20087
 
 
20088
 
    //! Load an image from a JPEG file.
20089
 
    CImg& load_jpeg(const char *const filename) {
20090
 
      return load_jpeg(0,filename);
20091
 
    }
20092
 
 
20093
 
    //! Load an image from a JPEG file.
20094
 
    static CImg get_load_jpeg(std::FILE *const file, const char *const filename=0) {
20095
 
      return CImg<T>().load_jpeg(file,filename);
20096
 
    }
20097
 
 
20098
 
    //! Load an image from a JPEG file.
20099
 
    static CImg get_load_jpeg(const char *const filename) {
20100
 
      return CImg<T>().load_jpeg(0,filename);
20101
 
    }
20102
 
 
20103
 
    //! Load an image using builtin ImageMagick++ Library.
20104
 
    /**
20105
 
       Added April/may 2006 by Christoph Hormann <chris_hormann@gmx.de>
20106
 
       This is experimental code, not much tested, use with care.
20107
 
    **/
20108
 
    CImg& load_magick(const char *const filename) {
20109
 
#ifdef cimg_use_magick
20110
 
      Magick::Image image(filename);
20111
 
      const unsigned int W = image.size().width(), H = image.size().height();
20112
 
      switch (image.type()) {
20113
 
      case Magick::PaletteMatteType:
20114
 
      case Magick::TrueColorMatteType:
20115
 
      case Magick::ColorSeparationType: {
20116
 
        assign(W,H,1,4);
20117
 
        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);
20118
 
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
20119
 
        for (unsigned int off = W*H; off; --off) {
20120
 
          *(rdata++) = (T)(pixels->red);
20121
 
          *(gdata++) = (T)(pixels->green);
20122
 
          *(bdata++) = (T)(pixels->blue);
20123
 
          *(adata++) = (T)(pixels->opacity);
20124
 
          ++pixels;
20125
 
        }
20126
 
      } break;
20127
 
      case Magick::PaletteType:
20128
 
      case Magick::TrueColorType: {
20129
 
        assign(W,H,1,3);
20130
 
        T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
20131
 
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
20132
 
        for (unsigned int off = W*H; off; --off) {
20133
 
          *(rdata++) = (T)(pixels->red);
20134
 
          *(gdata++) = (T)(pixels->green);
20135
 
          *(bdata++) = (T)(pixels->blue);
20136
 
          ++pixels;
20137
 
        }
20138
 
      } break;
20139
 
      case Magick::GrayscaleMatteType: {
20140
 
        assign(W,H,1,2);
20141
 
        T *data = ptr(0,0,0,0), *adata = ptr(0,0,0,1);
20142
 
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
20143
 
        for (unsigned int off = W*H; off; --off) {
20144
 
          *(data++) = (T)(pixels->red);
20145
 
          *(adata++) = (T)(pixels->opacity);
20146
 
          ++pixels;
20147
 
        }
20148
 
      } break;
20149
 
      default: {
20150
 
        assign(W,H,1,1);
20151
 
        T *data = ptr(0,0,0,0);
20152
 
        Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
20153
 
        for (unsigned int off = W*H; off; --off) {
20154
 
          *(data++) = (T)(pixels->red);
20155
 
          ++pixels;
20156
 
        }
20157
 
      } break;
20158
 
      }
20159
 
#else
20160
 
      throw CImgIOException("CImg<%s>::load_magick() : File '%s', Magick++ has not been linked during compilation.",
20161
 
                            pixel_type(),filename?filename:"(null)");
20162
 
#endif
20163
 
      return *this;
20164
 
    }
20165
 
 
20166
 
    //! Load an image using builtin ImageMagick++ Library.
20167
 
    static CImg get_load_magick(const char *const filename) {
20168
 
      return CImg<T>().load_magick(filename);
20169
 
    }
20170
 
 
20171
 
    //! Load an image from a .RAW file.
20172
 
    CImg& load_raw(std::FILE *const file, const char *const filename,
20173
 
                   const unsigned int sizex, const unsigned int sizey=1,
20174
 
                   const unsigned int sizez=1, const unsigned int sizev=1,
20175
 
                   const bool multiplexed = false, const bool endian_swap = false) {
20176
 
      assign(sizex,sizey,sizez,sizev,0);
20177
 
      const unsigned int siz = size();
20178
 
      if (siz) {
20179
 
        std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
20180
 
        if (!multiplexed) {
20181
 
          cimg::fread(ptr(),siz,nfile);
20182
 
          if (endian_swap) cimg::endian_swap(ptr(),siz);
20183
 
        }
20184
 
        else {
20185
 
          CImg<T> buf(1,1,1,sizev);
20186
 
          cimg_forXYZ(*this,x,y,z) {
20187
 
            cimg::fread(buf.ptr(),sizev,nfile);
20188
 
            if (endian_swap) cimg::endian_swap(buf.ptr(),sizev);
20189
 
            set_vector_at(buf,x,y,z); }
20190
 
        }
20191
 
        if (!file) cimg::fclose(nfile);
20192
 
      }
20193
 
      return *this;
20194
 
    }
20195
 
 
20196
 
    //! Load an image from a .RAW file.
20197
 
    CImg& load_raw(const char *const filename,
20198
 
                   const unsigned int sizex, const unsigned int sizey=1,
20199
 
                   const unsigned int sizez=1, const unsigned int sizev=1,
20200
 
                   const bool multiplexed = false, const bool endian_swap = false) {
20201
 
      return load_raw(0,filename,sizex,sizey,sizez,sizev,multiplexed,endian_swap);
20202
 
    }
20203
 
 
20204
 
    //! Load an image from a RAW file.
20205
 
    static CImg get_load_raw(std::FILE *const file, const char *const filename,
20206
 
                             const unsigned int sizex, const unsigned int sizey=1,
20207
 
                             const unsigned int sizez=1, const unsigned int sizev=1,
20208
 
                             const bool multiplexed=false, const bool endian_swap=false) {
20209
 
      return CImg<T>().load_raw(file,filename,sizex,sizey,sizez,sizev,multiplexed,endian_swap);
20210
 
    }
20211
 
 
20212
 
    //! Load an image from a RAW file.
20213
 
    static CImg get_load_raw(const char *const filename,
20214
 
                             const unsigned int sizex, const unsigned int sizey=1,
20215
 
                             const unsigned int sizez=1, const unsigned int sizev=1,
20216
 
                             const bool multiplexed = false, const bool endian_swap = false) {
20217
 
      return CImg<T>().load_raw(0,filename,sizex,sizey,sizez,sizev,multiplexed,endian_swap);
20218
 
    }
20219
 
 
20220
 
    //! Load an image from a RGBA file.
20221
 
    CImg& load_rgba(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
20222
 
      const int cimg_iobuffer = 12*1024*1024;
20223
 
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
20224
 
      CImg<unsigned char> raw;
20225
 
      assign(dimw,dimh,1,4);
20226
 
      T
20227
 
        *ptr_r = ptr(0,0,0,0),
20228
 
        *ptr_g = ptr(0,0,0,1),
20229
 
        *ptr_b = ptr(0,0,0,2),
20230
 
        *ptr_a = ptr(0,0,0,3);
20231
 
      for (int toread = (int)size(); toread>0; ) {
20232
 
        raw.assign(cimg::min(toread,cimg_iobuffer));
20233
 
        cimg::fread(raw.data,raw.width,nfile);
20234
 
        toread-=raw.width;
20235
 
        const unsigned char *ptrs = raw.ptr();
20236
 
        for (unsigned int off = raw.width/4; off; --off) {
20237
 
          *(ptr_r++) = (T)*(ptrs++);
20238
 
          *(ptr_g++) = (T)*(ptrs++);
20239
 
          *(ptr_b++) = (T)*(ptrs++);
20240
 
          *(ptr_a++) = (T)*(ptrs++);
20241
 
        }
20242
 
      }
20243
 
      if (!file) cimg::fclose(nfile);
20244
 
      return *this;
20245
 
    }
20246
 
 
20247
 
    //! Load an image from a RGBA file.
20248
 
    CImg& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh) {
20249
 
      return load_rgba(0,filename,dimw,dimh);
20250
 
    }
20251
 
 
20252
 
    //! Load an image from a RGBA file.
20253
 
    static CImg get_load_rgba(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
20254
 
      return CImg<T>().load_rgba(file,filename,dimw,dimh);
20255
 
    }
20256
 
 
20257
 
    //! Load an image from a RGBA file.
20258
 
    static CImg get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh) {
20259
 
      return CImg<T>().load_rgba(0,filename,dimw,dimh);
20260
 
    }
20261
 
 
20262
 
    //! Load an image from a RGB file.
20263
 
    CImg& load_rgb(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
20264
 
      const int cimg_iobuffer = 12*1024*1024;
20265
 
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
20266
 
      CImg<unsigned char> raw;
20267
 
      assign(dimw,dimh,1,3);
20268
 
      T
20269
 
        *ptr_r = ptr(0,0,0,0),
20270
 
        *ptr_g = ptr(0,0,0,1),
20271
 
        *ptr_b = ptr(0,0,0,2);
20272
 
      for (int toread = (int)size(); toread>0; ) {
20273
 
        raw.assign(cimg::min(toread,cimg_iobuffer));
20274
 
        cimg::fread(raw.data,raw.width,nfile);
20275
 
        toread-=raw.width;
20276
 
        const unsigned char *ptrs = raw.ptr();
20277
 
        for (unsigned int off = raw.width/3; off; --off) {
20278
 
          *(ptr_r++) = (T)*(ptrs++);
20279
 
          *(ptr_g++) = (T)*(ptrs++);
20280
 
          *(ptr_b++) = (T)*(ptrs++);
20281
 
        }
20282
 
      }
20283
 
      if (!file) cimg::fclose(nfile);
20284
 
      return *this;
20285
 
    }
20286
 
 
20287
 
    //! Load an image from a RGB file.
20288
 
    CImg& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh) {
20289
 
      return load_rgb(0,filename,dimw,dimh);
20290
 
    }
20291
 
 
20292
 
    //! Load an image from a RGB file.
20293
 
    static CImg get_load_rgb(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
20294
 
      return CImg<T>().load_rgb(file,filename,dimw,dimh);
20295
 
    }
20296
 
 
20297
 
    //! Load an image from a RGB file.
20298
 
    static CImg get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh) {
20299
 
      return CImg<T>().load_rgb(0,filename,dimw,dimh);
20300
 
    }
20301
 
 
20302
 
    static void _load_inr(std::FILE *file, int out[8], float *const voxsize=0) {
20303
 
 
20304
 
#define cimg_load_inr_case(Tf,sign,pixsize,Ts) \
20305
 
     if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \
20306
 
        Ts *xval, *val = new Ts[fopt[0]*fopt[3]]; \
20307
 
        cimg_forYZ(*this,y,z) { \
20308
 
            cimg::fread(val,fopt[0]*fopt[3],nfile); \
20309
 
            if (fopt[7]!=endian) cimg::endian_swap(val,fopt[0]*fopt[3]); \
20310
 
            xval = val; cimg_forX(*this,x) cimg_forV(*this,k) (*this)(x,y,z,k) = (T)*(xval++); \
20311
 
          } \
20312
 
        delete[] val; \
20313
 
        loaded = true; \
20314
 
      }
20315
 
 
 
27695
        short *buffer = new short[dimx*dimy*dimz*dimv];
 
27696
        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 
27697
        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 
27698
        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 
27699
        delete[] buffer;
 
27700
      } break;
 
27701
      case 8: {
 
27702
        int *buffer = new int[dimx*dimy*dimz*dimv];
 
27703
        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 
27704
        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 
27705
        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 
27706
        delete[] buffer;
 
27707
      } break;
 
27708
      case 16: {
 
27709
        float *buffer = new float[dimx*dimy*dimz*dimv];
 
27710
        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 
27711
        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 
27712
        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 
27713
        delete[] buffer;
 
27714
      } break;
 
27715
      case 64: {
 
27716
        double *buffer = new double[dimx*dimy*dimz*dimv];
 
27717
        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
 
27718
        if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
 
27719
        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
 
27720
        delete[] buffer;
 
27721
      } break;
 
27722
      default:
 
27723
        cimg::fclose(nfile);
 
27724
        throw CImgIOException("CImg<%s>::load_analyze() : File '%s, cannot read images with 'datatype = %d'",
 
27725
                              pixel_type(),filename,datatype);
 
27726
      }
 
27727
      cimg::fclose(nfile);
 
27728
      return *this;
 
27729
    }
 
27730
 
 
27731
    //! Load an image (list) from a .cimg file.
 
27732
    static CImg<T> get_load_cimg(const char *const filename, const char axis='z', const char align='p') {
 
27733
      return CImg<T>().load_cimg(filename,axis,align);
 
27734
    }
 
27735
 
 
27736
    //! Load an image (list) from a .cimg file.
 
27737
    static CImg<T> get_load_cimg(std::FILE *const file, const char axis='z', const char align='p') {
 
27738
      return CImg<T>().load_cimg(file,axis,align);
 
27739
    }
 
27740
 
 
27741
    //! Load an image (list) from a .cimg file (in-place).
 
27742
    CImg<T>& load_cimg(const char *const filename, const char axis='z', const char align='p') {
 
27743
      CImgList<T> list;
 
27744
      list.load_cimg(filename);
 
27745
      if (list.size==1) return list[0].transfer_to(*this);
 
27746
      return assign(list.get_append(axis,align));
 
27747
    }
 
27748
 
 
27749
    //! Load an image (list) from a .cimg file (in-place).
 
27750
    CImg<T>& load_cimg(std::FILE *const file, const char axis='z', const char align='p') {
 
27751
      CImgList<T> list;
 
27752
      list.load_cimg(file);
 
27753
      if (list.size==1) return list[0].transfer_to(*this);
 
27754
      return assign(list.get_append(axis,align));
 
27755
    }
 
27756
 
 
27757
    //! Load a sub-image (list) from a .cimg file.
 
27758
    static CImg<T> get_load_cimg(const char *const filename,
 
27759
                                 const unsigned int n0, const unsigned int n1,
 
27760
                                 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 
27761
                                 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 
27762
                                 const char axis='z', const char align='p') {
 
27763
      return CImg<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
 
27764
    }
 
27765
 
 
27766
    //! Load a sub-image (list) from a non-compressed .cimg file.
 
27767
    static CImg<T> get_load_cimg(std::FILE *const file,
 
27768
                                 const unsigned int n0, const unsigned int n1,
 
27769
                                 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 
27770
                                 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 
27771
                                 const char axis='z', const char align='p') {
 
27772
      return CImg<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
 
27773
    }
 
27774
 
 
27775
    //! Load a sub-image (list) from a non-compressed .cimg file (in-place).
 
27776
    CImg<T>& load_cimg(const char *const filename,
 
27777
                       const unsigned int n0, const unsigned int n1,
 
27778
                       const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 
27779
                       const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 
27780
                       const char axis='z', const char align='p') {
 
27781
      CImgList<T> list;
 
27782
      list.load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 
27783
      if (list.size==1) return list[0].transfer_to(*this);
 
27784
      return assign(list.get_append(axis,align));
 
27785
    }
 
27786
 
 
27787
    //! Load a sub-image (list) from a non-compressed .cimg file (in-place).
 
27788
    CImg<T>& load_cimg(std::FILE *const file,
 
27789
                       const unsigned int n0, const unsigned int n1,
 
27790
                       const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 
27791
                       const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
 
27792
                       const char axis='z', const char align='p') {
 
27793
      CImgList<T> list;
 
27794
      list.load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 
27795
      if (list.size==1) return list[0].transfer_to(*this);
 
27796
      return assign(list.get_append(axis,align));
 
27797
    }
 
27798
 
 
27799
    // Load an image from an INRIMAGE-4 file (internal).
 
27800
    static void _load_inr_header(std::FILE *file, int out[8], float *const voxsize) {
20316
27801
      char item[1024], tmp1[64], tmp2[64];
20317
27802
      out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1;
20318
27803
      std::fscanf(file,"%63s",item);
20326
27811
        std::sscanf(item," VDIM%*[^0-9]%d",out+3);
20327
27812
        std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6);
20328
27813
        if (voxsize) {
20329
 
          std::sscanf(item," VX%*[^0-9.eE+-]%f",voxsize);
20330
 
          std::sscanf(item," VY%*[^0-9.eE+-]%f",voxsize+1);
20331
 
          std::sscanf(item," VZ%*[^0-9.eE+-]%f",voxsize+2);
 
27814
          std::sscanf(item," VX%*[^0-9.+-]%f",voxsize);
 
27815
          std::sscanf(item," VY%*[^0-9.+-]%f",voxsize+1);
 
27816
          std::sscanf(item," VZ%*[^0-9.+-]%f",voxsize+2);
20332
27817
        }
20333
27818
        if (std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1;
20334
 
        switch(std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
 
27819
        switch (std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
20335
27820
        case 0: break;
20336
27821
        case 2: out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strcpy(tmp1,tmp2);
20337
27822
        case 1:
20350
27835
      if(out[7]<0) throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type is not defined",pixel_type());
20351
27836
    }
20352
27837
 
20353
 
    //! Load an image from an INRIMAGE-4 file.
20354
 
    CImg& load_inr(std::FILE *const file, const char *const filename=0, float *const voxsize=0) {
 
27838
    CImg<T>& _load_inr(std::FILE *const file, const char *const filename, float *const voxsize) {
 
27839
#define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \
 
27840
     if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \
 
27841
        Ts *xval, *val = new Ts[fopt[0]*fopt[3]]; \
 
27842
        cimg_forYZ(*this,y,z) { \
 
27843
            cimg::fread(val,fopt[0]*fopt[3],nfile); \
 
27844
            if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \
 
27845
            xval = val; cimg_forX(*this,x) cimg_forV(*this,k) (*this)(x,y,z,k) = (T)*(xval++); \
 
27846
          } \
 
27847
        delete[] val; \
 
27848
        loaded = true; \
 
27849
      }
 
27850
 
 
27851
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_inr() : Cannot load (null) filename.",pixel_type());
20355
27852
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
20356
 
      int fopt[8], endian=cimg::endian()?1:0;
 
27853
      int fopt[8], endian=cimg::endianness()?1:0;
20357
27854
      bool loaded = false;
20358
27855
      if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1;
20359
 
      _load_inr(nfile,fopt,voxsize);
 
27856
      _load_inr_header(nfile,fopt,voxsize);
20360
27857
      assign(fopt[0],fopt[1],fopt[2],fopt[3]);
20361
 
      cimg_load_inr_case(0,0,8, unsigned char);
20362
 
      cimg_load_inr_case(0,1,8, char);
20363
 
      cimg_load_inr_case(0,0,16,unsigned short);
20364
 
      cimg_load_inr_case(0,1,16,short);
20365
 
      cimg_load_inr_case(0,0,32,unsigned int);
20366
 
      cimg_load_inr_case(0,1,32,int);
20367
 
      cimg_load_inr_case(1,0,32,float);
20368
 
      cimg_load_inr_case(1,1,32,float);
20369
 
      cimg_load_inr_case(1,0,64,double);
20370
 
      cimg_load_inr_case(1,1,64,double);
 
27858
      _cimg_load_inr_case(0,0,8, unsigned char);
 
27859
      _cimg_load_inr_case(0,1,8, char);
 
27860
      _cimg_load_inr_case(0,0,16,unsigned short);
 
27861
      _cimg_load_inr_case(0,1,16,short);
 
27862
      _cimg_load_inr_case(0,0,32,unsigned int);
 
27863
      _cimg_load_inr_case(0,1,32,int);
 
27864
      _cimg_load_inr_case(1,0,32,float);
 
27865
      _cimg_load_inr_case(1,1,32,float);
 
27866
      _cimg_load_inr_case(1,0,64,double);
 
27867
      _cimg_load_inr_case(1,1,64,double);
20371
27868
      if (!loaded) {
20372
27869
        if (!file) cimg::fclose(nfile);
20373
27870
        throw CImgIOException("CImg<%s>::load_inr() : File '%s', cannot read images of the type specified in the file",
20378
27875
    }
20379
27876
 
20380
27877
    //! Load an image from an INRIMAGE-4 file.
20381
 
    CImg& load_inr(const char *const filename, float *const voxsize=0) {
20382
 
      return load_inr(0,filename,voxsize);
20383
 
    }
20384
 
 
20385
 
    //! Load an image from an INRIMAGE-4 file.
20386
 
    static CImg get_load_inr(std::FILE *const file, const char *const filename=0, float *voxsize=0) {
20387
 
      return CImg<T>().load_inr(file,filename,voxsize);
20388
 
    }
20389
 
 
20390
 
    //! Load an image from an INRIMAGE-4 file.
20391
 
    static CImg get_load_inr(const char *const filename, float *const voxsize=0) {
20392
 
      return CImg<T>().load_inr(0,filename,voxsize);
20393
 
    }
20394
 
 
20395
 
    //! Load an image from a PANDORE file.
20396
 
    CImg& load_pandore(std::FILE *const file, const char *const filename) {
20397
 
 
20398
 
#define cimg_load_pandore_case(nid,nbdim,nwidth,nheight,ndepth,ndim,stype) \
 
27878
    static CImg<T> get_load_inr(const char *const filename, float *const voxsize=0) {
 
27879
      return CImg<T>().load_inr(filename,voxsize);
 
27880
    }
 
27881
 
 
27882
    //! Load an image from an INRIMAGE-4 file.
 
27883
    static CImg<T> get_load_inr(std::FILE *const file, float *voxsize=0) {
 
27884
      return CImg<T>().load_inr(file,voxsize);
 
27885
    }
 
27886
 
 
27887
    //! Load an image from an INRIMAGE-4 file (in-place).
 
27888
    CImg<T>& load_inr(const char *const filename, float *const voxsize=0) {
 
27889
      return _load_inr(0,filename,voxsize);
 
27890
    }
 
27891
 
 
27892
    //! Load an image from an INRIMAGE-4 file (in-place).
 
27893
    CImg<T>& load_inr(std::FILE *const file, float *const voxsize=0) {
 
27894
      return _load_inr(file,0,voxsize);
 
27895
    }
 
27896
 
 
27897
    // Load an image from a PANDORE file (internal).
 
27898
    CImg<T>& _load_pandore(std::FILE *const file, const char *const filename) {
 
27899
#define _cimg_load_pandore_case(nid,nbdim,nwidth,nheight,ndepth,ndim,stype) \
20399
27900
      case nid: { \
20400
27901
        cimg::fread(dims,nbdim,nfile); \
20401
 
        if (endian) cimg::endian_swap(dims,nbdim); \
 
27902
        if (endian) cimg::invert_endianness(dims,nbdim); \
20402
27903
        assign(nwidth,nheight,ndepth,ndim); \
20403
27904
        const unsigned int siz = size(); \
20404
27905
        stype *buffer = new stype[siz]; \
20405
27906
        cimg::fread(buffer,siz,nfile); \
20406
 
        if (endian) cimg::endian_swap(buffer,siz); \
20407
 
        T *ptrd = ptr(); \
 
27907
        if (endian) cimg::invert_endianness(buffer,siz); \
 
27908
        T *ptrd = data; \
20408
27909
        cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \
20409
27910
        buffer-=siz; \
20410
27911
        delete[] buffer; \
20411
27912
       } \
20412
27913
       break;
20413
27914
 
 
27915
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_pandore() : Cannot load (null) filename.",pixel_type());
20414
27916
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
20415
27917
      typedef unsigned char uchar;
20416
27918
      typedef unsigned short ushort;
20427
27929
      int ptbuf[4];
20428
27930
      cimg::fread(&imageid,1,nfile);
20429
27931
      const bool endian = (imageid>255);
20430
 
      if (endian) cimg::endian_swap(imageid);
 
27932
      if (endian) cimg::invert_endianness(imageid);
20431
27933
 
20432
27934
      cimg::fread(tmp,20,nfile);
20433
27935
      switch (imageid) {
20434
 
        cimg_load_pandore_case(2,2,dims[1],1,1,1,uchar);
20435
 
        cimg_load_pandore_case(3,2,dims[1],1,1,1,long);
20436
 
        cimg_load_pandore_case(4,2,dims[1],1,1,1,float);
20437
 
        cimg_load_pandore_case(5,3,dims[2],dims[1],1,1,uchar);
20438
 
        cimg_load_pandore_case(6,3,dims[2],dims[1],1,1,long);
20439
 
        cimg_load_pandore_case(7,3,dims[2],dims[1],1,1,float);
20440
 
        cimg_load_pandore_case(8,4,dims[3],dims[2],dims[1],1,uchar);
20441
 
        cimg_load_pandore_case(9,4,dims[3],dims[2],dims[1],1,long);
20442
 
        cimg_load_pandore_case(10,4,dims[3],dims[2],dims[1],1,float);
 
27936
        _cimg_load_pandore_case(2,2,dims[1],1,1,1,uchar);
 
27937
        _cimg_load_pandore_case(3,2,dims[1],1,1,1,long);
 
27938
        _cimg_load_pandore_case(4,2,dims[1],1,1,1,float);
 
27939
        _cimg_load_pandore_case(5,3,dims[2],dims[1],1,1,uchar);
 
27940
        _cimg_load_pandore_case(6,3,dims[2],dims[1],1,1,long);
 
27941
        _cimg_load_pandore_case(7,3,dims[2],dims[1],1,1,float);
 
27942
        _cimg_load_pandore_case(8,4,dims[3],dims[2],dims[1],1,uchar);
 
27943
        _cimg_load_pandore_case(9,4,dims[3],dims[2],dims[1],1,long);
 
27944
        _cimg_load_pandore_case(10,4,dims[3],dims[2],dims[1],1,float);
20443
27945
 
20444
27946
      case 11: { // Region 1D
20445
27947
        cimg::fread(dims,3,nfile);
20446
 
        if (endian) cimg::endian_swap(dims,3);
 
27948
        if (endian) cimg::invert_endianness(dims,3);
20447
27949
        assign(dims[1],1,1,1);
20448
27950
        const unsigned siz = size();
20449
27951
        if (dims[2]<256) {
20450
27952
          unsigned char *buffer = new unsigned char[siz];
20451
27953
          cimg::fread(buffer,siz,nfile);
20452
 
          T *ptrd = ptr();
 
27954
          T *ptrd = data;
20453
27955
          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
20454
27956
          buffer-=siz;
20455
27957
          delete[] buffer;
20457
27959
          if (dims[2]<65536) {
20458
27960
            unsigned short *buffer = new unsigned short[siz];
20459
27961
            cimg::fread(buffer,siz,nfile);
20460
 
            if (endian) cimg::endian_swap(buffer,siz);
20461
 
            T *ptrd = ptr();
 
27962
            if (endian) cimg::invert_endianness(buffer,siz);
 
27963
            T *ptrd = data;
20462
27964
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
20463
27965
            buffer-=siz;
20464
27966
            delete[] buffer;
20465
27967
          } else {
20466
27968
            unsigned int *buffer = new unsigned int[siz];
20467
27969
            cimg::fread(buffer,siz,nfile);
20468
 
            if (endian) cimg::endian_swap(buffer,siz);
20469
 
            T *ptrd = ptr();
 
27970
            if (endian) cimg::invert_endianness(buffer,siz);
 
27971
            T *ptrd = data;
20470
27972
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
20471
27973
            buffer-=siz;
20472
27974
            delete[] buffer;
20476
27978
        break;
20477
27979
      case 12: { // Region 2D
20478
27980
        cimg::fread(dims,4,nfile);
20479
 
        if (endian) cimg::endian_swap(dims,4);
 
27981
        if (endian) cimg::invert_endianness(dims,4);
20480
27982
        assign(dims[2],dims[1],1,1);
20481
27983
        const unsigned int siz = size();
20482
27984
        if (dims[3]<256) {
20483
27985
          unsigned char *buffer = new unsigned char[siz];
20484
27986
          cimg::fread(buffer,siz,nfile);
20485
 
          T *ptrd = ptr();
 
27987
          T *ptrd = data;
20486
27988
          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
20487
27989
          buffer-=siz;
20488
27990
          delete[] buffer;
20490
27992
          if (dims[3]<65536) {
20491
27993
            unsigned short *buffer = new unsigned short[siz];
20492
27994
            cimg::fread(buffer,siz,nfile);
20493
 
            if (endian) cimg::endian_swap(buffer,siz);
20494
 
            T *ptrd = ptr();
 
27995
            if (endian) cimg::invert_endianness(buffer,siz);
 
27996
            T *ptrd = data;
20495
27997
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
20496
27998
            buffer-=siz;
20497
27999
            delete[] buffer;
20498
28000
          } else {
20499
28001
            unsigned long *buffer = new unsigned long[siz];
20500
28002
            cimg::fread(buffer,siz,nfile);
20501
 
            if (endian) cimg::endian_swap(buffer,siz);
20502
 
            T *ptrd = ptr();
 
28003
            if (endian) cimg::invert_endianness(buffer,siz);
 
28004
            T *ptrd = data;
20503
28005
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
20504
28006
            buffer-=siz;
20505
28007
            delete[] buffer;
20509
28011
        break;
20510
28012
      case 13: { // Region 3D
20511
28013
        cimg::fread(dims,5,nfile);
20512
 
        if (endian) cimg::endian_swap(dims,5);
 
28014
        if (endian) cimg::invert_endianness(dims,5);
20513
28015
        assign(dims[3],dims[2],dims[1],1);
20514
28016
        const unsigned int siz = size();
20515
28017
        if (dims[4]<256) {
20516
28018
          unsigned char *buffer = new unsigned char[siz];
20517
28019
          cimg::fread(buffer,siz,nfile);
20518
 
          T *ptrd = ptr();
 
28020
          T *ptrd = data;
20519
28021
          cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
20520
28022
          buffer-=siz;
20521
28023
          delete[] buffer;
20523
28025
          if (dims[4]<65536) {
20524
28026
            unsigned short *buffer = new unsigned short[siz];
20525
28027
            cimg::fread(buffer,siz,nfile);
20526
 
            if (endian) cimg::endian_swap(buffer,siz);
20527
 
            T *ptrd = ptr();
 
28028
            if (endian) cimg::invert_endianness(buffer,siz);
 
28029
            T *ptrd = data;
20528
28030
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
20529
28031
            buffer-=siz;
20530
28032
            delete[] buffer;
20531
28033
          } else {
20532
28034
            unsigned int *buffer = new unsigned int[siz];
20533
28035
            cimg::fread(buffer,siz,nfile);
20534
 
            if (endian) cimg::endian_swap(buffer,siz);
20535
 
            T *ptrd = ptr();
 
28036
            if (endian) cimg::invert_endianness(buffer,siz);
 
28037
            T *ptrd = data;
20536
28038
            cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
20537
28039
            buffer-=siz;
20538
28040
            delete[] buffer;
20540
28042
        }
20541
28043
      }
20542
28044
        break;
20543
 
        cimg_load_pandore_case(16,4,dims[2],dims[1],1,3,uchar);
20544
 
        cimg_load_pandore_case(17,4,dims[2],dims[1],1,3,long);
20545
 
        cimg_load_pandore_case(18,4,dims[2],dims[1],1,3,float);
20546
 
        cimg_load_pandore_case(19,5,dims[3],dims[2],dims[1],3,uchar);
20547
 
        cimg_load_pandore_case(20,5,dims[3],dims[2],dims[1],3,long);
20548
 
        cimg_load_pandore_case(21,5,dims[3],dims[2],dims[1],3,float);
20549
 
        cimg_load_pandore_case(22,2,dims[1],1,1,dims[0],uchar);
20550
 
        cimg_load_pandore_case(23,2,dims[1],1,1,dims[0],long);
20551
 
        cimg_load_pandore_case(24,2,dims[1],1,1,dims[0],ulong);
20552
 
        cimg_load_pandore_case(25,2,dims[1],1,1,dims[0],float);
20553
 
        cimg_load_pandore_case(26,3,dims[2],dims[1],1,dims[0],uchar);
20554
 
        cimg_load_pandore_case(27,3,dims[2],dims[1],1,dims[0],long);
20555
 
        cimg_load_pandore_case(28,3,dims[2],dims[1],1,dims[0],ulong);
20556
 
        cimg_load_pandore_case(29,3,dims[2],dims[1],1,dims[0],float);
20557
 
        cimg_load_pandore_case(30,4,dims[3],dims[2],dims[1],dims[0],uchar);
20558
 
        cimg_load_pandore_case(31,4,dims[3],dims[2],dims[1],dims[0],long);
20559
 
        cimg_load_pandore_case(32,4,dims[3],dims[2],dims[1],dims[0],ulong);
20560
 
        cimg_load_pandore_case(33,4,dims[3],dims[2],dims[1],dims[0],float);
 
28045
        _cimg_load_pandore_case(16,4,dims[2],dims[1],1,3,uchar);
 
28046
        _cimg_load_pandore_case(17,4,dims[2],dims[1],1,3,long);
 
28047
        _cimg_load_pandore_case(18,4,dims[2],dims[1],1,3,float);
 
28048
        _cimg_load_pandore_case(19,5,dims[3],dims[2],dims[1],3,uchar);
 
28049
        _cimg_load_pandore_case(20,5,dims[3],dims[2],dims[1],3,long);
 
28050
        _cimg_load_pandore_case(21,5,dims[3],dims[2],dims[1],3,float);
 
28051
        _cimg_load_pandore_case(22,2,dims[1],1,1,dims[0],uchar);
 
28052
        _cimg_load_pandore_case(23,2,dims[1],1,1,dims[0],long);
 
28053
        _cimg_load_pandore_case(24,2,dims[1],1,1,dims[0],ulong);
 
28054
        _cimg_load_pandore_case(25,2,dims[1],1,1,dims[0],float);
 
28055
        _cimg_load_pandore_case(26,3,dims[2],dims[1],1,dims[0],uchar);
 
28056
        _cimg_load_pandore_case(27,3,dims[2],dims[1],1,dims[0],long);
 
28057
        _cimg_load_pandore_case(28,3,dims[2],dims[1],1,dims[0],ulong);
 
28058
        _cimg_load_pandore_case(29,3,dims[2],dims[1],1,dims[0],float);
 
28059
        _cimg_load_pandore_case(30,4,dims[3],dims[2],dims[1],dims[0],uchar);
 
28060
        _cimg_load_pandore_case(31,4,dims[3],dims[2],dims[1],dims[0],long);
 
28061
        _cimg_load_pandore_case(32,4,dims[3],dims[2],dims[1],dims[0],ulong);
 
28062
        _cimg_load_pandore_case(33,4,dims[3],dims[2],dims[1],dims[0],float);
20561
28063
      case 34: // Points 1D
20562
28064
        cimg::fread(ptbuf,1,nfile);
20563
 
        if (endian) cimg::endian_swap(ptbuf,1);
 
28065
        if (endian) cimg::invert_endianness(ptbuf,1);
20564
28066
        assign(1); (*this)(0) = (T)ptbuf[0];
20565
28067
        break;
20566
28068
      case 35: // Points 2D
20567
28069
        cimg::fread(ptbuf,2,nfile);
20568
 
        if (endian) cimg::endian_swap(ptbuf,2);
 
28070
        if (endian) cimg::invert_endianness(ptbuf,2);
20569
28071
        assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0];
20570
28072
        break;
20571
28073
      case 36: // Points 3D
20572
28074
        cimg::fread(ptbuf,3,nfile);
20573
 
        if (endian) cimg::endian_swap(ptbuf,3);
 
28075
        if (endian) cimg::invert_endianness(ptbuf,3);
20574
28076
        assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0];
20575
28077
        break;
20576
28078
      default:
20583
28085
    }
20584
28086
 
20585
28087
    //! Load an image from a PANDORE file.
20586
 
    CImg& load_pandore(const char *const filename) {
20587
 
      return load_pandore(0,filename);
20588
 
    }
20589
 
 
20590
 
    //! Load an image from a PANDORE file.
20591
 
    static CImg get_load_pandore(std::FILE *const file, const char *const filename=0) {
20592
 
      return CImg<T>().load_pandore(file,filename);
20593
 
    }
20594
 
 
20595
 
    //! Load an image from a PANDORE file.
20596
 
    static CImg get_load_pandore(const char *const filename) {
20597
 
      return CImg<T>().load_pandore(0,filename);
20598
 
    }
20599
 
 
20600
 
    //! Load an image from an ANALYZE7.5/NIFTI file.
20601
 
    CImg& load_analyze(const char *const filename, float *const voxsize=0) {
20602
 
      std::FILE *file_header = 0, *file = 0;
20603
 
      bool error_file = false;
20604
 
      char body[1024];
20605
 
      const char *ext = cimg::filename_split(filename,body);
20606
 
      if (!cimg::strncasecmp(ext,"nii",3)) file_header = cimg::fopen(filename,"rb");
20607
 
      else {
20608
 
        if (!cimg::strncasecmp(ext,"hdr",3) ||
20609
 
            !cimg::strncasecmp(ext,"img",3)) {
20610
 
          std::sprintf(body+cimg::strlen(body),".hdr");
20611
 
          file_header = cimg::fopen(body,"rb");
20612
 
          if (!file_header) error_file = true;
20613
 
          else {
20614
 
            std::sprintf(body+cimg::strlen(body)-3,"img");
20615
 
            file = cimg::fopen(body,"rb");
20616
 
            if (!file) { cimg::fclose(file_header); error_file = true; }
20617
 
          }
20618
 
        }
20619
 
      }
20620
 
      if (error_file) throw CImgIOException("CImg<%s>::load_analyze() : Filename '%s', not recognized as an Analyze 7.5 or NIFTI file.",
20621
 
                                            pixel_type(),filename);
20622
 
 
20623
 
      // Read header
20624
 
      bool endian = false;
20625
 
      unsigned int header_size;
20626
 
      cimg::fread(&header_size,1,file_header);
20627
 
      if (header_size>=4096) { endian = true; cimg::endian_swap(header_size); }
20628
 
      unsigned char *header = new unsigned char[header_size];
20629
 
      cimg::fread(header+4,header_size-4,file_header);
20630
 
      if (file) cimg::fclose(file_header);
20631
 
      if (endian) {
20632
 
        cimg::endian_swap((short*)(header+40),5);
20633
 
        cimg::endian_swap((short*)(header+70),1);
20634
 
        cimg::endian_swap((short*)(header+72),1);
20635
 
        cimg::endian_swap((float*)(header+76),4);
20636
 
        cimg::endian_swap((float*)(header+112),1);
20637
 
      }
20638
 
      unsigned short *dim = (unsigned short*)(header+40), dimx=1, dimy=1, dimz=1, dimv=1;
20639
 
      if (!dim[0]) cimg::warn("CImg<%s>::load_analyze() : Specified image has zero dimensions.",pixel_type());
20640
 
      if (dim[0]>4) cimg::warn("CImg<%s>::load_analyze() : Number of image dimension is %d, reading only the 4 first dimensions",
20641
 
                               pixel_type(),dim[0]);
20642
 
      if (dim[0]>=1) dimx = dim[1];
20643
 
      if (dim[0]>=2) dimy = dim[2];
20644
 
      if (dim[0]>=3) dimz = dim[3];
20645
 
      if (dim[0]>=4) dimv = dim[4];
20646
 
 
20647
 
      float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
20648
 
      const unsigned short datatype = *(short*)(header+70);
20649
 
      if (voxsize) { const float *vsize = (float*)(header+76); voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3]; }
20650
 
      delete[] header;
20651
 
 
20652
 
      // Read pixel data
20653
 
      std::FILE *nfile = file?file:file_header;
20654
 
      assign(dimx,dimy,dimz,dimv);
20655
 
      switch (datatype) {
20656
 
      case 2: {
20657
 
        unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
20658
 
        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
20659
 
        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
20660
 
        delete[] buffer;
20661
 
      } break;
20662
 
      case 4: {
20663
 
        short *buffer = new short[dimx*dimy*dimz*dimv];
20664
 
        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
20665
 
        if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
20666
 
        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
20667
 
        delete[] buffer;
20668
 
      } break;
20669
 
      case 8: {
20670
 
        int *buffer = new int[dimx*dimy*dimz*dimv];
20671
 
        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
20672
 
        if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
20673
 
        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
20674
 
        delete[] buffer;
20675
 
      } break;
20676
 
      case 16: {
20677
 
        float *buffer = new float[dimx*dimy*dimz*dimv];
20678
 
        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
20679
 
        if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
20680
 
        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
20681
 
        delete[] buffer;
20682
 
      } break;
20683
 
      case 64: {
20684
 
        double *buffer = new double[dimx*dimy*dimz*dimv];
20685
 
        cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
20686
 
        if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv);
20687
 
        cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
20688
 
        delete[] buffer;
20689
 
      } break;
20690
 
      default:
20691
 
        cimg::fclose(nfile);
20692
 
        throw CImgIOException("CImg<%s>::load_analyze() : File '%s, cannot read images with 'datatype = %d'",
20693
 
                              pixel_type(),filename,datatype);
20694
 
      }
20695
 
      cimg::fclose(nfile);
 
28088
    static CImg<T> get_load_pandore(const char *const filename) {
 
28089
      return CImg<T>().load_pandore(filename);
 
28090
    }
 
28091
 
 
28092
    //! Load an image from a PANDORE file.
 
28093
    static CImg<T> get_load_pandore(std::FILE *const file) {
 
28094
      return CImg<T>().load_pandore(file);
 
28095
    }
 
28096
 
 
28097
    //! Load an image from a PANDORE file (in-place).
 
28098
    CImg<T>& load_pandore(const char *const filename) {
 
28099
      return _load_pandore(0,filename);
 
28100
    }
 
28101
 
 
28102
    //! Load an image from a PANDORE file (in-place).
 
28103
    CImg<T>& load_pandore(std::FILE *const file) {
 
28104
      return _load_pandore(file,0);
 
28105
    }
 
28106
 
 
28107
    //! Load an image from a PAR-REC (Philips) file.
 
28108
    static CImg<T> get_load_parrec(const char *const filename, const char axis='v', const char align='p') {
 
28109
      return CImg<T>().load_parrec(filename,axis,align);
 
28110
    }
 
28111
 
 
28112
    //! Load an image from a PAR-REC (Philips) file (in-place).
 
28113
    CImg<T>& load_parrec(const char *const filename, const char axis='v', const char align='p') {
 
28114
      CImgList<T> list;
 
28115
      list.load_parrec(filename);
 
28116
      if (list.size==1) return list[0].transfer_to(*this);
 
28117
      return assign(list.get_append(axis,align));
 
28118
    }
 
28119
 
 
28120
    // Load an image from a .RAW file (internal).
 
28121
    CImg<T>& _load_raw(std::FILE *const file, const char *const filename,
 
28122
                       const unsigned int sizex, const unsigned int sizey,
 
28123
                       const unsigned int sizez, const unsigned int sizev,
 
28124
                       const bool multiplexed, const bool invert_endianness) {
 
28125
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_raw() : Cannot load (null) filename.",pixel_type());
 
28126
      assign(sizex,sizey,sizez,sizev,0);
 
28127
      const unsigned int siz = size();
 
28128
      if (siz) {
 
28129
        std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
 
28130
        if (!multiplexed) {
 
28131
          cimg::fread(data,siz,nfile);
 
28132
          if (invert_endianness) cimg::invert_endianness(data,siz);
 
28133
        }
 
28134
        else {
 
28135
          CImg<T> buf(1,1,1,sizev);
 
28136
          cimg_forXYZ(*this,x,y,z) {
 
28137
            cimg::fread(buf.data,sizev,nfile);
 
28138
            if (invert_endianness) cimg::invert_endianness(buf.data,sizev);
 
28139
            set_vector_at(buf,x,y,z); }
 
28140
        }
 
28141
        if (!file) cimg::fclose(nfile);
 
28142
      }
20696
28143
      return *this;
20697
28144
    }
20698
28145
 
20699
 
    //! Load an image from an ANALYZE7.5/NIFTI file.
20700
 
    static CImg get_load_analyze(const char *const filename, float *const voxsize=0) {
20701
 
      return CImg<T>().load_analyze(filename,voxsize);
20702
 
    }
20703
 
 
20704
 
    //! Load a 3D object from a .OFF file (GeomView 3D object files).
20705
 
    template<typename tf,typename tc>
20706
 
    CImg& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
20707
 
      std::FILE *file=cimg::fopen(filename,"r");
 
28146
    //! Load an image from a .RAW file.
 
28147
    static CImg<T> get_load_raw(const char *const filename,
 
28148
                                const unsigned int sizex, const unsigned int sizey=1,
 
28149
                                const unsigned int sizez=1, const unsigned int sizev=1,
 
28150
                                const bool multiplexed=false, const bool invert_endianness=false) {
 
28151
      return CImg<T>().load_raw(filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 
28152
    }
 
28153
 
 
28154
    //! Load an image from a .RAW file.
 
28155
    static CImg<T> get_load_raw(std::FILE *const file,
 
28156
                                const unsigned int sizex, const unsigned int sizey=1,
 
28157
                                const unsigned int sizez=1, const unsigned int sizev=1,
 
28158
                                const bool multiplexed=false, const bool invert_endianness=false) {
 
28159
      return CImg<T>().load_raw(file,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 
28160
    }
 
28161
 
 
28162
    //! Load an image from a .RAW file (in-place).
 
28163
    CImg<T>& load_raw(const char *const filename,
 
28164
                      const unsigned int sizex, const unsigned int sizey=1,
 
28165
                      const unsigned int sizez=1, const unsigned int sizev=1,
 
28166
                      const bool multiplexed=false, const bool invert_endianness=false) {
 
28167
      return _load_raw(0,filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 
28168
    }
 
28169
 
 
28170
    //! Load an image from a .RAW file (in-place).
 
28171
    CImg<T>& load_raw(std::FILE *const file,
 
28172
                      const unsigned int sizex, const unsigned int sizey=1,
 
28173
                      const unsigned int sizez=1, const unsigned int sizev=1,
 
28174
                      const bool multiplexed=false, const bool invert_endianness=false) {
 
28175
      return _load_raw(file,0,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
 
28176
    }
 
28177
 
 
28178
    //! Load a video sequence using FFMPEG av's libraries.
 
28179
    static CImg<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
28180
                                   const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
 
28181
                                   const char axis='z', const char align='p') {
 
28182
      return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume).get_append(axis,align);
 
28183
    }
 
28184
 
 
28185
    //! Load a video sequence using FFMPEG av's libraries (in-place).
 
28186
    CImg<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
28187
                         const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
 
28188
                         const char axis='z', const char align='p') {
 
28189
      return get_load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume,axis,align).transfer_to(*this);
 
28190
    }
 
28191
 
 
28192
    //! Load an image sequence from a YUV file.
 
28193
    static CImg<T> get_load_yuv(const char *const filename,
 
28194
                                const unsigned int sizex, const unsigned int sizey=1,
 
28195
                                const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
28196
                                const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 
28197
      return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
 
28198
    }
 
28199
 
 
28200
    //! Load an image sequence from a YUV file.
 
28201
    static CImg<T> get_load_yuv(std::FILE *const file,
 
28202
                                const unsigned int sizex, const unsigned int sizey=1,
 
28203
                                const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
28204
                                const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 
28205
      return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
 
28206
    }
 
28207
 
 
28208
    //! Load an image sequence from a YUV file (in-place).
 
28209
    CImg<T>& load_yuv(const char *const filename,
 
28210
                      const unsigned int sizex, const unsigned int sizey=1,
 
28211
                      const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
28212
                      const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 
28213
      return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
 
28214
    }
 
28215
 
 
28216
    //! Load an image sequence from a YUV file (in-place).
 
28217
    CImg<T>& load_yuv(std::FILE *const file,
 
28218
                      const unsigned int sizex, const unsigned int sizey=1,
 
28219
                      const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
28220
                      const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
 
28221
      return get_load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
 
28222
    }
 
28223
 
 
28224
    //! Load a 3D object from a .OFF file (internal).
 
28225
    template<typename tf, typename tc>
 
28226
      CImg<T>& _load_off(std::FILE *const file, const char *const filename,
 
28227
                        CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces) {
 
28228
      if (!filename && !file) throw CImgArgumentException("CImg<%s>::load_off() : Cannot load (null) filename.",pixel_type());
 
28229
      std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
20708
28230
      unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0;
20709
28231
      char line[256] = { 0 };
20710
28232
      int err;
20711
28233
 
20712
28234
      // Skip comments, and read magic string OFF
20713
 
      do { err = std::fscanf(file,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
 
28235
      do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
20714
28236
      if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) {
20715
 
        cimg::fclose(file);
 
28237
        if (!file) cimg::fclose(nfile);
20716
28238
        throw CImgIOException("CImg<%s>::load_off() : File '%s', keyword 'OFF' not found.",pixel_type(),filename);
20717
28239
      }
20718
 
      do { err = std::fscanf(file,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
20719
 
 
 
28240
      do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
20720
28241
      if ((err = std::sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) {
20721
 
        cimg::fclose(file);
 
28242
        if (!file) cimg::fclose(nfile);
20722
28243
        throw CImgIOException("CImg<%s>::load_off() : File '%s', invalid vertices/primitives numbers.",pixel_type(),filename);
20723
28244
      }
20724
28245
 
20726
28247
      assign(nb_points,3);
20727
28248
      float X = 0, Y = 0, Z = 0;
20728
28249
      cimg_forX(*this,l) {
20729
 
        do { err = std::fscanf(file,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
 
28250
        do { err = std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
20730
28251
        if ((err = std::sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) {
20731
 
          cimg::fclose(file);
 
28252
          if (!file) cimg::fclose(nfile);
20732
28253
          throw CImgIOException("CImg<%s>::load_off() : File '%s', cannot read point %u/%u.\n",pixel_type(),filename,l+1,nb_points);
20733
28254
        }
20734
28255
        (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z;
20742
28263
        float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f;
20743
28264
        unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
20744
28265
        line[0]='\0';
20745
 
        if ((err = std::fscanf(file,"%u",&prim))!=1) stopflag=true;
 
28266
        if ((err = std::fscanf(nfile,"%u",&prim))!=1) stopflag=true;
20746
28267
        else {
20747
28268
          ++nb_read;
20748
28269
          switch (prim) {
20749
28270
          case 1: {
20750
 
            if ((err = std::fscanf(file,"%u%255[^\n] ",&i0,line))<2) {
 
28271
            if ((err = std::fscanf(nfile,"%u%255[^\n] ",&i0,line))<2) {
20751
28272
              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
20752
28273
                         pixel_type(),filename,nb_read,nb_primitives);
20753
 
              std::fscanf(file,"%*[^\n] ");
 
28274
              std::fscanf(nfile,"%*[^\n] ");
20754
28275
            } else {
20755
28276
              std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
20756
28277
              primitives.insert(CImg<tf>::vector(i0));
20758
28279
            }
20759
28280
          } break;
20760
28281
          case 2: {
20761
 
            if ((err = std::fscanf(file,"%u%u%255[^\n] ",&i0,&i1,line))<2) {
 
28282
            if ((err = std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line))<2) {
20762
28283
              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
20763
28284
                         pixel_type(),filename,nb_read,nb_primitives);
20764
 
              std::fscanf(file,"%*[^\n] ");
 
28285
              std::fscanf(nfile,"%*[^\n] ");
20765
28286
            } else {
20766
28287
              std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
20767
28288
              primitives.insert(CImg<tf>::vector(i0,i1));
20769
28290
            }
20770
28291
          } break;
20771
28292
          case 3: {
20772
 
            if ((err = std::fscanf(file,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line))<3) {
 
28293
            if ((err = std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line))<3) {
20773
28294
              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
20774
28295
                         pixel_type(),filename,nb_read,nb_primitives);
20775
 
              std::fscanf(file,"%*[^\n] ");
 
28296
              std::fscanf(nfile,"%*[^\n] ");
20776
28297
            } else {
20777
28298
              std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
20778
28299
              if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2));
20781
28302
            }
20782
28303
          } break;
20783
28304
          case 4: {
20784
 
            if ((err = std::fscanf(file,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line))<4) {
 
28305
            if ((err = std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line))<4) {
20785
28306
              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
20786
28307
                         pixel_type(),filename,nb_read,nb_primitives);
20787
 
              std::fscanf(file,"%*[^\n] ");
 
28308
              std::fscanf(nfile,"%*[^\n] ");
20788
28309
            } else {
20789
28310
              std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
20790
28311
              if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
20793
28314
            }
20794
28315
          } break;
20795
28316
          case 5: {
20796
 
            if ((err = std::fscanf(file,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line))<5) {
 
28317
            if ((err = std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line))<5) {
20797
28318
              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
20798
28319
                         pixel_type(),filename,nb_read,nb_primitives);
20799
 
              std::fscanf(file,"%*[^\n] ");
 
28320
              std::fscanf(nfile,"%*[^\n] ");
20800
28321
            } else {
20801
28322
              std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
20802
28323
              if (invert_faces) {
20812
28333
            }
20813
28334
          } break;
20814
28335
          case 6: {
20815
 
            if ((err = std::fscanf(file,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line))<6) {
 
28336
            if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line))<6) {
20816
28337
              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
20817
28338
                         pixel_type(),filename,nb_read,nb_primitives);
20818
 
              std::fscanf(file,"%*[^\n] ");
 
28339
              std::fscanf(nfile,"%*[^\n] ");
20819
28340
            } else {
20820
28341
              std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
20821
28342
              if (invert_faces) {
20831
28352
            }
20832
28353
          } break;
20833
28354
          case 7: {
20834
 
            if ((err = std::fscanf(file,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line))<7) {
 
28355
            if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line))<7) {
20835
28356
              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
20836
28357
                         pixel_type(),filename,nb_read,nb_primitives);
20837
 
              std::fscanf(file,"%*[^\n] ");
 
28358
              std::fscanf(nfile,"%*[^\n] ");
20838
28359
            } else {
20839
28360
              std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
20840
28361
              if (invert_faces) {
20852
28373
            }
20853
28374
          } break;
20854
28375
          case 8: {
20855
 
            if ((err = std::fscanf(file,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line))<7) {
 
28376
            if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line))<7) {
20856
28377
              cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
20857
28378
                         pixel_type(),filename,nb_read,nb_primitives);
20858
 
              std::fscanf(file,"%*[^\n] ");
 
28379
              std::fscanf(nfile,"%*[^\n] ");
20859
28380
            } else {
20860
28381
              std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
20861
28382
              if (invert_faces) {
20875
28396
          default:
20876
28397
            cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u (%u vertices).",
20877
28398
                       pixel_type(),filename,nb_read,nb_primitives,prim);
20878
 
            std::fscanf(file,"%*[^\n] ");
 
28399
            std::fscanf(nfile,"%*[^\n] ");
20879
28400
            break;
20880
28401
          }
20881
28402
        }
20882
28403
      }
20883
 
      cimg::fclose(file);
 
28404
      if (!file) cimg::fclose(nfile);
20884
28405
      if (primitives.size!=nb_primitives)
20885
28406
        cimg::warn("CImg<%s>::load_off() : File '%s', read only %u primitives instead of %u as claimed in the header.",
20886
28407
                   pixel_type(),filename,primitives.size,nb_primitives);
20887
28408
      return *this;
20888
28409
    }
20889
28410
 
20890
 
    //! Load a 3D object from a .OFF file (GeomView 3D object files).
20891
 
    template<typename tf,typename tc>
20892
 
    static CImg<T> get_load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors,
20893
 
                                const bool invert_faces=false) {
 
28411
    //! Load a 3D object from a .OFF file.
 
28412
    template<typename tf, typename tc>
 
28413
      static CImg<T> get_load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors,
 
28414
                                  const bool invert_faces=false) {
20894
28415
      return CImg<T>().load_off(filename,primitives,colors,invert_faces);
20895
28416
    }
20896
28417
 
20897
 
    //! Load an image from a DICOM file.
20898
 
    CImg& load_dicom(const char *const filename) {
20899
 
      static bool first_time = true;
20900
 
      char command[1024], filetmp[512], body[512];
20901
 
      if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; }
 
28418
    //! Load a 3D object from a .OFF file.
 
28419
    template<typename tf, typename tc>
 
28420
      static CImg<T> get_load_off(std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors,
 
28421
                                  const bool invert_faces=false) {
 
28422
      return CImg<T>().load_off(file,primitives,colors,invert_faces);
 
28423
    }
 
28424
 
 
28425
    //! Load a 3D object from a .OFF file (in-place).
 
28426
    template<typename tf, typename tc>
 
28427
      CImg<T>& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
 
28428
      return _load_off(0,filename,primitives,colors,invert_faces);
 
28429
    }
 
28430
 
 
28431
    //! Load a 3D object from a .OFF file (in-place).
 
28432
    template<typename tf, typename tc>
 
28433
      CImg<T>& load_off(std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
 
28434
      return _load_off(file,0,primitives,colors,invert_faces);
 
28435
    }
 
28436
 
 
28437
    //! Load a video sequence using FFMPEG's external tool 'ffmpeg'
 
28438
    static CImg<T> get_load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
 
28439
      return CImgList<T>().load_ffmpeg_external(filename).get_append(axis,align);
 
28440
    }
 
28441
 
 
28442
    //! Load a video sequence using FFMPEG's external tool 'ffmpeg (in-place).
 
28443
    CImg<T>& load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
 
28444
      return get_load_ffmpeg_external(filename,axis,align).transfer_to(*this);
 
28445
    }
 
28446
 
 
28447
    //! Load an image using GraphicsMagick's external tool 'gm'.
 
28448
    static CImg<T> get_load_graphicsmagick_external(const char *const filename) {
 
28449
      return CImg<T>().load_graphicsmagick_external(filename);
 
28450
    }
 
28451
 
 
28452
    //! Load an image using GraphicsMagick's external tool 'gm' (in-place).
 
28453
    CImg<T>& load_graphicsmagick_external(const char *const filename) {
 
28454
      if (!filename) throw CImgArgumentException("CImg<%s>::load_graphicsmagick_external() : Cannot load (null) filename.",pixel_type());
 
28455
      char command[1024], filetmp[512];
 
28456
      std::FILE *file = 0;
 
28457
      do {
 
28458
        std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 
28459
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
 
28460
      } while (file);
 
28461
      std::sprintf(command,"%s convert \"%s\" %s",cimg::graphicsmagick_path(),filename,filetmp);
 
28462
      cimg::system(command,cimg::graphicsmagick_path());
 
28463
      if (!(file = std::fopen(filetmp,"rb"))) {
 
28464
        cimg::fclose(cimg::fopen(filename,"r"));
 
28465
        throw CImgIOException("CImg<%s>::load_graphicsmagick_external() : Failed to open image '%s'.\n\n"
 
28466
                              "Path of 'GraphicsMagick's gm' : \"%s\"\n"
 
28467
                              "Path of temporary filename : \"%s\"",
 
28468
                              pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
 
28469
      } else cimg::fclose(file);
 
28470
      load_pnm(filetmp);
 
28471
      std::remove(filetmp);
 
28472
      return *this;
 
28473
    }
 
28474
 
 
28475
    //! Load a gzipped image file, using external tool 'gunzip'.
 
28476
    static CImg<T> get_load_gzip_external(const char *const filename) {
 
28477
      return CImg<T>().load_gzip_external(filename);
 
28478
    }
 
28479
 
 
28480
    //! Load a gzipped image file, using external tool 'gunzip' (in-place).
 
28481
    CImg<T>& load_gzip_external(const char *const filename) {
 
28482
      if (!filename) throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",pixel_type());
 
28483
      char command[1024], filetmp[512], body[512];
 
28484
      const char
 
28485
        *ext = cimg::split_filename(filename,body),
 
28486
        *ext2 = cimg::split_filename(body,0);
 
28487
      std::FILE *file = 0;
 
28488
      do {
 
28489
        if (!cimg::strcasecmp(ext,"gz")) {
 
28490
          if (*ext2) std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
28491
                                  cimg::filenamerand(),ext2);
 
28492
          else std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
28493
                                  cimg::filenamerand());
 
28494
        } else {
 
28495
           if (*ext) std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
28496
                                  cimg::filenamerand(),ext);
 
28497
           else std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
28498
                             cimg::filenamerand());
 
28499
        }
 
28500
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
 
28501
      } while (file);
 
28502
      std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
 
28503
      cimg::system(command);
 
28504
      if (!(file = std::fopen(filetmp,"rb"))) {
 
28505
        cimg::fclose(cimg::fopen(filename,"r"));
 
28506
        throw CImgIOException("CImg<%s>::load_gzip_external() : Failed to open file '%s'.",
 
28507
                              pixel_type(),filename);
 
28508
      } else cimg::fclose(file);
 
28509
      load(filetmp);
 
28510
      std::remove(filetmp);
 
28511
      return *this;
 
28512
    }
 
28513
 
 
28514
    //! Load an image using ImageMagick's external tool 'convert'.
 
28515
    static CImg<T> get_load_imagemagick_external(const char *const filename) {
 
28516
      return CImg<T>().load_imagemagick_external(filename);
 
28517
    }
 
28518
 
 
28519
    //! Load an image using ImageMagick's external tool 'convert' (in-place).
 
28520
    CImg<T>& load_imagemagick_external(const char *const filename) {
 
28521
      if (!filename) throw CImgArgumentException("CImg<%s>::load_imagemagick_external() : Cannot load (null) filename.",pixel_type());
 
28522
      char command[1024], filetmp[512];
 
28523
      std::FILE *file = 0;
 
28524
      do {
 
28525
        std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 
28526
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
 
28527
      } while (file);
 
28528
      std::sprintf(command,"%s \"%s\" %s",cimg::imagemagick_path(),filename,filetmp);
 
28529
      cimg::system(command,cimg::imagemagick_path());
 
28530
      if (!(file = std::fopen(filetmp,"rb"))) {
 
28531
        cimg::fclose(cimg::fopen(filename,"r"));
 
28532
        throw CImgIOException("CImg<%s>::load_imagemagick_external() : Failed to open image '%s'.\n\n"
 
28533
                              "Path of 'ImageMagick's convert' : \"%s\"\n"
 
28534
                              "Path of temporary filename : \"%s\"",
 
28535
                              pixel_type(),filename,cimg::imagemagick_path(),filetmp);
 
28536
      } else cimg::fclose(file);
 
28537
      load_pnm(filetmp);
 
28538
      std::remove(filetmp);
 
28539
      return *this;
 
28540
    }
 
28541
 
 
28542
    //! Load a DICOM image file, using XMedcon's external tool 'medcon'.
 
28543
    static CImg<T> get_load_medcon_external(const char *const filename) {
 
28544
      return CImg<T>().load_medcon_external(filename);
 
28545
    }
 
28546
 
 
28547
    //! Load a DICOM image file, using XMedcon's external tool 'medcon' (in-place).
 
28548
    CImg<T>& load_medcon_external(const char *const filename) {
 
28549
      if (!filename) throw CImgArgumentException("CImg<%s>::load_medcon_external() : Cannot load (null) filename.",pixel_type());
 
28550
      char command[1024], filetmp[512], body[512];
20902
28551
      cimg::fclose(cimg::fopen(filename,"r"));
20903
28552
      std::FILE *file;
20904
28553
      do {
20905
 
        std::sprintf(filetmp,"CImg%.4d.hdr",std::rand()%10000);
 
28554
        std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
20906
28555
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
20907
28556
      } while (file);
20908
28557
      std::sprintf(command,"%s -w -c anlz -o %s -f %s",cimg::medcon_path(),filetmp,filename);
20909
28558
      cimg::system(command);
20910
 
      cimg::filename_split(filetmp,body);
 
28559
      cimg::split_filename(filetmp,body);
20911
28560
      std::sprintf(command,"m000-%s.hdr",body);
20912
28561
      file = std::fopen(command,"rb");
20913
28562
      if (!file) {
20914
 
        throw CImgIOException("CImg<%s>::load_dicom() : Failed to open image '%s'.\n\n"
 
28563
        throw CImgIOException("CImg<%s>::load_medcon_external() : Failed to open image '%s'.\n\n"
20915
28564
                              "Path of 'medcon' : \"%s\"\n"
20916
28565
                              "Path of temporary filename : \"%s\"",
20917
28566
                              pixel_type(),filename,cimg::medcon_path(),filetmp);
20923
28572
      return *this;
20924
28573
    }
20925
28574
 
20926
 
    //! Load an image from a DICOM file.
20927
 
    static CImg get_load_dicom(const char *const filename) {
20928
 
      return CImg<T>().load_dicom(filename);
20929
 
    }
20930
 
 
20931
 
    //! Load an image using ImageMagick's convert.
20932
 
    CImg& load_imagemagick(const char *const filename) {
20933
 
      static bool first_time = true;
20934
 
      char command[1024], filetmp[512];
20935
 
      if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; }
20936
 
      std::FILE *file = 0;
20937
 
      do {
20938
 
        std::sprintf(filetmp,"%s%sCImg%.4d.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000);
20939
 
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
20940
 
      } while (file);
20941
 
      std::sprintf(command,"%s \"%s\" %s",cimg::imagemagick_path(),filename,filetmp);
20942
 
      cimg::system(command,cimg::imagemagick_path());
20943
 
      if (!(file = std::fopen(filetmp,"rb"))) {
20944
 
        cimg::fclose(cimg::fopen(filename,"r"));
20945
 
        throw CImgIOException("CImg<%s>::load_imagemagick() : Failed to open image '%s'.\n\n"
20946
 
                              "Path of 'ImageMagick's convert' : \"%s\"\n"
20947
 
                              "Path of temporary filename : \"%s\"",
20948
 
                              pixel_type(),filename,cimg::imagemagick_path(),filetmp);
20949
 
      } else cimg::fclose(file);
20950
 
      load_pnm(filetmp);
20951
 
      std::remove(filetmp);
20952
 
      return *this;
20953
 
    }
20954
 
 
20955
 
    //! Load an image using ImageMagick's convert.
20956
 
    static CImg get_load_imagemagick(const char *const filename) {
20957
 
      return CImg<T>().load_imagemagick(filename);
20958
 
    }
20959
 
 
20960
 
    //! Load an image using GraphicsMagick's convert.
20961
 
    CImg& load_graphicsmagick(const char *const filename) {
20962
 
      static bool first_time = true;
20963
 
      char command[1024], filetmp[512];
20964
 
      if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; }
20965
 
      std::FILE *file = 0;
20966
 
      do {
20967
 
        std::sprintf(filetmp,"%s%sCImg%.4d.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000);
20968
 
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
20969
 
      } while (file);
20970
 
      std::sprintf(command,"%s convert \"%s\" %s",cimg::graphicsmagick_path(),filename,filetmp);
20971
 
      cimg::system(command,cimg::graphicsmagick_path());
20972
 
      if (!(file = std::fopen(filetmp,"rb"))) {
20973
 
        cimg::fclose(cimg::fopen(filename,"r"));
20974
 
        throw CImgIOException("CImg<%s>::load_graphicsmagick() : Failed to open image '%s'.\n\n"
20975
 
                              "Path of 'GraphicsMagick's gm' : \"%s\"\n"
20976
 
                              "Path of temporary filename : \"%s\"",
20977
 
                              pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
20978
 
      } else cimg::fclose(file);
20979
 
      load_pnm(filetmp);
20980
 
      std::remove(filetmp);
20981
 
      return *this;
20982
 
    }
20983
 
 
20984
 
    //! Load an image using GraphicsMagick's convert.
20985
 
    static CImg get_load_graphicsmagick(const char *const filename) {
20986
 
      return CImg<T>().load_graphicsmagick(filename);
20987
 
    }
20988
 
 
20989
28575
    //! Load an image using ImageMagick's or GraphicsMagick's executables.
20990
 
    CImg& load_other(const char *const filename) {
 
28576
    static CImg<T> get_load_other(const char *const filename) {
 
28577
      return CImg<T>().load_other(filename);
 
28578
    }
 
28579
 
 
28580
    //! Load an image using ImageMagick's or GraphicsMagick's executables (in-place).
 
28581
    CImg<T>& load_other(const char *const filename) {
 
28582
      if (!filename) throw CImgArgumentException("CImg<%s>::load_other() : Cannot load (null) filename.",pixel_type());
20991
28583
      const unsigned int odebug = cimg::exception_mode();
20992
28584
      cimg::exception_mode() = 0;
20993
28585
      try { load_magick(filename); }
20994
28586
      catch (CImgException&) {
20995
 
        try { load_imagemagick(filename); }
 
28587
        try { load_imagemagick_external(filename); }
20996
28588
        catch (CImgException&) {
20997
 
          try { load_graphicsmagick(filename); }
 
28589
          try { load_graphicsmagick_external(filename); }
20998
28590
          catch (CImgException&) {
20999
28591
            assign();
21000
28592
          }
21002
28594
      }
21003
28595
      cimg::exception_mode() = odebug;
21004
28596
      if (is_empty())
21005
 
        throw CImgIOException("CImg<%s>::load_other() : Failed to open image '%s'.\n"
21006
 
                              "Check you have either the ImageMagick or GraphicsMagick package installed.",
 
28597
        throw CImgIOException("CImg<%s>::load_other() : Failed to open image file '%s'.\n",
21007
28598
                              pixel_type(),filename);
21008
28599
      return *this;
21009
28600
    }
21010
28601
 
21011
 
    //! Load an image using ImageMagick's or GraphicsMagick's executables.
21012
 
    static CImg get_load_other(const char *const filename) {
21013
 
      return CImg<T>().load_other(filename);
21014
 
    }
21015
 
 
21016
 
    //! Load an image from a PAR-REC (Philips) file.
21017
 
    CImg& load_parrec(const char *const filename, const char axis='v', const char align='p') {
21018
 
      CImgList<T> list;
21019
 
      list.load_parrec(filename);
21020
 
      if (list.size==1) return list[0].swap(*this);
21021
 
      return assign(list.get_append(axis,align));
21022
 
    }
21023
 
 
21024
 
    //! Load an image from a PAR-REC (Philips) file.
21025
 
    static CImg get_load_parrec(const char *const filename, const char axis='v', const char align='p') {
21026
 
      return CImg<T>().load_parrec(filename,axis,align);
21027
 
    }
21028
 
 
21029
 
    //! Load an image (list) from a .cimg file.
21030
 
    CImg& load_cimg(std::FILE *const file, const char axis='z', const char align='p') {
21031
 
      CImgList<T> list;
21032
 
      list.load_cimg(file);
21033
 
      if (list.size==1) return list[0].swap(*this);
21034
 
      return list.get_append(axis,align);
21035
 
    }
21036
 
 
21037
 
    //! Load an image (list) from a .cimg file.
21038
 
    CImg& load_cimg(const char *const filename, const char axis='z', const char align='p') {
21039
 
      CImgList<T> list;
21040
 
      list.load_cimg(filename);
21041
 
      if (list.size==1) return list[0].swap(*this);
21042
 
      return assign(list.get_append(axis,align));
21043
 
    }
21044
 
 
21045
 
    //! Load an image (list) from a .cimg file.
21046
 
    static CImg get_load_cimg(std::FILE *const file, const char axis='z', const char align='p') {
21047
 
      return CImg<T>().load_cimg(file,axis,align);
21048
 
    }
21049
 
 
21050
 
    //! Load an image (list) from a .cimg file.
21051
 
    static CImg get_load_cimg(const char *const filename, const char axis='z', const char align='p') {
21052
 
      return CImg<T>().load_cimg(filename,axis,align);
21053
 
    }
21054
 
 
21055
 
    //! Load a sub-image (list) from a .cimg file.
21056
 
    CImg& load_cimg(std::FILE *const file,
21057
 
                    const unsigned int n0, const unsigned int n1,
21058
 
                    const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
21059
 
                    const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
21060
 
                    const char axis='z', const char align='p') {
21061
 
      CImgList<T> list;
21062
 
      list.load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
21063
 
      if (list.size==1) return list[0].swap(*this);
21064
 
      return assign(list.get_append(axis,align));
21065
 
    }
21066
 
 
21067
 
    //! Load a sub-image (list) from a .cimg file.
21068
 
    CImg& load_cimg(const char *const filename,
21069
 
                    const unsigned int n0, const unsigned int n1,
21070
 
                    const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
21071
 
                    const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
21072
 
                    const char axis='z', const char align='p') {
21073
 
      CImgList<T> list;
21074
 
      list.load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
21075
 
      if (list.size==1) return list[0].swap(*this);
21076
 
      return assign(list.get_append(axis,align));
21077
 
    }
21078
 
 
21079
 
    //! Load an image sequence from a YUV file.
21080
 
    CImg& load_yuv(std::FILE *const file, const char *const filename,
21081
 
                   const unsigned int sizex, const unsigned int sizey=1,
21082
 
                   const unsigned int first_frame=0, const int last_frame=-1,
21083
 
                   const bool yuv2rgb = false, const char axis='z', const char align='p') {
21084
 
      return assign(get_load_yuv(file,filename,sizex,sizey,first_frame,last_frame,yuv2rgb,axis,align));
21085
 
    }
21086
 
 
21087
 
    //! Load an image sequence from a YUV file.
21088
 
    CImg& load_yuv(const char *const filename,
21089
 
                   const unsigned int sizex, const unsigned int sizey=1,
21090
 
                   const unsigned int first_frame=0, const int last_frame=-1,
21091
 
                   const bool yuv2rgb = false, const char axis='z', const char align='p') {
21092
 
      return assign(get_load_yuv(0,filename,sizex,sizey,first_frame,last_frame,yuv2rgb,axis,align));
21093
 
    }
21094
 
 
21095
 
    //! Load an image sequence from a YUV file.
21096
 
    static CImg get_load_yuv(std::FILE *const file, const char *const filename,
21097
 
                             const unsigned int sizex, const unsigned int sizey=1,
21098
 
                             const unsigned int first_frame=0, const int last_frame=-1,
21099
 
                             const bool yuv2rgb = false, const char axis='z', const char align='p') {
21100
 
      return CImgList<T>().load_yuv(file,filename,sizex,sizey,first_frame,last_frame,yuv2rgb).get_append(axis,align);
21101
 
    }
21102
 
 
21103
 
    //! Load an image sequence from a YUV file.
21104
 
    static CImg get_load_yuv(const char *const filename,
21105
 
                             const unsigned int sizex, const unsigned int sizey=1,
21106
 
                             const unsigned int first_frame=0, const int last_frame=-1,
21107
 
                             const bool yuv2rgb = false, const char axis='z', const char align='p') {
21108
 
      return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,yuv2rgb).get_append(axis,align);
21109
 
    }
 
28602
    //@}
 
28603
    //---------------------------
 
28604
    //
 
28605
    //! \name Image File Saving
 
28606
    //@{
 
28607
    //---------------------------
21110
28608
 
21111
28609
    //! Save the image as a file.
21112
28610
    /**
21113
 
       The used file format is defined by the file extension in the filename \p filename.\n
21114
 
       Parameter \p number can be used to add a 6-digit number to the filename before saving.\n
21115
 
       If \p normalize is true, a normalized version of the image (between [0,255]) is saved.
 
28611
       The used file format is defined by the file extension in the filename \p filename.
 
28612
       Parameter \p number can be used to add a 6-digit number to the filename before saving.
21116
28613
    **/
21117
 
    const CImg& save(const char *const filename, const int number=-1) const {
 
28614
    const CImg<T>& save(const char *const filename, const int number=-1) const {
 
28615
      if (!filename) throw CImgArgumentException("CImg<%s>::save() : Instance image (%u,%u,%u,%u,%p) cannot be save as a (null) filename.",
 
28616
                                                 pixel_type(),width,height,depth,dim,data);
21118
28617
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
21119
28618
                                                  pixel_type(),width,height,depth,dim,data,filename);
21120
 
      if (!filename) throw CImgArgumentException("CImg<%s>::save() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
21121
 
                                                 pixel_type(),width,height,depth,dim,data);
21122
 
      const char *ext = cimg::filename_split(filename);
 
28619
      const char *ext = cimg::split_filename(filename);
21123
28620
      char nfilename[1024];
21124
28621
      const char *const fn = (number>=0)?cimg::filename_number(filename,number,6,nfilename):filename;
21125
28622
#ifdef cimg_save_plugin
21126
28623
      cimg_save_plugin(fn);
21127
28624
#endif
21128
 
      if (!cimg::strncasecmp(ext,"asc",3)) return save_ascii(fn);
21129
 
      if (!cimg::strncasecmp(ext,"dlm",3) ||
21130
 
          !cimg::strncasecmp(ext,"txt",3)) return save_dlm(fn);
21131
 
      if (!cimg::strncasecmp(ext,"inr",3)) return save_inr(fn);
21132
 
      if (!cimg::strncasecmp(ext,"hdr",3) ||
21133
 
          !cimg::strncasecmp(ext,"nii",3)) return save_analyze(fn);
21134
 
      if (!cimg::strncasecmp(ext,"dcm",3)) return save_dicom(fn);
21135
 
      if (!cimg::strncasecmp(ext,"pan",3)) return save_pandore(fn);
21136
 
      if (!cimg::strncasecmp(ext,"bmp",3)) return save_bmp(fn);
21137
 
      if (!cimg::strncasecmp(ext,"png",3)) return save_png(fn);
21138
 
      if (!cimg::strncasecmp(ext,"tif",3)) return save_tiff(fn);
21139
 
      if (!cimg::strncasecmp(ext,"jpg",3) ||
21140
 
          !cimg::strncasecmp(ext,"jpeg",4)) return save_jpeg(fn);
21141
 
      if (!cimg::strncasecmp(ext,"rgba",4)) return save_rgba(fn);
21142
 
      if (!cimg::strncasecmp(ext,"rgb",3)) return save_rgb(fn);
21143
 
      if (!cimg::strncasecmp(ext,"raw",3)) return save_raw(fn);
21144
 
      if (!cimg::strncasecmp(ext,"cimg",4) || ext[0]=='\0') return save_cimg(fn);
21145
 
      if (!cimg::strncasecmp(ext,"pgm",3) ||
21146
 
          !cimg::strncasecmp(ext,"ppm",3) ||
21147
 
          !cimg::strncasecmp(ext,"pnm",3)) return save_pnm(fn);
21148
 
      if (!cimg::strncasecmp(ext,"yuv",3)) return save_yuv(fn,true);
 
28625
#ifdef cimg_save_plugin1
 
28626
      cimg_save_plugin1(fn);
 
28627
#endif
 
28628
#ifdef cimg_save_plugin2
 
28629
      cimg_save_plugin2(fn);
 
28630
#endif
 
28631
#ifdef cimg_save_plugin3
 
28632
      cimg_save_plugin3(fn);
 
28633
#endif
 
28634
#ifdef cimg_save_plugin4
 
28635
      cimg_save_plugin4(fn);
 
28636
#endif
 
28637
#ifdef cimg_save_plugin5
 
28638
      cimg_save_plugin5(fn);
 
28639
#endif
 
28640
#ifdef cimg_save_plugin6
 
28641
      cimg_save_plugin6(fn);
 
28642
#endif
 
28643
#ifdef cimg_save_plugin7
 
28644
      cimg_save_plugin7(fn);
 
28645
#endif
 
28646
#ifdef cimg_save_plugin8
 
28647
      cimg_save_plugin8(fn);
 
28648
#endif
 
28649
      // ASCII formats
 
28650
      if (!cimg::strcasecmp(ext,"asc")) return save_ascii(fn);
 
28651
      if (!cimg::strcasecmp(ext,"dlm") ||
 
28652
          !cimg::strcasecmp(ext,"txt")) return save_dlm(fn);
 
28653
      if (!cimg::strcasecmp(ext,"cpp") ||
 
28654
          !cimg::strcasecmp(ext,"hpp") ||
 
28655
          !cimg::strcasecmp(ext,"h") ||
 
28656
          !cimg::strcasecmp(ext,"c")) return save_cpp(fn);
 
28657
 
 
28658
      // 2D binary formats
 
28659
      if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(fn);
 
28660
      if (!cimg::strcasecmp(ext,"jpg") ||
 
28661
          !cimg::strcasecmp(ext,"jpeg")) return save_jpeg(fn);
 
28662
      if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(fn);
 
28663
      if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(fn);
 
28664
      if (!cimg::strcasecmp(ext,"png")) return save_png(fn);
 
28665
      if (!cimg::strcasecmp(ext,"pgm") ||
 
28666
          !cimg::strcasecmp(ext,"ppm") ||
 
28667
          !cimg::strcasecmp(ext,"pnm")) return save_pnm(fn);
 
28668
      if (!cimg::strcasecmp(ext,"tif")) return save_tiff(fn);
 
28669
 
 
28670
      // 3D binary formats
 
28671
      if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
 
28672
      if (!cimg::strcasecmp(ext,"cimg") || ext[0]=='\0') return save_cimg(fn,false);
 
28673
      if (!cimg::strcasecmp(ext,"dcm")) return save_medcon_external(fn);
 
28674
      if (!cimg::strcasecmp(ext,"hdr") ||
 
28675
          !cimg::strcasecmp(ext,"nii")) return save_analyze(fn);
 
28676
      if (!cimg::strcasecmp(ext,"inr")) return save_inr(fn);
 
28677
      if (!cimg::strcasecmp(ext,"pan")) return save_pandore(fn);
 
28678
      if (!cimg::strcasecmp(ext,"raw")) return save_raw(fn);
 
28679
 
 
28680
      // Archive files
 
28681
      if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
 
28682
 
 
28683
      // Image sequences
 
28684
      if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
 
28685
      if (!cimg::strcasecmp(ext,"avi") ||
 
28686
          !cimg::strcasecmp(ext,"mov") ||
 
28687
          !cimg::strcasecmp(ext,"mpg") ||
 
28688
          !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg_external(fn);
21149
28689
      return save_other(fn);
21150
28690
    }
21151
28691
 
21152
 
    //! Save the image as an ASCII file (ASCII Raw + simple header).
21153
 
    const CImg& save_ascii(std::FILE *const file, const char *const filename=0) const {
 
28692
    // Save the image as an ASCII file (ASCII Raw + simple header) (internal).
 
28693
    const CImg<T>& _save_ascii(std::FILE *const file, const char *const filename) const {
21154
28694
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_ascii() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
21155
28695
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21156
28696
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_ascii() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
21167
28707
    }
21168
28708
 
21169
28709
    //! Save the image as an ASCII file (ASCII Raw + simple header).
21170
 
    const CImg& save_ascii(const char *const filename) const {
21171
 
      return save_ascii(0,filename);
21172
 
    }
21173
 
 
21174
 
    //! Save the image as a DLM file.
21175
 
    const CImg& save_dlm(std::FILE *const file, const char *const filename=0) const {
 
28710
    const CImg<T>& save_ascii(const char *const filename) const {
 
28711
      return _save_ascii(0,filename);
 
28712
    }
 
28713
 
 
28714
    //! Save the image as an ASCII file (ASCII Raw + simple header).
 
28715
    const CImg<T>& save_ascii(std::FILE *const file) const {
 
28716
      return _save_ascii(file,0);
 
28717
    }
 
28718
 
 
28719
    // Save the image as a C or CPP source file (internal).
 
28720
    const CImg<T>& _save_cpp(std::FILE *const file, const char *const filename) const {
 
28721
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_cpp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 
28722
                                                          pixel_type(),width,height,depth,dim,data);
 
28723
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_cpp() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
 
28724
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
28725
      std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
 
28726
      char varname[1024] = { 0 };
 
28727
      if (filename) std::sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname);
 
28728
      if (varname[0]=='\0') std::sprintf(varname,"unnamed");
 
28729
      std::fprintf(nfile,
 
28730
                   "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n"
 
28731
                   "%s data_%s[] = { \n  ",
 
28732
                   varname,width,height,depth,dim,pixel_type(),pixel_type(),varname);
 
28733
      for (unsigned long off = 0, siz = size()-1; off<=siz; ++off) {
 
28734
        std::fprintf(nfile,cimg::type<T>::format(),cimg::type<T>::format((*this)[off]));
 
28735
        if (off==siz) std::fprintf(nfile," };\n");
 
28736
        else if (!((off+1)%16)) std::fprintf(nfile,",\n  ");
 
28737
        else std::fprintf(nfile,", ");
 
28738
      }
 
28739
      if (!file) cimg::fclose(nfile);
 
28740
      return *this;
 
28741
    }
 
28742
 
 
28743
    //! Save the image as a CPP source file.
 
28744
    const CImg<T>& save_cpp(const char *const filename) const {
 
28745
      return _save_cpp(0,filename);
 
28746
    }
 
28747
 
 
28748
    //! Save the image as a CPP source file.
 
28749
    const CImg<T>& save_cpp(std::FILE *const file) const {
 
28750
      return _save_cpp(file,0);
 
28751
    }
 
28752
 
 
28753
    // Save the image as a DLM file (internal).
 
28754
    const CImg<T>& _save_dlm(std::FILE *const file, const char *const filename) const {
 
28755
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 
28756
                                                          pixel_type(),width,height,depth,dim,data);
21176
28757
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
21177
28758
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21178
 
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
21179
 
                                                          pixel_type(),width,height,depth,dim,data);
21180
28759
      if (depth>1)
21181
28760
        cimg::warn("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p) is volumetric. Pixel values along Z will be unrolled (file '%s').",
21182
28761
                   pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21187
28766
      std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
21188
28767
      const T* ptrs = data;
21189
28768
      cimg_forYZV(*this,y,z,v) {
21190
 
        cimg_forX(*this,x) std::fprintf(nfile,"%g%s",(double)*(ptrs++),(x==(int)width-1)?"":",");
 
28769
        cimg_forX(*this,x) std::fprintf(nfile,"%g%s",(double)*(ptrs++),(x==dimx()-1)?"":",");
21191
28770
        std::fputc('\n',nfile);
21192
28771
      }
21193
28772
      if (!file) cimg::fclose(nfile);
21195
28774
    }
21196
28775
 
21197
28776
    //! Save the image as a DLM file.
21198
 
    const CImg& save_dlm(const char *const filename) const {
21199
 
      return save_dlm(0,filename);
21200
 
    }
21201
 
 
21202
 
    //! Save the image as a PNM file.
21203
 
    const CImg& save_pnm(std::FILE *const file, const char *const filename=0) const {
 
28777
    const CImg<T>& save_dlm(const char *const filename) const {
 
28778
      return _save_dlm(0,filename);
 
28779
    }
 
28780
 
 
28781
    //! Save the image as a DLM file.
 
28782
    const CImg<T>& save_dlm(std::FILE *const file) const {
 
28783
      return _save_dlm(file,0);
 
28784
    }
 
28785
 
 
28786
   // Save the image as a BMP file (internal).
 
28787
    const CImg<T>& _save_bmp(std::FILE *const file, const char *const filename) const {
 
28788
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
 
28789
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
28790
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 
28791
                                                          pixel_type(),width,height,depth,dim,data);
 
28792
      if (depth>1)
 
28793
        cimg::warn("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved (file '%s').",
 
28794
                   pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
28795
      if (dim>3)
 
28796
        cimg::warn("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved (file '%s').",
 
28797
                   pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
28798
 
 
28799
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 
28800
      unsigned char header[54] = { 0 }, align_buf[4] = { 0 };
 
28801
      const unsigned int
 
28802
        align     = (4-(3*width)%4)%4,
 
28803
        buf_size  = (3*width+align)*dimy(),
 
28804
        file_size = 54+buf_size;
 
28805
      header[0] = 'B'; header[1] = 'M';
 
28806
      header[0x02] = file_size&0xFF;
 
28807
      header[0x03] = (file_size>>8)&0xFF;
 
28808
      header[0x04] = (file_size>>16)&0xFF;
 
28809
      header[0x05] = (file_size>>24)&0xFF;
 
28810
      header[0x0A] = 0x36;
 
28811
      header[0x0E] = 0x28;
 
28812
      header[0x12] = width&0xFF;
 
28813
      header[0x13] = (width>>8)&0xFF;
 
28814
      header[0x14] = (width>>16)&0xFF;
 
28815
      header[0x15] = (width>>24)&0xFF;
 
28816
      header[0x16] = height&0xFF;
 
28817
      header[0x17] = (height>>8)&0xFF;
 
28818
      header[0x18] = (height>>16)&0xFF;
 
28819
      header[0x19] = (height>>24)&0xFF;
 
28820
      header[0x1A] = 1;
 
28821
      header[0x1B] = 0;
 
28822
      header[0x1C] = 24;
 
28823
      header[0x1D] = 0;
 
28824
      header[0x22] = buf_size&0xFF;
 
28825
      header[0x23] = (buf_size>>8)&0xFF;
 
28826
      header[0x24] = (buf_size>>16)&0xFF;
 
28827
      header[0x25] = (buf_size>>24)&0xFF;
 
28828
      header[0x27] = 0x1;
 
28829
      header[0x2B] = 0x1;
 
28830
      cimg::fwrite(header,54,nfile);
 
28831
 
 
28832
      const T
 
28833
        *pR = ptr(0,height-1,0,0),
 
28834
        *pG = (dim>=2)?ptr(0,height-1,0,1):0,
 
28835
        *pB = (dim>=3)?ptr(0,height-1,0,2):0;
 
28836
 
 
28837
      switch (dim) {
 
28838
      case 1: {
 
28839
        cimg_forY(*this,y) { cimg_forX(*this,x) {
 
28840
          const unsigned char val = (unsigned char)*(pR++);
 
28841
          std::fputc(val,nfile); std::fputc(val,nfile); std::fputc(val,nfile);
 
28842
        }
 
28843
        cimg::fwrite(align_buf,align,nfile);
 
28844
        pR-=2*width;
 
28845
        }} break;
 
28846
      case 2: {
 
28847
        cimg_forY(*this,y) { cimg_forX(*this,x) {
 
28848
          std::fputc(0,nfile);
 
28849
          std::fputc((unsigned char)(*(pG++)),nfile);
 
28850
          std::fputc((unsigned char)(*(pR++)),nfile);
 
28851
        }
 
28852
        cimg::fwrite(align_buf,align,nfile);
 
28853
        pR-=2*width; pG-=2*width;
 
28854
        }} break;
 
28855
      default: {
 
28856
        cimg_forY(*this,y) { cimg_forX(*this,x) {
 
28857
          std::fputc((unsigned char)(*(pB++)),nfile);
 
28858
          std::fputc((unsigned char)(*(pG++)),nfile);
 
28859
          std::fputc((unsigned char)(*(pR++)),nfile);
 
28860
        }
 
28861
        cimg::fwrite(align_buf,align,nfile);
 
28862
        pR-=2*width; pG-=2*width; pB-=2*width;
 
28863
        }} break;
 
28864
      }
 
28865
      if (!file) cimg::fclose(nfile);
 
28866
      return *this;
 
28867
    }
 
28868
 
 
28869
    //! Save the image as a BMP file.
 
28870
    const CImg<T>& save_bmp(const char *const filename) const {
 
28871
      return _save_bmp(0,filename);
 
28872
    }
 
28873
 
 
28874
    //! Save the image as a BMP file.
 
28875
    const CImg<T>& save_bmp(std::FILE *const file) const {
 
28876
      return _save_bmp(file,0);
 
28877
    }
 
28878
 
 
28879
    // Save a file in JPEG format (internal).
 
28880
    const CImg<T>& _save_jpeg(std::FILE *const file, const char *const filename, const unsigned int quality) const {
 
28881
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
 
28882
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
28883
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 
28884
                                                          pixel_type(),width,height,depth,dim,data);
 
28885
      if (depth>1)
 
28886
        cimg::warn("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved (file '%s').",
 
28887
                   pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
28888
#ifndef cimg_use_jpeg
 
28889
      if (!file) return save_other(filename,quality);
 
28890
      else throw CImgIOException("CImg<%s>::save_jpeg() : Cannot save a JPEG image in a *FILE output. Use libjpeg instead.",
 
28891
                                 pixel_type());
 
28892
#else
 
28893
      // Fill pixel buffer
 
28894
      unsigned char *buf;
 
28895
      unsigned int dimbuf = 0;
 
28896
      J_COLOR_SPACE colortype = JCS_RGB;
 
28897
      switch (dim) {
 
28898
      case 1: { // Greyscale images
 
28899
        unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=1)];
 
28900
        colortype = JCS_GRAYSCALE;
 
28901
        const T *ptr_g = data;
 
28902
        cimg_forXY(*this,x,y) *(buf2++) = (unsigned char)*(ptr_g++);
 
28903
      } break;
 
28904
      case 2: { // RG images
 
28905
        unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
 
28906
        const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1);
 
28907
        colortype = JCS_RGB;
 
28908
        cimg_forXY(*this,x,y) {
 
28909
          *(buf2++) = (unsigned char)*(ptr_r++);
 
28910
          *(buf2++) = (unsigned char)*(ptr_g++);
 
28911
          *(buf2++) = 0;
 
28912
        }
 
28913
      } break;
 
28914
      case 3: { // RGB images
 
28915
        unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
 
28916
        const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
 
28917
        colortype = JCS_RGB;
 
28918
        cimg_forXY(*this,x,y) {
 
28919
          *(buf2++) = (unsigned char)*(ptr_r++);
 
28920
          *(buf2++) = (unsigned char)*(ptr_g++);
 
28921
          *(buf2++) = (unsigned char)*(ptr_b++);
 
28922
        }
 
28923
      } break;
 
28924
      default: { // YCMYK images
 
28925
        unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=4)];
 
28926
        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);
 
28927
        colortype = JCS_CMYK;
 
28928
        cimg_forXY(*this,x,y) {
 
28929
          *(buf2++) = (unsigned char)*(ptr_r++);
 
28930
          *(buf2++) = (unsigned char)*(ptr_g++);
 
28931
          *(buf2++) = (unsigned char)*(ptr_b++);
 
28932
          *(buf2++) = (unsigned char)*(ptr_a++);
 
28933
        }
 
28934
      } break;
 
28935
      }
 
28936
 
 
28937
      // Call libjpeg functions
 
28938
      struct jpeg_compress_struct cinfo;
 
28939
      struct jpeg_error_mgr jerr;
 
28940
      cinfo.err = jpeg_std_error(&jerr);
 
28941
      jpeg_create_compress(&cinfo);
 
28942
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 
28943
      jpeg_stdio_dest(&cinfo,nfile);
 
28944
      cinfo.image_width = width;
 
28945
      cinfo.image_height = height;
 
28946
      cinfo.input_components = dimbuf;
 
28947
      cinfo.in_color_space = colortype;
 
28948
      jpeg_set_defaults(&cinfo);
 
28949
      jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
 
28950
      jpeg_start_compress(&cinfo,TRUE);
 
28951
 
 
28952
      const unsigned int row_stride = width*dimbuf;
 
28953
      JSAMPROW row_pointer[1];
 
28954
      while (cinfo.next_scanline < cinfo.image_height) {
 
28955
        row_pointer[0] = &buf[cinfo.next_scanline*row_stride];
 
28956
        jpeg_write_scanlines(&cinfo,row_pointer,1);
 
28957
      }
 
28958
      jpeg_finish_compress(&cinfo);
 
28959
 
 
28960
      delete[] buf;
 
28961
      if (!file) cimg::fclose(nfile);
 
28962
      jpeg_destroy_compress(&cinfo);
 
28963
      return *this;
 
28964
#endif
 
28965
    }
 
28966
 
 
28967
    //! Save a file in JPEG format.
 
28968
    const CImg<T>& save_jpeg(const char *const filename, const unsigned int quality=100) const {
 
28969
      return _save_jpeg(0,filename,quality);
 
28970
    }
 
28971
 
 
28972
    //! Save a file in JPEG format.
 
28973
    const CImg<T>& save_jpeg(std::FILE *const file, const unsigned int quality=100) const {
 
28974
      return _save_jpeg(file,0,quality);
 
28975
    }
 
28976
 
 
28977
    //! Save the image using built-in ImageMagick++ library.
 
28978
    const CImg<T>& save_magick(const char *const filename) const {
 
28979
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
 
28980
                                                  pixel_type(),width,height,depth,dim,data);
 
28981
      if (!filename) throw CImgArgumentException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 
28982
                                                 pixel_type(),width,height,depth,dim,data);
 
28983
#ifdef cimg_use_magick
 
28984
      Magick::Image image(Magick::Geometry(width,height),"black");
 
28985
      image.type(Magick::TrueColorType);
 
28986
      const T
 
28987
        *rdata = ptr(0,0,0,0),
 
28988
        *gdata = dim>1?ptr(0,0,0,1):0,
 
28989
        *bdata = dim>2?ptr(0,0,0,2):0;
 
28990
      Magick::PixelPacket *pixels = image.getPixels(0,0,width,height);
 
28991
      switch (dim) {
 
28992
      case 1: // Scalar images
 
28993
        for (unsigned int off = width*height; off; --off) {
 
28994
          pixels->red = pixels->green = pixels->blue = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
 
28995
          ++pixels;
 
28996
        }
 
28997
        break;
 
28998
      case 2: // RG images
 
28999
        for (unsigned int off = width*height; off; --off) {
 
29000
          pixels->red   = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
 
29001
          pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
 
29002
          pixels->blue  = 0;
 
29003
          ++pixels;
 
29004
        }
 
29005
        break;
 
29006
      default: // RGB images
 
29007
        for (unsigned int off = width*height; off; --off) {
 
29008
          pixels->red   = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
 
29009
          pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
 
29010
          pixels->blue  = Magick::Color::scaleDoubleToQuantum(*(bdata++)/255.0);
 
29011
          ++pixels;
 
29012
        }
 
29013
        break;
 
29014
      }
 
29015
      image.syncPixels();
 
29016
      image.write(filename);
 
29017
#else
 
29018
      throw CImgIOException("CImg<%s>::save_magick() : File '%s', Magick++ library has not been linked.",
 
29019
                            pixel_type(),filename);
 
29020
#endif
 
29021
      return *this;
 
29022
    }
 
29023
 
 
29024
    // Save an image to a PNG file (internal).
 
29025
    // Most of this function has been written by Eric Fausett
 
29026
    const CImg<T>& _save_png(std::FILE *const file, const char *const filename) const {
 
29027
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
 
29028
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
29029
      if (!filename) throw CImgArgumentException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 
29030
                                                 pixel_type(),width,height,depth,dim,data);
 
29031
      if (depth>1)
 
29032
        cimg::warn("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved (file '%s').",
 
29033
                 pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
29034
#ifndef cimg_use_png
 
29035
      if (!file) return save_other(filename);
 
29036
      else throw CImgIOException("CImg<%s>::save_png() : Cannot save a PNG image in a *FILE output. You must use 'libpng' to do this instead.",
 
29037
                                 pixel_type());
 
29038
#else
 
29039
      const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
 
29040
      std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb");
 
29041
 
 
29042
      // Setup PNG structures for write
 
29043
      png_voidp user_error_ptr = 0;
 
29044
      png_error_ptr user_error_fn = 0, user_warning_fn = 0;
 
29045
      png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn, user_warning_fn);
 
29046
      if(!png_ptr){
 
29047
        if (!file) cimg::fclose(nfile);
 
29048
        throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'png_ptr' data structure.",
 
29049
                              pixel_type(),nfilename?nfilename:"(unknown)");
 
29050
      }
 
29051
      png_infop info_ptr = png_create_info_struct(png_ptr);
 
29052
      if (!info_ptr) {
 
29053
        png_destroy_write_struct(&png_ptr,(png_infopp)0);
 
29054
        if (!file) cimg::fclose(nfile);
 
29055
        throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'info_ptr' data structure.",
 
29056
                              pixel_type(),nfilename?nfilename:"(unknown)");
 
29057
      }
 
29058
      if (setjmp(png_jmpbuf(png_ptr))) {
 
29059
        png_destroy_write_struct(&png_ptr, &info_ptr);
 
29060
        if (!file) cimg::fclose(nfile);
 
29061
        throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
 
29062
                              pixel_type(),nfilename?nfilename:"(unknown)");
 
29063
      }
 
29064
      png_init_io(png_ptr, nfile);
 
29065
      png_uint_32 width = dimx(), height = dimy();
 
29066
      float vmin, vmax = (float)maxmin(vmin);
 
29067
      const int bit_depth = (vmin<0 || vmax>=256)?16:8;
 
29068
      int color_type;
 
29069
      switch (dimv()) {
 
29070
      case 1: color_type = PNG_COLOR_TYPE_GRAY; break;
 
29071
      case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
 
29072
      case 3: color_type = PNG_COLOR_TYPE_RGB; break;
 
29073
      default: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break;
 
29074
      }
 
29075
      const int interlace_type = PNG_INTERLACE_NONE;
 
29076
      const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
 
29077
      const int filter_method = PNG_FILTER_TYPE_DEFAULT;
 
29078
      png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type,compression_type, filter_method);
 
29079
      png_write_info(png_ptr, info_ptr);
 
29080
      const int byte_depth = bit_depth>>3;
 
29081
      const int numChan = dimv()>4?4:dimv();
 
29082
      const int pixel_bit_depth_flag = numChan * (bit_depth-1);
 
29083
 
 
29084
      // Allocate Memory for Image Save and Fill pixel data
 
29085
      png_bytep *imgData = new png_byte*[height];
 
29086
      for (unsigned int row = 0; row<height; ++row) imgData[row] = new png_byte[byte_depth*numChan*width];
 
29087
      const T *pC0 = ptr(0,0,0,0);
 
29088
      switch (pixel_bit_depth_flag) {
 
29089
      case 7 :  { // Gray 8-bit
 
29090
        cimg_forY(*this,y) {
 
29091
          unsigned char *ptrd = imgData[y];
 
29092
          cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++);
 
29093
        }
 
29094
      } break;
 
29095
      case 14: { // Gray w/ Alpha 8-bit
 
29096
        const T *pC1 = ptr(0,0,0,1);
 
29097
        cimg_forY(*this,y) {
 
29098
          unsigned char *ptrd = imgData[y];
 
29099
          cimg_forX(*this,x) {
 
29100
            *(ptrd++) = (unsigned char)*(pC0++);
 
29101
            *(ptrd++) = (unsigned char)*(pC1++);
 
29102
          }
 
29103
        }
 
29104
      } break;
 
29105
      case 21:  { // RGB 8-bit
 
29106
        const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
 
29107
        cimg_forY(*this,y) {
 
29108
          unsigned char *ptrd = imgData[y];
 
29109
          cimg_forX(*this,x) {
 
29110
            *(ptrd++) = (unsigned char)*(pC0++);
 
29111
            *(ptrd++) = (unsigned char)*(pC1++);
 
29112
            *(ptrd++) = (unsigned char)*(pC2++);
 
29113
          }
 
29114
        }
 
29115
      } break;
 
29116
      case 28: { // RGB x/ Alpha 8-bit
 
29117
        const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
 
29118
        cimg_forY(*this,y){
 
29119
          unsigned char *ptrd = imgData[y];
 
29120
          cimg_forX(*this,x){
 
29121
            *(ptrd++) = (unsigned char)*(pC0++);
 
29122
            *(ptrd++) = (unsigned char)*(pC1++);
 
29123
            *(ptrd++) = (unsigned char)*(pC2++);
 
29124
            *(ptrd++) = (unsigned char)*(pC3++);
 
29125
          }
 
29126
        }
 
29127
      } break;
 
29128
      case 15: { // Gray 16-bit
 
29129
        cimg_forY(*this,y){
 
29130
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
 
29131
          cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++);
 
29132
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],width);
 
29133
        }
 
29134
      } break;
 
29135
      case 30: { // Gray w/ Alpha 16-bit
 
29136
        const T *pC1 = ptr(0,0,0,1);
 
29137
        cimg_forY(*this,y){
 
29138
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
 
29139
          cimg_forX(*this,x) {
 
29140
            *(ptrd++) = (unsigned short)*(pC0++);
 
29141
            *(ptrd++) = (unsigned short)*(pC1++);
 
29142
          }
 
29143
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*width);
 
29144
        }
 
29145
      } break;
 
29146
      case 45: { // RGB 16-bit
 
29147
        const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
 
29148
        cimg_forY(*this,y) {
 
29149
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
 
29150
          cimg_forX(*this,x) {
 
29151
            *(ptrd++) = (unsigned short)*(pC0++);
 
29152
            *(ptrd++) = (unsigned short)*(pC1++);
 
29153
            *(ptrd++) = (unsigned short)*(pC2++);
 
29154
          }
 
29155
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*width);
 
29156
        }
 
29157
      } break;
 
29158
      case 60: { // RGB w/ Alpha 16-bit
 
29159
        const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
 
29160
        cimg_forY(*this,y) {
 
29161
          unsigned short *ptrd = (unsigned short*)(imgData[y]);
 
29162
          cimg_forX(*this,x) {
 
29163
            *(ptrd++) = (unsigned short)*(pC0++);
 
29164
            *(ptrd++) = (unsigned short)*(pC1++);
 
29165
            *(ptrd++) = (unsigned short)*(pC2++);
 
29166
            *(ptrd++) = (unsigned short)*(pC3++);
 
29167
          }
 
29168
          if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*width);
 
29169
        }
 
29170
      } break;
 
29171
      default:
 
29172
        if (!file) cimg::fclose(nfile);
 
29173
        throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
 
29174
                              pixel_type(),nfilename?nfilename:"(unknown)");
 
29175
        break;
 
29176
      }
 
29177
      png_write_image(png_ptr, imgData);
 
29178
      png_write_end(png_ptr, info_ptr);
 
29179
      png_destroy_write_struct(&png_ptr, &info_ptr);
 
29180
 
 
29181
      // Deallocate Image Write Memory
 
29182
      cimg_forY(*this,n) delete[] imgData[n];
 
29183
      delete[] imgData;
 
29184
      if (!file) cimg::fclose(nfile);
 
29185
      return *this;
 
29186
#endif
 
29187
    }
 
29188
 
 
29189
    //! Save a file in PNG format
 
29190
    const CImg<T>& save_png(const char *const filename) const {
 
29191
      return _save_png(0,filename);
 
29192
    }
 
29193
 
 
29194
    //! Save a file in PNG format
 
29195
    const CImg<T>& save_png(std::FILE *const file) const {
 
29196
      return _save_png(file,0);
 
29197
    }
 
29198
 
 
29199
    // Save the image as a PNM file (internal function).
 
29200
    const CImg<T>& _save_pnm(std::FILE *const file, const char *const filename) const {
 
29201
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 
29202
                                                          pixel_type(),width,height,depth,dim,data);
21204
29203
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
21205
29204
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21206
 
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
21207
 
                                                          pixel_type(),width,height,depth,dim,data);
21208
 
      const CImgStats st(*this,false);
 
29205
      double stmin, stmax = (double)maxmin(stmin);
21209
29206
      if (depth>1)
21210
29207
        cimg::warn("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved (file '%s').",
21211
29208
                 pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21212
29209
      if (dim>3)
21213
29210
        cimg::warn("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved (file '%s').",
21214
29211
                 pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21215
 
      const double stmin = st.min, stmax = st.max;
21216
29212
      if (stmin<0 || stmax>65535) cimg::warn("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p) has pixel values in [%g,%g]. Probable type overflow (file '%s').",pixel_type(),width,height,depth,dim,data,stmin,stmax,filename?filename:"(unknown)");
21217
29213
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
21218
29214
      const T
21219
29215
        *ptrR = ptr(0,0,0,0),
21220
 
        *ptrG = (dim>=2)?ptr(0,0,0,1):ptrR,
21221
 
        *ptrB = (dim>=3)?ptr(0,0,0,2):ptrR;
 
29216
        *ptrG = (dim>=2)?ptr(0,0,0,1):0,
 
29217
        *ptrB = (dim>=3)?ptr(0,0,0,2):0;
21222
29218
      const unsigned int buf_size = width*height*(dim==1?1:3);
21223
29219
 
21224
 
      std::fprintf(nfile,"P%c\n# CREATOR: CImg : Original size=%ux%ux%ux%u\n%u %u\n%u\n",
21225
 
                   (dim==1?'5':'6'),width,height,depth,dim,width,height,(st.max)<256?255:65535);
 
29220
      std::fprintf(nfile,"P%c\n# CREATOR: CImg Library (original size = %ux%ux%ux%u)\n%u %u\n%u\n",
 
29221
                   (dim==1?'5':'6'),width,height,depth,dim,width,height,stmax<256?255:(stmax<4096?4095:65535));
21226
29222
 
21227
 
      switch(dim) {
21228
 
      case 1: {
21229
 
        if ((st.max)<256) { // Binary PGM 8 bits
 
29223
      switch (dim) {
 
29224
      case 1: { // Scalar image
 
29225
        if (stmax<256) { // Binary PGM 8 bits
21230
29226
          unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
21231
29227
          cimg_forXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++);
21232
29228
          cimg::fwrite(ptrd,buf_size,nfile);
21234
29230
        } else {             // Binary PGM 16 bits
21235
29231
          unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
21236
29232
          cimg_forXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++);
21237
 
          if (!cimg::endian()) cimg::endian_swap(ptrd,buf_size);
21238
 
          cimg::fwrite(ptrd,buf_size,nfile);
21239
 
          delete[] ptrd;
21240
 
        }
21241
 
      } break;
21242
 
      default: {
21243
 
        if ((st.max)<256) { // Binary PPM 8 bits
 
29233
          if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
 
29234
          cimg::fwrite(ptrd,buf_size,nfile);
 
29235
          delete[] ptrd;
 
29236
        }
 
29237
      } break;
 
29238
      case 2: { // RG image
 
29239
        if (stmax<256) { // Binary PPM 8 bits
 
29240
          unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
 
29241
          cimg_forXY(*this,x,y) {
 
29242
            *(xptrd++) = (unsigned char)*(ptrR++);
 
29243
            *(xptrd++) = (unsigned char)*(ptrG++);
 
29244
            *(xptrd++) = 0;
 
29245
          }
 
29246
          cimg::fwrite(ptrd,buf_size,nfile);
 
29247
          delete[] ptrd;
 
29248
        } else {             // Binary PPM 16 bits
 
29249
          unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
 
29250
          cimg_forXY(*this,x,y) {
 
29251
            *(xptrd++) = (unsigned short)*(ptrR++);
 
29252
            *(xptrd++) = (unsigned short)*(ptrG++);
 
29253
            *(xptrd++) = 0;
 
29254
          }
 
29255
          if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
 
29256
          cimg::fwrite(ptrd,buf_size,nfile);
 
29257
          delete[] ptrd;
 
29258
        }
 
29259
      } break;
 
29260
      default: { // RGB image
 
29261
        if (stmax<256) { // Binary PPM 8 bits
21244
29262
          unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
21245
29263
          cimg_forXY(*this,x,y) {
21246
29264
            *(xptrd++) = (unsigned char)*(ptrR++);
21256
29274
            *(xptrd++) = (unsigned short)*(ptrG++);
21257
29275
            *(xptrd++) = (unsigned short)*(ptrB++);
21258
29276
          }
21259
 
          if (!cimg::endian()) cimg::endian_swap(ptrd,buf_size);
 
29277
          if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
21260
29278
          cimg::fwrite(ptrd,buf_size,nfile);
21261
29279
          delete[] ptrd;
21262
29280
        }
21267
29285
    }
21268
29286
 
21269
29287
    //! Save the image as a PNM file.
21270
 
    const CImg& save_pnm(const char *const filename) const {
21271
 
      return save_pnm(0,filename);
21272
 
    }
21273
 
 
21274
 
    //! Save an image as a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net )
21275
 
    const CImg& save_dicom(const char *const filename) const {
21276
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_dicom() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
21277
 
                                                  pixel_type(),width,height,depth,dim,data,filename);
21278
 
      if (!filename) throw CImgArgumentException("CImg<%s>::save_dicom() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 
29288
    const CImg<T>& save_pnm(const char *const filename) const {
 
29289
      return _save_pnm(0,filename);
 
29290
    }
 
29291
 
 
29292
    //! Save the image as a PNM file.
 
29293
    const CImg<T>& save_pnm(std::FILE *const file) const {
 
29294
      return _save_pnm(file,0);
 
29295
    }
 
29296
 
 
29297
    // Save the image as a RGB file (internal).
 
29298
    const CImg<T>& _save_rgb(std::FILE *const file, const char *const filename) const {
 
29299
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
 
29300
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
29301
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 
29302
                                                          pixel_type(),width,height,depth,dim,data);
 
29303
      if (dim!=3)
 
29304
        cimg::warn("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p) has not exactly 3 channels (file '%s').",
 
29305
                   pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
29306
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 
29307
      const unsigned int wh = width*height;
 
29308
      unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer;
 
29309
      const T
 
29310
        *ptr1 = ptr(0,0,0,0),
 
29311
        *ptr2 = dim>1?ptr(0,0,0,1):0,
 
29312
        *ptr3 = dim>2?ptr(0,0,0,2):0;
 
29313
      switch (dim) {
 
29314
      case 1: { // Scalar image
 
29315
        for (unsigned int k=0; k<wh; ++k) {
 
29316
          const unsigned char val = (unsigned char)*(ptr1++);
 
29317
          *(nbuffer++) = val;
 
29318
          *(nbuffer++) = val;
 
29319
          *(nbuffer++) = val;
 
29320
        }} break;
 
29321
      case 2: { // RG image
 
29322
        for (unsigned int k=0; k<wh; ++k) {
 
29323
          *(nbuffer++) = (unsigned char)(*(ptr1++));
 
29324
          *(nbuffer++) = (unsigned char)(*(ptr2++));
 
29325
          *(nbuffer++) = 0;
 
29326
        }} break;
 
29327
      default: { // RGB image
 
29328
        for (unsigned int k=0; k<wh; ++k) {
 
29329
          *(nbuffer++) = (unsigned char)(*(ptr1++));
 
29330
          *(nbuffer++) = (unsigned char)(*(ptr2++));
 
29331
          *(nbuffer++) = (unsigned char)(*(ptr3++));
 
29332
        }} break;
 
29333
      }
 
29334
      cimg::fwrite(buffer,3*wh,nfile);
 
29335
      if (!file) cimg::fclose(nfile);
 
29336
      delete[] buffer;
 
29337
      return *this;
 
29338
    }
 
29339
 
 
29340
    //! Save the image as a RGB file.
 
29341
    const CImg<T>& save_rgb(const char *const filename) const {
 
29342
      return _save_rgb(0,filename);
 
29343
    }
 
29344
 
 
29345
    //! Save the image as a RGB file.
 
29346
    const CImg<T>& save_rgb(std::FILE *const file) const {
 
29347
      return _save_rgb(file,0);
 
29348
    }
 
29349
 
 
29350
    // Save the image as a RGBA file (internal).
 
29351
    const CImg<T>& _save_rgba(std::FILE *const file, const char *const filename) const {
 
29352
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
 
29353
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
29354
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 
29355
                                                          pixel_type(),width,height,depth,dim,data);
 
29356
      if (dim!=4)
 
29357
        cimg::warn("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p) has not exactly 4 channels (file '%s').",
 
29358
                   pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
29359
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 
29360
      const unsigned int wh = width*height;
 
29361
      unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer;
 
29362
      const T
 
29363
        *ptr1 = ptr(0,0,0,0),
 
29364
        *ptr2 = dim>1?ptr(0,0,0,1):0,
 
29365
        *ptr3 = dim>2?ptr(0,0,0,2):0,
 
29366
        *ptr4 = dim>3?ptr(0,0,0,3):0;
 
29367
      switch (dim) {
 
29368
      case 1: { // Scalar images
 
29369
        for (unsigned int k=0; k<wh; ++k) {
 
29370
          const unsigned char val = (unsigned char)*(ptr1++);
 
29371
          *(nbuffer++) = val;
 
29372
          *(nbuffer++) = val;
 
29373
          *(nbuffer++) = val;
 
29374
          *(nbuffer++) = 255;
 
29375
        }} break;
 
29376
      case 2: { // RG images
 
29377
        for (unsigned int k=0; k<wh; ++k) {
 
29378
          *(nbuffer++) = (unsigned char)(*(ptr1++));
 
29379
          *(nbuffer++) = (unsigned char)(*(ptr2++));
 
29380
          *(nbuffer++) = 0;
 
29381
          *(nbuffer++) = 255;
 
29382
        }} break;
 
29383
      case 3: { // RGB images
 
29384
        for (unsigned int k=0; k<wh; ++k) {
 
29385
          *(nbuffer++) = (unsigned char)(*(ptr1++));
 
29386
          *(nbuffer++) = (unsigned char)(*(ptr2++));
 
29387
          *(nbuffer++) = (unsigned char)(*(ptr3++));
 
29388
          *(nbuffer++) = 255;
 
29389
        }} break;
 
29390
      default: { // RGBA images
 
29391
        for (unsigned int k=0; k<wh; ++k) {
 
29392
          *(nbuffer++) = (unsigned char)(*(ptr1++));
 
29393
          *(nbuffer++) = (unsigned char)(*(ptr2++));
 
29394
          *(nbuffer++) = (unsigned char)(*(ptr3++));
 
29395
          *(nbuffer++) = (unsigned char)(*(ptr4++));
 
29396
        }} break;
 
29397
      }
 
29398
      cimg::fwrite(buffer,4*wh,nfile);
 
29399
      if (!file) cimg::fclose(nfile);
 
29400
      delete[] buffer;
 
29401
      return *this;
 
29402
    }
 
29403
 
 
29404
    //! Save the image as a RGBA file.
 
29405
    const CImg<T>& save_rgba(const char *const filename) const {
 
29406
      return _save_rgba(0,filename);
 
29407
    }
 
29408
 
 
29409
    //! Save the image as a RGBA file.
 
29410
    const CImg<T>& save_rgba(std::FILE *const file) const {
 
29411
      return _save_rgba(file,0);
 
29412
    }
 
29413
 
 
29414
    // Save a plane into a tiff file
 
29415
#ifdef cimg_use_tiff
 
29416
    const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory) const {
 
29417
      if (is_empty() || !tif) return *this;
 
29418
      const char *const filename = TIFFFileName(tif);
 
29419
      uint32 rowsperstrip = (uint32)-1;
 
29420
      uint16 spp = dim, bpp = sizeof(T)*8, photometric, compression = COMPRESSION_NONE;
 
29421
      if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB;
 
29422
      else photometric = PHOTOMETRIC_MINISBLACK;
 
29423
      TIFFSetDirectory(tif,directory);
 
29424
      TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,width);
 
29425
      TIFFSetField(tif,TIFFTAG_IMAGELENGTH,height);
 
29426
      TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
 
29427
      TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp);
 
29428
      if (cimg::type<T>::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3);
 
29429
      else if (cimg::type<T>::min()==0) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,1);
 
29430
      else TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,2);
 
29431
      TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp);
 
29432
      TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
 
29433
      TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric);
 
29434
      TIFFSetField(tif,TIFFTAG_COMPRESSION,compression);
 
29435
      rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip);
 
29436
      TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip);
 
29437
      TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB);
 
29438
      TIFFSetField(tif,TIFFTAG_SOFTWARE,"CImg");
 
29439
      T *buf = (T*)_TIFFmalloc(TIFFStripSize(tif));
 
29440
      if (buf){
 
29441
        for (unsigned int row = 0; row<height; row+=rowsperstrip) {
 
29442
          uint32 nrow = (row+rowsperstrip>height?height-row:rowsperstrip);
 
29443
          tstrip_t strip = TIFFComputeStrip(tif,row,0);
 
29444
          tsize_t i = 0;
 
29445
          for (unsigned int rr = 0; rr<nrow; ++rr)
 
29446
            for (unsigned int cc = 0; cc<width; ++cc)
 
29447
              for (unsigned int vv = 0; vv<spp; ++vv)
 
29448
                buf[i++] = (*this)(cc,row+rr,vv);
 
29449
          if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(T))<0)
 
29450
            throw CImgException("CImg<%s>::save_tiff() : File '%s', an error occure while writing a strip.",
 
29451
                                pixel_type(),filename?filename:"(FILE*)");
 
29452
        }
 
29453
        _TIFFfree(buf);
 
29454
      }
 
29455
      TIFFWriteDirectory(tif);
 
29456
      return (*this);
 
29457
    }
 
29458
#endif
 
29459
 
 
29460
    //! Save a file in TIFF format.
 
29461
    const CImg<T>& save_tiff(const char *const filename) const {
 
29462
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_tiff() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
 
29463
                                                  pixel_type(),filename,width,height,depth,dim,data);
 
29464
      if (!filename) throw CImgArgumentException("CImg<%s>::save_tiff() : Specified filename is (null) for instance image (%u,%u,%u,%u,%p).",
21279
29465
                                                 pixel_type(),width,height,depth,dim,data);
21280
 
      static bool first_time = true;
21281
 
      char command[1024], filetmp[512], body[512];
21282
 
      if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; }
21283
 
      std::FILE *file;
21284
 
      do {
21285
 
        std::sprintf(filetmp,"CImg%.4d.hdr",std::rand()%10000);
21286
 
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
21287
 
      } while (file);
21288
 
      save_analyze(filetmp);
21289
 
      std::sprintf(command,"%s -w -c dicom -o %s -f %s",cimg::medcon_path(),filename,filetmp);
21290
 
      cimg::system(command);
21291
 
      std::remove(filetmp);
21292
 
      cimg::filename_split(filetmp,body);
21293
 
      std::sprintf(filetmp,"%s.img",body);
21294
 
      std::remove(filetmp);
21295
 
      std::sprintf(command,"m000-%s",filename);
21296
 
      file = std::fopen(command,"rb");
21297
 
      if (!file) {
21298
 
        cimg::fclose(cimg::fopen(filename,"r"));
21299
 
        throw CImgIOException("CImg<%s>::save_dicom() : Failed to save image '%s'.\n\n"
21300
 
                              "Path of 'medcon' : \"%s\"\n"
21301
 
                              "Path of temporary filename : \"%s\"",
21302
 
                              pixel_type(),filename,cimg::medcon_path(),filetmp);
21303
 
      } else cimg::fclose(file);
21304
 
      std::rename(command,filename);
 
29466
#ifdef cimg_use_tiff
 
29467
      TIFF *tif = TIFFOpen(filename,"w");
 
29468
      if (tif) {
 
29469
        cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z);
 
29470
        TIFFClose(tif);
 
29471
      } else throw CImgException("CImg<%s>::save_tiff() : File '%s', error while opening file stream for writing.",
 
29472
                                 pixel_type(),filename);
 
29473
#else
 
29474
      return save_other(filename);
 
29475
#endif
21305
29476
      return *this;
21306
29477
    }
21307
29478
 
21308
29479
    //! Save the image as an ANALYZE7.5 or NIFTI file.
21309
 
    const CImg& save_analyze(const char *const filename, const float *const voxsize=0) const {
 
29480
    const CImg<T>& save_analyze(const char *const filename, const float *const voxsize=0) const {
21310
29481
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_analyze() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
21311
29482
                                                  pixel_type(),width,height,depth,dim,data,filename);
21312
29483
      if (!filename) throw CImgArgumentException("CImg<%s>::save_analyze() :  Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
21313
29484
                                                 pixel_type(),width,height,depth,dim,data);
21314
29485
      std::FILE *file;
21315
29486
      char header[348], hname[1024], iname[1024];
21316
 
      const char *ext = cimg::filename_split(filename);
 
29487
      const char *ext = cimg::split_filename(filename);
21317
29488
      short datatype=-1;
21318
29489
      std::memset(header,0,348);
21319
29490
      if (!ext[0]) { std::sprintf(hname,"%s.hdr",filename); std::sprintf(iname,"%s.img",filename); }
21369
29540
    }
21370
29541
 
21371
29542
    //! Save the image as a .cimg file.
21372
 
    const CImg& save_cimg(std::FILE *const file, const char *const filename=0) const {
21373
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_cimg() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
21374
 
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21375
 
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_cimg() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
21376
 
                                                          pixel_type(),width,height,depth,dim,data);
21377
 
      CImgList<T> tmp(1);
21378
 
      tmp[0].width = width;
21379
 
      tmp[0].height = height;
21380
 
      tmp[0].depth = depth;
21381
 
      tmp[0].dim = dim;
21382
 
      tmp[0].data = data;
21383
 
      tmp.save_cimg(file,filename);
21384
 
      tmp[0].width = tmp[0].height = tmp[0].depth = tmp[0].dim = 0;
21385
 
      tmp[0].data = 0;
21386
 
      return *this;
21387
 
    }
21388
 
 
21389
 
    //! Save the image as a .cimg file.
21390
 
    const CImg& save_cimg(const char *const filename) const {
21391
 
      return save_cimg(0,filename);
21392
 
    }
21393
 
 
21394
 
    //! Insert the image into an existing .cimg file, at specified coordinates.
21395
 
    const CImg& save_cimg(std::FILE *const file,
21396
 
                          const unsigned int n0,
21397
 
                          const unsigned int x0, const unsigned int y0,
21398
 
                          const unsigned int z0, const unsigned int v0) const {
21399
 
      CImgList<T> tmp(1);
21400
 
      tmp[0].width = width;
21401
 
      tmp[0].height = height;
21402
 
      tmp[0].depth = depth;
21403
 
      tmp[0].dim = dim;
21404
 
      tmp[0].data = data;
21405
 
      tmp.save_cimg(file,n0,x0,y0,z0,v0);
21406
 
      tmp[0].width = tmp[0].height = tmp[0].depth = tmp[0].dim = 0;
21407
 
      tmp[0].data = 0;
21408
 
      return *this;
21409
 
    }
21410
 
 
21411
 
    //! Insert the image into an existing .cimg file, at specified coordinates.
21412
 
    const CImg& save_cimg(const char *const filename,
21413
 
                          const unsigned int n0,
21414
 
                          const unsigned int x0, const unsigned int y0,
21415
 
                          const unsigned int z0, const unsigned int v0) const {
21416
 
      CImgList<T> tmp(1);
21417
 
      tmp[0].width = width;
21418
 
      tmp[0].height = height;
21419
 
      tmp[0].depth = depth;
21420
 
      tmp[0].dim = dim;
21421
 
      tmp[0].data = data;
21422
 
      tmp.save_cimg(filename,n0,x0,y0,z0,v0);
21423
 
      tmp[0].width = tmp[0].height = tmp[0].depth = tmp[0].dim = 0;
21424
 
      tmp[0].data = 0;
21425
 
      return *this;
 
29543
    const CImg<T>& save_cimg(const char *const filename, const bool compress=false) const {
 
29544
      CImgList<T>(*this,true).save_cimg(filename,compress);
 
29545
      return *this;
 
29546
    }
 
29547
 
 
29548
    // Save the image as a .cimg file.
 
29549
    const CImg<T>& save_cimg(std::FILE *const file, const bool compress=false) const {
 
29550
      CImgList<T>(*this,true).save_cimg(file,compress);
 
29551
      return *this;
 
29552
    }
 
29553
 
 
29554
    //! Insert the image into an existing .cimg file, at specified coordinates.
 
29555
    const CImg<T>& save_cimg(const char *const filename,
 
29556
                             const unsigned int n0,
 
29557
                             const unsigned int x0, const unsigned int y0,
 
29558
                             const unsigned int z0, const unsigned int v0) const {
 
29559
      CImgList<T>(*this,true).save_cimg(filename,n0,x0,y0,z0,v0);
 
29560
      return *this;
 
29561
    }
 
29562
 
 
29563
    //! Insert the image into an existing .cimg file, at specified coordinates.
 
29564
    const CImg<T>& save_cimg(std::FILE *const file,
 
29565
                             const unsigned int n0,
 
29566
                             const unsigned int x0, const unsigned int y0,
 
29567
                             const unsigned int z0, const unsigned int v0) const {
 
29568
      CImgList<T>(*this,true).save_cimg(file,n0,x0,y0,z0,v0);
 
29569
      return *this;
 
29570
    }
 
29571
 
 
29572
    //! Save an empty .cimg file with specified dimensions.
 
29573
    static void save_empty_cimg(const char *const filename,
 
29574
                                const unsigned int dx, const unsigned int dy=1,
 
29575
                                const unsigned int dz=1, const unsigned int dv=1) {
 
29576
      return CImgList<T>::save_empty_cimg(filename,1,dx,dy,dz,dv);
21426
29577
    }
21427
29578
 
21428
29579
    //! Save an empty .cimg file with specified dimensions.
21432
29583
      return CImgList<T>::save_empty_cimg(file,1,dx,dy,dz,dv);
21433
29584
    }
21434
29585
 
21435
 
    //! Save an empty .cimg file with specified dimensions.
21436
 
    static void save_empty_cimg(const char *const filename,
21437
 
                                const unsigned int dx, const unsigned int dy=1,
21438
 
                                const unsigned int dz=1, const unsigned int dv=1) {
21439
 
      return CImgList<T>::save_empty_cimg(filename,1,dx,dy,dz,dv);
21440
 
    }
21441
 
 
21442
 
    //! Save the image as a RAW file
21443
 
    const CImg& save_raw(std::FILE *const file, const char *const filename=0, const bool multiplexed=false) const {
21444
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
21445
 
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21446
 
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
21447
 
                                                          pixel_type(),width,height,depth,dim,data);
21448
 
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
21449
 
      if (!multiplexed) cimg::fwrite(data,size(),nfile);
21450
 
      else {
21451
 
        CImg<T> buf(dim);
21452
 
        cimg_forXYZ(*this,x,y,z) {
21453
 
          cimg_forV(*this,k) buf[k] = (*this)(x,y,z,k);
21454
 
          cimg::fwrite(buf.data,dim,nfile);
21455
 
        }
21456
 
      }
21457
 
      if (!file) cimg::fclose(nfile);
21458
 
      return *this;
21459
 
    }
21460
 
 
21461
 
    //! Save the image as a RAW file
21462
 
    const CImg& save_raw(const char *const filename=0, const bool multiplexed=false) const {
21463
 
      return save_raw(0,filename,multiplexed);
21464
 
    }
21465
 
 
21466
 
    //! Save the image using ImageMagick's convert.
21467
 
    /** Function that saves the image for other file formats that are not natively handled by CImg,
21468
 
        using the tool 'convert' from the ImageMagick package.\n
21469
 
        This is the case for all compressed image formats (GIF,PNG,JPG,TIF,...). You need to install
21470
 
        the ImageMagick package in order to get
21471
 
        this function working properly (see http://www.imagemagick.org ).
21472
 
    **/
21473
 
    const CImg& save_imagemagick(const char *const filename, const unsigned int quality=100) const {
21474
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_imagemagick() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s')",
21475
 
                                                  pixel_type(),width,height,depth,dim,data,filename);
21476
 
      if (!filename) throw CImgArgumentException("CImg<%s>::save_imagemagick() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
21477
 
                                                 pixel_type(),width,height,depth,dim,data);
21478
 
      static bool first_time = true;
21479
 
      char command[512],filetmp[512];
21480
 
      if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; }
21481
 
      std::FILE *file;
21482
 
      do {
21483
 
        if (dim==1) std::sprintf(filetmp,"%s%sCImg%.4d.pgm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000);
21484
 
        else std::sprintf(filetmp,"%s%sCImg%.4d.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000);
21485
 
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
21486
 
      } while (file);
21487
 
      save_pnm(filetmp);
21488
 
      std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::imagemagick_path(),quality,filetmp,filename);
21489
 
      cimg::system(command);
21490
 
      file = std::fopen(filename,"rb");
21491
 
      if (!file) throw CImgIOException("CImg<%s>::save_imagemagick() : Failed to save image '%s'.\n\n"
21492
 
                                       "Path of 'convert' : \"%s\"\n"
21493
 
                                       "Path of temporary filename : \"%s\"\n",
21494
 
                                       pixel_type(),filename,cimg::imagemagick_path(),filetmp);
21495
 
      if (file) cimg::fclose(file);
21496
 
      std::remove(filetmp);
21497
 
      return *this;
21498
 
    }
21499
 
 
21500
 
    //! Save the image using GraphicsMagick's gm.
21501
 
    /** Function that saves the image for other file formats that are not natively handled by CImg,
21502
 
        using the tool 'gm' from the GraphicsMagick package.\n
21503
 
        This is the case for all compressed image formats (GIF,PNG,JPG,TIF,...). You need to install
21504
 
        the GraphicsMagick package in order to get
21505
 
        this function working properly (see http://www.graphicsmagick.org ).
21506
 
    **/
21507
 
    const CImg& save_graphicsmagick(const char *const filename, const unsigned int quality=100) const {
21508
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_graphicsmagick() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s')",
21509
 
                                                  pixel_type(),width,height,depth,dim,data,filename);
21510
 
      if (!filename) throw CImgArgumentException("CImg<%s>::save_graphicsmagick() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
21511
 
                                                 pixel_type(),width,height,depth,dim,data);
21512
 
      static bool first_time = true;
21513
 
      char command[512],filetmp[512];
21514
 
      if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; }
21515
 
      std::FILE *file;
21516
 
      do {
21517
 
        if (dim==1) std::sprintf(filetmp,"%s%sCImg%.4d.pgm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000);
21518
 
        else std::sprintf(filetmp,"%s%sCImg%.4d.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000);
21519
 
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
21520
 
      } while (file);
21521
 
      save_pnm(filetmp);
21522
 
      std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::graphicsmagick_path(),quality,filetmp,filename);
21523
 
      cimg::system(command);
21524
 
      file = std::fopen(filename,"rb");
21525
 
      if (!file) throw CImgIOException("CImg<%s>::save_graphicsmagick() : Failed to save image '%s'.\n\n"
21526
 
                                       "Path of 'gm' : \"%s\"\n"
21527
 
                                       "Path of temporary filename : \"%s\"\n",
21528
 
                                       pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
21529
 
      if (file) cimg::fclose(file);
21530
 
      std::remove(filetmp);
21531
 
      return *this;
21532
 
    }
21533
 
 
21534
 
    const CImg& save_other(const char *const filename, const unsigned int quality=100) const {
21535
 
      const unsigned int odebug = cimg::exception_mode();
21536
 
      bool is_saved = true;
21537
 
      cimg::exception_mode() = 0;
21538
 
      try { save_magick(filename); }
21539
 
      catch (CImgException&) {
21540
 
        try { save_imagemagick(filename,quality); }
21541
 
        catch (CImgException&) {
21542
 
          try { save_graphicsmagick(filename,quality); }
21543
 
          catch (CImgException&) {
21544
 
            is_saved = false;
21545
 
          }
21546
 
        }
21547
 
      }
21548
 
      cimg::exception_mode() = odebug;
21549
 
      if (!is_saved) throw CImgIOException("CImg<%s>::save_other() : File '%s' cannot be saved.\n"
21550
 
                                           "Check you have either the ImageMagick or GraphicsMagick package installed.",
21551
 
                                           pixel_type(),filename);
21552
 
      return *this;
21553
 
    }
21554
 
 
21555
 
    //! Save the image as an INRIMAGE-4 file.
21556
 
    const CImg& save_inr(std::FILE *const file, const char *const filename=0, const float *const voxsize=0) const {
 
29586
    // Save the image as an INRIMAGE-4 file (internal).
 
29587
    const CImg<T>& _save_inr(std::FILE *const file, const char *const filename, const float *const voxsize) const {
21557
29588
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_inr() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
21558
29589
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21559
29590
      if (!filename) throw CImgArgumentException("CImg<%s>::save_inr() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
21573
29604
      char header[257];
21574
29605
      int err = std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim);
21575
29606
      if (voxsize) err += std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]);
21576
 
      err += std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endian()?"sun":"decm");
 
29607
      err += std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm");
21577
29608
      std::memset(header+err,'\n',252-err);
21578
29609
      std::memcpy(header+252,"##}\n",4);
21579
29610
      cimg::fwrite(header,256,nfile);
21583
29614
    }
21584
29615
 
21585
29616
    //! Save the image as an INRIMAGE-4 file.
21586
 
    const CImg& save_inr(const char *const filename, const float *const voxsize=0) const {
21587
 
      return save_inr(0,filename,voxsize);
21588
 
    }
21589
 
 
21590
 
#define cimg_save_pandore_case(sy,sz,sv,stype,id) \
21591
 
   if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !strcmp(stype,pixel_type())) { \
21592
 
      unsigned int *iheader = (unsigned int*)(header+12); \
21593
 
      nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \
21594
 
      cimg::fwrite(header,36,nfile); \
21595
 
      cimg::fwrite(dims,nbdims,nfile); \
21596
 
      if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
21597
 
        unsigned char *buffer = new unsigned char[size()]; \
21598
 
        const T *ptrs = ptr(); \
21599
 
        cimg_foroff(*this,off) *(buffer++) = (unsigned char)(*(ptrs++)); \
21600
 
        buffer-=size(); \
21601
 
        cimg::fwrite(buffer,size(),nfile); \
21602
 
        delete[] buffer; \
21603
 
      } \
21604
 
      if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
21605
 
        unsigned long *buffer = new unsigned long[size()]; \
21606
 
        const T *ptrs = ptr(); \
21607
 
        cimg_foroff(*this,off) *(buffer++) = (long)(*(ptrs++)); \
21608
 
        buffer-=size(); \
21609
 
        cimg::fwrite(buffer,size(),nfile); \
21610
 
        delete[] buffer; \
21611
 
      } \
21612
 
      if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
21613
 
        float *buffer = new float[size()]; \
21614
 
        const T *ptrs = ptr(); \
21615
 
        cimg_foroff(*this,off) *(buffer++) = (float)(*(ptrs++)); \
21616
 
        buffer-=size(); \
21617
 
        cimg::fwrite(buffer,size(),nfile); \
21618
 
        delete[] buffer; \
21619
 
      } \
21620
 
      saved = true; \
21621
 
    }
21622
 
 
21623
 
    unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace=0) const {
 
29617
    const CImg<T>& save_inr(const char *const filename, const float *const voxsize=0) const {
 
29618
      return _save_inr(0,filename,voxsize);
 
29619
    }
 
29620
 
 
29621
    //! Save the image as an INRIMAGE-4 file.
 
29622
    const CImg<T>& save_inr(std::FILE *const file, const float *const voxsize=0) const {
 
29623
      return _save_inr(file,0,voxsize);
 
29624
    }
 
29625
 
 
29626
    // Save the image as a PANDORE-5 file (internal).
 
29627
    unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const {
21624
29628
      unsigned int nbdims = 0;
21625
29629
      if (id==2 || id==3 || id==4)    { dims[0] = 1;   dims[1] = width;  nbdims = 2; }
21626
29630
      if (id==5 || id==6 || id==7)    { dims[0] = 1;   dims[1] = height; dims[2] = width;  nbdims=3; }
21633
29637
      return nbdims;
21634
29638
    }
21635
29639
 
21636
 
    //! Save the image as a PANDORE-5 file.
21637
 
    const CImg& save_pandore(std::FILE *const file, const char *const filename=0, const unsigned int colorspace=0) const {
 
29640
    const CImg<T>& _save_pandore(std::FILE *const file, const char *const filename, const unsigned int colorspace) const {
 
29641
#define _cimg_save_pandore_case(sy,sz,sv,stype,id) \
 
29642
      if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !strcmp(stype,pixel_type())) { \
 
29643
        unsigned int *iheader = (unsigned int*)(header+12); \
 
29644
        nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \
 
29645
        cimg::fwrite(header,36,nfile); \
 
29646
        cimg::fwrite(dims,nbdims,nfile); \
 
29647
        if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
 
29648
          unsigned char *buffer = new unsigned char[size()]; \
 
29649
          const T *ptrs = data; \
 
29650
          cimg_foroff(*this,off) *(buffer++) = (unsigned char)(*(ptrs++)); \
 
29651
          buffer-=size(); \
 
29652
          cimg::fwrite(buffer,size(),nfile); \
 
29653
          delete[] buffer; \
 
29654
        } \
 
29655
        if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
 
29656
          unsigned long *buffer = new unsigned long[size()]; \
 
29657
          const T *ptrs = data; \
 
29658
          cimg_foroff(*this,off) *(buffer++) = (long)(*(ptrs++)); \
 
29659
          buffer-=size(); \
 
29660
          cimg::fwrite(buffer,size(),nfile); \
 
29661
          delete[] buffer; \
 
29662
        } \
 
29663
        if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
 
29664
          float *buffer = new float[size()]; \
 
29665
          const T *ptrs = data; \
 
29666
          cimg_foroff(*this,off) *(buffer++) = (float)(*(ptrs++)); \
 
29667
          buffer-=size(); \
 
29668
          cimg::fwrite(buffer,size(),nfile); \
 
29669
          delete[] buffer; \
 
29670
        } \
 
29671
        saved = true; \
 
29672
      }
 
29673
 
21638
29674
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_pandore() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
21639
29675
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21640
29676
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_pandore() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
21646
29682
                                   'N','o',' ','d','a','t','e',0,0,0,
21647
29683
                                   0 };
21648
29684
      unsigned int nbdims,dims[5];
21649
 
      bool saved=false;
21650
 
      cimg_save_pandore_case(1,1,1,"unsigned char",2);
21651
 
      cimg_save_pandore_case(1,1,1,"char",3);
21652
 
      cimg_save_pandore_case(1,1,1,"short",3);
21653
 
      cimg_save_pandore_case(1,1,1,"unsigned short",3);
21654
 
      cimg_save_pandore_case(1,1,1,"unsigned int",3);
21655
 
      cimg_save_pandore_case(1,1,1,"int",3);
21656
 
      cimg_save_pandore_case(1,1,1,"unsigned long",4);
21657
 
      cimg_save_pandore_case(1,1,1,"long",3);
21658
 
      cimg_save_pandore_case(1,1,1,"float",4);
21659
 
      cimg_save_pandore_case(1,1,1,"double",4);
21660
 
 
21661
 
      cimg_save_pandore_case(0,1,1,"unsigned char",5);
21662
 
      cimg_save_pandore_case(0,1,1,"char",6);
21663
 
      cimg_save_pandore_case(0,1,1,"short",6);
21664
 
      cimg_save_pandore_case(0,1,1,"unsigned short",6);
21665
 
      cimg_save_pandore_case(0,1,1,"unsigned int",6);
21666
 
      cimg_save_pandore_case(0,1,1,"int",6);
21667
 
      cimg_save_pandore_case(0,1,1,"unsigned long",7);
21668
 
      cimg_save_pandore_case(0,1,1,"long",6);
21669
 
      cimg_save_pandore_case(0,1,1,"float",7);
21670
 
      cimg_save_pandore_case(0,1,1,"double",7);
21671
 
 
21672
 
      cimg_save_pandore_case(0,0,1,"unsigned char",8);
21673
 
      cimg_save_pandore_case(0,0,1,"char",9);
21674
 
      cimg_save_pandore_case(0,0,1,"short",9);
21675
 
      cimg_save_pandore_case(0,0,1,"unsigned short",9);
21676
 
      cimg_save_pandore_case(0,0,1,"unsigned int",9);
21677
 
      cimg_save_pandore_case(0,0,1,"int",9);
21678
 
      cimg_save_pandore_case(0,0,1,"unsigned long",10);
21679
 
      cimg_save_pandore_case(0,0,1,"long",9);
21680
 
      cimg_save_pandore_case(0,0,1,"float",10);
21681
 
      cimg_save_pandore_case(0,0,1,"double",10);
21682
 
 
21683
 
      cimg_save_pandore_case(0,1,3,"unsigned char",16);
21684
 
      cimg_save_pandore_case(0,1,3,"char",17);
21685
 
      cimg_save_pandore_case(0,1,3,"short",17);
21686
 
      cimg_save_pandore_case(0,1,3,"unsigned short",17);
21687
 
      cimg_save_pandore_case(0,1,3,"unsigned int",17);
21688
 
      cimg_save_pandore_case(0,1,3,"int",17);
21689
 
      cimg_save_pandore_case(0,1,3,"unsigned long",18);
21690
 
      cimg_save_pandore_case(0,1,3,"long",17);
21691
 
      cimg_save_pandore_case(0,1,3,"float",18);
21692
 
      cimg_save_pandore_case(0,1,3,"double",18);
21693
 
 
21694
 
      cimg_save_pandore_case(0,0,3,"unsigned char",19);
21695
 
      cimg_save_pandore_case(0,0,3,"char",20);
21696
 
      cimg_save_pandore_case(0,0,3,"short",20);
21697
 
      cimg_save_pandore_case(0,0,3,"unsigned short",20);
21698
 
      cimg_save_pandore_case(0,0,3,"unsigned int",20);
21699
 
      cimg_save_pandore_case(0,0,3,"int",20);
21700
 
      cimg_save_pandore_case(0,0,3,"unsigned long",21);
21701
 
      cimg_save_pandore_case(0,0,3,"long",20);
21702
 
      cimg_save_pandore_case(0,0,3,"float",21);
21703
 
      cimg_save_pandore_case(0,0,3,"double",21);
21704
 
 
21705
 
      cimg_save_pandore_case(1,1,0,"unsigned char",22);
21706
 
      cimg_save_pandore_case(1,1,0,"char",23);
21707
 
      cimg_save_pandore_case(1,1,0,"short",23);
21708
 
      cimg_save_pandore_case(1,1,0,"unsigned short",23);
21709
 
      cimg_save_pandore_case(1,1,0,"unsigned int",23);
21710
 
      cimg_save_pandore_case(1,1,0,"int",23);
21711
 
      cimg_save_pandore_case(1,1,0,"unsigned long",25);
21712
 
      cimg_save_pandore_case(1,1,0,"long",23);
21713
 
      cimg_save_pandore_case(1,1,0,"float",25);
21714
 
      cimg_save_pandore_case(1,1,0,"double",25);
21715
 
 
21716
 
      cimg_save_pandore_case(0,1,0,"unsigned char",26);
21717
 
      cimg_save_pandore_case(0,1,0,"char",27);
21718
 
      cimg_save_pandore_case(0,1,0,"short",27);
21719
 
      cimg_save_pandore_case(0,1,0,"unsigned short",27);
21720
 
      cimg_save_pandore_case(0,1,0,"unsigned int",27);
21721
 
      cimg_save_pandore_case(0,1,0,"int",27);
21722
 
      cimg_save_pandore_case(0,1,0,"unsigned long",29);
21723
 
      cimg_save_pandore_case(0,1,0,"long",27);
21724
 
      cimg_save_pandore_case(0,1,0,"float",29);
21725
 
      cimg_save_pandore_case(0,1,0,"double",29);
21726
 
 
21727
 
      cimg_save_pandore_case(0,0,0,"unsigned char",30);
21728
 
      cimg_save_pandore_case(0,0,0,"char",31);
21729
 
      cimg_save_pandore_case(0,0,0,"short",31);
21730
 
      cimg_save_pandore_case(0,0,0,"unsigned short",31);
21731
 
      cimg_save_pandore_case(0,0,0,"unsigned int",31);
21732
 
      cimg_save_pandore_case(0,0,0,"int",31);
21733
 
      cimg_save_pandore_case(0,0,0,"unsigned long",33);
21734
 
      cimg_save_pandore_case(0,0,0,"long",31);
21735
 
      cimg_save_pandore_case(0,0,0,"float",33);
21736
 
      cimg_save_pandore_case(0,0,0,"double",33);
21737
 
 
21738
 
      if (!file) cimg::fclose(nfile);
21739
 
      return *this;
21740
 
    }
21741
 
 
21742
 
    //! Save the image as a PANDORE-5 file.
21743
 
    const CImg& save_pandore(const char *const filename=0, const unsigned int colorspace=0) const {
21744
 
      return save_pandore(0,filename,colorspace);
21745
 
    }
21746
 
 
21747
 
    //! Save the image as a YUV video sequence file
21748
 
    const CImg& save_yuv(std::FILE *const file, const char *const filename=0, const bool rgb2yuv=true) const {
21749
 
      CImgList<T>(*this).save_yuv(file,filename,rgb2yuv);
21750
 
      return *this;
21751
 
    }
21752
 
 
21753
 
    //! Save the image as a YUV video sequence file
21754
 
    const CImg& save_yuv(const char *const filename, const bool rgb2yuv=true) const {
21755
 
      return save_yuv(0,filename,rgb2yuv);
21756
 
    }
21757
 
 
21758
 
    //! Save the image as a BMP file
21759
 
    const CImg& save_bmp(std::FILE *const file, const char *const filename=0) const {
21760
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
21761
 
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21762
 
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
21763
 
                                                          pixel_type(),width,height,depth,dim,data);
21764
 
      if (depth>1)
21765
 
        cimg::warn("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved (file '%s').",
21766
 
                   pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21767
 
      if (dim>3)
21768
 
        cimg::warn("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved (file '%s').",
21769
 
                   pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21770
 
 
21771
 
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
21772
 
      unsigned char header[54] = { 0 }, align_buf[4] = { 0 };
21773
 
      const unsigned int
21774
 
        align     = (4-(3*width)%4)%4,
21775
 
        buf_size  = (3*width+align)*dimy(),
21776
 
        file_size = 54+buf_size;
21777
 
      header[0] = 'B'; header[1] = 'M';
21778
 
      header[0x02] = file_size&0xFF;
21779
 
      header[0x03] = (file_size>>8)&0xFF;
21780
 
      header[0x04] = (file_size>>16)&0xFF;
21781
 
      header[0x05] = (file_size>>24)&0xFF;
21782
 
      header[0x0A] = 0x36;
21783
 
      header[0x0E] = 0x28;
21784
 
      header[0x12] = width&0xFF;
21785
 
      header[0x13] = (width>>8)&0xFF;
21786
 
      header[0x14] = (width>>16)&0xFF;
21787
 
      header[0x15] = (width>>24)&0xFF;
21788
 
      header[0x16] = height&0xFF;
21789
 
      header[0x17] = (height>>8)&0xFF;
21790
 
      header[0x18] = (height>>16)&0xFF;
21791
 
      header[0x19] = (height>>24)&0xFF;
21792
 
      header[0x1A] = 1;
21793
 
      header[0x1B] = 0;
21794
 
      header[0x1C] = 24;
21795
 
      header[0x1D] = 0;
21796
 
      header[0x22] = buf_size&0xFF;
21797
 
      header[0x23] = (buf_size>>8)&0xFF;
21798
 
      header[0x24] = (buf_size>>16)&0xFF;
21799
 
      header[0x25] = (buf_size>>24)&0xFF;
21800
 
      header[0x27] = 0x1;
21801
 
      header[0x2B] = 0x1;
21802
 
      cimg::fwrite(header,54,nfile);
21803
 
 
21804
 
      const T
21805
 
        *pR = ptr(0,height-1,0,0),
21806
 
        *pG = (dim>=2)?ptr(0,height-1,0,1):pR,
21807
 
        *pB = (dim>=3)?ptr(0,height-1,0,2):pR;
21808
 
 
21809
 
      cimg_forY(*this,y) {
21810
 
        cimg_forX(*this,x) {
21811
 
          std::fputc((unsigned char)(*(pB++)),nfile);
21812
 
          std::fputc((unsigned char)(*(pG++)),nfile);
21813
 
          std::fputc((unsigned char)(*(pR++)),nfile);
21814
 
        }
21815
 
        cimg::fwrite(align_buf,align,nfile);
21816
 
        pR-=2*width; pG-=2*width; pB-=2*width;
21817
 
      }
21818
 
      if (!file) cimg::fclose(nfile);
21819
 
      return *this;
21820
 
    }
21821
 
 
21822
 
    //! Save the image as a BMP file
21823
 
    const CImg& save_bmp(const char *const filename) const {
21824
 
      return save_bmp(0,filename);
21825
 
    }
21826
 
 
21827
 
    //! Save an image to a PNG file.
21828
 
    // Most of this function has been written by Eric Fausett
21829
 
    /**
21830
 
       \param filename = name of the png image file to save
21831
 
       \return *this
21832
 
       \note The png format specifies a variety of possible data formats.  Grey scale, Grey
21833
 
       scale with Alpha, RGB color, RGB color with Alpha, and Palletized color are supported.
21834
 
       Per channel bit depths of 1, 2, 4, 8, and 16 are natively supported. The
21835
 
       type of file saved depends on the number of channels in the CImg file.  If there is 4 or more
21836
 
       channels, the image will be saved as an RGB color with Alpha image using the bottom 4 channels.
21837
 
       If there are 3 channels, the saved image will be an RGB color image.  If 2 channels then the
21838
 
       image saved will be Grey scale with Alpha, and if 1 channel will be saved as a Grey scale
21839
 
       image.
21840
 
    **/
21841
 
    const CImg& save_png(std::FILE *const file, const char *const filename=0) const {
21842
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
21843
 
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21844
 
      if (!filename) throw CImgArgumentException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
21845
 
                                                 pixel_type(),width,height,depth,dim,data);
21846
 
      if (depth>1)
21847
 
        cimg::warn("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved (file '%s').",
21848
 
                 pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
21849
 
#ifndef cimg_use_png
21850
 
      if (!file) return save_other(filename);
21851
 
      else throw CImgIOException("CImg<%s>::save_png() : Cannot save a PNG image in a *FILE output. Use libpng instead.",
21852
 
                                 pixel_type());
21853
 
#else
21854
 
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
21855
 
 
21856
 
      // Setup PNG structures for write
21857
 
      png_voidp user_error_ptr = 0;
21858
 
      png_error_ptr user_error_fn = 0, user_warning_fn = 0;
21859
 
      png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
21860
 
                                                    user_error_ptr, user_error_fn, user_warning_fn);
21861
 
      if(!png_ptr){
21862
 
        if (!file) cimg::fclose(nfile);
21863
 
        throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'png_ptr' data structure.",
21864
 
                              pixel_type(),filename?filename:"(unknown)");
21865
 
      }
21866
 
      png_infop info_ptr = png_create_info_struct(png_ptr);
21867
 
      if(!info_ptr){
21868
 
        png_destroy_write_struct(&png_ptr,(png_infopp)0);
21869
 
        if (!file) cimg::fclose(nfile);
21870
 
        throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'info_ptr' data structure.",
21871
 
                              pixel_type(),filename?filename:"(unknown)");
21872
 
      }
21873
 
      if (setjmp(png_jmpbuf(png_ptr))){
21874
 
        png_destroy_write_struct(&png_ptr, &info_ptr);
21875
 
        if (!file) cimg::fclose(nfile);
21876
 
        throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
21877
 
                              pixel_type(),filename?filename:"(unknown)");
21878
 
      }
21879
 
 
21880
 
      png_init_io(png_ptr, nfile);
21881
 
      png_uint_32 width = dimx();
21882
 
      png_uint_32 height = dimy();
21883
 
      const CImgStats stats(*this,false);
21884
 
      const float vmin = (float)stats.min, vmax = (float)stats.max;
21885
 
      const int bit_depth = (vmin<0 || vmax>=256)?16:8;
21886
 
      int color_type;
21887
 
      switch (dimv()) {
21888
 
      case 1: color_type = PNG_COLOR_TYPE_GRAY; break;
21889
 
      case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
21890
 
      case 3: color_type = PNG_COLOR_TYPE_RGB; break;
21891
 
      default: color_type = PNG_COLOR_TYPE_RGB_ALPHA;
21892
 
      }
21893
 
      const int interlace_type = PNG_INTERLACE_NONE;
21894
 
      const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
21895
 
      const int filter_method = PNG_FILTER_TYPE_DEFAULT;
21896
 
      png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type,
21897
 
                   compression_type, filter_method);
21898
 
      png_write_info(png_ptr, info_ptr);
21899
 
      const int byte_depth = bit_depth>>3;
21900
 
      const int numChan = dimv()>4?4:dimv();
21901
 
      const int pixel_bit_depth_flag = numChan * (bit_depth-1);
21902
 
 
21903
 
      // Allocate Memory for Image Save and Fill pixel data
21904
 
      png_bytep *imgData = new png_byte*[height];
21905
 
      for (unsigned int row=0; row<height; ++row) imgData[row] = new png_byte[byte_depth * numChan * width];
21906
 
      const T *pC0 = ptr(0,0,0,0);
21907
 
      switch(pixel_bit_depth_flag) {
21908
 
      case 7 :  { // Gray 8-bit
21909
 
        cimg_forY(*this,y) {
21910
 
          unsigned char *ptrs = imgData[y];
21911
 
          cimg_forX(*this,x) *(ptrs++) = (unsigned char)*(pC0++);
21912
 
        }
21913
 
      } break;
21914
 
      case 14: { // Gray w/ Alpha 8-bit
21915
 
        const T *pC1 = ptr(0,0,0,1);
21916
 
        cimg_forY(*this,y) {
21917
 
          unsigned char *ptrs = imgData[y];
21918
 
          cimg_forX(*this,x) {
21919
 
            *(ptrs++) = (unsigned char)*(pC0++);
21920
 
            *(ptrs++) = (unsigned char)*(pC1++);
21921
 
          }
21922
 
        }
21923
 
      } break;
21924
 
      case 21:  { // RGB 8-bit
21925
 
        const T *pC1 = ptr(0,0,0,1);
21926
 
        const T *pC2 = ptr(0,0,0,2);
21927
 
        cimg_forY(*this,y) {
21928
 
          unsigned char *ptrs = imgData[y];
21929
 
          cimg_forX(*this,x) {
21930
 
            *(ptrs++) = (unsigned char)*(pC0++);
21931
 
            *(ptrs++) = (unsigned char)*(pC1++);
21932
 
            *(ptrs++) = (unsigned char)*(pC2++);
21933
 
          }
21934
 
        }
21935
 
      } break;
21936
 
      case 28: { // RGB x/ Alpha 8-bit
21937
 
        const T *pC1 = ptr(0,0,0,1);
21938
 
        const T *pC2 = ptr(0,0,0,2);
21939
 
        const T *pC3 = ptr(0,0,0,3);
21940
 
        cimg_forY(*this,y){
21941
 
          unsigned char *ptrs = imgData[y];
21942
 
          cimg_forX(*this,x){
21943
 
            *(ptrs++) = (unsigned char)*(pC0++);
21944
 
            *(ptrs++) = (unsigned char)*(pC1++);
21945
 
            *(ptrs++) = (unsigned char)*(pC2++);
21946
 
            *(ptrs++) = (unsigned char)*(pC3++);
21947
 
          }
21948
 
        }
21949
 
      } break;
21950
 
      case 15: { // Gray 16-bit
21951
 
        cimg_forY(*this,y){
21952
 
          unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
21953
 
          cimg_forX(*this,x) *(ptrs++) = (unsigned short)*(pC0++);
21954
 
        }
21955
 
      } break;
21956
 
      case 30: { // Gray w/ Alpha 16-bit
21957
 
        const T *pC1 = ptr(0,0,0,1);
21958
 
        cimg_forY(*this,y){
21959
 
          unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
21960
 
          cimg_forX(*this,x) {
21961
 
            *(ptrs++) = (unsigned short)*(pC0++);
21962
 
            *(ptrs++) = (unsigned short)*(pC1++);
21963
 
          }
21964
 
        }
21965
 
      } break;
21966
 
      case 45: { // RGB 16-bit
21967
 
        const T *pC1 = ptr(0,0,0,1);
21968
 
        const T *pC2 = ptr(0,0,0,2);
21969
 
        cimg_forY(*this,y) {
21970
 
          unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
21971
 
          cimg_forX(*this,x) {
21972
 
            *(ptrs++) = (unsigned short)*(pC0++);
21973
 
            *(ptrs++) = (unsigned short)*(pC1++);
21974
 
            *(ptrs++) = (unsigned short)*(pC2++);
21975
 
          }
21976
 
        }
21977
 
      } break;
21978
 
      case 60: { // RGB w/ Alpha 16-bit
21979
 
        const T *pC1 = ptr(0,0,0,1);
21980
 
        const T *pC2 = ptr(0,0,0,2);
21981
 
        const T *pC3 = ptr(0,0,0,3);
21982
 
        cimg_forY(*this,y) {
21983
 
          unsigned short *ptrs = reinterpret_cast<unsigned short*>(imgData[y]);
21984
 
          cimg_forX(*this,x) {
21985
 
            *(ptrs++) = (unsigned short)*(pC0++);
21986
 
            *(ptrs++) = (unsigned short)*(pC1++);
21987
 
            *(ptrs++) = (unsigned short)*(pC2++);
21988
 
            *(ptrs++) = (unsigned short)*(pC3++);
21989
 
          }
21990
 
        }
21991
 
      } break;
21992
 
      default:
21993
 
        if (!file) cimg::fclose(nfile);
21994
 
        throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
21995
 
                              pixel_type(),filename?filename:"(unknown)");
21996
 
        break;
21997
 
      }
21998
 
      png_write_image(png_ptr, imgData);
21999
 
      png_write_end(png_ptr, info_ptr);
22000
 
      png_destroy_write_struct(&png_ptr, &info_ptr);
22001
 
 
22002
 
      // Deallocate Image Write Memory
22003
 
      for (unsigned int n=0; n<height; ++n) delete[] imgData[n];
22004
 
      delete[] imgData;
22005
 
      if (!file) cimg::fclose(nfile);
22006
 
      return *this;
22007
 
#endif
22008
 
    }
22009
 
 
22010
 
    //! Save a file in PNG format
22011
 
    const CImg& save_png(const char *const filename) const {
22012
 
      return save_png(0,filename);
22013
 
    }
22014
 
 
22015
 
    //! Save a file in TIFF format.
22016
 
    const CImg& save_tiff(const char *const filename) const {
22017
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_tiff() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
22018
 
                                                  pixel_type(),width,height,depth,dim,data,filename);
22019
 
      if (!filename) throw CImgArgumentException("CImg<%s>::save_tiff() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
22020
 
                                                 pixel_type(),width,height,depth,dim,data);
22021
 
#ifdef cimg_use_tiff
22022
 
      uint32 rowsperstrip = (uint32) -1;
22023
 
      uint16 spp = dimv(), bpp = sizeof(T)*8;
22024
 
      uint16 photometric;
22025
 
      if (spp==3 || spp==4)
22026
 
        photometric = PHOTOMETRIC_RGB;
22027
 
          else
22028
 
            photometric = PHOTOMETRIC_MINISBLACK;
22029
 
      uint16 compression = COMPRESSION_NONE;
22030
 
      TIFF *out;
22031
 
      out = TIFFOpen(filename,"w");
22032
 
      if (out) {
22033
 
        for (unsigned int dir=0; dir<depth; ++dir) {
22034
 
          TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32)dimx());
22035
 
          TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32)dimy());
22036
 
          TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
22037
 
          TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, spp);
22038
 
          TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bpp);
22039
 
          TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
22040
 
          TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
22041
 
          TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
22042
 
          rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
22043
 
          TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
22044
 
          TIFFSetField(out, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
22045
 
          TIFFSetField(out, TIFFTAG_SOFTWARE, "CImg");
22046
 
          T *buf = (T *)_TIFFmalloc(TIFFStripSize(out));
22047
 
          if (buf){
22048
 
            for (unsigned int row = 0; row < height; row+=rowsperstrip) {
22049
 
              uint32 nrow = (row+rowsperstrip>height?height-row:rowsperstrip);
22050
 
              tstrip_t strip = TIFFComputeStrip(out, row, 0);
22051
 
              tsize_t i = 0;
22052
 
              for (unsigned int rr=0; rr<nrow; ++rr)
22053
 
                for (unsigned int cc=0; cc<width; ++cc)
22054
 
                  for (unsigned int vv=0; vv<spp; ++vv)
22055
 
                    buf[i++] = (*this)(cc,row+rr,dir,vv);
22056
 
              if(TIFFWriteEncodedStrip(out, strip, buf, i*sizeof(T))<0){
22057
 
                throw CImgException("CImg<%s>::save_tiff() : File '%s', an error occure while writing a strip.",
22058
 
                                    pixel_type(),filename?filename:"(FILE*)");
22059
 
              }
22060
 
            }
22061
 
            _TIFFfree(buf);
22062
 
          }
22063
 
          TIFFWriteDirectory(out);
22064
 
        }
22065
 
        TIFFClose(out);
22066
 
      }
22067
 
      else throw CImgException("CImg<%s>::save_tiff() : File '%s', error while writing tiff file.",
22068
 
                               pixel_type(),filename);
22069
 
#else
22070
 
      return save_other(filename);
22071
 
#endif
22072
 
      return *this;
22073
 
    }
22074
 
 
22075
 
    //! Save a file in JPEG format.
22076
 
    const CImg<T>& save_jpeg(std::FILE *const file, const char *const filename=0, const unsigned int quality=100) const {
22077
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
22078
 
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
22079
 
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
22080
 
                                                          pixel_type(),width,height,depth,dim,data);
22081
 
      if (depth>1)
22082
 
        cimg::warn("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved (file '%s').",
22083
 
                   pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
22084
 
#ifndef cimg_use_jpeg
22085
 
      if (!file) return save_other(filename,quality);
22086
 
      else throw CImgIOException("CImg<%s>::save_jpeg() : Cannot save a JPEG image in a *FILE output. Use libjpeg instead.",
22087
 
                                 pixel_type());
22088
 
#else
22089
 
 
22090
 
      // Fill pixel buffer
22091
 
      unsigned char *buf;
22092
 
      unsigned int dimbuf = 0;
22093
 
      J_COLOR_SPACE colortype = JCS_RGB;
22094
 
      switch (dim) {
22095
 
      case 1: { // Greyscale images
22096
 
        unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=1)];
22097
 
        colortype = JCS_GRAYSCALE;
22098
 
        const T *ptr_g = ptr();
22099
 
        cimg_forXY(*this,x,y) *(buf2++) = (unsigned char)*(ptr_g++);
22100
 
      } break;
22101
 
      case 2:
22102
 
      case 3: { // RGB images
22103
 
        unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
22104
 
        const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,dim>2?2:0);
22105
 
        colortype = JCS_RGB;
22106
 
        cimg_forXY(*this,x,y) {
22107
 
          *(buf2++) = (unsigned char)*(ptr_r++);
22108
 
          *(buf2++) = (unsigned char)*(ptr_g++);
22109
 
          *(buf2++) = (unsigned char)*(ptr_b++);
22110
 
        }
22111
 
      } break;
22112
 
      default: { // YCMYK images
22113
 
        unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=4)];
22114
 
        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);
22115
 
        colortype = JCS_CMYK;
22116
 
        cimg_forXY(*this,x,y) {
22117
 
          *(buf2++) = (unsigned char)*(ptr_r++);
22118
 
          *(buf2++) = (unsigned char)*(ptr_g++);
22119
 
          *(buf2++) = (unsigned char)*(ptr_b++);
22120
 
          *(buf2++) = (unsigned char)*(ptr_a++);
22121
 
        }
22122
 
      } break;
22123
 
      }
22124
 
 
22125
 
      // Call libjpeg functions
22126
 
      struct jpeg_compress_struct cinfo;
22127
 
      struct jpeg_error_mgr jerr;
22128
 
      cinfo.err = jpeg_std_error(&jerr);
22129
 
      jpeg_create_compress(&cinfo);
22130
 
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
22131
 
      jpeg_stdio_dest(&cinfo,nfile);
22132
 
      cinfo.image_width = width;
22133
 
      cinfo.image_height = height;
22134
 
      cinfo.input_components = dimbuf;
22135
 
      cinfo.in_color_space = colortype;
22136
 
      jpeg_set_defaults(&cinfo);
22137
 
      jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
22138
 
      jpeg_start_compress(&cinfo,TRUE);
22139
 
 
22140
 
      const unsigned int row_stride = width*dimbuf;
22141
 
      JSAMPROW row_pointer[1];
22142
 
      while (cinfo.next_scanline < cinfo.image_height) {
22143
 
        row_pointer[0] = &buf[cinfo.next_scanline*row_stride];
22144
 
        jpeg_write_scanlines(&cinfo,row_pointer,1);
22145
 
      }
22146
 
      jpeg_finish_compress(&cinfo);
22147
 
 
22148
 
      delete[] buf;
22149
 
      if (!file) cimg::fclose(nfile);
22150
 
      jpeg_destroy_compress(&cinfo);
22151
 
      return *this;
22152
 
#endif
22153
 
    }
22154
 
 
22155
 
    //! Save a file in JPEG format.
22156
 
    const CImg<T>& save_jpeg(const char *const filename, const unsigned int quality=100) const {
22157
 
      return save_jpeg(0,filename,quality);
22158
 
    }
22159
 
 
22160
 
    //! Save the image using built-in ImageMagick++ library
22161
 
    const CImg& save_magick(const char *const filename) const {
22162
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
22163
 
                                                  pixel_type(),width,height,depth,dim,data);
22164
 
      if (!filename) throw CImgArgumentException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
22165
 
                                                 pixel_type(),width,height,depth,dim,data);
22166
 
#ifdef cimg_use_magick
22167
 
      Magick::Image image(Magick::Geometry(width,height),"black");
22168
 
      image.type(Magick::TrueColorType);
22169
 
      const T *rdata = ptr(0,0,0,0), *gdata = dim>1?ptr(0,0,0,1):rdata, *bdata = dim>2?ptr(0,0,0,2):gdata;
22170
 
      cimg_forXY(*this,x,y) image.pixelColor(x,y,Magick::ColorRGB(*(rdata++)/255.0,*(gdata++)/255.0,*(bdata++)/255.0));
22171
 
      image.syncPixels();
22172
 
      image.write(filename);
22173
 
#else
22174
 
      throw CImgIOException("CImg<%s>::save_magick() : File '%s', Magick++ library has not been linked.",
22175
 
                            pixel_type(),filename);
22176
 
#endif
22177
 
      return *this;
22178
 
    }
22179
 
 
22180
 
    //! Save the image as a RGBA file
22181
 
    const CImg& save_rgba(std::FILE *const file, const char *const filename=0) const {
22182
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
22183
 
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
22184
 
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
22185
 
                                                          pixel_type(),width,height,depth,dim,data);
22186
 
      if (dim!=4)
22187
 
        cimg::warn("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p) has not exactly 4 channels (file '%s').",
22188
 
                   pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
22189
 
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
22190
 
      const unsigned int wh = width*height;
22191
 
      unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer;
22192
 
      const T
22193
 
        *ptr1 = ptr(0,0,0,0),
22194
 
        *ptr2 = dim>1?ptr(0,0,0,1):ptr1,
22195
 
        *ptr3 = dim>2?ptr(0,0,0,2):ptr1,
22196
 
        *ptr4 = dim>3?ptr(0,0,0,3):0;
22197
 
      for (unsigned int k=0; k<wh; ++k) {
22198
 
        *(nbuffer++) = (unsigned char)(*(ptr1++));
22199
 
        *(nbuffer++) = (unsigned char)(*(ptr2++));
22200
 
        *(nbuffer++) = (unsigned char)(*(ptr3++));
22201
 
        *(nbuffer++) = (unsigned char)(ptr4?(*(ptr4++)):255);
22202
 
      }
22203
 
      cimg::fwrite(buffer,4*wh,nfile);
22204
 
      if (!file) cimg::fclose(nfile);
22205
 
      delete[] buffer;
22206
 
      return *this;
22207
 
    }
22208
 
 
22209
 
    //! Save the image as a RGBA file
22210
 
    const CImg& save_rgba(const char *const filename) const {
22211
 
      return save_rgba(0,filename);
22212
 
    }
22213
 
 
22214
 
    //! Save the image as a RGB file
22215
 
    const CImg& save_rgb(std::FILE *const file, const char *const filename=0) const {
22216
 
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
22217
 
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
22218
 
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
22219
 
                                                          pixel_type(),width,height,depth,dim,data);
22220
 
      if (dim!=3)
22221
 
        cimg::warn("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p) has not exactly 3 channels (file '%s').",
22222
 
                   pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
22223
 
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
22224
 
      const unsigned int wh = width*height;
22225
 
      unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer;
22226
 
      const T
22227
 
        *ptr1 = ptr(0,0,0,0),
22228
 
        *ptr2 = dim>1?ptr(0,0,0,1):ptr1,
22229
 
        *ptr3 = dim>2?ptr(0,0,0,2):ptr1;
22230
 
      for (unsigned int k=0; k<wh; ++k) {
22231
 
        *(nbuffer++) = (unsigned char)(*(ptr1++));
22232
 
        *(nbuffer++) = (unsigned char)(*(ptr2++));
22233
 
        *(nbuffer++) = (unsigned char)(*(ptr3++));
22234
 
      }
22235
 
      cimg::fwrite(buffer,3*wh,nfile);
22236
 
      if (!file) cimg::fclose(nfile);
22237
 
      delete[] buffer;
22238
 
      return *this;
22239
 
    }
22240
 
 
22241
 
    //! Save the image as a RGB file
22242
 
    const CImg& save_rgb(const char *const filename) const {
22243
 
      return save_rgb(0,filename);
22244
 
    }
22245
 
 
22246
 
    //! Get a 40x38 color logo of a 'danger' item
22247
 
    static CImg get_logo40x38() {
22248
 
      static bool first_time = true;
22249
 
      static CImg<T> res(40,38,1,3);
22250
 
      if (first_time) {
22251
 
        const unsigned char *ptrs = cimg::logo40x38;
22252
 
        T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2);
22253
 
        for (unsigned int off = 0; off<res.width*res.height;) {
22254
 
          const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++);
22255
 
          for (unsigned int l=0; l<n; ++off, ++l) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; }
22256
 
        }
22257
 
        first_time = false;
22258
 
      }
22259
 
      return res;
22260
 
    }
22261
 
 
22262
 
    //! Save OFF files (GeomView 3D object files)
 
29685
      bool saved = false;
 
29686
      _cimg_save_pandore_case(1,1,1,"unsigned char",2);
 
29687
      _cimg_save_pandore_case(1,1,1,"char",3);
 
29688
      _cimg_save_pandore_case(1,1,1,"short",3);
 
29689
      _cimg_save_pandore_case(1,1,1,"unsigned short",3);
 
29690
      _cimg_save_pandore_case(1,1,1,"unsigned int",3);
 
29691
      _cimg_save_pandore_case(1,1,1,"int",3);
 
29692
      _cimg_save_pandore_case(1,1,1,"unsigned long",4);
 
29693
      _cimg_save_pandore_case(1,1,1,"long",3);
 
29694
      _cimg_save_pandore_case(1,1,1,"float",4);
 
29695
      _cimg_save_pandore_case(1,1,1,"double",4);
 
29696
 
 
29697
      _cimg_save_pandore_case(0,1,1,"unsigned char",5);
 
29698
      _cimg_save_pandore_case(0,1,1,"char",6);
 
29699
      _cimg_save_pandore_case(0,1,1,"short",6);
 
29700
      _cimg_save_pandore_case(0,1,1,"unsigned short",6);
 
29701
      _cimg_save_pandore_case(0,1,1,"unsigned int",6);
 
29702
      _cimg_save_pandore_case(0,1,1,"int",6);
 
29703
      _cimg_save_pandore_case(0,1,1,"unsigned long",7);
 
29704
      _cimg_save_pandore_case(0,1,1,"long",6);
 
29705
      _cimg_save_pandore_case(0,1,1,"float",7);
 
29706
      _cimg_save_pandore_case(0,1,1,"double",7);
 
29707
 
 
29708
      _cimg_save_pandore_case(0,0,1,"unsigned char",8);
 
29709
      _cimg_save_pandore_case(0,0,1,"char",9);
 
29710
      _cimg_save_pandore_case(0,0,1,"short",9);
 
29711
      _cimg_save_pandore_case(0,0,1,"unsigned short",9);
 
29712
      _cimg_save_pandore_case(0,0,1,"unsigned int",9);
 
29713
      _cimg_save_pandore_case(0,0,1,"int",9);
 
29714
      _cimg_save_pandore_case(0,0,1,"unsigned long",10);
 
29715
      _cimg_save_pandore_case(0,0,1,"long",9);
 
29716
      _cimg_save_pandore_case(0,0,1,"float",10);
 
29717
      _cimg_save_pandore_case(0,0,1,"double",10);
 
29718
 
 
29719
      _cimg_save_pandore_case(0,1,3,"unsigned char",16);
 
29720
      _cimg_save_pandore_case(0,1,3,"char",17);
 
29721
      _cimg_save_pandore_case(0,1,3,"short",17);
 
29722
      _cimg_save_pandore_case(0,1,3,"unsigned short",17);
 
29723
      _cimg_save_pandore_case(0,1,3,"unsigned int",17);
 
29724
      _cimg_save_pandore_case(0,1,3,"int",17);
 
29725
      _cimg_save_pandore_case(0,1,3,"unsigned long",18);
 
29726
      _cimg_save_pandore_case(0,1,3,"long",17);
 
29727
      _cimg_save_pandore_case(0,1,3,"float",18);
 
29728
      _cimg_save_pandore_case(0,1,3,"double",18);
 
29729
 
 
29730
      _cimg_save_pandore_case(0,0,3,"unsigned char",19);
 
29731
      _cimg_save_pandore_case(0,0,3,"char",20);
 
29732
      _cimg_save_pandore_case(0,0,3,"short",20);
 
29733
      _cimg_save_pandore_case(0,0,3,"unsigned short",20);
 
29734
      _cimg_save_pandore_case(0,0,3,"unsigned int",20);
 
29735
      _cimg_save_pandore_case(0,0,3,"int",20);
 
29736
      _cimg_save_pandore_case(0,0,3,"unsigned long",21);
 
29737
      _cimg_save_pandore_case(0,0,3,"long",20);
 
29738
      _cimg_save_pandore_case(0,0,3,"float",21);
 
29739
      _cimg_save_pandore_case(0,0,3,"double",21);
 
29740
 
 
29741
      _cimg_save_pandore_case(1,1,0,"unsigned char",22);
 
29742
      _cimg_save_pandore_case(1,1,0,"char",23);
 
29743
      _cimg_save_pandore_case(1,1,0,"short",23);
 
29744
      _cimg_save_pandore_case(1,1,0,"unsigned short",23);
 
29745
      _cimg_save_pandore_case(1,1,0,"unsigned int",23);
 
29746
      _cimg_save_pandore_case(1,1,0,"int",23);
 
29747
      _cimg_save_pandore_case(1,1,0,"unsigned long",25);
 
29748
      _cimg_save_pandore_case(1,1,0,"long",23);
 
29749
      _cimg_save_pandore_case(1,1,0,"float",25);
 
29750
      _cimg_save_pandore_case(1,1,0,"double",25);
 
29751
 
 
29752
      _cimg_save_pandore_case(0,1,0,"unsigned char",26);
 
29753
      _cimg_save_pandore_case(0,1,0,"char",27);
 
29754
      _cimg_save_pandore_case(0,1,0,"short",27);
 
29755
      _cimg_save_pandore_case(0,1,0,"unsigned short",27);
 
29756
      _cimg_save_pandore_case(0,1,0,"unsigned int",27);
 
29757
      _cimg_save_pandore_case(0,1,0,"int",27);
 
29758
      _cimg_save_pandore_case(0,1,0,"unsigned long",29);
 
29759
      _cimg_save_pandore_case(0,1,0,"long",27);
 
29760
      _cimg_save_pandore_case(0,1,0,"float",29);
 
29761
      _cimg_save_pandore_case(0,1,0,"double",29);
 
29762
 
 
29763
      _cimg_save_pandore_case(0,0,0,"unsigned char",30);
 
29764
      _cimg_save_pandore_case(0,0,0,"char",31);
 
29765
      _cimg_save_pandore_case(0,0,0,"short",31);
 
29766
      _cimg_save_pandore_case(0,0,0,"unsigned short",31);
 
29767
      _cimg_save_pandore_case(0,0,0,"unsigned int",31);
 
29768
      _cimg_save_pandore_case(0,0,0,"int",31);
 
29769
      _cimg_save_pandore_case(0,0,0,"unsigned long",33);
 
29770
      _cimg_save_pandore_case(0,0,0,"long",31);
 
29771
      _cimg_save_pandore_case(0,0,0,"float",33);
 
29772
      _cimg_save_pandore_case(0,0,0,"double",33);
 
29773
 
 
29774
      if (!file) cimg::fclose(nfile);
 
29775
      return *this;
 
29776
    }
 
29777
 
 
29778
    //! Save the image as a PANDORE-5 file.
 
29779
    const CImg<T>& save_pandore(const char *const filename, const unsigned int colorspace=0) const {
 
29780
      return _save_pandore(0,filename,colorspace);
 
29781
    }
 
29782
 
 
29783
    //! Save the image as a PANDORE-5 file.
 
29784
    const CImg<T>& save_pandore(std::FILE *const file, const unsigned int colorspace=0) const {
 
29785
      return _save_pandore(file,0,colorspace);
 
29786
    }
 
29787
 
 
29788
   // Save the image as a RAW file (internal).
 
29789
    const CImg<T>& _save_raw(std::FILE *const file, const char *const filename, const bool multiplexed) const {
 
29790
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
 
29791
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
 
29792
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
 
29793
                                                          pixel_type(),width,height,depth,dim,data);
 
29794
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
 
29795
      if (!multiplexed) cimg::fwrite(data,size(),nfile);
 
29796
      else {
 
29797
        CImg<T> buf(dim);
 
29798
        cimg_forXYZ(*this,x,y,z) {
 
29799
          cimg_forV(*this,k) buf[k] = (*this)(x,y,z,k);
 
29800
          cimg::fwrite(buf.data,dim,nfile);
 
29801
        }
 
29802
      }
 
29803
      if (!file) cimg::fclose(nfile);
 
29804
      return *this;
 
29805
    }
 
29806
 
 
29807
    //! Save the image as a RAW file.
 
29808
    const CImg<T>& save_raw(const char *const filename, const bool multiplexed=false) const {
 
29809
      return _save_raw(0,filename,multiplexed);
 
29810
    }
 
29811
 
 
29812
    //! Save the image as a RAW file.
 
29813
    const CImg<T>& save_raw(std::FILE *const file, const bool multiplexed=false) const {
 
29814
      return _save_raw(file,0,multiplexed);
 
29815
    }
 
29816
 
 
29817
    //! Save the image as a YUV video sequence file.
 
29818
    const CImg<T>& save_yuv(const char *const filename, const bool rgb2yuv=true) const {
 
29819
      get_split('z').save_yuv(filename,rgb2yuv);
 
29820
      return *this;
 
29821
    }
 
29822
 
 
29823
    //! Save the image as a YUV video sequence file.
 
29824
    const CImg<T>& save_yuv(std::FILE *const file, const bool rgb2yuv=true) const {
 
29825
      get_split('z').save_yuv(file,rgb2yuv);
 
29826
      return *this;
 
29827
    }
 
29828
 
 
29829
   // Save OFF files (internal).
22263
29830
    template<typename tf, typename tc>
22264
 
    const CImg& save_off(std::FILE *const file, const char *const filename,
22265
 
                         const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 
29831
    const CImg<T>& _save_off(std::FILE *const file, const char *const filename,
 
29832
                             const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces) const {
22266
29833
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_off() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
22267
29834
                                                  pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)");
22268
29835
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_off() : Specified filename is (null).",pixel_type());
22269
 
      if (height<3) return get_resize(-100,3,1,1,0).save_off(file,filename,primitives,colors,invert_faces);
 
29836
      if (height<3) return get_resize(-100,3,1,1,0)._save_off(file,filename,primitives,colors,invert_faces);
22270
29837
      std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
22271
29838
      std::fprintf(nfile,"OFF\n%u %u %u\n",width,primitives.size,3*primitives.size);
22272
29839
      cimg_forX(*this,i) std::fprintf(nfile,"%f %f %f\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2)));
22276
29843
        const CImg<tc>& color = colors[l];
22277
29844
        const unsigned int s = textured?color.dimv():color.size();
22278
29845
        const float
22279
 
          r = textured?(s>0?(float)(CImgStats(color.get_shared_channel(0),false).mean/255.0f):1.0f):(s>0?(float)(color(0)/255.0f):1.0f),
22280
 
          g = textured?(s>1?(float)(CImgStats(color.get_shared_channel(1),false).mean/255.0f):r)   :(s>1?(float)(color(1)/255.0f):r),
22281
 
          b = textured?(s>2?(float)(CImgStats(color.get_shared_channel(2),false).mean/255.0f):r)   :(s>2?(float)(color(2)/255.0f):r);
 
29846
          r = textured?(s>0?(float)(color.get_shared_channel(0).mean()/255.0f):1.0f):(s>0?(float)(color(0)/255.0f):1.0f),
 
29847
          g = textured?(s>1?(float)(color.get_shared_channel(1).mean()/255.0f):r)   :(s>1?(float)(color(1)/255.0f):r),
 
29848
          b = textured?(s>2?(float)(color.get_shared_channel(2).mean()/255.0f):r)   :(s>2?(float)(color(2)/255.0f):r);
22282
29849
 
22283
29850
        switch (prim) {
22284
29851
        case 1:
22307
29874
      return *this;
22308
29875
    }
22309
29876
 
22310
 
    //! Save OFF files (GeomView 3D object files)
22311
 
    template<typename tf, typename tc>
22312
 
    const CImg& save_off(const char *const filename,
22313
 
                         const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
22314
 
      return save_off(0,filename,primitives,colors,invert_faces);
 
29877
    //! Save OFF files.
 
29878
    template<typename tf, typename tc>
 
29879
    const CImg<T>& save_off(const char *const filename,
 
29880
                            const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 
29881
      return _save_off(0,filename,primitives,colors,invert_faces);
 
29882
    }
 
29883
 
 
29884
    //! Save OFF files.
 
29885
    template<typename tf, typename tc>
 
29886
      const CImg<T>& save_off(std::FILE *const file,
 
29887
                            const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 
29888
      return _save_off(file,0,primitives,colors,invert_faces);
 
29889
    }
 
29890
 
 
29891
    //! Save the image as a video sequence file, using the external tool 'ffmpeg'.
 
29892
    const CImg<T>& save_ffmpeg_external(const char *const filename, const char *const codec="mpeg2video") const {
 
29893
      get_split('z').save_ffmpeg_external(filename,codec);
 
29894
      return *this;
 
29895
    }
 
29896
 
 
29897
    //! Save the image using GraphicsMagick's gm.
 
29898
    /** Function that saves the image for other file formats that are not natively handled by CImg,
 
29899
        using the tool 'gm' from the GraphicsMagick package.\n
 
29900
        This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
 
29901
        the GraphicsMagick package in order to get
 
29902
        this function working properly (see http://www.graphicsmagick.org ).
 
29903
    **/
 
29904
    const CImg<T>& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const {
 
29905
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_graphicsmagick_external() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s')",
 
29906
                                                  pixel_type(),width,height,depth,dim,data,filename);
 
29907
      if (!filename) throw CImgArgumentException("CImg<%s>::save_graphicsmagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 
29908
                                                 pixel_type(),width,height,depth,dim,data);
 
29909
      char command[1024],filetmp[512];
 
29910
      std::FILE *file;
 
29911
      do {
 
29912
        if (dim==1) std::sprintf(filetmp,"%s%s%s.pgm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 
29913
        else std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 
29914
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
 
29915
      } while (file);
 
29916
      save_pnm(filetmp);
 
29917
      std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::graphicsmagick_path(),quality,filetmp,filename);
 
29918
      cimg::system(command);
 
29919
      file = std::fopen(filename,"rb");
 
29920
      if (!file) throw CImgIOException("CImg<%s>::save_graphicsmagick_external() : Failed to save image '%s'.\n\n"
 
29921
                                       "Path of 'gm' : \"%s\"\n"
 
29922
                                       "Path of temporary filename : \"%s\"\n",
 
29923
                                       pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
 
29924
      if (file) cimg::fclose(file);
 
29925
      std::remove(filetmp);
 
29926
      return *this;
 
29927
    }
 
29928
 
 
29929
    //! Save an image as a gzipped file, using external tool 'gzip'.
 
29930
    const CImg<T>& save_gzip_external(const char *const filename) const {
 
29931
      if (!filename)
 
29932
        throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
 
29933
                              pixel_type());
 
29934
      char command[1024], filetmp[512], body[512];
 
29935
      const char
 
29936
        *ext = cimg::split_filename(filename,body),
 
29937
        *ext2 = cimg::split_filename(body,0);
 
29938
      std::FILE *file;
 
29939
      do {
 
29940
        if (!cimg::strcasecmp(ext,"gz")) {
 
29941
          if (*ext2) std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
29942
                                  cimg::filenamerand(),ext2);
 
29943
          else std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
29944
                            cimg::filenamerand());
 
29945
        } else {
 
29946
          if (*ext) std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
29947
                                 cimg::filenamerand(),ext);
 
29948
          else std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
29949
                                 cimg::filenamerand());
 
29950
        }
 
29951
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
 
29952
      } while (file);
 
29953
      save(filetmp);
 
29954
      std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
 
29955
      cimg::system(command);
 
29956
      file = std::fopen(filename,"rb");
 
29957
      if (!file)
 
29958
        throw CImgIOException("CImgList<%s>::save_gzip_external() : Failed to save image file '%s'.",
 
29959
                              pixel_type(),filename);
 
29960
      else cimg::fclose(file);
 
29961
      std::remove(filetmp);
 
29962
      return *this;
 
29963
    }
 
29964
 
 
29965
    //! Save the image using ImageMagick's convert.
 
29966
    /** Function that saves the image for other file formats that are not natively handled by CImg,
 
29967
        using the tool 'convert' from the ImageMagick package.\n
 
29968
        This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
 
29969
        the ImageMagick package in order to get
 
29970
        this function working properly (see http://www.imagemagick.org ).
 
29971
    **/
 
29972
    const CImg<T>& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const {
 
29973
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_imagemagick_external() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s')",
 
29974
                                                  pixel_type(),width,height,depth,dim,data,filename);
 
29975
      if (!filename) throw CImgArgumentException("CImg<%s>::save_imagemagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 
29976
                                                 pixel_type(),width,height,depth,dim,data);
 
29977
      char command[1024], filetmp[512];
 
29978
      std::FILE *file;
 
29979
      do {
 
29980
        std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand(),dim==1?"pgm":"ppm");
 
29981
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
 
29982
      } while (file);
 
29983
      save_pnm(filetmp);
 
29984
      std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::imagemagick_path(),quality,filetmp,filename);
 
29985
      cimg::system(command);
 
29986
      file = std::fopen(filename,"rb");
 
29987
      if (!file) throw CImgIOException("CImg<%s>::save_imagemagick_external() : Failed to save image '%s'.\n\n"
 
29988
                                       "Path of 'convert' : \"%s\"\n"
 
29989
                                       "Path of temporary filename : \"%s\"\n",
 
29990
                                       pixel_type(),filename,cimg::imagemagick_path(),filetmp);
 
29991
      if (file) cimg::fclose(file);
 
29992
      std::remove(filetmp);
 
29993
      return *this;
 
29994
    }
 
29995
 
 
29996
    //! Save an image as a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net )
 
29997
    const CImg<T>& save_medcon_external(const char *const filename) const {
 
29998
      if (!filename) throw CImgArgumentException("CImg<%s>::save_medcon_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
 
29999
                                                 pixel_type(),width,height,depth,dim,data);
 
30000
      if (is_empty()) throw CImgInstanceException("CImg<%s>::save_medcon_external() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').",
 
30001
                                                  pixel_type(),width,height,depth,dim,data,filename);
 
30002
      char command[1024], filetmp[512], body[512];
 
30003
      std::FILE *file;
 
30004
      do {
 
30005
        std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
 
30006
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
 
30007
      } while (file);
 
30008
      save_analyze(filetmp);
 
30009
      std::sprintf(command,"%s -w -c dicom -o %s -f %s",cimg::medcon_path(),filename,filetmp);
 
30010
      cimg::system(command);
 
30011
      std::remove(filetmp);
 
30012
      cimg::split_filename(filetmp,body);
 
30013
      std::sprintf(filetmp,"%s.img",body);
 
30014
      std::remove(filetmp);
 
30015
      std::sprintf(command,"m000-%s",filename);
 
30016
      file = std::fopen(command,"rb");
 
30017
      if (!file) {
 
30018
        cimg::fclose(cimg::fopen(filename,"r"));
 
30019
        throw CImgIOException("CImg<%s>::save_medcon_external() : Failed to save image '%s'.\n\n"
 
30020
                              "Path of 'medcon' : \"%s\"\n"
 
30021
                              "Path of temporary filename : \"%s\"",
 
30022
                              pixel_type(),filename,cimg::medcon_path(),filetmp);
 
30023
      } else cimg::fclose(file);
 
30024
      std::rename(command,filename);
 
30025
      return *this;
 
30026
    }
 
30027
 
 
30028
    // Try to save the image if other extension is provided.
 
30029
    const CImg<T>& save_other(const char *const filename, const unsigned int quality=100) const {
 
30030
      if (!filename)
 
30031
        throw CImgIOException("CImg<%s>::save_other() : Cannot save (null) filename.",
 
30032
                              pixel_type());
 
30033
      const unsigned int odebug = cimg::exception_mode();
 
30034
      bool is_saved = true;
 
30035
      cimg::exception_mode() = 0;
 
30036
      try { save_magick(filename); }
 
30037
      catch (CImgException&) {
 
30038
        try { save_imagemagick_external(filename,quality); }
 
30039
        catch (CImgException&) {
 
30040
          try { save_graphicsmagick_external(filename,quality); }
 
30041
          catch (CImgException&) {
 
30042
            is_saved = false;
 
30043
          }
 
30044
        }
 
30045
      }
 
30046
      cimg::exception_mode() = odebug;
 
30047
      if (!is_saved) throw CImgIOException("CImg<%s>::save_other() : File '%s' cannot be saved.\n"
 
30048
                                           "Check you have either the ImageMagick or GraphicsMagick package installed.",
 
30049
                                           pixel_type(),filename);
 
30050
      return *this;
 
30051
    }
 
30052
 
 
30053
    // Get a 40x38 color logo of a 'danger' item (internal).
 
30054
    static CImg<T> get_logo40x38() {
 
30055
      static bool first_time = true;
 
30056
      static CImg<T> res(40,38,1,3);
 
30057
      if (first_time) {
 
30058
        const unsigned char *ptrs = cimg::logo40x38;
 
30059
        T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2);
 
30060
        for (unsigned int off = 0; off<res.width*res.height;) {
 
30061
          const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++);
 
30062
          for (unsigned int l=0; l<n; ++off, ++l) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; }
 
30063
        }
 
30064
        first_time = false;
 
30065
      }
 
30066
      return res;
22315
30067
    }
22316
30068
 
22317
30069
  };
22332
30084
  //! Class representing list of images CImg<T>.
22333
30085
  template<typename T> struct CImgList {
22334
30086
 
22335
 
    //! Size of the list (number of elements inside)
 
30087
    //! Size of the list (number of elements inside).
22336
30088
    unsigned int size;
22337
30089
 
22338
 
    //! Allocation size of the list
 
30090
    //! Allocation size of the list.
22339
30091
    unsigned int allocsize;
22340
30092
 
22341
 
    //! Pointer to the first list element
 
30093
    //! Pointer to the first list element.
22342
30094
    CImg<T> *data;
22343
30095
 
22344
 
    //! Define a CImgList<T>::iterator
 
30096
    //! Define a CImgList<T>::iterator.
22345
30097
    typedef CImg<T>* iterator;
22346
30098
 
22347
 
    //! Define a CImgList<T>::const_iterator
 
30099
    //! Define a CImgList<T>::const_iterator.
22348
30100
    typedef const CImg<T>* const_iterator;
22349
30101
 
22350
 
    //! Get value type
 
30102
    //! Get value type.
22351
30103
    typedef T value_type;
22352
30104
 
 
30105
    // Define useful T-dependant typenames.
 
30106
    typedef typename cimg::superset<T,unsigned char>::type Tuchar;
 
30107
    typedef typename cimg::superset<T,int>::type Tint;
 
30108
    typedef typename cimg::superset<T,float>::type Tfloat;
 
30109
    typedef typename cimg::superset<T,float>::type Tdouble;
 
30110
 
22353
30111
    //@}
22354
30112
    //---------------------------
22355
30113
    //
22359
30117
#ifdef cimglist_plugin
22360
30118
#include cimglist_plugin
22361
30119
#endif
 
30120
#ifdef cimglist_plugin1
 
30121
#include cimglist_plugin1
 
30122
#endif
 
30123
#ifdef cimglist_plugin2
 
30124
#include cimglist_plugin2
 
30125
#endif
 
30126
#ifdef cimglist_plugin3
 
30127
#include cimglist_plugin3
 
30128
#endif
 
30129
#ifdef cimglist_plugin4
 
30130
#include cimglist_plugin4
 
30131
#endif
 
30132
#ifdef cimglist_plugin5
 
30133
#include cimglist_plugin5
 
30134
#endif
 
30135
#ifdef cimglist_plugin6
 
30136
#include cimglist_plugin6
 
30137
#endif
 
30138
#ifdef cimglist_plugin7
 
30139
#include cimglist_plugin7
 
30140
#endif
 
30141
#ifdef cimglist_plugin8
 
30142
#include cimglist_plugin8
 
30143
#endif
22362
30144
    //@}
22363
30145
 
22364
30146
    //------------------------------------------
22367
30149
    //@{
22368
30150
    //------------------------------------------
22369
30151
 
22370
 
    //! Default constructor
 
30152
    //! Destructor.
 
30153
    ~CImgList() {
 
30154
      if (data) delete[] data;
 
30155
    }
 
30156
 
 
30157
    //! Default constructor.
22371
30158
    CImgList():
22372
30159
      size(0),allocsize(0),data(0) {}
22373
30160
 
22374
 
    //! Destructor
22375
 
    ~CImgList() {
22376
 
      if (data) delete[] data;
22377
 
    }
22378
 
 
22379
 
    //! In-place version of the default constructor and default destructor
22380
 
    CImgList& assign() {
22381
 
      if (data) delete[] data;
22382
 
      size = allocsize = 0;
22383
 
      data = 0;
22384
 
      return *this;
22385
 
    }
22386
 
 
22387
 
    //! Equivalent to assign() (STL-compliant name)
22388
 
    CImgList& clear() {
22389
 
      return assign();
22390
 
    }
22391
 
 
22392
 
    //! Copy constructor
 
30161
    //! Construct an image list containing n empty images.
 
30162
    explicit CImgList(const unsigned int n):
 
30163
      size(n) {
 
30164
      data = new CImg<T>[allocsize = cimg::max(16UL,cimg::nearest_pow2(n))];
 
30165
    }
 
30166
 
 
30167
    //! Default copy constructor.
22393
30168
    template<typename t> CImgList(const CImgList<t>& list):
22394
30169
      size(0),allocsize(0),data(0) {
22395
 
      assign(list);
 
30170
      assign(list.size);
 
30171
      cimglist_for(*this,l) data[l].assign(list[l],false);
22396
30172
    }
22397
30173
 
22398
 
    CImgList(const CImgList& list):
 
30174
    CImgList(const CImgList<T>& list):
22399
30175
      size(0),allocsize(0),data(0) {
22400
30176
      assign(list.size);
22401
 
      cimglist_for(*this,l) (*this)[l].assign(list[l],list[l].is_shared);
 
30177
      cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
22402
30178
    }
22403
30179
 
22404
 
    //! Copy constructor that create a shared object
 
30180
    //! Advanced copy constructor.
22405
30181
    template<typename t> CImgList(const CImgList<t>& list, const bool shared):
22406
30182
      size(0),allocsize(0),data(0) {
22407
 
      assign(list,shared?1:0);
 
30183
      assign(list.size);
 
30184
      if (shared) throw CImgArgumentException("CImgList<%s>::CImgList() : Cannot construct a list instance with shared images from "
 
30185
                                              "a CImgList<%s> (different pixel types).",pixel_type(),CImgList<t>::pixel_type());
 
30186
      cimglist_for(*this,l) data[l].assign(list[l],false);
22408
30187
    }
22409
30188
 
22410
 
    CImgList(const CImgList& list, const bool shared):
 
30189
    CImgList(const CImgList<T>& list, const bool shared):
22411
30190
      size(0),allocsize(0),data(0) {
22412
 
      assign(list,shared?1:0);
22413
 
    }
22414
 
 
22415
 
    //! In-place version of the copy constructor
22416
 
    template<typename t> CImgList& assign(const CImgList<t>& list, const int shared=0) {
22417
30191
      assign(list.size);
22418
 
      if (shared>=0) cimglist_for(*this,l) (*this)[l].assign(list[l],shared?true:false);
22419
 
      else cimglist_for(*this,l) (*this)[l].assign(list[l],list[l].is_shared);
22420
 
      return *this;
22421
 
    }
22422
 
 
22423
 
    //! Construct an image list containing n empty images
22424
 
    explicit CImgList(const unsigned int n):
22425
 
      size(n) {
22426
 
      data = new CImg<T>[allocsize=cimg::nearest_pow2(n)];
22427
 
    }
22428
 
 
22429
 
    //! In-place version of the previous constructor
22430
 
    CImgList& assign(const unsigned int n) {
22431
 
      if (n) {
22432
 
        if (allocsize<n || allocsize>(n<<2)) {
22433
 
          if (data) delete[] data;
22434
 
          data = new CImg<T>[allocsize=cimg::nearest_pow2(n)];
22435
 
        }
22436
 
        size = n;
22437
 
      } else return assign();
22438
 
      return *this;
22439
 
    }
22440
 
 
22441
 
    //! Construct an image list containing n images with specified size
 
30192
      cimglist_for(*this,l) data[l].assign(list[l],shared);
 
30193
    }
 
30194
 
 
30195
    //! Construct an image list containing n images with specified size.
22442
30196
    CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1,
22443
30197
             const unsigned int depth=1, const unsigned int dim=1):
22444
30198
      size(0),allocsize(0),data(0) {
22445
 
      assign(n,width,height,depth,dim);
22446
 
    }
22447
 
 
22448
 
    //! In-place version of the previous constructor
22449
 
    CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height=1,
22450
 
                     const unsigned int depth=1, const unsigned int dim=1) {
22451
 
      const unsigned int siz = width*height*depth*dim;
22452
 
      if (n && siz) { assign(n); cimglist_for(*this,l) data[l].assign(width,height,depth,dim); }
22453
 
      else return assign();
22454
 
      return *this;
22455
 
    }
22456
 
 
22457
 
    //! Construct an image list containing n images with specified size, filled with val
 
30199
      assign(n);
 
30200
      cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
 
30201
    }
 
30202
 
 
30203
    //! Construct an image list containing n images with specified size, filled with specified value.
22458
30204
    CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
22459
 
             const unsigned int depth, const unsigned int dim, const T& val):
 
30205
             const unsigned int depth, const unsigned int dim, const T val):
22460
30206
      size(0),allocsize(0),data(0) {
22461
 
      assign(n,width,height,depth,dim,val);
22462
 
    }
22463
 
 
22464
 
    //! In-place version of the previous constructor
22465
 
    CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height,
22466
 
                     const unsigned int depth, const unsigned int dim, const T& val) {
22467
 
      assign(n,width,height,depth,dim);
22468
 
      cimglist_for(*this,l) data[l].fill(val);
22469
 
      return *this;
 
30207
      assign(n);
 
30208
      cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
22470
30209
    }
22471
30210
 
22472
30211
    //! Construct an image list containing n images with specified size and specified pixel values (int version).
22473
30212
    CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
22474
30213
             const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...):
22475
30214
      size(0),allocsize(0),data(0) {
22476
 
#define _CImgList_stdarg(t) \
22477
 
      assign(n,width,height,depth,dim); \
22478
 
      const unsigned int siz = width*height*depth*dim, nsiz = siz*n; \
22479
 
      T *ptrd = data->data; \
22480
 
      va_list ap; \
22481
 
      va_start(ap,val1); \
22482
 
      for (unsigned int l=0, s=0, i=0; i<nsiz; ++i) { \
22483
 
        *(ptrd++) = (T)(i==0?val0:(i==1?val1:va_arg(ap,t))); \
22484
 
        if ((++s)==siz) { ptrd = data[++l].data; s=0; }\
22485
 
      } \
22486
 
      va_end(ap);
22487
 
      _CImgList_stdarg(int);
22488
 
    }
22489
 
 
22490
 
    //! In-place version of the previous constructor.
22491
 
    CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height,
22492
 
                     const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...) {
22493
 
      _CImgList_stdarg(int);
22494
 
      return *this;
 
30215
#define _CImgList_stdarg(t) { \
 
30216
        assign(n,width,height,depth,dim); \
 
30217
        const unsigned int siz = width*height*depth*dim, nsiz = siz*n; \
 
30218
        T *ptrd = data->data; \
 
30219
        va_list ap; \
 
30220
        va_start(ap,val1); \
 
30221
        for (unsigned int l=0, s=0, i=0; i<nsiz; ++i) { \
 
30222
          *(ptrd++) = (T)(i==0?val0:(i==1?val1:va_arg(ap,t))); \
 
30223
          if ((++s)==siz) { ptrd = data[++l].data; s=0; } \
 
30224
        } \
 
30225
        va_end(ap); \
 
30226
      }
 
30227
      _CImgList_stdarg(int);
22495
30228
    }
22496
30229
 
22497
30230
    //! Construct an image list containing n images with specified size and specified pixel values (double version).
22501
30234
      _CImgList_stdarg(double);
22502
30235
    }
22503
30236
 
22504
 
    //! In-place version of the previous constructor.
22505
 
    CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height,
22506
 
                     const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...) {
22507
 
      _CImgList_stdarg(double);
22508
 
      return *this;
22509
 
    }
22510
 
 
22511
 
    //! Construct a list containing n copies of the image img
22512
 
    template<typename t> CImgList(const unsigned int n, const CImg<t>& img, const bool shared=false):
22513
 
      size(0),allocsize(0),data(0) {
22514
 
      assign(n,img,shared);
22515
 
    }
22516
 
 
22517
 
    //! In-place version of the previous constructor
22518
 
    template<typename t> CImgList& assign(const unsigned int n, const CImg<t>& img, const bool shared=false) {
 
30237
    //! Construct a list containing n copies of the image img.
 
30238
    template<typename t> CImgList(const unsigned int n, const CImg<t>& img):
 
30239
      size(0),allocsize(0),data(0) {
 
30240
      assign(n);
 
30241
      cimglist_for(*this,l) data[l].assign(img,img.is_shared);
 
30242
    }
 
30243
 
 
30244
    //! Construct a list containing n copies of the image img, forcing the shared state.
 
30245
    template<typename t> CImgList(const unsigned int n, const CImg<t>& img, const bool shared):
 
30246
      size(0),allocsize(0),data(0) {
22519
30247
      assign(n);
22520
30248
      cimglist_for(*this,l) data[l].assign(img,shared);
22521
 
      return *this;
22522
 
    }
22523
 
 
22524
 
    //! Construct an image list from one image
22525
 
    template<typename t> explicit CImgList(const CImg<t>& img, const bool shared=false):
22526
 
      size(0),allocsize(0),data(0) {
22527
 
      assign(img,shared);
22528
 
    }
22529
 
 
22530
 
    //! In-place version of the previous constructor
22531
 
    template<typename t> CImgList& assign(const CImg<t>& img, const bool shared=false) {
22532
 
      return assign(1,img,shared);
22533
 
    }
22534
 
 
22535
 
    //! Construct an image list from two images
22536
 
    template<typename t1, typename t2> CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false):
22537
 
      size(0),allocsize(0),data(0) {
22538
 
      assign(img1,img2,shared);
22539
 
    }
22540
 
 
22541
 
    //! In-place version of the previous constructor
22542
 
    template<typename t1, typename t2> CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false) {
 
30249
    }
 
30250
 
 
30251
    //! Construct an image list from one image.
 
30252
    template<typename t> explicit CImgList(const CImg<t>& img):
 
30253
      size(0),allocsize(0),data(0) {
 
30254
      assign(1);
 
30255
      data[0].assign(img,img.is_shared);
 
30256
    }
 
30257
 
 
30258
    //! Construct an image list from one image, forcing the shared state.
 
30259
    template<typename t> explicit CImgList(const CImg<t>& img, const bool shared):
 
30260
      size(0),allocsize(0),data(0) {
 
30261
      assign(1);
 
30262
      data[0].assign(img,shared);
 
30263
    }
 
30264
 
 
30265
    //! Construct an image list from two images.
 
30266
    template<typename t1, typename t2> CImgList(const CImg<t1>& img1, const CImg<t2>& img2):
 
30267
      size(0),allocsize(0),data(0) {
 
30268
      assign(2);
 
30269
      data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared);
 
30270
    }
 
30271
 
 
30272
    //! Construct an image list from two images, forcing the shared state.
 
30273
    template<typename t1, typename t2> CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared):
 
30274
      size(0),allocsize(0),data(0) {
22543
30275
      assign(2);
22544
30276
      data[0].assign(img1,shared); data[1].assign(img2,shared);
22545
 
      return *this;
22546
 
    }
22547
 
 
22548
 
    //! Construct an image list from three images
22549
 
    template<typename t1, typename t2, typename t3> CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false):
22550
 
      size(0),allocsize(0),data(0) {
22551
 
      assign(img1,img2,img3,shared);
22552
 
    }
22553
 
 
22554
 
    //! In-place version of the previous constructor
22555
 
    template<typename t1, typename t2, typename t3> CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false) {
 
30277
    }
 
30278
 
 
30279
    //! Construct an image list from three images.
 
30280
    template<typename t1, typename t2, typename t3> CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3):
 
30281
      size(0),allocsize(0),data(0) {
 
30282
      assign(3);
 
30283
      data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared);
 
30284
    }
 
30285
 
 
30286
    //! Construct an image list from three images, forcing the shared state.
 
30287
    template<typename t1, typename t2, typename t3> CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared):
 
30288
      size(0),allocsize(0),data(0) {
22556
30289
      assign(3);
22557
30290
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
22558
 
      return *this;
22559
 
    }
22560
 
 
22561
 
    //! Construct an image list from four images
22562
 
    template<typename t1, typename t2, typename t3, typename t4>
22563
 
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const bool shared=false):
22564
 
      size(0),allocsize(0),data(0) {
22565
 
      assign(img1,img2,img3,img4,shared);
22566
 
    }
22567
 
 
22568
 
    //! In-place version of the previous constructor
22569
 
    template<typename t1, typename t2, typename t3, typename t4>
22570
 
    CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const bool shared=false) {
 
30291
    }
 
30292
 
 
30293
    //! Construct an image list from four images.
 
30294
    template<typename t1, typename t2, typename t3, typename t4>
 
30295
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4):
 
30296
      size(0),allocsize(0),data(0) {
 
30297
      assign(4);
 
30298
      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);
 
30299
    }
 
30300
 
 
30301
    //! Construct an image list from four images, forcing the shared state.
 
30302
    template<typename t1, typename t2, typename t3, typename t4>
 
30303
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const bool shared):
 
30304
      size(0),allocsize(0),data(0) {
22571
30305
      assign(4);
22572
30306
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
22573
 
      return *this;
22574
 
    }
22575
 
 
22576
 
    //! Construct an image list from five images
22577
 
    template<typename t1, typename t2, typename t3, typename t4, typename t5>
22578
 
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, const bool shared=false):
22579
 
      size(0),allocsize(0),data(0) {
22580
 
      assign(img1,img2,img3,img4,img5,shared);
22581
 
    }
22582
 
 
22583
 
    //! In-place version of the previous constructor
22584
 
    template<typename t1, typename t2, typename t3, typename t4, typename t5>
22585
 
    CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5,
22586
 
                     const bool shared=false) {
 
30307
    }
 
30308
 
 
30309
    //! Construct an image list from five images.
 
30310
    template<typename t1, typename t2, typename t3, typename t4, typename t5>
 
30311
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30312
             const CImg<t5>& img5):
 
30313
      size(0),allocsize(0),data(0) {
 
30314
      assign(5);
 
30315
      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);
 
30316
      data[4].assign(img5,img5.is_shared);
 
30317
    }
 
30318
 
 
30319
    //! Construct an image list from five images, forcing the shared state.
 
30320
    template<typename t1, typename t2, typename t3, typename t4, typename t5>
 
30321
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30322
             const CImg<t5>& img5, const bool shared):
 
30323
      size(0),allocsize(0),data(0) {
22587
30324
      assign(5);
22588
30325
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
22589
30326
      data[4].assign(img5,shared);
22590
 
      return *this;
22591
 
    }
22592
 
 
22593
 
    //! Construct an image list from six images
22594
 
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
22595
 
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5,
22596
 
             const CImg<t6>& img6, const bool shared=false):
22597
 
      size(0),allocsize(0),data(0) {
22598
 
      assign(img1,img2,img3,img4,img5,img6,shared);
22599
 
    }
22600
 
 
22601
 
    //! In-place version of the previous constructor
22602
 
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
22603
 
    CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5,
22604
 
                     const CImg<t6>& img6, const bool shared=false) {
 
30327
    }
 
30328
 
 
30329
    //! Construct an image list from six images.
 
30330
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
 
30331
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30332
             const CImg<t5>& img5, const CImg<t6>& img6):
 
30333
      size(0),allocsize(0),data(0) {
 
30334
      assign(6);
 
30335
      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);
 
30336
      data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared);
 
30337
    }
 
30338
 
 
30339
    //! Construct an image list from six images, forcing the shared state.
 
30340
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
 
30341
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30342
             const CImg<t5>& img5, const CImg<t6>& img6, const bool shared):
 
30343
      size(0),allocsize(0),data(0) {
22605
30344
      assign(6);
22606
30345
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
22607
30346
      data[4].assign(img5,shared); data[5].assign(img6,shared);
22608
 
      return *this;
22609
 
    }
22610
 
 
22611
 
    //! Construct an image list from seven images
22612
 
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
22613
 
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5,
22614
 
             const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false):
22615
 
      size(0),allocsize(0),data(0) {
22616
 
      assign(img1,img2,img3,img4,img5,img6,img7,shared);
22617
 
    }
22618
 
 
22619
 
    //! In-place version of the previous constructor
22620
 
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
22621
 
    CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5,
22622
 
                     const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false) {
 
30347
    }
 
30348
 
 
30349
    //! Construct an image list from seven images.
 
30350
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
 
30351
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30352
             const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7):
 
30353
      size(0),allocsize(0),data(0) {
 
30354
      assign(7);
 
30355
      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);
 
30356
      data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared); data[6].assign(img7,img7.is_shared);
 
30357
    }
 
30358
 
 
30359
    //! Construct an image list from seven images, forcing the shared state.
 
30360
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
 
30361
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30362
             const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared):
 
30363
      size(0),allocsize(0),data(0) {
22623
30364
      assign(7);
22624
30365
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
22625
30366
      data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
22626
 
      return *this;
22627
 
    }
22628
 
 
22629
 
    //! Construct an image list from eight images
22630
 
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
22631
 
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5,
22632
 
             const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false):
22633
 
      size(0),allocsize(0),data(0) {
22634
 
      assign(img1,img2,img3,img4,img5,img6,img7,img8,shared);
22635
 
    }
22636
 
 
22637
 
    //! In-place version of the previous constructor
22638
 
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
22639
 
    CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5,
22640
 
                     const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false) {
 
30367
    }
 
30368
 
 
30369
    //! Construct an image list from eight images.
 
30370
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
 
30371
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30372
             const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8):
 
30373
      size(0),allocsize(0),data(0) {
 
30374
      assign(8);
 
30375
      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);
 
30376
      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);
 
30377
    }
 
30378
 
 
30379
    //! Construct an image list from eight images, forcing the shared state.
 
30380
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
 
30381
    CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30382
             const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared):
 
30383
      size(0),allocsize(0),data(0) {
22641
30384
      assign(8);
22642
30385
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
22643
30386
      data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
22644
 
      return *this;
22645
30387
    }
22646
30388
 
22647
 
    //! Construct an image list from a filename
 
30389
    //! Construct an image list from a filename.
22648
30390
    CImgList(const char *const filename):
22649
30391
      size(0),allocsize(0),data(0) {
22650
30392
      assign(filename);
22651
30393
    }
22652
30394
 
22653
 
    //! In-place version of the previous constructor
22654
 
    CImgList& assign(const char *const filename) {
 
30395
    //! In-place version of the default constructor and default destructor.
 
30396
    CImgList<T>& assign() {
 
30397
      if (data) delete[] data;
 
30398
      size = allocsize = 0;
 
30399
      data = 0;
 
30400
      return *this;
 
30401
    }
 
30402
 
 
30403
    //! Equivalent to assign() (STL-compliant name).
 
30404
    CImgList<T>& clear() {
 
30405
      return assign();
 
30406
    }
 
30407
 
 
30408
    //! In-place version of the corresponding constructor.
 
30409
    CImgList<T>& assign(const unsigned int n) {
 
30410
      if (n) {
 
30411
        if (allocsize<n || allocsize>(n<<2)) {
 
30412
          if (data) delete[] data;
 
30413
          data = new CImg<T>[allocsize=cimg::max(16UL,cimg::nearest_pow2(n))];
 
30414
        }
 
30415
        size = n;
 
30416
      } else assign();
 
30417
      return *this;
 
30418
    }
 
30419
 
 
30420
    //! In-place version of the corresponding constructor.
 
30421
    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height=1,
 
30422
                        const unsigned int depth=1, const unsigned int dim=1) {
 
30423
      assign(n);
 
30424
      cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
 
30425
      return *this;
 
30426
    }
 
30427
 
 
30428
    //! In-place version of the corresponding constructor.
 
30429
    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
 
30430
                        const unsigned int depth, const unsigned int dim, const T val) {
 
30431
      assign(n);
 
30432
      cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
 
30433
      return *this;
 
30434
    }
 
30435
 
 
30436
    //! In-place version of the corresponding constructor.
 
30437
    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
 
30438
                        const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...) {
 
30439
      _CImgList_stdarg(int);
 
30440
      return *this;
 
30441
    }
 
30442
 
 
30443
    //! In-place version of the corresponding constructor.
 
30444
    CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
 
30445
                        const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...) {
 
30446
      _CImgList_stdarg(double);
 
30447
      return *this;
 
30448
    }
 
30449
 
 
30450
    //! In-place version of the copy constructor.
 
30451
    template<typename t> CImgList<T>& assign(const CImgList<t>& list) {
 
30452
      assign(list.size);
 
30453
      cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
 
30454
      return *this;
 
30455
    }
 
30456
 
 
30457
    //! In-place version of the copy constructor.
 
30458
    template<typename t> CImgList<T>& assign(const CImgList<t>& list, const bool shared) {
 
30459
      assign(list.size);
 
30460
      cimglist_for(*this,l) data[l].assign(list[l],shared);
 
30461
      return *this;
 
30462
    }
 
30463
 
 
30464
    //! In-place version of the corresponding constructor.
 
30465
    template<typename t> CImgList<T>& assign(const unsigned int n, const CImg<t>& img, const bool shared=false) {
 
30466
      assign(n);
 
30467
      cimglist_for(*this,l) data[l].assign(img,shared);
 
30468
      return *this;
 
30469
    }
 
30470
 
 
30471
    //! In-place version of the corresponding constructor.
 
30472
    template<typename t> CImgList<T>& assign(const CImg<t>& img, const bool shared=false) {
 
30473
      assign(1);
 
30474
      data[0].assign(img,shared);
 
30475
      return *this;
 
30476
    }
 
30477
 
 
30478
    //! In-place version of the corresponding constructor.
 
30479
    template<typename t1, typename t2>
 
30480
    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false) {
 
30481
      assign(2);
 
30482
      data[0].assign(img1,shared); data[1].assign(img2,shared);
 
30483
      return *this;
 
30484
    }
 
30485
 
 
30486
    //! In-place version of the corresponding constructor.
 
30487
    template<typename t1, typename t2, typename t3>
 
30488
    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false) {
 
30489
      assign(3);
 
30490
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
 
30491
      return *this;
 
30492
    }
 
30493
 
 
30494
    //! In-place version of the corresponding constructor.
 
30495
    template<typename t1, typename t2, typename t3, typename t4>
 
30496
    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30497
                        const bool shared=false) {
 
30498
      assign(4);
 
30499
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 
30500
      return *this;
 
30501
    }
 
30502
 
 
30503
    //! In-place version of the corresponding constructor.
 
30504
    template<typename t1, typename t2, typename t3, typename t4, typename t5>
 
30505
    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30506
                        const CImg<t5>& img5, const bool shared=false) {
 
30507
      assign(5);
 
30508
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 
30509
      data[4].assign(img5,shared);
 
30510
      return *this;
 
30511
    }
 
30512
 
 
30513
    //! In-place version of the corresponding constructor.
 
30514
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
 
30515
    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30516
                        const CImg<t5>& img5, const CImg<t6>& img6, const bool shared=false) {
 
30517
      assign(6);
 
30518
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 
30519
      data[4].assign(img5,shared); data[5].assign(img6,shared);
 
30520
      return *this;
 
30521
    }
 
30522
 
 
30523
    //! In-place version of the corresponding constructor.
 
30524
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
 
30525
    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30526
                        const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false) {
 
30527
      assign(7);
 
30528
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 
30529
      data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
 
30530
      return *this;
 
30531
    }
 
30532
 
 
30533
    //! In-place version of the corresponding constructor.
 
30534
    template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
 
30535
    CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
 
30536
                        const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false) {
 
30537
      assign(8);
 
30538
      data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
 
30539
      data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
 
30540
      return *this;
 
30541
    }
 
30542
 
 
30543
    //! In-place version of the corresponding constructor.
 
30544
    CImgList<T>& assign(const char *const filename) {
22655
30545
      return load(filename);
22656
30546
    }
22657
30547
 
 
30548
    //! Transfer the content of the instance image list into another one.
 
30549
    template<typename t> CImgList<T>& transfer_to(CImgList<t>& list) {
 
30550
      list.assign(*this);
 
30551
      assign();
 
30552
      return list;
 
30553
    }
 
30554
 
 
30555
    CImgList<T>& transfer_to(CImgList<T>& list) {
 
30556
      list.assign();
 
30557
      return swap(list);
 
30558
    }
 
30559
 
 
30560
    //! Swap all fields of two CImgList instances (use with care !)
 
30561
    CImgList<T>& swap(CImgList<T>& list) {
 
30562
      cimg::swap(size,list.size);
 
30563
      cimg::swap(allocsize,list.allocsize);
 
30564
      cimg::swap(data,list.data);
 
30565
      return list;
 
30566
    }
 
30567
 
22658
30568
    //! Return a string describing the type of the image pixels in the list (template parameter \p T).
22659
30569
    static const char* pixel_type() {
22660
 
      return cimg::type<T>::id();
 
30570
      return cimg::type<T>::string();
22661
30571
    }
22662
30572
 
22663
 
    //! Return \p true if list is empty
 
30573
    //! Return \p true if list is empty.
22664
30574
    bool is_empty() const {
22665
30575
      return (!data || !size);
22666
30576
    }
22667
30577
 
 
30578
    //! Return \p true if list is not empty.
22668
30579
    operator bool() const {
22669
30580
      return !is_empty();
22670
30581
    }
22671
30582
 
22672
 
    //! Return \c true if the list contains an image with indice k
22673
 
    bool contains(const int k) const {
22674
 
      return data && k<(int)size;
22675
 
    }
22676
 
 
22677
 
    //! Return \c true if the k-th image of the list contains the pixel (x,y,z,v)
22678
 
    bool contains(const int k, const int x, const int y=0, const int z=0, const int v=0) const {
22679
 
      return contains(k) && data[k].contains(x,y,z,v);
 
30583
    //! Return \c true if the list contains the pixel (n,x,y,z,v).
 
30584
    bool containsNXYZV(const int n, const int x=0, const int y=0, const int z=0, const int v=0) const {
 
30585
      if (is_empty()) return false;
 
30586
      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();
 
30587
    }
 
30588
 
 
30589
    //! Return \c true if the list contains the image (n).
 
30590
    bool containsN(const int n) const {
 
30591
      if (is_empty()) return false;
 
30592
      return n>=0 && n<(int)size;
 
30593
    }
 
30594
 
 
30595
    //! Return \c true if one of the image list contains the pixel. If true, set coordinates (n,x,y,z,v).
 
30596
    template<typename t> bool contains(const T& pixel, t& n, t& x, t&y, t& z, t& v) const {
 
30597
      if (is_empty()) return false;
 
30598
      cimglist_for(*this,l) if (data[l].contains(pixel,x,y,z,v)) { n = (t)l; return true; }
 
30599
      return false;
 
30600
    }
 
30601
 
 
30602
    //! Return \c true if one of the image list contains the pixel. If true, set coordinates (n,x,y,z).
 
30603
    template<typename t> bool contains(const T& pixel, t& n, t& x, t&y, t& z) const {
 
30604
      t v;
 
30605
      return contains(pixel,n,x,y,z,v);
 
30606
    }
 
30607
 
 
30608
    //! Return \c true if one of the image list contains the pixel. If true, set coordinates (n,x,y).
 
30609
    template<typename t> bool contains(const T& pixel, t& n, t& x, t&y) const {
 
30610
      t z,v;
 
30611
      return contains(pixel,n,x,y,z,v);
 
30612
    }
 
30613
 
 
30614
    //! Return \c true if one of the image list contains the pixel. If true, set coordinates (n,x).
 
30615
    template<typename t> bool contains(const T& pixel, t& n, t& x) const {
 
30616
      t y,z,v;
 
30617
      return contains(pixel,n,x,y,z,v);
 
30618
    }
 
30619
 
 
30620
    //! Return \c true if one of the image list contains the pixel. If true, set coordinates (n).
 
30621
    template<typename t> bool contains(const T& pixel, t& n) const {
 
30622
      t x,y,z,v;
 
30623
      return contains(pixel,n,x,y,z,v);
 
30624
    }
 
30625
 
 
30626
    //! Return \c true if one of the image list contains the pixel.
 
30627
    bool contains(const T& pixel) const {
 
30628
      unsigned int n,x,y,z,v;
 
30629
      return contains(pixel,n,x,y,z,v);
 
30630
    }
 
30631
 
 
30632
    //! Return \c true if the list contains the image 'img'. If true, returns the position (n) of the image in the list.
 
30633
    template<typename t> bool contains(const CImg<T>& img, t& n) const {
 
30634
      if (is_empty()) return false;
 
30635
      const CImg<T> *const ptr = &img;
 
30636
      cimglist_for(*this,i) if (data+i==ptr) { n = (t)i; return true; }
 
30637
      return false;
 
30638
    }
 
30639
 
 
30640
    //! Return \c true if the list contains the image img.
 
30641
    bool contains(const CImg<T>& img) const {
 
30642
      unsigned int n;
 
30643
      return contains(img,n);
22680
30644
    }
22681
30645
 
22682
30646
    //@}
22687
30651
    //------------------------------
22688
30652
 
22689
30653
    //! Assignment operator
22690
 
    template<typename t> CImgList& operator=(const CImgList<t>& list) {
 
30654
    template<typename t> CImgList<T>& operator=(const CImgList<t>& list) {
22691
30655
      return assign(list);
22692
30656
    }
22693
30657
 
22694
 
    CImgList& operator=(const CImgList& list) {
 
30658
    CImgList<T>& operator=(const CImgList<T>& list) {
22695
30659
      return assign(list);
22696
30660
    }
22697
30661
 
22698
30662
    //! Assignment operator.
22699
 
    template<typename t> CImgList& operator=(const CImg<t>& img) {
 
30663
    template<typename t> CImgList<T>& operator=(const CImg<t>& img) {
22700
30664
      cimglist_for(*this,l) data[l]=img;
22701
30665
      return *this;
22702
30666
    }
22703
30667
 
22704
30668
    //! Assignment operator.
22705
 
    CImgList& operator=(const T& val) {
 
30669
    CImgList<T>& operator=(const T val) {
22706
30670
      cimglist_for(*this,l) data[l].fill(val);
22707
30671
      return *this;
22708
30672
    }
22709
30673
 
22710
 
    //! Operator+
22711
 
    CImgList operator+() const {
 
30674
    //! Operator+.
 
30675
    CImgList<T> operator+() const {
22712
30676
      return CImgList<T>(*this);
22713
30677
    }
22714
30678
 
22715
 
    //! Operator+=
 
30679
    //! Operator+=.
22716
30680
#ifdef cimg_use_visualcpp6
22717
 
    CImgList& operator+=(const T& val) {
 
30681
    CImgList<T>& operator+=(const T val) {
22718
30682
#else
22719
 
    template<typename t> CImgList& operator+=(const t& val) {
 
30683
    template<typename t> CImgList<T>& operator+=(const t val) {
22720
30684
#endif
22721
30685
      cimglist_for(*this,l) (*this)[l]+=val;
22722
30686
      return *this;
22723
30687
    }
22724
30688
 
22725
 
    //! Operator+=
22726
 
    template<typename t> CImgList& operator+=(const CImgList<t>& list) {
 
30689
    //! Operator+=.
 
30690
    template<typename t> CImgList<T>& operator+=(const CImgList<t>& list) {
22727
30691
      const unsigned int sizemax = cimg::min(size,list.size);
22728
30692
      for (unsigned int l=0; l<sizemax; ++l) (*this)[l]+=list[l];
22729
30693
      return *this;
22730
30694
    }
22731
30695
 
22732
 
    //! Operator++
22733
 
    CImgList& operator++() {
 
30696
    //! Operator++ (prefix).
 
30697
    CImgList<T>& operator++() {
22734
30698
      cimglist_for(*this,l) ++(*this)[l];
22735
30699
      return *this;
22736
30700
    }
22737
30701
 
22738
 
    //! Operator-
22739
 
    CImgList operator-() const {
 
30702
    //! Operator++ (postfix).
 
30703
    CImgList<T> operator++(int) {
 
30704
      CImgList<T> copy(*this);
 
30705
      ++*this;
 
30706
      return copy;
 
30707
    }
 
30708
 
 
30709
    //! Operator-.
 
30710
    CImgList<T> operator-() const {
22740
30711
      CImgList<T> res(size);
22741
30712
      cimglist_for(res,l) res[l].assign(-data[l]);
22742
30713
      return res;
22744
30715
 
22745
30716
    //! Operator-=.
22746
30717
#ifdef cimg_use_visualcpp6
22747
 
    CImgList& operator-=(const T& val) {
 
30718
    CImgList<T>& operator-=(const T val) {
22748
30719
#else
22749
 
    template<typename t> CImgList& operator-=(const t& val) {
 
30720
    template<typename t> CImgList<T>& operator-=(const t val) {
22750
30721
#endif
22751
30722
      cimglist_for(*this,l) (*this)[l]-=val;
22752
30723
      return *this;
22753
30724
    }
22754
30725
 
22755
30726
    //! Operator-=.
22756
 
    template<typename t> CImgList& operator-=(const CImgList<t>& list) {
 
30727
    template<typename t> CImgList<T>& operator-=(const CImgList<t>& list) {
22757
30728
      const unsigned int sizemax = min(size,list.size);
22758
30729
      for (unsigned int l=0; l<sizemax; ++l) (*this)[l]-=list[l];
22759
30730
      return *this;
22760
30731
    }
22761
30732
 
22762
 
    //! Operator--
22763
 
    CImgList& operator--() {
 
30733
    //! Operator-- (prefix).
 
30734
    CImgList<T>& operator--() {
22764
30735
      cimglist_for(*this,l) --(*this)[l];
22765
30736
      return *this;
22766
30737
    }
22767
30738
 
 
30739
    //! Operator-- (postfix).
 
30740
    CImgList<T> operator--(int) {
 
30741
      CImgList<T> copy(*this);
 
30742
      --*this;
 
30743
      return copy;
 
30744
    }
 
30745
 
22768
30746
    //! Operator*=.
22769
30747
#ifdef cimg_use_visualcpp6
22770
 
    CImgList& operator*=(const double val) {
 
30748
    CImgList<T>& operator*=(const double val) {
22771
30749
#else
22772
 
    template<typename t> CImgList& operator*=(const t& val) {
 
30750
    template<typename t> CImgList<T>& operator*=(const t val) {
22773
30751
#endif
22774
30752
      cimglist_for(*this,l) (*this)[l]*=val;
22775
30753
      return *this;
22776
30754
    }
22777
30755
 
22778
30756
    //! Operator*=.
22779
 
    template<typename t> CImgList& operator*=(const CImgList<t>& list) {
 
30757
    template<typename t> CImgList<T>& operator*=(const CImgList<t>& list) {
22780
30758
      const unsigned int N = cimg::min(size,list.size);
22781
30759
      for (unsigned int l=0; l<N; ++l) (*this)[l]*=list[l];
22782
30760
      return this;
22784
30762
 
22785
30763
    //! Operator/=.
22786
30764
#ifdef cimg_use_visualcpp6
22787
 
    CImgList& operator/=(const double val) {
 
30765
    CImgList<T>& operator/=(const double val) {
22788
30766
#else
22789
 
    template<typename t> CImgList& operator/=(const t& val) {
 
30767
    template<typename t> CImgList<T>& operator/=(const t val) {
22790
30768
#endif
22791
30769
      cimglist_for(*this,l) (*this)[l]/=val;
22792
30770
      return *this;
22793
30771
    }
22794
30772
 
22795
30773
    //! Operator/=.
22796
 
    template<typename t> CImgList& operator/=(const CImgList<t>& list) {
 
30774
    template<typename t> CImgList<T>& operator/=(const CImgList<t>& list) {
22797
30775
      const unsigned int N = cimg::min(size,list.size);
22798
30776
      for (unsigned int l=0; l<N; ++l) (*this)[l]/=list[l];
22799
30777
      return this;
22800
30778
    }
22801
30779
 
 
30780
    //! Return a reference to the maximum pixel value of the instance list.
 
30781
    const T& max() const {
 
30782
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",pixel_type());
 
30783
      const T *ptrmax = data->data;
 
30784
      T max_value = *ptrmax;
 
30785
      cimglist_for(*this,l) {
 
30786
        const CImg<T>& img = data[l];
 
30787
        cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 
30788
      }
 
30789
      return *ptrmax;
 
30790
    }
 
30791
 
 
30792
    //! Return a reference to the maximum pixel value of the instance list.
 
30793
    T& max() {
 
30794
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",pixel_type());
 
30795
      T *ptrmax = data->data;
 
30796
      T max_value = *ptrmax;
 
30797
      cimglist_for(*this,l) {
 
30798
        const CImg<T>& img = data[l];
 
30799
        cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
 
30800
      }
 
30801
      return *ptrmax;
 
30802
    }
 
30803
 
 
30804
    //! Return a reference to the minimum pixel value of the instance list.
 
30805
    const T& min() const {
 
30806
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",pixel_type());
 
30807
      const T *ptrmin = data->data;
 
30808
      T min_value = *ptrmin;
 
30809
      cimglist_for(*this,l) {
 
30810
        const CImg<T>& img = data[l];
 
30811
        cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 
30812
      }
 
30813
      return *ptrmin;
 
30814
    }
 
30815
 
 
30816
    //! Return a reference to the minimum pixel value of the instance list.
 
30817
    T& min() {
 
30818
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",pixel_type());
 
30819
      T *ptrmin = data->data;
 
30820
      T min_value = *ptrmin;
 
30821
      cimglist_for(*this,l) {
 
30822
        const CImg<T>& img = data[l];
 
30823
        cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
 
30824
      }
 
30825
      return *ptrmin;
 
30826
    }
 
30827
 
 
30828
    //! Return a reference to the minimum pixel value of the instance list.
 
30829
    template<typename t> const T& minmax(t& max_val) const {
 
30830
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",pixel_type());
 
30831
      const T *ptrmin = data->data;
 
30832
      T min_value = *ptrmin, max_value = min_value;
 
30833
      cimglist_for(*this,l) {
 
30834
        const CImg<T>& img = data[l];
 
30835
        cimg_for(img,ptr,T) {
 
30836
          const T val = *ptr;
 
30837
          if (val<min_value) { min_value = val; ptrmin = ptr; }
 
30838
          if (val>max_value) max_value = val;
 
30839
        }
 
30840
      }
 
30841
      max_val = (t)max_value;
 
30842
      return *ptrmin;
 
30843
    }
 
30844
 
 
30845
    //! Return a reference to the minimum pixel value of the instance list.
 
30846
    template<typename t> T& minmax(t& max_val) {
 
30847
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",pixel_type());
 
30848
      T *ptrmin = data->data;
 
30849
      T min_value = *ptrmin, max_value = min_value;
 
30850
      cimglist_for(*this,l) {
 
30851
        const CImg<T>& img = data[l];
 
30852
        cimg_for(img,ptr,T) {
 
30853
          const T val = *ptr;
 
30854
          if (val<min_value) { min_value = val; ptrmin = ptr; }
 
30855
          if (val>max_value) max_value = val;
 
30856
        }
 
30857
      }
 
30858
      max_val = (t)max_value;
 
30859
      return *ptrmin;
 
30860
    }
 
30861
 
 
30862
    //! Return a reference to the minimum pixel value of the instance list.
 
30863
    template<typename t> const T& maxmin(t& min_val) const {
 
30864
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",pixel_type());
 
30865
      const T *ptrmax = data->data;
 
30866
      T min_value = *ptrmax, max_value = min_value;
 
30867
      cimglist_for(*this,l) {
 
30868
        const CImg<T>& img = data[l];
 
30869
        cimg_for(img,ptr,T) {
 
30870
          const T val = *ptr;
 
30871
          if (val>max_value) { max_value = val; ptrmax = ptr; }
 
30872
          if (val<min_value) min_value = val;
 
30873
        }
 
30874
      }
 
30875
      min_val = (t)min_value;
 
30876
      return *ptrmax;
 
30877
    }
 
30878
 
 
30879
    //! Return a reference to the minimum pixel value of the instance list.
 
30880
    template<typename t> T& maxmin(t& min_val) {
 
30881
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",pixel_type());
 
30882
      T *ptrmax = data->data;
 
30883
      T min_value = *ptrmax, max_value = min_value;
 
30884
      cimglist_for(*this,l) {
 
30885
        const CImg<T>& img = data[l];
 
30886
        cimg_for(img,ptr,T) {
 
30887
          const T val = *ptr;
 
30888
          if (val>max_value) { max_value = val; ptrmax = ptr; }
 
30889
          if (val<min_value) min_value = val;
 
30890
        }
 
30891
      }
 
30892
      min_val = (t)min_value;
 
30893
      return *ptrmax;
 
30894
    }
 
30895
 
 
30896
    //! Return the mean pixel value of the instance list.
 
30897
    double mean() const {
 
30898
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::mean() : Instance image list is empty.",pixel_type());
 
30899
      double val = 0;
 
30900
      unsigned int siz = 0;
 
30901
      cimglist_for(*this,l) {
 
30902
        const CImg<T>& img = data[l];
 
30903
        cimg_for(img,ptr,T) val+=(double)*ptr;
 
30904
        siz+=img.size();
 
30905
      }
 
30906
      return val/siz;
 
30907
    }
 
30908
 
 
30909
    //! Return the variance of the instance list.
 
30910
    double variance() {
 
30911
      if (is_empty())
 
30912
        throw CImgInstanceException("CImgList<%s>::variance() : Instance image list is empty.",pixel_type());
 
30913
      double res = 0;
 
30914
      unsigned int siz = 0;
 
30915
      double S = 0, S2 = 0;
 
30916
      cimglist_for(*this,l) {
 
30917
        const CImg<T>& img = data[l];
 
30918
        cimg_for(img,ptr,T) { const double val = (double)*ptr; S+=val;  S2+=val*val; }
 
30919
        siz+=img.size();
 
30920
      }
 
30921
      res = (S2 - S*S/siz)/siz;
 
30922
      return res;
 
30923
    }
 
30924
 
22802
30925
    //@}
22803
30926
    //-------------------------
22804
30927
    //
22846
30969
      return (*this)[pos](x,y,z,v);
22847
30970
    }
22848
30971
 
22849
 
    //! Equivalent to CImgList<T>::operator[], with boundary checking
 
30972
    //! Equivalent to CImgList<T>::operator[], with boundary checking.
22850
30973
    CImg<T>& at(const unsigned int pos) {
22851
30974
      if (pos>=size)
22852
30975
        throw CImgArgumentException("CImgList<%s>::at() : bad list position %u, in a list of %u images",
22861
30984
      return data[pos];
22862
30985
    }
22863
30986
 
22864
 
    //! Returns a reference to last element
 
30987
    //! Returns a reference to last element.
22865
30988
    CImg<T>& back() {
22866
30989
      return (*this)(size-1);
22867
30990
    }
22870
30993
      return (*this)(size-1);
22871
30994
    }
22872
30995
 
22873
 
    //! Returns a reference to the first element
 
30996
    //! Returns a reference to the first element.
22874
30997
    CImg<T>& front() {
22875
30998
      return *data;
22876
30999
    }
22898
31021
    }
22899
31022
 
22900
31023
    //! Insert a copy of the image \p img into the current image list, at position \p pos.
22901
 
    template<typename t> CImgList& insert(const CImg<t>& img, const unsigned int pos, const bool shared) {
 
31024
    template<typename t> CImgList<typename cimg::superset<T,t>::type>
 
31025
      get_insert(const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
 
31026
      typedef typename cimg::superset<T,t>::type Tt;
 
31027
      return CImgList<Tt>(*this).insert(img,pos,shared);
 
31028
    }
 
31029
 
 
31030
    //! Insert a copy of the image \p img into the current image list, at position \p pos (in-place).
 
31031
    template<typename t> CImgList<T>& insert(const CImg<t>& img, const unsigned int pos, const bool shared) {
22902
31032
      const unsigned int npos = pos==~0U?size:pos;
22903
31033
      if (npos>size)
22904
31034
        throw CImgArgumentException("CImgList<%s>::insert() : Cannot insert at position %u into a list with %u elements",
22906
31036
      if (shared)
22907
31037
        throw CImgArgumentException("CImgList<%s>::insert(): Cannot insert a shared image CImg<%s> into a CImgList<%s>",
22908
31038
                                    pixel_type(),img.pixel_type(),pixel_type());
22909
 
      CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=1)]:0;
 
31039
      CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
22910
31040
      if (!size || !data) {
22911
31041
        data = new_data;
22912
31042
        *data = img;
22925
31055
      return *this;
22926
31056
    }
22927
31057
 
22928
 
    CImgList& insert(const CImg<T>& img, const unsigned int pos, const bool shared) {
 
31058
    CImgList<T>& insert(const CImg<T>& img, const unsigned int pos, const bool shared) {
22929
31059
      const unsigned int npos = pos==~0U?size:pos;
22930
31060
      if (npos>size)
22931
31061
        throw CImgArgumentException("CImgList<%s>::insert() : Can't insert at position %u into a list with %u elements",
22932
31062
                                    pixel_type(),npos,size);
22933
 
      CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=1)]:0;
 
31063
      CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
22934
31064
      if (!size || !data) {
22935
31065
        data = new_data;
22936
31066
        if (shared && img) {
22968
31098
 
22969
31099
    // The two functions below are necessary due to Visual C++ 6.0 function overloading bugs, when
22970
31100
    // default parameters are used in function signatures.
22971
 
    template<typename t> CImgList& insert(const CImg<t>& img, const unsigned int pos) {
 
31101
    template<typename t> CImgList<T>& insert(const CImg<t>& img, const unsigned int pos) {
22972
31102
      return insert(img,pos,false);
22973
31103
    }
22974
 
    template<typename t> CImgList& insert(const CImg<t>& img) {
 
31104
 
 
31105
    //! Insert a copy of the image \p img into the current image list, at position \p pos (in-place).
 
31106
    template<typename t> CImgList<T>& insert(const CImg<t>& img) {
22975
31107
      return insert(img,~0U,false);
22976
31108
    }
22977
31109
 
22978
 
   template<typename t> CImgList<typename cimg::largest<T,t>::type>
22979
 
     get_insert(const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
22980
 
     typedef typename cimg::largest<T,t>::type restype;
22981
 
     return CImgList<restype>(*this).insert(img,pos,shared);
22982
 
   }
 
31110
    //! Insert n empty images img into the current image list, at position \p pos.
 
31111
    template<typename t> CImgList<typename cimg::superset<T,t>::type>
 
31112
      get_insert(const unsigned int n, const unsigned int pos=~0U) const {
 
31113
      typedef typename cimg::superset<T,t>::type Tt;
 
31114
      return CImgList<Tt>(*this).insert(n,pos);
 
31115
    }
 
31116
 
 
31117
    //! Insert n empty images img into the current image list, at position \p pos (in-place).
 
31118
    CImgList<T>& insert(const unsigned int n, const unsigned int pos=~0U) {
 
31119
      CImg<T> foo;
 
31120
      const unsigned int npos = pos==~0U?size:pos;
 
31121
      for (unsigned int i=0; i<n; ++i) insert(foo,npos+i);
 
31122
      return *this;
 
31123
    }
22983
31124
 
22984
31125
    //! Insert n copies of the image \p img into the current image list, at position \p pos.
22985
 
    template<typename t> CImgList& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) {
 
31126
    template<typename t> CImgList<typename cimg::superset<T,t>::type>
 
31127
      get_insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
 
31128
      typedef typename cimg::superset<T,t>::type Tt;
 
31129
      return CImgList<Tt>(*this).insert(n,img,pos,shared);
 
31130
    }
 
31131
 
 
31132
    //! Insert n copies of the image \p img into the current image list, at position \p pos (in-place).
 
31133
    template<typename t> CImgList<T>& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) {
22986
31134
      const unsigned int npos = pos==~0U?size:pos;
22987
31135
      insert(img,npos,shared);
22988
31136
      for (unsigned int i=1; i<n; ++i) insert(data[npos],npos+i,shared);
22989
31137
      return *this;
22990
31138
    }
22991
31139
 
22992
 
    template<typename t> CImgList<typename cimg::largest<T,t>::type>
22993
 
      get_insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
22994
 
      typedef typename cimg::largest<T,t>::type restype;
22995
 
      return CImgList<restype>(*this).insert(n,img,pos,shared);
22996
 
    }
22997
 
 
22998
31140
    //! Insert a copy of the image list \p list into the current image list, starting from position \p pos.
22999
 
    template<typename t> CImgList& insert(const CImgList<t>& list, const unsigned int pos=~0U, const int shared=0) {
 
31141
    template<typename t> CImgList<typename cimg::superset<T,t>::type>
 
31142
      get_insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
 
31143
      typedef typename cimg::superset<T,t>::type Tt;
 
31144
      return CImgList<Tt>(*this).insert(list,pos,shared);
 
31145
    }
 
31146
 
 
31147
    //! Insert a copy of the image list \p list into the current image list, starting from position \p pos (in-place).
 
31148
    template<typename t> CImgList<T>& insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
23000
31149
      const unsigned int npos = pos==~0U?size:pos;
23001
 
      if ((void*)this!=(void*)&list) {
23002
 
        if (shared>=0) cimglist_for(list,l) insert(list[l],npos+l,shared?true:false);
23003
 
        else cimglist_for(list,l) insert(list[l],npos+l,list[l].is_shared);
23004
 
      } else insert(CImgList<T>(list),npos,shared);
 
31150
      if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos+l,shared);
 
31151
      else insert(CImgList<T>(list),npos,shared);
23005
31152
      return *this;
23006
31153
    }
23007
31154
 
23008
 
    template<typename t> CImgList<typename cimg::largest<T,t>::type>
23009
 
      get_insert(const CImgList<t>& list, const unsigned int pos=~0U, int shared=0) const {
23010
 
      typedef typename cimg::largest<T,t>::type restype;
23011
 
      return CImgList<restype>(*this).insert(list,pos,shared);
23012
 
    }
23013
 
 
23014
 
    //! Insert a copy of the image \p img at the end of the current image list.
23015
 
    template<typename t> CImgList& operator<<(const CImg<t>& img) {
23016
 
      return insert(img);
23017
 
    }
23018
 
 
23019
 
    //! Insert a copy of the image list \p list at the end of the current image list.
23020
 
    template<typename t> CImgList& operator<<(const CImgList<t>& list) {
23021
 
      return insert(list);
23022
 
    }
23023
 
 
23024
 
    //! Return a copy of the current image list, where the image \p img has been inserted at the end.
23025
 
    template<typename t> CImgList& operator>>(CImg<t>& img) const {
23026
 
      typedef typename cimg::largest<T,t>::type restype;
23027
 
      return CImgList<restype>(*this).insert(img);
23028
 
    }
23029
 
 
23030
 
    //! Insert a copy of the current image list at the beginning of the image list \p list.
23031
 
    template<typename t> CImgList& operator>>(CImgList<t>& list) const {
23032
 
      return list.insert(*this,0);
23033
 
    }
23034
 
 
23035
 
    //! Display an image list into a CImgDisplay
23036
 
    const CImgList& operator>>(CImgDisplay& disp) const {
23037
 
      return display(disp);
23038
 
    }
23039
 
 
23040
31155
    //! Insert n copies of the list \p list at position \p pos of the current list.
23041
 
    template<typename t> CImgList& insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const int shared=0) {
 
31156
    template<typename t> CImgList<typename cimg::superset<T,t>::type>
 
31157
      get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
 
31158
      typedef typename cimg::superset<T,t>::type Tt;
 
31159
      return CImgList<Tt>(*this).insert(n,list,pos,shared);
 
31160
    }
 
31161
 
 
31162
    //! Insert n copies of the list \p list at position \p pos of the current list (in-place).
 
31163
    template<typename t> CImgList<T>& insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
23042
31164
      const unsigned int npos = pos==~0U?size:pos;
23043
31165
      for (unsigned int i=0; i<n; ++i) insert(list,npos,shared);
23044
31166
      return *this;
23045
31167
    }
23046
31168
 
23047
 
    template<typename t> CImgList<typename cimg::largest<T,t>::type>
23048
 
      get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const int shared=0) const {
23049
 
      typedef typename cimg::largest<T,t>::type restype;
23050
 
      return CImgList<restype>(*this).insert(n,list,pos,shared);
23051
 
    }
23052
 
 
23053
 
    //! Insert image \p img at the end of the list.
23054
 
    template<typename t> CImgList& push_back(const CImg<t>& img) {
23055
 
      return insert(img);
23056
 
    }
23057
 
 
23058
 
    //! Insert image \p img at the front of the list.
23059
 
    template<typename t> CImgList& push_front(const CImg<t>& img) {
23060
 
      return insert(img,0);
23061
 
    }
23062
 
 
23063
 
    //! Insert list \p list at the end of the current list.
23064
 
    template<typename t> CImgList& push_back(const CImgList<t>& list) {
23065
 
      return insert(list);
23066
 
    }
23067
 
 
23068
 
    //! Insert list \p list at the front of the current list.
23069
 
    template<typename t> CImgList& push_front(const CImgList<t>& list) {
23070
 
      return insert(list,0);
23071
 
    }
23072
 
 
23073
 
    //! Remove the image at position \p pos from the image list.
23074
 
    CImgList& remove(const unsigned int pos) {
23075
 
      if (pos>=size)
23076
 
        cimg::warn("CImgList<%s>::remove() : Cannot remove an image from a list (%p,%u), at position %u.",
23077
 
                   pixel_type(),data,size,pos);
 
31169
    //! Remove the images at positions \p pos1 to \p pos2 from the image list.
 
31170
    CImgList<T> get_remove(const unsigned int pos1, const unsigned int pos2) const {
 
31171
      return (+*this).remove(pos1,pos2);
 
31172
    }
 
31173
 
 
31174
    //! Remove the images at positions \p pos1 to \p pos2 from the image list (in-place).
 
31175
    CImgList<T>& remove(const unsigned int pos1, const unsigned int pos2) {
 
31176
      const unsigned int
 
31177
        npos1 = pos1<pos2?pos1:pos2,
 
31178
        tpos2 = pos1<pos2?pos2:pos1,
 
31179
        npos2 = tpos2<size?tpos2:size-1;
 
31180
      if (npos1>=size)
 
31181
        cimg::warn("CImgList<%s>::remove() : Cannot remove images from a list (%p,%u), at positions %u->%u.",
 
31182
                   pixel_type(),data,size,npos1,tpos2);
23078
31183
      else {
23079
 
        data[pos].assign();
23080
 
        if (!(--size)) return assign();
23081
 
        if (size<8 || size>(allocsize>>2)) { // Removing item without reallocation.
23082
 
          if (pos!=size) {
23083
 
            std::memmove(data+pos,data+pos+1,sizeof(CImg<T>)*(size-pos));
23084
 
            CImg<T> &tmp = data[size];
23085
 
            tmp.width = tmp.height = tmp.depth = tmp.dim = 0; tmp.data = 0;
23086
 
          }
23087
 
        } else { // Removing item with reallocation.
 
31184
        if (tpos2>=size)
 
31185
          cimg::warn("CImgList<%s>::remove() : Cannot remove all images from a list (%p,%u), at positions %u->%u.",
 
31186
                     pixel_type(),data,size,npos1,tpos2);
 
31187
        for (unsigned int k = npos1; k<=npos2; ++k) data[k].assign();
 
31188
        const unsigned int nb = 1 + npos2 - npos1;
 
31189
        if (!(size-=nb)) return assign();
 
31190
        if (size>(allocsize>>2) || allocsize<=8) { // Removing items without reallocation.
 
31191
          if (npos1!=size) std::memmove(data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
 
31192
          std::memset(data+size,0,sizeof(CImg<T>)*nb);
 
31193
        } else { // Removing items with reallocation.
23088
31194
          allocsize>>=2;
 
31195
          while (allocsize>8 && size<(allocsize>>1)) allocsize>>=1;
23089
31196
          CImg<T> *new_data = new CImg<T>[allocsize];
23090
 
          if (pos) std::memcpy(new_data,data,sizeof(CImg<T>)*pos);
23091
 
          if (pos!=size) std::memcpy(new_data+pos,data+pos+1,sizeof(CImg<T>)*(size-pos));
23092
 
          std::memset(data,0,sizeof(CImg<T>)*(size+1));
 
31197
          if (npos1) std::memcpy(new_data,data,sizeof(CImg<T>)*npos1);
 
31198
          if (npos1!=size) std::memcpy(new_data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
 
31199
          if (size!=allocsize) std::memset(new_data+size,0,sizeof(allocsize-size));
 
31200
          std::memset(data,0,sizeof(CImg<T>)*(size+nb));
23093
31201
          delete[] data;
23094
31202
          data = new_data;
23095
31203
        }
23097
31205
      return *this;
23098
31206
    }
23099
31207
 
23100
 
    CImgList get_remove(const unsigned int pos) const {
 
31208
    //! Remove the image at position \p pos from the image list.
 
31209
    CImgList<T> get_remove(const unsigned int pos) const {
23101
31210
      return (+*this).remove(pos);
23102
31211
    }
23103
31212
 
23104
 
    //! Remove last element of the list;
23105
 
    CImgList& pop_back() {
23106
 
      return remove(size-1);
23107
 
    }
23108
 
 
23109
 
    //! Remove first element of the list;
23110
 
    CImgList& pop_front() {
23111
 
      return remove(0);
23112
 
    }
23113
 
 
23114
 
    //! Remove the element pointed by iterator \p iter;
23115
 
    CImgList& erase(const iterator iter) {
23116
 
      return remove(iter-data);
 
31213
    //! Remove the image at position \p pos from the image list (in-place).
 
31214
    CImgList<T>& remove(const unsigned int pos) {
 
31215
      return remove(pos,pos);
23117
31216
    }
23118
31217
 
23119
31218
    //! Remove the last image from the image list.
23120
 
    CImgList& remove() {
 
31219
    CImgList<T> get_remove() const {
 
31220
      return (+*this).remove();
 
31221
    }
 
31222
 
 
31223
    //! Remove the last image from the image list (in-place).
 
31224
    CImgList<T>& remove() {
23121
31225
      if (size) return remove(size-1);
23122
31226
      else cimg::warn("CImgList<%s>::remove() : List is empty",pixel_type());
23123
31227
      return *this;
23124
31228
    }
23125
31229
 
23126
 
    CImgList get_remove() const {
23127
 
      return (+*this).remove();
 
31230
    //! Reverse list order.
 
31231
    CImgList<T> get_reverse() const {
 
31232
      return (+*this).reverse();
23128
31233
    }
23129
31234
 
23130
 
    //! Reverse list order
23131
 
    CImgList& reverse() {
 
31235
    //! Reverse list order (in-place).
 
31236
    CImgList<T>& reverse() {
23132
31237
      for (unsigned int l=0; l<size/2; ++l) (*this)[l].swap((*this)[size-1-l]);
23133
31238
      return *this;
23134
31239
    }
23135
31240
 
23136
 
    //! Get reversed list
23137
 
    CImgList get_reverse() const {
23138
 
      return (+*this).reverse();
23139
 
    }
23140
 
 
23141
 
    //! Get a sub-list
23142
 
    CImgList get_crop(const unsigned int i0, const unsigned int i1, const bool shared=false) const {
 
31241
    //! Get a sub-list.
 
31242
    CImgList<T> get_crop(const unsigned int i0, const unsigned int i1, const bool shared=false) const {
23143
31243
      if (i0>i1 || i1>=size)
23144
31244
        throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
23145
31245
                                    pixel_type(),i0,i1,size,data);
23148
31248
      return res;
23149
31249
    }
23150
31250
 
23151
 
    //! Replace a list by its sublist
23152
 
    CImgList& crop(const unsigned int i0, const unsigned int i1, const bool shared=false) {
23153
 
      return get_crop(i0,i1,shared).swap(*this);
23154
 
    }
23155
 
 
23156
 
    //! Get sub-images of a sublist
23157
 
    CImgList get_crop(const unsigned int i0, const unsigned int i1,
 
31251
    //! Get a sub-list (in-place).
 
31252
    CImgList<T>& crop(const unsigned int i0, const unsigned int i1, const bool shared=false) {
 
31253
      return get_crop(i0,i1,shared).transfer_to(*this);
 
31254
    }
 
31255
 
 
31256
    //! Get sub-images of a sublist.
 
31257
    CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 
31258
                         const int x0, const int y0, const int z0, const int v0,
 
31259
                         const int x1, const int y1, const int z1, const int v1) const {
 
31260
      if (i0>i1 || i1>=size)
 
31261
        throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
 
31262
                                    pixel_type(),i0,i1,size,data);
 
31263
      CImgList<T> res(i1-i0+1);
 
31264
      cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,v0,x1,y1,z1,v1);
 
31265
      return res;
 
31266
    }
 
31267
 
 
31268
    //! Get sub-images of a sublist (in-place).
 
31269
    CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
23158
31270
                      const int x0, const int y0, const int z0, const int v0,
23159
 
                      const int x1, const int y1, const int z1, const int v1) const {
 
31271
                      const int x1, const int y1, const int z1, const int v1) {
 
31272
      return get_crop(i0,i1,x0,y0,z0,v0,x1,y1,z1,v1).transfer_to(*this);
 
31273
    }
 
31274
 
 
31275
    //! Get sub-images of a sublist.
 
31276
    CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 
31277
                         const int x0, const int y0, const int z0,
 
31278
                         const int x1, const int y1, const int z1) const {
23160
31279
      if (i0>i1 || i1>=size)
23161
31280
        throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
23162
31281
                                    pixel_type(),i0,i1,size,data);
23163
31282
      CImgList<T> res(i1-i0+1);
23164
 
      cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,v0,x1,y1,z1,v1);
 
31283
      cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,x1,y1,z1);
23165
31284
      return res;
23166
31285
    }
23167
31286
 
23168
 
    //! Get sub-images of a sublist
23169
 
    CImgList& crop(const unsigned int i0, const unsigned int i1,
23170
 
                   const int x0, const int y0, const int z0, const int v0,
23171
 
                   const int x1, const int y1, const int z1, const int v1) {
23172
 
      return get_crop(i0,i1,x0,y0,z0,v0,x1,y1,z1,v1).swap(*this);
23173
 
    }
23174
 
 
23175
 
    //! Get sub-images of a sublist
23176
 
    CImgList get_crop(const unsigned int i0, const unsigned int i1,
 
31287
    //! Get sub-images of a sublist (in-place).
 
31288
    CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
23177
31289
                      const int x0, const int y0, const int z0,
23178
 
                      const int x1, const int y1, const int z1) const {
 
31290
                      const int x1, const int y1, const int z1) {
 
31291
      return get_crop(i0,i1,x0,y0,z0,x1,y1,z1).transfer_to(*this);
 
31292
    }
 
31293
 
 
31294
    //! Get sub-images of a sublist.
 
31295
    CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 
31296
                         const int x0, const int y0,
 
31297
                         const int x1, const int y1) const {
23179
31298
      if (i0>i1 || i1>=size)
23180
31299
        throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
23181
31300
                                    pixel_type(),i0,i1,size,data);
23182
31301
      CImgList<T> res(i1-i0+1);
23183
 
      cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,x1,y1,z1);
 
31302
      cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,x1,y1);
23184
31303
      return res;
23185
31304
    }
23186
31305
 
23187
 
    //! Get sub-images of a sublist
23188
 
    CImgList& crop(const unsigned int i0, const unsigned int i1,
23189
 
                   const int x0, const int y0, const int z0,
23190
 
                   const int x1, const int y1, const int z1) {
23191
 
      return get_crop(i0,i1,x0,y0,z0,x1,y1,z1).swap(*this);
23192
 
    }
23193
 
 
23194
 
    //! Get sub-images of a sublist
23195
 
    CImgList get_crop(const unsigned int i0, const unsigned int i1,
 
31306
    //! Get sub-images of a sublist (in-place).
 
31307
    CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
23196
31308
                      const int x0, const int y0,
23197
 
                      const int x1, const int y1) const {
23198
 
      if (i0>i1 || i1>=size)
23199
 
        throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
23200
 
                                    pixel_type(),i0,i1,size,data);
23201
 
      CImgList<T> res(i1-i0+1);
23202
 
      cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,x1,y1);
23203
 
      return res;
23204
 
    }
23205
 
 
23206
 
    //! Get sub-images of a sublist
23207
 
    CImgList& crop(const unsigned int i0, const unsigned int i1,
23208
 
                   const int x0, const int y0,
23209
 
                   const int x1, const int y1) {
23210
 
      return get_crop(i0,i1,x0,y0,x1,y1).swap(*this);
23211
 
    }
23212
 
 
23213
 
    //! Get sub-images of a sublist
23214
 
    CImgList get_crop(const unsigned int i0, const unsigned int i1,
23215
 
                      const int x0, const int x1) const {
 
31309
                      const int x1, const int y1) {
 
31310
      return get_crop(i0,i1,x0,y0,x1,y1).transfer_to(*this);
 
31311
    }
 
31312
 
 
31313
    //! Get sub-images of a sublist.
 
31314
    CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
 
31315
                         const int x0, const int x1) const {
23216
31316
      if (i0>i1 || i1>=size)
23217
31317
        throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
23218
31318
                                    pixel_type(),i0,i1,size,data);
23221
31321
      return res;
23222
31322
    }
23223
31323
 
23224
 
    //! Get sub-images of a sublist
23225
 
    CImgList& crop(const unsigned int i0, const unsigned int i1,
23226
 
                   const int x0, const int x1) {
23227
 
      return get_crop(i0,i1,x0,x1).swap(*this);
 
31324
    //! Get sub-images of a sublist (in-place).
 
31325
    CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
 
31326
                      const int x0, const int x1) {
 
31327
      return get_crop(i0,i1,x0,x1).transfer_to(*this);
 
31328
    }
 
31329
 
 
31330
    //! Insert a copy of the image \p img at the end of the current image list (in-place).
 
31331
    template<typename t> CImgList<T>& operator<<(const CImg<t>& img) {
 
31332
      return insert(img);
 
31333
    }
 
31334
 
 
31335
    //! Insert a copy of the image list \p list at the end of the current image list (in-place).
 
31336
    template<typename t> CImgList<T>& operator<<(const CImgList<t>& list) {
 
31337
      return insert(list);
 
31338
    }
 
31339
 
 
31340
    //! Return a copy of the current image list, where the image \p img has been inserted at the end (in-place).
 
31341
    template<typename t> CImgList<T>& operator>>(CImg<t>& img) const {
 
31342
      typedef typename cimg::superset<T,t>::type Tt;
 
31343
      return CImgList<Tt>(*this).insert(img);
 
31344
    }
 
31345
 
 
31346
    //! Insert a copy of the current image list at the beginning of the image list \p list (in-place).
 
31347
    template<typename t> CImgList<T>& operator>>(CImgList<t>& list) const {
 
31348
      return list.insert(*this,0);
 
31349
    }
 
31350
 
 
31351
    //! Display an image list into a CImgDisplay.
 
31352
    const CImgList<T>& operator>>(CImgDisplay& disp) const {
 
31353
      return display(disp);
 
31354
    }
 
31355
 
 
31356
    //! Insert image \p img at the end of the list.
 
31357
    template<typename t> CImgList<T>& push_back(const CImg<t>& img) {
 
31358
      return insert(img);
 
31359
    }
 
31360
 
 
31361
    //! Insert image \p img at the front of the list.
 
31362
    template<typename t> CImgList<T>& push_front(const CImg<t>& img) {
 
31363
      return insert(img,0);
 
31364
    }
 
31365
 
 
31366
    //! Insert list \p list at the end of the current list.
 
31367
    template<typename t> CImgList<T>& push_back(const CImgList<t>& list) {
 
31368
      return insert(list);
 
31369
    }
 
31370
 
 
31371
    //! Insert list \p list at the front of the current list.
 
31372
    template<typename t> CImgList<T>& push_front(const CImgList<t>& list) {
 
31373
      return insert(list,0);
 
31374
    }
 
31375
 
 
31376
    //! Remove last element of the list.
 
31377
    CImgList<T>& pop_back() {
 
31378
      return remove(size-1);
 
31379
    }
 
31380
 
 
31381
    //! Remove first element of the list.
 
31382
    CImgList<T>& pop_front() {
 
31383
      return remove(0);
 
31384
    }
 
31385
 
 
31386
    //! Remove the element pointed by iterator \p iter.
 
31387
    CImgList<T>& erase(const iterator iter) {
 
31388
      return remove(iter-data);
23228
31389
    }
23229
31390
 
23230
31391
    //@}
23235
31396
    //----------------------------
23236
31397
 
23237
31398
    //! Compute the Fast Fourier Transform (along the specified axis).
23238
 
    CImgList& FFT(const char axe, const bool inverse=false) {
 
31399
    CImgList<Tfloat> get_FFT(const char axe, const bool invert=false) const {
 
31400
      return CImgList<Tfloat>(*this).FFT(axe,invert);
 
31401
    }
 
31402
 
 
31403
    //! Compute the Fast Fourier Transform (along the specified axis) (in-place).
 
31404
    CImgList<T>& FFT(const char axe, const bool invert=false) {
23239
31405
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",pixel_type(),size,data);
23240
31406
      if (!data[0]) throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) is empty",
23241
31407
                                                pixel_type(),data[0].width,data[0].height,data[0].depth,data[0].dim,data[0].data);
23254
31420
      switch (cimg::uncase(axe)) {
23255
31421
      case 'x': {
23256
31422
        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.width);
23257
 
        data_plan = fftw_plan_dft_1d(Ir.width, data_in, data_in, inverse?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE);
 
31423
        data_plan = fftw_plan_dft_1d(Ir.width, data_in, data_in, invert?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE);
23258
31424
        cimg_forYZV(Ir,y,z,k) {
23259
31425
          T *ptrr = Ir.ptr(0,y,z,k), *ptri = Ii.ptr(0,y,z,k);
23260
31426
          double *ptrd = (double*)data_in;
23266
31432
 
23267
31433
      case 'y': {
23268
31434
        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.height);
23269
 
        data_plan = fftw_plan_dft_1d(Ir.height, data_in, data_in, inverse?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE);
 
31435
        data_plan = fftw_plan_dft_1d(Ir.height, data_in, data_in, invert?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE);
23270
31436
        const unsigned int off = Ir.width;
23271
31437
        cimg_forXZV(Ir,x,z,k) {
23272
31438
          T *ptrr = Ir.ptr(x,0,z,k), *ptri = Ii.ptr(x,0,z,k);
23279
31445
 
23280
31446
      case 'z': {
23281
31447
        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.depth);
23282
 
        data_plan = fftw_plan_dft_1d(Ir.depth, data_in, data_in, inverse?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE);
 
31448
        data_plan = fftw_plan_dft_1d(Ir.depth, data_in, data_in, invert?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE);
23283
31449
        const unsigned int off = Ir.width*Ir.height;
23284
31450
        cimg_forXYV(Ir,x,y,k) {
23285
31451
          T *ptrr = Ir.ptr(x,y,0,k), *ptri = Ii.ptr(x,y,0,k);
23292
31458
 
23293
31459
      case 'v': {
23294
31460
        data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.dim);
23295
 
        data_plan = fftw_plan_dft_1d(Ir.dim, data_in, data_in, inverse?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE);
 
31461
        data_plan = fftw_plan_dft_1d(Ir.dim, data_in, data_in, invert?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE);
23296
31462
        const unsigned int off = Ir.width*Ir.height*Ir.depth;
23297
31463
        cimg_forXYZ(Ir,x,y,z) {
23298
31464
          T *ptrr = Ir.ptr(x,y,z,0), *ptri = Ii.ptr(x,y,z,0);
23318
31484
            const unsigned int ri = N-1-i, rj = N-1-j;
23319
31485
            cimg::swap(Ir(ri,y,z,v),Ir(rj,y,z,v)); cimg::swap(Ii(ri,y,z,v),Ii(rj,y,z,v));
23320
31486
          }}
23321
 
          for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
 
31487
          for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
23322
31488
        }
23323
31489
        for (unsigned int delta=2; delta<=N; delta<<=1) {
23324
31490
          const unsigned int delta2 = (delta>>1);
23325
31491
          for (unsigned int i=0; i<N; i+=delta) {
23326
31492
            float wr = 1, wi = 0;
23327
 
            const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
 
31493
            const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
23328
31494
                        ca = (float)std::cos(angle),
23329
31495
                        sa = (float)std::sin(angle);
23330
31496
            for (unsigned int k=0; k<delta2; ++k) {
23343
31509
            }
23344
31510
          }
23345
31511
        }
23346
 
        if (inverse) (*this)/=N;
 
31512
        if (invert) (*this)/=N;
23347
31513
      } break;
23348
31514
 
23349
31515
      case 'y': { // Fourier along Y
23356
31522
            const unsigned int ri = N-1-i, rj = N-1-j;
23357
31523
            cimg::swap(Ir(x,ri,z,v),Ir(x,rj,z,v)); cimg::swap(Ii(x,ri,z,v),Ii(x,rj,z,v));
23358
31524
          }}
23359
 
          for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
 
31525
          for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
23360
31526
        }
23361
31527
        for (unsigned int delta=2; delta<=N; delta<<=1) {
23362
31528
          const unsigned int delta2 = (delta>>1);
23363
31529
          for (unsigned int i=0; i<N; i+=delta) {
23364
31530
            float wr = 1, wi = 0;
23365
 
            const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
 
31531
            const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
23366
31532
                        ca = (float)std::cos(angle), sa = (float)std::sin(angle);
23367
31533
            for (unsigned int k=0; k<delta2; ++k) {
23368
31534
              const unsigned int j = i + k, nj = j + delta2;
23380
31546
            }
23381
31547
          }
23382
31548
        }
23383
 
        if (inverse) (*this)/=N;
 
31549
        if (invert) (*this)/=N;
23384
31550
      } break;
23385
31551
 
23386
31552
      case 'z': { // Fourier along Z
23393
31559
            const unsigned int ri = N-1-i, rj = N-1-j;
23394
31560
            cimg::swap(Ir(x,y,ri,v),Ir(x,y,rj,v)); cimg::swap(Ii(x,y,ri,v),Ii(x,y,rj,v));
23395
31561
          }}
23396
 
          for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1);
 
31562
          for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
23397
31563
        }
23398
31564
        for (unsigned int delta=2; delta<=N; delta<<=1) {
23399
31565
          const unsigned int delta2 = (delta>>1);
23400
31566
          for (unsigned int i=0; i<N; i+=delta) {
23401
31567
            float wr = 1, wi = 0;
23402
 
            const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta),
 
31568
            const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
23403
31569
                        ca = (float)std::cos(angle), sa = (float)std::sin(angle);
23404
31570
            for (unsigned int k=0; k<delta2; ++k) {
23405
31571
              const unsigned int j = i + k, nj = j + delta2;
23417
31583
            }
23418
31584
          }
23419
31585
        }
23420
 
        if (inverse) (*this)/=N;
 
31586
        if (invert) (*this)/=N;
23421
31587
      } break;
23422
31588
 
23423
31589
      default: throw CImgArgumentException("CImgList<%s>::FFT() : unknown axe '%c', must be 'x','y' or 'z'");
23426
31592
      return *this;
23427
31593
    }
23428
31594
 
23429
 
    //! Return the Fast Fourier Transform of a complex image (along a specified axis).
23430
 
    CImgList<typename cimg::largest<T,float>::type> get_FFT(const char axe, const bool inverse=false) const {
23431
 
      typedef typename cimg::largest<T,float>::type restype;
23432
 
      return CImgList<restype>(*this).FFT(axe,inverse);
23433
 
    }
23434
 
 
23435
31595
    //! Compute the Fast Fourier Transform of a complex image.
23436
 
    CImgList& FFT(const bool inverse=false) {
 
31596
    CImgList<Tfloat> get_FFT(const bool invert=false) const {
 
31597
      return CImgList<Tfloat>(*this).FFT(invert);
 
31598
    }
 
31599
 
 
31600
    //! Compute the Fast Fourier Transform of a complex image (in-place).
 
31601
    CImgList<T>& FFT(const bool invert=false) {
23437
31602
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",pixel_type(),size,data);
23438
31603
      if (size>2) cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",pixel_type(),size,data);
23439
 
      if (size==1) insert(CImg<T>(data[0].width,data[0].height,data[0].depth,data[0].dim,0));
23440
 
      CImg<T> &Ir = data[0];
23441
 
 
 
31604
      if (size==1) insert(CImg<T>(data->width,data->height,data->depth,data->dim,0));
 
31605
      CImg<T> &Ir = data[0], &Ii = data[1];
 
31606
      if (Ii.width!=Ir.width || Ii.height!=Ir.height || Ii.depth!=Ir.depth || Ii.dim!=Ir.dim)
 
31607
        throw CImgInstanceException("CImgList<%s>::FFT() : Real (%u,%u,%u,%u,%p) and Imaginary (%u,%u,%u,%u,%p) parts "
 
31608
                                    "of the instance image have different dimensions",
 
31609
                                    pixel_type(),Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,
 
31610
                                    Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data);
23442
31611
#ifdef cimg_use_fftw3
23443
 
      CImg<T> &Ii = data[1];
23444
31612
      fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.width*Ir.height*Ir.depth);
23445
31613
      fftw_plan data_plan;
23446
31614
      const unsigned int w = Ir.width, wh = w*Ir.height, whd = wh*Ir.depth;
23447
 
      data_plan = fftw_plan_dft_3d(Ir.width, Ir.height, Ir.depth, data_in, data_in, inverse?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE);
 
31615
      data_plan = fftw_plan_dft_3d(Ir.width, Ir.height, Ir.depth, data_in, data_in, invert?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE);
23448
31616
      cimg_forV(Ir,k) {
23449
31617
        T *ptrr = Ir.ptr(0,0,0,k), *ptri = Ii.ptr(0,0,0,k);
23450
31618
        double *ptrd = (double*)data_in;
23451
 
        cimg_forX(Ir,x) { cimg_forY(Ir,y) { cimg_forZ(Ir,z)
23452
 
          { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=wh; ptri+=wh; }
23453
 
        ptrr-=whd-w; ptri-=whd-w; }
23454
 
        ptrr-=wh-1; ptri-=wh-1; }
 
31619
        cimg_forX(Ir,x) {
 
31620
          cimg_forY(Ir,y) {
 
31621
            cimg_forZ(Ir,z) {
 
31622
              *(ptrd++) = (double)*ptrr;
 
31623
              *(ptrd++) = (double)*ptri;
 
31624
              ptrr+=wh;
 
31625
              ptri+=wh;
 
31626
            }
 
31627
            ptrr-=whd-w;
 
31628
            ptri-=whd-w;
 
31629
          }
 
31630
          ptrr-=wh-1;
 
31631
          ptri-=wh-1;
 
31632
        }
23455
31633
        fftw_execute(data_plan);
23456
31634
        ptrd = (double*)data_in;
23457
 
        ptrr = Ir.ptr(0,0,0,k), ptri = Ii.ptr(0,0,0,k);
23458
 
        { cimg_forX(Ir,x) { cimg_forY(Ir,y) { cimg_forZ(Ir,z)
23459
 
          { *ptrr = (T)*(ptrd++); *ptri = (T)*(ptrd++); ptrr+=wh; ptri+=wh; }}
23460
 
        ptrr-=whd-w; ptri-=whd-w; }
23461
 
        ptrr-=wh-1; ptri-=wh-1; }
 
31635
        ptrr = Ir.ptr(0,0,0,k);
 
31636
        ptri = Ii.ptr(0,0,0,k);
 
31637
        { cimg_forX(Ir,x) {
 
31638
          cimg_forY(Ir,y) {
 
31639
            cimg_forZ(Ir,z) {
 
31640
              *ptrr = (T)*(ptrd++);
 
31641
              *ptri = (T)*(ptrd++);
 
31642
              ptrr+=wh;
 
31643
              ptri+=wh;
 
31644
            }
 
31645
            ptrr-=whd-w;
 
31646
            ptri-=whd-w;
 
31647
          }
 
31648
          ptrr-=wh-1;
 
31649
          ptri-=wh-1;
 
31650
        }}
23462
31651
      }
23463
31652
      fftw_destroy_plan(data_plan);
23464
31653
      fftw_free(data_in);
23465
31654
#else
23466
 
      if (Ir.depth>1)  FFT('z',inverse);
23467
 
      if (Ir.height>1) FFT('y',inverse);
23468
 
      if (Ir.width>1)  FFT('x',inverse);
 
31655
      if (Ir.depth>1)  FFT('z',invert);
 
31656
      if (Ir.height>1) FFT('y',invert);
 
31657
      if (Ir.width>1)  FFT('x',invert);
23469
31658
#endif
23470
31659
      return *this;
23471
31660
    }
23472
31661
 
23473
 
    //! Return the Fast Fourier Transform of a complex image
23474
 
    CImgList<typename cimg::largest<T,float>::type> get_FFT(const bool inverse=false) const {
23475
 
      typedef typename cimg::largest<T,float>::type restype;
23476
 
      return CImgList<restype>(*this).FFT(inverse);
 
31662
    // Return a list where each image has been split along the specified axis.
 
31663
    CImgList<T> get_split(const char axe='x') const {
 
31664
      CImgList<T> res;
 
31665
      cimglist_for(*this,l) {
 
31666
        CImgList<T> tmp = data[l].get_split(axe);
 
31667
        const unsigned int pos = res.size;
 
31668
        res.insert(tmp.size);
 
31669
        cimglist_for(tmp,i) tmp[i].transfer_to(data[pos+i]);
 
31670
      }
 
31671
      return res;
 
31672
    }
 
31673
 
 
31674
    // Return a list where each image has been split along the specified axis (in-place).
 
31675
    CImgList<T>& split(const char axe='x') {
 
31676
      return get_split(axe).transfer_to(*this);
 
31677
    }
 
31678
 
 
31679
    //! Return a single image which is the concatenation of all images of the current CImgList instance.
 
31680
    /**
 
31681
       \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'.
 
31682
       \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
 
31683
       \return A CImg<T> image corresponding to the concatenation is returned.
 
31684
    **/
 
31685
    CImg<T> get_append(const char axe='x', const char align='c') const {
 
31686
      if (is_empty()) return CImg<T>();
 
31687
      if (size==1) return +((*this)[0]);
 
31688
      unsigned int dx = 0, dy = 0, dz = 0, dv = 0, pos = 0;
 
31689
      CImg<T> res;
 
31690
      switch (cimg::uncase(axe)) {
 
31691
      case 'x': {
 
31692
        switch (cimg::uncase(align)) {
 
31693
        case 'x': { dy = dz = dv = 1; cimglist_for(*this,l) dx+=(*this)[l].size(); } break;
 
31694
        case 'y': { dx = size; dz = dv = 1; cimglist_for(*this,l) dy = cimg::max(dy,(unsigned int)(*this)[l].size()); } break;
 
31695
        case 'z': { dx = size; dy = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 
31696
        case 'v': { dx = size; dy = dz = 1; cimglist_for(*this,l) dv = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 
31697
        default:
 
31698
          cimglist_for(*this,l) {
 
31699
            const CImg<T>& img = (*this)[l];
 
31700
            dx += img.width;
 
31701
            dy = cimg::max(dy,img.height);
 
31702
            dz = cimg::max(dz,img.depth);
 
31703
            dv = cimg::max(dv,img.dim);
 
31704
          }
 
31705
        }
 
31706
        res.assign(dx,dy,dz,dv,0);
 
31707
        switch (cimg::uncase(align)) {
 
31708
        case 'x': {
 
31709
          cimglist_for(*this,l) { res.draw_image(CImg<T>((*this)[l],true).unroll('x'),pos,0,0,0); pos+=(*this)[l].size(); }
 
31710
        } break;
 
31711
        case 'y': {
 
31712
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('y'),pos++,0,0,0);
 
31713
        } break;
 
31714
        case 'z': {
 
31715
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('z'),pos++,0,0,0);
 
31716
        } break;
 
31717
        case 'v': {
 
31718
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('v'),pos++,0,0,0);
 
31719
        } break;
 
31720
        case 'p': {
 
31721
          cimglist_for(*this,l) { res.draw_image((*this)[l],pos,0,0,0); pos+=(*this)[l].width; }
 
31722
        } break;
 
31723
        case 'n': {
 
31724
          cimglist_for(*this,l) { res.draw_image((*this)[l],pos,dy-(*this)[l].height,dz-(*this)[l].depth,dv-(*this)[l].dim); pos+=(*this)[l].width; }
 
31725
        } break;
 
31726
        default : {
 
31727
          cimglist_for(*this,l) { res.draw_image((*this)[l],pos,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2); pos+=(*this)[l].width; }
 
31728
        } break;
 
31729
        }
 
31730
      } break;
 
31731
 
 
31732
      case 'y': {
 
31733
        switch (cimg::uncase(align)) {
 
31734
        case 'x': { dy = size; dz = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
 
31735
        case 'y': { dx = dz = dv = 1; cimglist_for(*this,l) dy+=(*this)[l].size(); } break;
 
31736
        case 'z': { dy = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 
31737
        case 'v': { dy = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
 
31738
        default:
 
31739
          cimglist_for(*this,l) {
 
31740
            const CImg<T>& img = (*this)[l];
 
31741
            dx = cimg::max(dx,img.width);
 
31742
            dy += img.height;
 
31743
            dz = cimg::max(dz,img.depth);
 
31744
            dv = cimg::max(dv,img.dim);
 
31745
          }
 
31746
        }
 
31747
        res.assign(dx,dy,dz,dv,0);
 
31748
        switch (cimg::uncase(align)) {
 
31749
        case 'x': {
 
31750
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('x'),0,pos++,0,0);
 
31751
        } break;
 
31752
        case 'y': {
 
31753
          cimglist_for(*this,l) { res.draw_image(CImg<T>((*this)[l],true).unroll('y'),0,pos,0,0); pos+=(*this)[l].size(); }
 
31754
        } break;
 
31755
        case 'z': {
 
31756
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('z'),0,pos++,0,0);
 
31757
        } break;
 
31758
        case 'v': {
 
31759
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('v'),0,pos++,0,0);
 
31760
        } break;
 
31761
        case 'p': {
 
31762
          cimglist_for(*this,l) { res.draw_image((*this)[l],0,pos,0,0); pos+=(*this)[l].height; }
 
31763
        } break;
 
31764
        case 'n': {
 
31765
          cimglist_for(*this,l) { res.draw_image((*this)[l],dx-(*this)[l].width,pos,dz-(*this)[l].depth,dv-(*this)[l].dim); pos+=(*this)[l].height; }
 
31766
        } break;
 
31767
        default : {
 
31768
          cimglist_for(*this,l) { res.draw_image((*this)[l],(dx-(*this)[l].width)/2,pos,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2);
 
31769
          pos+=(*this)[l].height; }
 
31770
        } break;
 
31771
        }
 
31772
      } break;
 
31773
 
 
31774
      case 'z': {
 
31775
        switch (cimg::uncase(align)) {
 
31776
        case 'x': { dz = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
 
31777
        case 'y': { dz = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 
31778
        case 'z': { dx = dy = dv = 1; cimglist_for(*this,l) dz+=(*this)[l].size(); } break;
 
31779
        case 'v': { dz = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
 
31780
        default :
 
31781
          cimglist_for(*this,l) {
 
31782
            const CImg<T>& img = (*this)[l];
 
31783
            dx = cimg::max(dx,img.width);
 
31784
            dy = cimg::max(dy,img.height);
 
31785
            dz += img.depth;
 
31786
            dv = cimg::max(dv,img.dim);
 
31787
          }
 
31788
        }
 
31789
        res.assign(dx,dy,dz,dv,0);
 
31790
        switch (cimg::uncase(align)) {
 
31791
        case 'x': {
 
31792
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('x'),0,0,pos++,0);
 
31793
        } break;
 
31794
        case 'y': {
 
31795
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('y'),0,0,pos++,0);
 
31796
        } break;
 
31797
        case 'z': {
 
31798
          cimglist_for(*this,l) { res.draw_image(CImg<T>((*this)[l],true).unroll('z'),0,0,pos,0); pos+=(*this)[l].size(); }
 
31799
        } break;
 
31800
        case 'v': {
 
31801
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('v'),0,0,pos++,0);
 
31802
        } break;
 
31803
        case 'p': {
 
31804
          cimglist_for(*this,l) { res.draw_image((*this)[l],0,0,pos,0); pos+=(*this)[l].depth; }
 
31805
        } break;
 
31806
        case 'n': {
 
31807
          cimglist_for(*this,l) { res.draw_image((*this)[l],dx-(*this)[l].width,dy-(*this)[l].height,pos,dv-(*this)[l].dim); pos+=(*this)[l].depth; }
 
31808
        } break;
 
31809
        case 'c': {
 
31810
          cimglist_for(*this,l) { res.draw_image((*this)[l],(dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,pos,(dv-(*this)[l].dim)/2);
 
31811
          pos+=(*this)[l].depth; }
 
31812
        } break;
 
31813
        }
 
31814
      } break;
 
31815
 
 
31816
      case 'v': {
 
31817
        switch (cimg::uncase(align)) {
 
31818
        case 'x': { dv = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
 
31819
        case 'y': { dv = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
 
31820
        case 'z': { dv = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
 
31821
        case 'v': { dx = dy = dz = 1; cimglist_for(*this,l) dv+=(*this)[l].size(); } break;
 
31822
        default :
 
31823
          cimglist_for(*this,l) {
 
31824
            const CImg<T>& img = (*this)[l];
 
31825
            dx = cimg::max(dx,img.width);
 
31826
            dy = cimg::max(dy,img.height);
 
31827
            dz = cimg::max(dz,img.depth);
 
31828
            dv += img.dim;
 
31829
          }
 
31830
        }
 
31831
        res.assign(dx,dy,dz,dv,0);
 
31832
        switch (cimg::uncase(align)) {
 
31833
        case 'x': {
 
31834
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('x'),0,0,0,pos++);
 
31835
        } break;
 
31836
        case 'y': {
 
31837
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('y'),0,0,0,pos++);
 
31838
        } break;
 
31839
        case 'z': {
 
31840
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('v'),0,0,0,pos++);
 
31841
        } break;
 
31842
        case 'v': {
 
31843
          cimglist_for(*this,l) { res.draw_image(CImg<T>((*this)[l],true).unroll('z'),0,0,0,pos); pos+=(*this)[l].size(); }
 
31844
        } break;
 
31845
        case 'p': {
 
31846
          cimglist_for(*this,l) { res.draw_image((*this)[l],0,0,0,pos); pos+=(*this)[l].dim; }
 
31847
        } break;
 
31848
        case 'n': {
 
31849
          cimglist_for(*this,l) { res.draw_image((*this)[l],dx-(*this)[l].width,dy-(*this)[l].height,dz-(*this)[l].depth,pos); pos+=(*this)[l].dim; }
 
31850
        } break;
 
31851
        case 'c': {
 
31852
          cimglist_for(*this,l) { res.draw_image((*this)[l],(dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,pos);
 
31853
          pos+=(*this)[l].dim; }
 
31854
        } break;
 
31855
        }
 
31856
      } break;
 
31857
      default: throw CImgArgumentException("CImgList<%s>::get_append() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
 
31858
      }
 
31859
      return res;
 
31860
    }
 
31861
 
 
31862
    // Create an auto-cropped font (along the X axis) from a input font \p font (internal)
 
31863
    CImgList<T> get_crop_font() const {
 
31864
      CImgList<T> res;
 
31865
      cimglist_for(*this,l) {
 
31866
        const CImg<T>& letter = (*this)[l];
 
31867
        int xmin = letter.width, xmax = 0;
 
31868
        cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
 
31869
        if (xmin>xmax) res.insert(CImg<T>(letter.width,letter.height,1,letter.dim,0));
 
31870
        else res.insert(letter.get_crop(xmin,0,xmax,letter.height-1));
 
31871
      }
 
31872
      res[' '].resize(res['f'].width);
 
31873
      res[' '+256].resize(res['f'].width);
 
31874
      return res;
 
31875
    }
 
31876
 
 
31877
    // Create an auto-cropped font (along the X axis) from a input font \p font (internal).
 
31878
    CImgList<T>& crop_font() {
 
31879
      return get_crop_font().transfer_to(*this);
 
31880
    }
 
31881
 
 
31882
    // Get a font as an image list (internal).
 
31883
    static CImgList<T> get_font(const unsigned int *const font, const unsigned int w, const unsigned int h,
 
31884
                                const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true) {
 
31885
      CImgList<T> res = CImgList<T>(256,w,h,1,3).insert(CImgList<T>(256,w,h,1,1));
 
31886
      const unsigned int *ptr = font;
 
31887
      unsigned int m = 0, val = 0;
 
31888
      for (unsigned int y=0; y<h; ++y)
 
31889
        for (unsigned int x=0; x<256*w; ++x) {
 
31890
          m>>=1; if (!m) { m = 0x80000000; val = *(ptr++); }
 
31891
          CImg<T>& img = res[x/w], &mask = res[x/w+256];
 
31892
          unsigned int xm = x%w;
 
31893
          img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0);
 
31894
        }
 
31895
      if (variable_size) res.crop_font();
 
31896
      if (paddingx || paddingy) cimglist_for(res,l) res[l].resize(res[l].dimx()+paddingx, res[l].dimy()+paddingy,1,-100,0);
 
31897
      return res;
 
31898
    }
 
31899
 
 
31900
    // Get a font as an image list (internal).
 
31901
    CImgList<T>& font(const unsigned int *const font, const unsigned int w, const unsigned int h,
 
31902
                      const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true) {
 
31903
      return get_font(font,w,h,paddingx,paddingy,variable_size).transfer_to(*this);
 
31904
    }
 
31905
 
 
31906
    //! Return a CImg pre-defined font with desired size.
 
31907
    /**
 
31908
       \param font_height = height of the desired font (can be 11,13,24,38 or 57)
 
31909
       \param fixed_size = tell if the font has a fixed or variable width.
 
31910
    **/
 
31911
    static CImgList<T> get_font(const unsigned int font_width, const bool variable_size=true) {
 
31912
      if (font_width<=11) {
 
31913
        static CImgList<T> font7x11, nfont7x11;
 
31914
        if (!variable_size && !font7x11)  font7x11  = get_font(cimg::font7x11,7,11,1,0,false);
 
31915
        if (variable_size  && !nfont7x11) nfont7x11 = get_font(cimg::font7x11,7,11,1,0,true);
 
31916
        return variable_size?nfont7x11:font7x11;
 
31917
      }
 
31918
      if (font_width<=13) {
 
31919
        static CImgList<T> font10x13, nfont10x13;
 
31920
        if (!variable_size && !font10x13)  font10x13  = get_font(cimg::font10x13,10,13,1,0,false);
 
31921
        if (variable_size  && !nfont10x13) nfont10x13 = get_font(cimg::font10x13,10,13,1,0,true);
 
31922
        return variable_size?nfont10x13:font10x13;
 
31923
      }
 
31924
      if (font_width<=17) {
 
31925
        static CImgList<T> font8x17, nfont8x17;
 
31926
        if (!variable_size && !font8x17)  font8x17  = get_font(cimg::font8x17,8,17,1,0,false);
 
31927
        if (variable_size  && !nfont8x17) nfont8x17 = get_font(cimg::font8x17,8,17,1,0,true);
 
31928
        return variable_size?nfont8x17:font8x17;
 
31929
      }
 
31930
      if (font_width<=19) {
 
31931
        static CImgList<T> font10x19, nfont10x19;
 
31932
        if (!variable_size && !font10x19)  font10x19  = get_font(cimg::font10x19,10,19,2,0,false);
 
31933
        if (variable_size  && !nfont10x19) nfont10x19 = get_font(cimg::font10x19,10,19,2,0,true);
 
31934
        return variable_size?nfont10x19:font10x19;
 
31935
      }
 
31936
      if (font_width<=24) {
 
31937
        static CImgList<T> font12x24, nfont12x24;
 
31938
        if (!variable_size && !font12x24)  font12x24  = get_font(cimg::font12x24,12,24,2,0,false);
 
31939
        if (variable_size  && !nfont12x24) nfont12x24 = get_font(cimg::font12x24,12,24,2,0,true);
 
31940
        return variable_size?nfont12x24:font12x24;
 
31941
      }
 
31942
      if (font_width<=32) {
 
31943
        static CImgList<T> font16x32, nfont16x32;
 
31944
        if (!variable_size && !font16x32)  font16x32  = get_font(cimg::font16x32,16,32,2,0,false);
 
31945
        if (variable_size  && !nfont16x32) nfont16x32 = get_font(cimg::font16x32,16,32,2,0,true);
 
31946
        return variable_size?nfont16x32:font16x32;
 
31947
      }
 
31948
      if (font_width<=38) {
 
31949
        static CImgList<T> font19x38, nfont19x38;
 
31950
        if (!variable_size && !font19x38)  font19x38  = get_font(cimg::font19x38,19,38,3,0,false);
 
31951
        if (variable_size  && !nfont19x38) nfont19x38 = get_font(cimg::font19x38,19,38,3,0,true);
 
31952
        return variable_size?nfont19x38:font19x38;
 
31953
      }
 
31954
      static CImgList<T> font29x57, nfont29x57;
 
31955
      if (!variable_size && !font29x57)  font29x57  = get_font(cimg::font29x57,29,57,5,0,false);
 
31956
      if (variable_size  && !nfont29x57) nfont29x57 = get_font(cimg::font29x57,29,57,5,0,true);
 
31957
      return variable_size?nfont29x57:font29x57;
 
31958
    }
 
31959
 
 
31960
    //! Return a CImg pre-defined font with desired size.
 
31961
    CImgList<T>& font(const unsigned int font_width, const bool variable_size=true) {
 
31962
      return get_font(font_width,variable_size).transfer_to(*this);
 
31963
    }
 
31964
 
 
31965
    //! Display the current CImgList instance in an existing CImgDisplay window (by reference).
 
31966
    /**
 
31967
       This function displays the list images of the current CImgList instance into an existing CImgDisplay window.
 
31968
       Images of the list are concatenated in a single temporarly image for visualization purposes.
 
31969
       The function returns immediately.
 
31970
       \param disp : reference to an existing CImgDisplay instance, where the current image list will be displayed.
 
31971
       \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'.
 
31972
       \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
 
31973
       \return A reference to the current CImgList instance is returned.
 
31974
    **/
 
31975
    const CImgList<T>& display(CImgDisplay& disp, const char axe='x', const char align='c') const {
 
31976
      get_append(axe,align).display(disp);
 
31977
      return *this;
 
31978
    }
 
31979
 
 
31980
    //! Display the current CImgList instance in a new display window.
 
31981
    /**
 
31982
       This function opens a new window with a specific title and displays the list images of the current CImgList instance into it.
 
31983
       Images of the list are concatenated in a single temporarly image for visualization purposes.
 
31984
       The function returns when a key is pressed or the display window is closed by the user.
 
31985
       \param title : specify the title of the opening display window.
 
31986
       \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'.
 
31987
       \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
 
31988
       \return A reference to the current CImgList instance is returned.
 
31989
    **/
 
31990
    const CImgList<T>& display(const char *const title=0, const unsigned normalization_type=1,
 
31991
                               const bool display_info=true, const char axe='x', const char align='c') const {
 
31992
      if (is_empty())
 
31993
        throw CImgInstanceException("CImgList<%s>::display() : Instance list (%u,%u) is empty.",
 
31994
                                    pixel_type(),size,data);
 
31995
      const CImg<T> visu = get_append(axe,align);
 
31996
      char ntitle[64] = { 0 };
 
31997
      if (!title) std::sprintf(ntitle,"CImgList<%s>",pixel_type());
 
31998
      if (display_info) print(title?title:ntitle);
 
31999
      visu.display(title?title:ntitle,normalization_type,false);
 
32000
      return *this;
23477
32001
    }
23478
32002
 
23479
32003
    //@}
23480
32004
    //----------------------------------
23481
32005
    //
23482
 
    //! \name Input-Output and Display
 
32006
    //! \name Input-Output
23483
32007
    //@{
23484
32008
    //----------------------------------
23485
32009
 
23486
32010
    //! Print informations about the list on the standard output.
23487
 
    const CImgList& print(const char* title=0, const int print_flag=1) const {
23488
 
      if (print_flag>=0) {
23489
 
        char tmp[1024];
23490
 
        std::fprintf(stderr,"%-8s(this=%p) : { size=%u, data=%p }\n",title?title:"CImgList",
23491
 
                     (void*)this,size,(void*)data);
23492
 
        switch (print_flag) {
23493
 
        case 1: {
23494
 
          cimglist_for(*this,l)
23495
 
            if (l<4 || l>=size-4) {
23496
 
              std::sprintf(tmp,"%s[%d]",title?title:"CImgList",l);
23497
 
              data[l].print(tmp,print_flag);
23498
 
          } else {
23499
 
            if (l==4) std::fprintf(stderr,"...\n");
23500
 
          }
23501
 
        } break;
23502
 
        default: {
23503
 
          cimglist_for(*this,l) {
23504
 
            std::sprintf(tmp,"%s[%d]",title?title:"CImgList",l);
23505
 
            data[l].print(tmp,print_flag);
23506
 
          }
23507
 
        } break;
23508
 
        }
 
32011
    const CImgList<T>& print(const char* title=0, const bool display_stats=true) const {
 
32012
      unsigned long msiz = 0;
 
32013
      cimglist_for(*this,l) msiz += data[l].size();
 
32014
      msiz*=sizeof(T);
 
32015
      const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2);
 
32016
      char ntitle[64] = { 0 };
 
32017
      if (!title) std::sprintf(ntitle,"CImgList<%s>",pixel_type());
 
32018
      std::fprintf(stderr,"%s: this = %p, size = %u [%lu %s], data = (CImg<%s>*)%p.\n",
 
32019
                   title?title:ntitle,(void*)this,size,
 
32020
                   mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
 
32021
                   mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
 
32022
                   pixel_type(),(void*)data);
 
32023
      char tmp[16] = { 0 };
 
32024
      cimglist_for(*this,ll) {
 
32025
        std::sprintf(tmp,"[%d]",ll);
 
32026
        std::fprintf(stderr,"  ");
 
32027
        data[ll].print(tmp,display_stats);
 
32028
        if (ll==3 && size>8) { ll = size-5; std::fprintf(stderr,"  ...\n"); }
23509
32029
      }
23510
32030
      return *this;
23511
32031
    }
23512
32032
 
23513
 
    //! Display informations about the list on the standard output.
23514
 
    const CImgList& print(const int print_flag) const {
23515
 
      return print(0,print_flag);
23516
 
    }
23517
 
 
23518
32033
    //! Load an image list from a file.
23519
 
    CImgList& load(const char *const filename) {
23520
 
      const char *ext = cimg::filename_split(filename);
 
32034
    static CImgList<T> get_load(const char *const filename) {
 
32035
      return CImgList<T>().load(filename);
 
32036
    }
 
32037
 
 
32038
    //! Load an image list from a file (in-place).
 
32039
    CImgList<T>& load(const char *const filename) {
 
32040
      const char *ext = cimg::split_filename(filename);
23521
32041
#ifdef cimglist_load_plugin
23522
32042
      cimglist_load_plugin(filename);
23523
32043
#endif
23524
 
      if (!cimg::strncasecmp(ext,"cimg",4) || !ext[0]) return load_cimg(filename);
23525
 
      if (!cimg::strncasecmp(ext,"rec",3) ||
23526
 
          !cimg::strncasecmp(ext,"par",3)) return load_parrec(filename);
 
32044
#ifdef cimglist_load_plugin1
 
32045
      cimglist_load_plugin1(filename);
 
32046
#endif
 
32047
#ifdef cimglist_load_plugin2
 
32048
      cimglist_load_plugin2(filename);
 
32049
#endif
 
32050
#ifdef cimglist_load_plugin3
 
32051
      cimglist_load_plugin3(filename);
 
32052
#endif
 
32053
#ifdef cimglist_load_plugin4
 
32054
      cimglist_load_plugin4(filename);
 
32055
#endif
 
32056
#ifdef cimglist_load_plugin5
 
32057
      cimglist_load_plugin5(filename);
 
32058
#endif
 
32059
#ifdef cimglist_load_plugin6
 
32060
      cimglist_load_plugin6(filename);
 
32061
#endif
 
32062
#ifdef cimglist_load_plugin7
 
32063
      cimglist_load_plugin7(filename);
 
32064
#endif
 
32065
#ifdef cimglist_load_plugin8
 
32066
      cimglist_load_plugin8(filename);
 
32067
#endif
 
32068
      if (!cimg::strcasecmp(ext,"tif") || !cimg::strncasecmp(ext,"tiff",4)) return load_tiff(filename);
 
32069
      if (!cimg::strcasecmp(ext,"cimg") ||
 
32070
          !cimg::strcasecmp(ext,"cimgz") ||
 
32071
          !ext[0]) return load_cimg(filename);
 
32072
      if (!cimg::strcasecmp(ext,"rec") ||
 
32073
          !cimg::strcasecmp(ext,"par")) return load_parrec(filename);
 
32074
      if (!cimg::strcasecmp(ext,"avi") ||
 
32075
          !cimg::strcasecmp(ext,"mov") ||
 
32076
          !cimg::strcasecmp(ext,"mpg") ||
 
32077
          !cimg::strcasecmp(ext,"mpeg") ||
 
32078
          !cimg::strcasecmp(ext,"ogg") ||
 
32079
          !cimg::strcasecmp(ext,"flv")) return load_ffmpeg(filename);
 
32080
      if (!cimg::strcasecmp(ext,"gz")) return load_gzip_external(filename);
23527
32081
      assign(1);
23528
32082
      data->load(filename);
23529
32083
      return *this;
23530
32084
    }
23531
32085
 
23532
 
    //! Load an image list from a file.
23533
 
    static CImgList get_load(const char *const filename) {
23534
 
      return CImgList<T>().load(filename);
23535
 
    }
 
32086
    // Load an image list from a .cimg file (internal).
 
32087
    CImgList<T>& _load_cimg(std::FILE *const file, const char *const filename) {
 
32088
#ifdef cimg_use_zlib
 
32089
#define _cimgz_load_cimg_case(Tss) { \
 
32090
   Bytef *const cbuf = new Bytef[csiz]; \
 
32091
   cimg::fread(cbuf,csiz,nfile); \
 
32092
   raw.assign(W,H,D,V); \
 
32093
   unsigned long destlen = raw.size()*sizeof(T); \
 
32094
   uncompress((Bytef*)raw.data,&destlen,cbuf,csiz); \
 
32095
   delete[] cbuf; \
 
32096
   const Tss *ptrs = raw.data; \
 
32097
   for (unsigned int off = raw.size(); off; --off) *(ptrd++) = (T)*(ptrs++); \
 
32098
}
 
32099
#else
 
32100
#define _cimgz_load_cimg_case(Tss) \
 
32101
   throw CImgIOException("CImgList<%s>::load_cimg() : File '%s' contains compressed data, zlib must be used",pixel_type(),filename?filename:"(FILE*)");
 
32102
#endif
23536
32103
 
23537
 
    //! Load an image list from a .cimg file.
23538
 
    CImgList& load_cimg(std::FILE *const file, const char *const filename=0) {
23539
 
#define cimg_load_cimg_case(Ts,Tss) \
 
32104
#define _cimg_load_cimg_case(Ts,Tss) \
23540
32105
      if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
23541
32106
        for (unsigned int l=0; l<N; ++l) { \
23542
32107
          j = 0; while((i=std::fgetc(nfile))!='\n') tmp[j++] = (char)i; tmp[j] = '\0'; \
23543
 
          W = H = D = V = 0; \
23544
 
          if (std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
 
32108
          W = H = D = V = 0; csiz = 0; \
 
32109
          if ((err = std::sscanf(tmp,"%u %u %u %u #%u",&W,&H,&D,&V,&csiz))<4) \
23545
32110
            throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
23546
32111
                                  pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
23547
32112
          if (W*H*D*V>0) { \
23548
32113
            CImg<Tss> raw; \
23549
32114
            CImg<T> &img = data[l]; \
23550
32115
            img.assign(W,H,D,V); \
23551
 
            T *ptrd = img.ptr(); \
23552
 
            for (int toread = (int)img.size(); toread>0; ) { \
 
32116
            T *ptrd = img.data; \
 
32117
            if (err==5) _cimgz_load_cimg_case(Tss) \
 
32118
            else for (int toread = (int)img.size(); toread>0; ) { \
23553
32119
              raw.assign(cimg::min(toread,cimg_iobuffer)); \
23554
32120
              cimg::fread(raw.data,raw.width,nfile); \
23555
 
              if (endian!=cimg::endian()) cimg::endian_swap(raw.data,raw.width); \
 
32121
              if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
23556
32122
              toread-=raw.width; \
23557
 
              const Tss *ptrs = raw.ptr(); \
 
32123
              const Tss *ptrs = raw.data; \
23558
32124
              for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
23559
32125
            } \
23560
32126
          } \
23561
32127
        } \
23562
32128
        loaded = true; \
23563
32129
      }
 
32130
 
 
32131
      if (!filename && !file)
 
32132
        throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
 
32133
                                    pixel_type());
23564
32134
      typedef unsigned char uchar;
23565
32135
      typedef unsigned short ushort;
23566
32136
      typedef unsigned int uint;
23567
32137
      typedef unsigned long ulong;
23568
32138
      const int cimg_iobuffer = 12*1024*1024;
23569
32139
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
23570
 
      bool loaded = false, endian = cimg::endian();
 
32140
      bool loaded = false, endian = cimg::endianness();
23571
32141
      char tmp[256], str_pixeltype[256], str_endian[256];
23572
 
      unsigned int j, err, N=0, W, H, D, V;
 
32142
      unsigned int j, err, N=0, W, H, D, V, csiz;
23573
32143
      int i;
23574
32144
      j = 0; while((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
23575
32145
      err = std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
23581
32151
      if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
23582
32152
      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
23583
32153
      assign(N);
23584
 
      cimg_load_cimg_case("bool",bool);
23585
 
      cimg_load_cimg_case("unsigned_char",uchar);
23586
 
      cimg_load_cimg_case("uchar",uchar);
23587
 
      cimg_load_cimg_case("char",char);
23588
 
      cimg_load_cimg_case("unsigned_short",ushort);
23589
 
      cimg_load_cimg_case("ushort",ushort);
23590
 
      cimg_load_cimg_case("short",short);
23591
 
      cimg_load_cimg_case("unsigned_int",uint);
23592
 
      cimg_load_cimg_case("uint",uint);
23593
 
      cimg_load_cimg_case("int",int);
23594
 
      cimg_load_cimg_case("unsigned_long",ulong);
23595
 
      cimg_load_cimg_case("ulong",ulong);
23596
 
      cimg_load_cimg_case("long",long);
23597
 
      cimg_load_cimg_case("float",float);
23598
 
      cimg_load_cimg_case("double",double);
 
32154
      _cimg_load_cimg_case("bool",bool);
 
32155
      _cimg_load_cimg_case("unsigned_char",uchar);
 
32156
      _cimg_load_cimg_case("uchar",uchar);
 
32157
      _cimg_load_cimg_case("char",char);
 
32158
      _cimg_load_cimg_case("unsigned_short",ushort);
 
32159
      _cimg_load_cimg_case("ushort",ushort);
 
32160
      _cimg_load_cimg_case("short",short);
 
32161
      _cimg_load_cimg_case("unsigned_int",uint);
 
32162
      _cimg_load_cimg_case("uint",uint);
 
32163
      _cimg_load_cimg_case("int",int);
 
32164
      _cimg_load_cimg_case("unsigned_long",ulong);
 
32165
      _cimg_load_cimg_case("ulong",ulong);
 
32166
      _cimg_load_cimg_case("long",long);
 
32167
      _cimg_load_cimg_case("float",float);
 
32168
      _cimg_load_cimg_case("double",double);
23599
32169
      if (!loaded) {
23600
32170
        if (!file) cimg::fclose(nfile);
23601
32171
        throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
23606
32176
    }
23607
32177
 
23608
32178
    //! Load an image list from a .cimg file.
23609
 
    CImgList& load_cimg(const char *const filename) {
23610
 
      return load_cimg(0,filename);
23611
 
    }
23612
 
 
23613
 
    //! Load an image list from a .cimg file.
23614
 
    static CImgList get_load_cimg(std::FILE *const file, const char *const filename=0) {
23615
 
      return CImgList<T>().load_cimg(file,filename);
23616
 
    }
23617
 
 
23618
 
    //! Load an image list from a .cimg file.
23619
 
    static CImgList get_load_cimg(const char *const filename) {
23620
 
      return CImgList<T>().load_cimg(0,filename);
23621
 
    }
23622
 
 
23623
 
    // Load a sub-image list from a .cimg file (inner routine).
23624
 
    CImgList& load_cimg(std::FILE *const file, const char *const filename,
23625
 
                        const unsigned int n0, const unsigned int n1,
23626
 
                        const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
23627
 
                        const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
23628
 
#define cimg_load_cimg_case2(Ts,Tss) \
 
32179
    static CImgList<T> get_load_cimg(const char *const filename) {
 
32180
      return CImgList<T>().load_cimg(filename);
 
32181
    }
 
32182
 
 
32183
    //! Load an image list from a .cimg file.
 
32184
    static CImgList<T> get_load_cimg(std::FILE *const file) {
 
32185
      return CImgList<T>().load_cimg(file);
 
32186
    }
 
32187
 
 
32188
    //! Load an image list from a .cimg file (in-place).
 
32189
    CImgList<T>& load_cimg(const char *const filename) {
 
32190
      return _load_cimg(0,filename);
 
32191
    }
 
32192
 
 
32193
    //! Load an image list from a .cimg file (in-place).
 
32194
    CImgList<T>& load_cimg(std::FILE *const file) {
 
32195
      return _load_cimg(file,0);
 
32196
    }
 
32197
 
 
32198
    // Load a sub-image list from a non compressed .cimg file (internal).
 
32199
    CImgList<T>& _load_cimg(std::FILE *const file, const char *const filename,
 
32200
                            const unsigned int n0, const unsigned int n1,
 
32201
                            const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 
32202
                            const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 
32203
#define _cimg_load_cimg_case2(Ts,Tss) \
23629
32204
      if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
23630
32205
        for (unsigned int l=0; l<=nn1; ++l) { \
23631
32206
          j = 0; while((i=std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j]='\0'; \
23644
32219
              CImg<Tss> raw(1+nx1-x0); \
23645
32220
              CImg<T> &img = data[l-n0]; \
23646
32221
              img.assign(1+nx1-x0,1+ny1-y0,1+nz1-z0,1+nv1-v0); \
23647
 
              T *ptrd = img.ptr(); \
 
32222
              T *ptrd = img.data; \
23648
32223
              const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
23649
32224
              if (skipvb) std::fseek(nfile,skipvb,SEEK_CUR); \
23650
32225
              for (unsigned int v=1+nv1-v0; v; --v) { \
23657
32232
                    const unsigned int skipxb = x0*sizeof(Tss); \
23658
32233
                    if (skipxb) std::fseek(nfile,skipxb,SEEK_CUR); \
23659
32234
                    cimg::fread(raw.data,raw.width,nfile); \
23660
 
                    if (endian!=cimg::endian()) cimg::endian_swap(raw.data,raw.width); \
23661
 
                    const Tss *ptrs = raw.ptr(); \
 
32235
                    if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
 
32236
                    const Tss *ptrs = raw.data; \
23662
32237
                    for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
23663
32238
                    const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
23664
32239
                    if (skipxe) std::fseek(nfile,skipxe,SEEK_CUR); \
23676
32251
        } \
23677
32252
        loaded = true; \
23678
32253
      }
 
32254
 
 
32255
      if (!filename && !file)
 
32256
        throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
 
32257
                                    pixel_type());
23679
32258
      typedef unsigned char uchar;
23680
32259
      typedef unsigned short ushort;
23681
32260
      typedef unsigned int uint;
23685
32264
                                    "(%u,%u,%u,%u)->(%u,%u,%u,%u).",pixel_type(),filename?filename:"(FILE*)",
23686
32265
                                    n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
23687
32266
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
23688
 
      bool loaded = false, endian = cimg::endian();
 
32267
      bool loaded = false, endian = cimg::endianness();
23689
32268
      char tmp[256], str_pixeltype[256], str_endian[256];
23690
32269
      unsigned int j, err, N, W, H, D, V;
23691
32270
      int i;
23700
32279
      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
23701
32280
      const unsigned int nn1 = n1>=N?N-1:n1;
23702
32281
      assign(1+nn1-n0);
23703
 
      cimg_load_cimg_case2("bool",bool);
23704
 
      cimg_load_cimg_case2("unsigned_char",uchar);
23705
 
      cimg_load_cimg_case2("uchar",uchar);
23706
 
      cimg_load_cimg_case2("char",char);
23707
 
      cimg_load_cimg_case2("unsigned_short",ushort);
23708
 
      cimg_load_cimg_case2("ushort",ushort);
23709
 
      cimg_load_cimg_case2("short",short);
23710
 
      cimg_load_cimg_case2("unsigned_int",uint);
23711
 
      cimg_load_cimg_case2("uint",uint);
23712
 
      cimg_load_cimg_case2("int",int);
23713
 
      cimg_load_cimg_case2("unsigned_long",ulong);
23714
 
      cimg_load_cimg_case2("ulong",ulong);
23715
 
      cimg_load_cimg_case2("long",long);
23716
 
      cimg_load_cimg_case2("float",float);
23717
 
      cimg_load_cimg_case2("double",double);
 
32282
      _cimg_load_cimg_case2("bool",bool);
 
32283
      _cimg_load_cimg_case2("unsigned_char",uchar);
 
32284
      _cimg_load_cimg_case2("uchar",uchar);
 
32285
      _cimg_load_cimg_case2("char",char);
 
32286
      _cimg_load_cimg_case2("unsigned_short",ushort);
 
32287
      _cimg_load_cimg_case2("ushort",ushort);
 
32288
      _cimg_load_cimg_case2("short",short);
 
32289
      _cimg_load_cimg_case2("unsigned_int",uint);
 
32290
      _cimg_load_cimg_case2("uint",uint);
 
32291
      _cimg_load_cimg_case2("int",int);
 
32292
      _cimg_load_cimg_case2("unsigned_long",ulong);
 
32293
      _cimg_load_cimg_case2("ulong",ulong);
 
32294
      _cimg_load_cimg_case2("long",long);
 
32295
      _cimg_load_cimg_case2("float",float);
 
32296
      _cimg_load_cimg_case2("double",double);
23718
32297
      if (!loaded) {
23719
32298
        if (!file) cimg::fclose(nfile);
23720
32299
        throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
23724
32303
      return *this;
23725
32304
    }
23726
32305
 
23727
 
    //! Load a sub-image list from a .cimg file.
23728
 
    CImgList& load_cimg(std::FILE *const file,
23729
 
                        const unsigned int n0, const unsigned int n1,
23730
 
                        const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
23731
 
                        const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
23732
 
      return load_cimg(file,0,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
23733
 
    }
23734
 
 
23735
 
    //! Load a sub-image list from a .cimg file.
23736
 
    CImgList& load_cimg(const char *const filename,
23737
 
                        const unsigned int n0, const unsigned int n1,
23738
 
                        const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
23739
 
                        const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
23740
 
      return load_cimg(0,filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 
32306
    //! Load a sub-image list from a non compressed .cimg file.
 
32307
    static CImgList<T> get_load_cimg(const char *const filename,
 
32308
                                     const unsigned int n0, const unsigned int n1,
 
32309
                                     const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 
32310
                                     const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 
32311
      return CImgList<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 
32312
    }
 
32313
 
 
32314
    //! Load a sub-image list from a non compressed .cimg file.
 
32315
    static CImgList<T> get_load_cimg(std::FILE *const file,
 
32316
                                     const unsigned int n0, const unsigned int n1,
 
32317
                                     const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 
32318
                                     const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 
32319
      return CImgList<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 
32320
    }
 
32321
 
 
32322
    //! Load a sub-image list from a non compressed .cimg file (in-place).
 
32323
    CImgList<T>& load_cimg(const char *const filename,
 
32324
                           const unsigned int n0, const unsigned int n1,
 
32325
                           const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 
32326
                           const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 
32327
      return _load_cimg(0,filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
 
32328
    }
 
32329
 
 
32330
    //! Load a sub-image list from a non compressed .cimg file (in-place).
 
32331
    CImgList<T>& load_cimg(std::FILE *const file,
 
32332
                           const unsigned int n0, const unsigned int n1,
 
32333
                           const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
 
32334
                           const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
 
32335
      return _load_cimg(file,0,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
23741
32336
    }
23742
32337
 
23743
32338
    //! Load an image list from a PAR/REC (Philips) file.
23744
 
    CImgList& load_parrec(const char *const filename) {
 
32339
    static CImgList<T> get_load_parrec(const char *const filename) {
 
32340
      return CImgList<T>().load_parrec(filename);
 
32341
    }
 
32342
 
 
32343
    //! Load an image list from a PAR/REC (Philips) file (in-place).
 
32344
    CImgList<T>& load_parrec(const char *const filename) {
 
32345
      if (!filename)
 
32346
        throw CImgArgumentException("CImgList<%s>::load_parrec() : Cannot load (null) filename.",
 
32347
                                    pixel_type());
23745
32348
      char body[1024], filenamepar[1024], filenamerec[1024];
23746
 
      const char *ext = cimg::filename_split(filename,body);
 
32349
      const char *ext = cimg::split_filename(filename,body);
23747
32350
      if (!cimg::strncmp(ext,"par",3)) { std::strcpy(filenamepar,filename); std::sprintf(filenamerec,"%s.rec",body); }
23748
32351
      if (!cimg::strncmp(ext,"PAR",3)) { std::strcpy(filenamepar,filename); std::sprintf(filenamerec,"%s.REC",body); }
23749
32352
      if (!cimg::strncmp(ext,"rec",3)) { std::strcpy(filenamerec,filename); std::sprintf(filenamepar,"%s.par",body); }
23759
32362
      do {
23760
32363
        unsigned int sn,sizex,sizey,pixsize;
23761
32364
        float rs,ri,ss;
23762
 
        err=std::fscanf(file,"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\n]",&sn,&pixsize,&sizex,&sizey,&ri,&rs,&ss);
 
32365
        err = std::fscanf(file,"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\n]",&sn,&pixsize,&sizex,&sizey,&ri,&rs,&ss);
23763
32366
        if (err==7) {
23764
 
          st_slices.insert(CImg<float>::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,ri,rs,ss,0));
23765
 
          unsigned int i; for (i=0; i<st_global.size && sn<=st_global[i][2]; ++i);
 
32367
          st_slices.insert(CImg<float>::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,
 
32368
                                               ri,rs,ss,0));
 
32369
          unsigned int i; for (i=0; i<st_global.size && sn<=st_global[i][2]; ++i) {}
23766
32370
          if (i==st_global.size) st_global.insert(CImg<unsigned int>::vector(sizex,sizey,sn));
23767
32371
          else {
23768
32372
            CImg<unsigned int> &vec = st_global[i];
23794
32398
        case 8: {
23795
32399
          CImg<unsigned char> buf(sizex,sizey);
23796
32400
          cimg::fread(buf.data,sizex*sizey,file2);
23797
 
          if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey);
 
32401
          if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
23798
32402
          CImg<T>& img = (*this)[imn];
23799
32403
          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
23800
32404
        } break;
23801
32405
        case 16: {
23802
32406
          CImg<unsigned short> buf(sizex,sizey);
23803
32407
          cimg::fread(buf.data,sizex*sizey,file2);
23804
 
          if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey);
 
32408
          if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
23805
32409
          CImg<T>& img = (*this)[imn];
23806
32410
          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
23807
32411
        } break;
23808
32412
        case 32: {
23809
32413
          CImg<unsigned int> buf(sizex,sizey);
23810
32414
          cimg::fread(buf.data,sizex*sizey,file2);
23811
 
          if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey);
 
32415
          if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
23812
32416
          CImg<T>& img = (*this)[imn];
23813
32417
          cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
23814
32418
        } break;
23828
32432
      return *this;
23829
32433
    }
23830
32434
 
23831
 
    //! Load an image list from a PAR/REC (Philips) file.
23832
 
    static CImgList get_load_parrec(const char *const filename) {
23833
 
      return CImgList<T>().load_parrec(filename);
23834
 
    }
23835
 
 
23836
 
 
23837
 
    //! Load an image sequence from a YUV file.
23838
 
    CImgList& load_yuv(std::FILE *const file, const char *const filename,
23839
 
                       const unsigned int sizex, const unsigned int sizey=1,
23840
 
                       const unsigned int first_frame=0, const int last_frame=-1,
23841
 
                       const bool yuv2rgb=false) {
 
32435
    // Load an image sequence from a YUV file (internal).
 
32436
    CImgList<T>& _load_yuv(std::FILE *const file, const char *const filename,
 
32437
                           const unsigned int sizex, const unsigned int sizey,
 
32438
                           const unsigned int first_frame, const unsigned int last_frame,
 
32439
                           const unsigned int step_frame, const bool yuv2rgb) {
 
32440
      if (!filename && !file)
 
32441
        throw CImgArgumentException("CImgList<%s>::load_yuv() : Cannot load (null) filename.",
 
32442
                                    pixel_type());
23842
32443
      if (sizex%2 || sizey%2)
23843
32444
        throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', image dimensions along X and Y must be "
23844
32445
                                    "even numbers (given are %ux%u)\n",pixel_type(),filename?filename:"(unknown)",sizex,sizey);
23845
32446
      if (!sizex || !sizey)
23846
32447
        throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given image sequence size (%u,%u) is invalid",
23847
32448
                                    pixel_type(),filename?filename:"(unknown)",sizex,sizey);
23848
 
      if (last_frame>0 && first_frame>(unsigned int)last_frame)
23849
 
        throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given first frame %u is posterior to last frame %d.",
23850
 
                                    pixel_type(),filename?filename:"(unknown)",first_frame,last_frame);
23851
 
      if (!sizex || !sizey)
23852
 
        throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given frame size (%u,%u) is invalid.",
23853
 
                                    pixel_type(),filename?filename:"(unknown)",sizex,sizey);
 
32449
 
 
32450
      const unsigned int
 
32451
        nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 
32452
        nlast_frame = first_frame<last_frame?last_frame:first_frame,
 
32453
        nstep_frame = step_frame?step_frame:1;
 
32454
 
23854
32455
      CImg<unsigned char> tmp(sizex,sizey,1,3), UV(sizex/2,sizey/2,1,2);
23855
32456
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
23856
32457
      bool stopflag = false;
23857
32458
      int err;
23858
 
      if (first_frame) {
23859
 
        err = std::fseek(nfile,first_frame*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
 
32459
      if (nfirst_frame) {
 
32460
        err = std::fseek(nfile,nfirst_frame*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
23860
32461
        if (err) {
23861
32462
          if (!file) cimg::fclose(nfile);
23862
32463
          throw CImgIOException("CImgList<%s>::load_yuv() : File '%s' doesn't contain frame number %u "
23863
 
                                "(out of range error).",pixel_type(),filename?filename:"(FILE*)",first_frame);
 
32464
                                "(out of range error).",pixel_type(),filename?filename:"(FILE*)",nfirst_frame);
23864
32465
        }
23865
32466
      }
23866
32467
      unsigned int frame;
23867
 
      for (frame = first_frame; !stopflag && (last_frame<0 || frame<=(unsigned int)last_frame); ++frame) {
 
32468
      for (frame = nfirst_frame; !stopflag && frame<=nlast_frame; frame+=nstep_frame) {
23868
32469
        tmp.fill(0);
23869
 
        // TRY to read the luminance, don't replace by cimg::fread !
23870
 
        err = (int)std::fread((void*)(tmp.ptr()),1,(size_t)(tmp.width*tmp.height),nfile);
 
32470
        // *TRY* to read the luminance part, do not replace by cimg::fread !
 
32471
        err = (int)std::fread((void*)(tmp.data),1,(size_t)(tmp.width*tmp.height),nfile);
23871
32472
        if (err!=(int)(tmp.width*tmp.height)) {
23872
32473
          stopflag = true;
23873
32474
          if (err>0) cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
23875
32476
                                pixel_type(),filename?filename:"(unknown)",sizex,sizey);
23876
32477
        } else {
23877
32478
          UV.fill(0);
23878
 
          // TRY to read the luminance, don't replace by cimg::fread !
23879
 
          err = (int)std::fread((void*)(UV.ptr()),1,(size_t)(UV.size()),nfile);
 
32479
          // *TRY* to read the luminance part, do not replace by cimg::fread !
 
32480
          err = (int)std::fread((void*)(UV.data),1,(size_t)(UV.size()),nfile);
23880
32481
          if (err!=(int)(UV.size())) {
23881
32482
            stopflag = true;
23882
32483
            if (err>0) cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
23884
32485
                                  pixel_type(),filename?filename:"(unknown)",sizex,sizey);
23885
32486
          } else {
23886
32487
            cimg_forXY(UV,x,y) {
23887
 
              const int x2=2*x, y2=2*y;
 
32488
              const int x2 = x*2, y2 = y*2;
23888
32489
              tmp(x2,y2,1) = tmp(x2+1,y2,1) = tmp(x2,y2+1,1) = tmp(x2+1,y2+1,1) = UV(x,y,0);
23889
32490
              tmp(x2,y2,2) = tmp(x2+1,y2,2) = tmp(x2,y2+1,2) = tmp(x2+1,y2+1,2) = UV(x,y,1);
23890
32491
            }
23891
32492
            if (yuv2rgb) tmp.YCbCrtoRGB();
23892
32493
            insert(tmp);
 
32494
            if (nstep_frame>1) std::fseek(nfile,(nstep_frame-1)*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
23893
32495
          }
23894
32496
        }
23895
32497
      }
23896
 
      if (stopflag && last_frame>=0 && frame!=(unsigned int)last_frame)
 
32498
      if (stopflag && nlast_frame!=~0U && frame!=nlast_frame)
23897
32499
        cimg::warn("CImgList<%s>::load_yuv() : File '%s', frame %d not reached since only %u frames were found in the file.",
23898
 
                   pixel_type(),filename?filename:"(unknown)",last_frame,frame-1,filename);
 
32500
                   pixel_type(),filename?filename:"(unknown)",nlast_frame,frame-1,filename);
23899
32501
      if (!file) cimg::fclose(nfile);
23900
32502
      return *this;
23901
32503
    }
23902
32504
 
23903
32505
    //! Load an image sequence from a YUV file.
23904
 
    CImgList& load_yuv(const char *const filename,
23905
 
                       const unsigned int sizex, const unsigned int sizey,
23906
 
                       const unsigned int first_frame=0, const int last_frame=-1,
23907
 
                       const bool yuv2rgb=false) {
23908
 
      return load_yuv(0,filename,sizex,sizey,first_frame,last_frame,yuv2rgb);
23909
 
    }
23910
 
 
23911
 
    //! Load an image sequence from a YUV file.
23912
 
    static CImgList get_load_yuv(std::FILE *const file, const char *const filename,
23913
 
                                 const unsigned int sizex, const unsigned int sizey=1,
23914
 
                                 const unsigned int first_frame=0, const int last_frame=-1,
23915
 
                                 const bool yuv2rgb=false) {
23916
 
      return CImgList<T>().load_yuv(file,filename,sizex,sizey,first_frame,last_frame,yuv2rgb);
23917
 
    }
23918
 
 
23919
 
    //! Load an image sequence from a YUV file.
23920
 
    static CImgList get_load_yuv(const char *const filename,
23921
 
                                 const unsigned int sizex, const unsigned int sizey=1,
23922
 
                                 const unsigned int first_frame=0, const int last_frame=-1,
23923
 
                                 const bool yuv2rgb=false) {
23924
 
      return CImgList<T>().load_yuv(0,filename,sizex,sizey,first_frame,last_frame,yuv2rgb);
23925
 
    }
23926
 
 
23927
 
    //! Load a 3D object from a .OFF file (GeomView 3D object files).
23928
 
    template<typename tf,typename tc>
23929
 
    CImgList& load_off(std::FILE *const file, const char *const filename,
23930
 
                       CImgList<tf>& primitives, CImgList<tc>& colors,
23931
 
                       const bool invert_faces=false) {
23932
 
      return assign(CImg<T>::get_load_off(file,filename,primitives,colors,invert_faces).get_split('x'));
23933
 
    }
23934
 
 
23935
 
    //! Load a 3D object from a .OFF file (GeomView 3D object files).
23936
 
    template<typename tf,typename tc>
23937
 
    CImgList& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors,
23938
 
                       const bool invert_faces=false) {
23939
 
      return load_off(0,filename,primitives,colors,invert_faces);
23940
 
    }
23941
 
 
23942
 
    //! Load a 3D object from a .OFF file (GeomView 3D object files).
23943
 
    template<typename tf,typename tc>
23944
 
      static CImgList<T> get_load_off(std::FILE *const file, const char *const filename,
23945
 
                                      CImgList<tf>& primitives, CImgList<tc>& colors,
23946
 
                                      const bool invert_faces=false) {
23947
 
      return CImgList<T>().load_off(file,filename,primitives,colors,invert_faces);
23948
 
    }
23949
 
 
23950
 
    //! Load a 3D object from a .OFF file (GeomView 3D object files).
23951
 
    template<typename tf,typename tc>
 
32506
    static CImgList<T> get_load_yuv(const char *const filename,
 
32507
                                    const unsigned int sizex, const unsigned int sizey=1,
 
32508
                                    const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
32509
                                    const unsigned int step_frame=1, const bool yuv2rgb=true) {
 
32510
      return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 
32511
    }
 
32512
 
 
32513
    //! Load an image sequence from a YUV file.
 
32514
    static CImgList<T> get_load_yuv(std::FILE *const file,
 
32515
                                    const unsigned int sizex, const unsigned int sizey=1,
 
32516
                                    const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
32517
                                    const unsigned int step_frame=1, const bool yuv2rgb=true) {
 
32518
      return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 
32519
    }
 
32520
 
 
32521
    //! Load an image sequence from a YUV file (in-place).
 
32522
    CImgList<T>& load_yuv(const char *const filename,
 
32523
                          const unsigned int sizex, const unsigned int sizey,
 
32524
                          const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
32525
                          const unsigned int step_frame=1, const bool yuv2rgb=true) {
 
32526
      return _load_yuv(0,filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 
32527
    }
 
32528
 
 
32529
    //! Load an image sequence from a YUV file (in-place).
 
32530
    CImgList<T>& load_yuv(std::FILE *const file,
 
32531
                          const unsigned int sizex, const unsigned int sizey,
 
32532
                          const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
32533
                          const unsigned int step_frame=1, const bool yuv2rgb=true) {
 
32534
      return _load_yuv(file,0,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
 
32535
    }
 
32536
 
 
32537
    //! Load an image from a video file, using ffmpeg libraries.
 
32538
    static CImgList<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
32539
                                       const unsigned int step_frame=1, const bool pixel_format=true) {
 
32540
      return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format);
 
32541
    }
 
32542
 
 
32543
    //! Load an image from a video file, using ffmpeg libraries (in-place).
 
32544
    // This piece of code has been firstly created by David Starweather (starkdg(at)users(dot)sourceforge(dot)net)
 
32545
    // I modified it afterwards for direct inclusion in the library core.
 
32546
    CImgList<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
32547
                             const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false) {
 
32548
      if (!filename)
 
32549
        throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : Cannot load (null) filename.",
 
32550
                                    pixel_type());
 
32551
      const unsigned int
 
32552
        nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 
32553
        nlast_frame = first_frame<last_frame?last_frame:first_frame,
 
32554
        nstep_frame = step_frame?step_frame:1;
 
32555
      assign();
 
32556
 
 
32557
#ifndef cimg_use_ffmpeg
 
32558
      if ((nfirst_frame || nlast_frame!=~0U || nstep_frame>1) && (pixel_format || !pixel_format) || resume)
 
32559
        throw CImgArgumentException("CImg<%s>::load_tiff() : File '%s', reading sub-frames from a video file requires the use of ffmpeg.\n"
 
32560
                                    "('cimg_use_ffmpeg' must be defined).",pixel_type(),filename);
 
32561
      return load_ffmpeg_external(filename);
 
32562
#else
 
32563
      const unsigned int ffmpeg_pixfmt = pixel_format?PIX_FMT_RGB24:PIX_FMT_GRAY8;
 
32564
      static bool first_time = true;
 
32565
      static AVFormatContext *format_ctx = 0;
 
32566
      static AVCodecContext *codec_ctx = 0;
 
32567
      static AVCodec *codec = 0;
 
32568
      static AVFrame *avframe = 0, *converted_frame = 0;
 
32569
      static unsigned int vstream = 0;
 
32570
      if (first_time) { av_register_all(); first_time = false; }
 
32571
 
 
32572
      if (resume) {
 
32573
        if (!format_ctx || !codec_ctx || !codec || !avframe || !converted_frame)
 
32574
          throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : File '%s', cannot resume due to unallocated FFMPEG structures.",
 
32575
                                      pixel_type(),filename);
 
32576
      } else {
 
32577
        // Allocate ffmpeg structures.
 
32578
        if (!format_ctx) format_ctx = new AVFormatContext; else av_close_input_file(format_ctx);
 
32579
        if (!codec_ctx) codec_ctx = new AVCodecContext;
 
32580
        if (!codec) codec = new AVCodec;
 
32581
        if (!avframe) avframe = avcodec_alloc_frame();
 
32582
        if (!converted_frame) converted_frame = avcodec_alloc_frame();
 
32583
        if (!format_ctx || !codec_ctx || !codec || !avframe || !converted_frame) {
 
32584
          cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot allocate FFMPEG structures.\n"
 
32585
                     "Trying with external ffmpeg executable.",pixel_type(),filename);
 
32586
          if (format_ctx) { delete format_ctx; format_ctx = 0; }
 
32587
          if (codec_ctx) { delete codec_ctx; codec_ctx = 0; }
 
32588
          if (codec) { delete codec; codec = 0; }
 
32589
          if (avframe) { delete avframe; avframe = 0; }
 
32590
          if (converted_frame) { delete converted_frame; converted_frame = 0; }
 
32591
          return load_ffmpeg_external(filename);
 
32592
        }
 
32593
 
 
32594
        // Open video file, find video stream and codec.
 
32595
        if (av_open_input_file(&format_ctx,filename,0,0,0)!=0)
 
32596
          throw CImgIOException("CImgList<%s>::load_ffmpeg() : File '%s' cannot be opened.",pixel_type(),filename);
 
32597
        if (av_find_stream_info(format_ctx)<0) {
 
32598
          cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve stream information.\n"
 
32599
                     "Trying with external ffmpeg executable.",pixel_type(),filename);
 
32600
          return load_ffmpeg_external(filename);
 
32601
        }
 
32602
#if cimg_debug>=3
 
32603
        dump_format(format_ctx,0,0,0);
 
32604
#endif
 
32605
        for (vstream = 0; vstream<format_ctx->nb_streams && format_ctx->streams[vstream]->codec->codec_type!=CODEC_TYPE_VIDEO; ) ++vstream;
 
32606
        if (vstream==format_ctx->nb_streams) {
 
32607
          cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve video stream.\n"
 
32608
                     "Trying with external ffmpeg executable.",pixel_type(),filename);
 
32609
          av_close_input_file(format_ctx);
 
32610
          return load_ffmpeg_external(filename);
 
32611
        }
 
32612
        codec_ctx = format_ctx->streams[vstream]->codec;
 
32613
        codec = avcodec_find_decoder(codec_ctx->codec_id);
 
32614
        if (!codec) {
 
32615
          cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot find video codec.\n"
 
32616
                     "Trying with external ffmpeg executable.",pixel_type(),filename);
 
32617
          return load_ffmpeg_external(filename);
 
32618
        }
 
32619
        if (avcodec_open(codec_ctx,codec)<0) { // Open codec
 
32620
          cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot open video codec.\n"
 
32621
                     "Trying with external ffmpeg executable.",pixel_type(),filename);
 
32622
          return load_ffmpeg_external(filename);
 
32623
        }
 
32624
      }
 
32625
 
 
32626
      // Read video frames
 
32627
      const unsigned int numBytes = avpicture_get_size(ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
 
32628
      uint8_t *const buffer = new uint8_t[numBytes];
 
32629
      avpicture_fill((AVPicture *)converted_frame,buffer,ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
 
32630
 
 
32631
      const T foo = (T)0;
 
32632
      AVPacket packet;
 
32633
      for (unsigned int frame = 0, next_frame = nfirst_frame; frame<=nlast_frame && av_read_frame(format_ctx,&packet)>=0; ) {
 
32634
        if (packet.stream_index==(int)vstream) {
 
32635
          int frame_finished = 0;
 
32636
          avcodec_decode_video(codec_ctx,avframe,&frame_finished,packet.data,packet.size);
 
32637
          if (frame_finished) {
 
32638
            if (frame==next_frame) {
 
32639
              SwsContext *c = sws_getContext(codec_ctx->width,codec_ctx->height,codec_ctx->pix_fmt,codec_ctx->width,
 
32640
                                             codec_ctx->height,ffmpeg_pixfmt,1,0,0,0);
 
32641
              sws_scale(c,avframe->data,avframe->linesize,0,codec_ctx->height,converted_frame->data,converted_frame->linesize);
 
32642
              if (ffmpeg_pixfmt==PIX_FMT_RGB24) {
 
32643
                CImg<unsigned char> next_image(*converted_frame->data,3,codec_ctx->width,codec_ctx->height,1,true);
 
32644
                insert(next_image.get_permute_axes("yzvx",foo));
 
32645
              } else {
 
32646
                CImg<unsigned char> next_image(*converted_frame->data,1,codec_ctx->width,codec_ctx->height,1,true);
 
32647
                insert(next_image.get_permute_axes("yzvx",foo));
 
32648
              }
 
32649
              next_frame+=nstep_frame;
 
32650
            }
 
32651
            ++frame;
 
32652
          }
 
32653
          av_free_packet(&packet);
 
32654
          if (next_frame>nlast_frame) break;
 
32655
        }
 
32656
      }
 
32657
      delete[] buffer;
 
32658
      return *this;
 
32659
#endif
 
32660
    }
 
32661
 
 
32662
    //! Load an image from a video file (MPEG,AVI) using the external tool 'ffmpeg'.
 
32663
    static CImgList<T> get_load_ffmpeg_external(const char *const filename) {
 
32664
      return CImgList<T>().load_ffmpeg_external(filename);
 
32665
    }
 
32666
 
 
32667
    //! Load an image from a video file (MPEG,AVI) using the external tool 'ffmpeg (in-place).
 
32668
    CImgList<T>& load_ffmpeg_external(const char *const filename) {
 
32669
      if (!filename)
 
32670
        throw CImgArgumentException("CImgList<%s>::load_ffmpeg_external() : Cannot load (null) filename.",
 
32671
                                    pixel_type());
 
32672
      char command[1024], filetmp[512], filetmp2[512];
 
32673
      std::FILE *file = 0;
 
32674
      do {
 
32675
        std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 
32676
        std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
 
32677
        if ((file=std::fopen(filetmp2,"rb"))!=0) std::fclose(file);
 
32678
      } while (file);
 
32679
      std::sprintf(filetmp2,"%s_%%6d.ppm",filetmp);
 
32680
#if cimg_OS!=2
 
32681
      std::sprintf(command,"%s -i \"%s\" %s >/dev/null 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
 
32682
#else
 
32683
      std::sprintf(command,"%s -i \"%s\" %s",cimg::ffmpeg_path(),filename,filetmp2);
 
32684
#endif
 
32685
      cimg::system(command,0);
 
32686
      const unsigned int odebug = cimg::exception_mode();
 
32687
      cimg::exception_mode() = 0;
 
32688
      assign();
 
32689
      unsigned int i = 1;
 
32690
      for (bool stopflag = false; !stopflag; ++i) {
 
32691
        std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,i);
 
32692
        CImg<T> img;
 
32693
        try { img.load_pnm(filetmp2); }
 
32694
        catch (CImgException&) { stopflag = true; }
 
32695
        if (img) { insert(img); std::remove(filetmp2); }
 
32696
      }
 
32697
      cimg::exception_mode() = odebug;
 
32698
      if (is_empty())
 
32699
        throw CImgIOException("CImgList<%s>::load_ffmpeg_external() : Failed to open image sequence '%s'.\n"
 
32700
                              "Check the filename and if the 'ffmpeg' tool is installed on your system.",
 
32701
                              pixel_type(),filename);
 
32702
      return *this;
 
32703
    }
 
32704
 
 
32705
    //! Load a gzipped list, using external tool 'gunzip'.
 
32706
    static CImgList<T> get_load_gzip_external(const char *const filename) {
 
32707
      return CImgList<T>().load_gzip_external(filename);
 
32708
    }
 
32709
 
 
32710
    //! Load a gzipped list, using external tool 'gunzip' (in-place).
 
32711
    CImgList<T>& load_gzip_external(const char *const filename) {
 
32712
      if (!filename)
 
32713
        throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
 
32714
                              pixel_type());
 
32715
      char command[1024], filetmp[512], body[512];
 
32716
      const char
 
32717
        *ext = cimg::split_filename(filename,body),
 
32718
        *ext2 = cimg::split_filename(body,0);
 
32719
      std::FILE *file = 0;
 
32720
      do {
 
32721
        if (!cimg::strcasecmp(ext,"gz")) {
 
32722
          if (*ext2) std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
32723
                                  cimg::filenamerand(),ext2);
 
32724
          else std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
32725
                                  cimg::filenamerand());
 
32726
        } else {
 
32727
           if (*ext) std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
32728
                                  cimg::filenamerand(),ext);
 
32729
           else std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
32730
                             cimg::filenamerand());
 
32731
        }
 
32732
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
 
32733
      } while (file);
 
32734
      std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
 
32735
      cimg::system(command);
 
32736
      if (!(file = std::fopen(filetmp,"rb"))) {
 
32737
        cimg::fclose(cimg::fopen(filename,"r"));
 
32738
        throw CImgIOException("CImg<%s>::load_gzip_external() : Failed to open file '%s'.",
 
32739
                              pixel_type(),filename);
 
32740
      } else cimg::fclose(file);
 
32741
      load(filetmp);
 
32742
      std::remove(filetmp);
 
32743
      return *this;
 
32744
    }
 
32745
 
 
32746
    //! Load a 3D object from a .OFF file.
 
32747
    template<typename tf, typename tc>
23952
32748
      static CImgList<T> get_load_off(const char *const filename,
23953
32749
                                      CImgList<tf>& primitives, CImgList<tc>& colors,
23954
32750
                                      const bool invert_faces=false) {
23955
 
      return CImgList<T>().load_off(0,filename,primitives,colors,invert_faces);
 
32751
      return CImg<T>().load_off(filename,primitives,colors,invert_faces).get_split('x');
 
32752
    }
 
32753
 
 
32754
    //! Load a 3D object from a .OFF file (in-place).
 
32755
    template<typename tf, typename tc>
 
32756
    CImgList<T>& load_off(const char *const filename,
 
32757
                          CImgList<tf>& primitives, CImgList<tc>& colors,
 
32758
                          const bool invert_faces=false) {
 
32759
      return get_load_off(filename,primitives,colors,invert_faces).transfer_to(*this);
 
32760
    }
 
32761
 
 
32762
    //! Load a TIFF file.
 
32763
    static CImgList<T> get_load_tiff(const char *const filename,
 
32764
                                     const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
32765
                                     const unsigned int step_frame=1) {
 
32766
      return CImgList<T>().load_tiff(filename,first_frame,last_frame,step_frame);
 
32767
    }
 
32768
 
 
32769
    //! Load a TIFF file (in-place).
 
32770
    CImgList<T>& load_tiff(const char *const filename,
 
32771
                           const unsigned int first_frame=0, const unsigned int last_frame=~0U,
 
32772
                           const unsigned int step_frame=1) {
 
32773
      const unsigned int
 
32774
        nfirst_frame = first_frame<last_frame?first_frame:last_frame,
 
32775
        nstep_frame = step_frame?step_frame:1;
 
32776
      unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
 
32777
#ifndef cimg_use_tiff
 
32778
      if (nfirst_frame || nlast_frame!=~0U || nstep_frame!=1)
 
32779
        throw CImgArgumentException("CImgList<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
 
32780
                                    "('cimg_use_tiff' must be defined).",pixel_type(),filename);
 
32781
      return assign(CImg<T>::get_load_tiff(filename));
 
32782
#else
 
32783
      TIFF *tif = TIFFOpen(filename,"r");
 
32784
      if (tif) {
 
32785
        unsigned int nb_images = 0;
 
32786
        do ++nb_images; while (TIFFReadDirectory(tif));
 
32787
        if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
 
32788
          cimg::warn("CImgList<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
 
32789
                     pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
 
32790
        if (nfirst_frame>=nb_images) return assign();
 
32791
        if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
 
32792
        assign(1+(nlast_frame-nfirst_frame)/nstep_frame);
 
32793
        TIFFSetDirectory(tif,0);
 
32794
#if cimg_debug>=3
 
32795
        TIFFSetWarningHandler(0);
 
32796
        TIFFSetErrorHandler(0);
 
32797
#endif
 
32798
        cimglist_for(*this,l) data[l]._load_tiff(tif,nfirst_frame+l*nstep_frame);
 
32799
        TIFFClose(tif);
 
32800
      } else throw CImgException("CImgList<%s>::load_tiff() : File '%s', cannot open file.",pixel_type(),filename);
 
32801
      return *this;
 
32802
#endif
23956
32803
    }
23957
32804
 
23958
32805
    //! Save an image list into a file.
23959
32806
    /**
23960
32807
       Depending on the extension of the given filename, a file format is chosen for the output file.
23961
32808
    **/
23962
 
    const CImgList& save(const char *const filename, const int number=-1) const {
 
32809
    const CImgList<T>& save(const char *const filename, const int number=-1) const {
23963
32810
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::save() : Instance list (%u,%p) is empty (file '%s').",
23964
32811
                                                  pixel_type(),size,data,filename);
23965
32812
      if (!filename) throw CImgArgumentException("CImg<%s>::save() : Instance list (%u,%p), specified filename is (null).",
23966
32813
                                                 pixel_type(),size,data);
23967
 
      const char *ext = cimg::filename_split(filename);
 
32814
      const char *ext = cimg::split_filename(filename);
23968
32815
      char nfilename[1024];
23969
32816
      const char *const fn = (number>=0)?cimg::filename_number(filename,number,6,nfilename):filename;
23970
32817
#ifdef cimglist_save_plugin
23971
32818
      cimglist_save_plugin(fn);
23972
32819
#endif
23973
 
      if (!cimg::strncasecmp(ext,"cimg",4) || !ext[0]) return save_cimg(fn);
23974
 
      if (!cimg::strncasecmp(ext,"yuv",3)) return save_yuv(fn,true);
23975
 
      if (size==1) data[0].save(fn,-1);
23976
 
      else cimglist_for(*this,l) data[l].save(fn,l);
 
32820
#ifdef cimglist_save_plugin1
 
32821
      cimglist_save_plugin1(fn);
 
32822
#endif
 
32823
#ifdef cimglist_save_plugin2
 
32824
      cimglist_save_plugin2(fn);
 
32825
#endif
 
32826
#ifdef cimglist_save_plugin3
 
32827
      cimglist_save_plugin3(fn);
 
32828
#endif
 
32829
#ifdef cimglist_save_plugin4
 
32830
      cimglist_save_plugin4(fn);
 
32831
#endif
 
32832
#ifdef cimglist_save_plugin5
 
32833
      cimglist_save_plugin5(fn);
 
32834
#endif
 
32835
#ifdef cimglist_save_plugin6
 
32836
      cimglist_save_plugin6(fn);
 
32837
#endif
 
32838
#ifdef cimglist_save_plugin7
 
32839
      cimglist_save_plugin7(fn);
 
32840
#endif
 
32841
#ifdef cimglist_save_plugin8
 
32842
      cimglist_save_plugin8(fn);
 
32843
#endif
 
32844
#ifdef cimg_use_tiff
 
32845
      if (!cimg::strcasecmp(ext,"tif") || !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
 
32846
#endif
 
32847
      if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
 
32848
      if (!cimg::strcasecmp(ext,"cimg") || !ext[0]) return save_cimg(fn,false);
 
32849
      if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
 
32850
      if (!cimg::strcasecmp(ext,"avi") ||
 
32851
          !cimg::strcasecmp(ext,"mov") ||
 
32852
          !cimg::strcasecmp(ext,"mpg") ||
 
32853
          !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg_external(fn);
 
32854
      if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
 
32855
      if (size==1) data[0].save(fn,-1); else cimglist_for(*this,l) data[l].save(fn,l);
23977
32856
      return *this;
23978
32857
    }
23979
32858
 
23980
 
    //! Save an image sequence into a YUV file
23981
 
    const CImgList& save_yuv(std::FILE *const file, const char *const filename=0, const bool rgb2yuv=true) const {
 
32859
    // Save an image sequence into a YUV file (internal).
 
32860
    const CImgList<T>& _save_yuv(std::FILE *const file, const char *const filename, const bool rgb2yuv) const {
23982
32861
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::save_yuv() : Instance list (%u,%p) is empty (file '%s').",
23983
32862
                                                  pixel_type(),size,data,filename?filename:"(unknown)");
23984
32863
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_yuv() : Instance list (%u,%p), specified file is (null).",
23991
32870
      cimglist_for(*this,l) {
23992
32871
        CImg<unsigned char> YCbCr((*this)[l]);
23993
32872
        if (rgb2yuv) YCbCr.RGBtoYCbCr();
23994
 
        cimg::fwrite(YCbCr.ptr(),YCbCr.width*YCbCr.height,nfile);
 
32873
        cimg::fwrite(YCbCr.data,YCbCr.width*YCbCr.height,nfile);
23995
32874
        cimg::fwrite(YCbCr.get_resize(YCbCr.width/2, YCbCr.height/2,1,3,3).ptr(0,0,0,1),
23996
32875
                     YCbCr.width*YCbCr.height/2,nfile);
23997
32876
      }
23999
32878
      return *this;
24000
32879
    }
24001
32880
 
24002
 
    //! Save an image sequence into a YUV file
24003
 
    const CImgList& save_yuv(const char *const filename=0, const bool rgb2yuv=true) const {
24004
 
      return save_yuv(0,filename,rgb2yuv);
 
32881
    //! Save an image sequence into a YUV file.
 
32882
    const CImgList<T>& save_yuv(const char *const filename=0, const bool rgb2yuv=true) const {
 
32883
      return _save_yuv(0,filename,rgb2yuv);
 
32884
    }
 
32885
 
 
32886
    //! Save an image sequence into a YUV file.
 
32887
    const CImgList<T>& save_yuv(std::FILE *const file, const bool rgb2yuv=true) const {
 
32888
      return _save_yuv(file,0,rgb2yuv);
24005
32889
    }
24006
32890
 
24007
32891
    //! Save an image list into a .cimg file.
24010
32894
       \param filename : name of the output file.
24011
32895
       \return A reference to the current CImgList instance is returned.
24012
32896
    **/
24013
 
    const CImgList& save_cimg(std::FILE *const file, const char *const filename=0) const {
24014
 
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::save_cimg() : Instance list (%u,%p) is empty (file '%s').",
 
32897
    const CImgList<T>& _save_cimg(std::FILE *const file, const char *const filename, const bool compression) const {
 
32898
      if (is_empty())
 
32899
        throw CImgInstanceException("CImgList<%s>::save_cimg() : Instance list (%u,%p) is empty (file '%s').",
24015
32900
                                                  pixel_type(),size,data,filename?filename:"(unknown)");
24016
 
      if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
 
32901
      if (!file && !filename)
 
32902
        throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
24017
32903
                                                          pixel_type(),size,data);
24018
32904
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
24019
 
      const char *const ptype = pixel_type(), *const etype = cimg::endian()?"big":"little";
 
32905
      const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little";
24020
32906
      if (!cimg::strncmp(ptype,"unsigned",8)) std::fprintf(nfile,"%u unsigned_%s %s_endian\n",size,ptype+9,etype);
24021
32907
      else std::fprintf(nfile,"%u %s %s_endian\n",size,ptype,etype);
24022
32908
      cimglist_for(*this,l) {
24023
32909
        const CImg<T>& img = data[l];
24024
 
        std::fprintf(nfile,"%u %u %u %u\n",img.width,img.height,img.depth,img.dim);
 
32910
        std::fprintf(nfile,"%u %u %u %u",img.width,img.height,img.depth,img.dim);
24025
32911
        if (img.data) {
24026
 
          if (cimg::endian()) {
24027
 
            CImg<T> tmp(img);
24028
 
            cimg::endian_swap(tmp.data,tmp.size());
24029
 
            cimg::fwrite(tmp.data,img.width*img.height*img.depth*img.dim,nfile);
24030
 
          } else cimg::fwrite(img.data,img.width*img.height*img.depth*img.dim,nfile);
 
32912
          CImg<T> tmp;
 
32913
          if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp.data,tmp.size()); }
 
32914
          const CImg<T>& ref = cimg::endianness()?tmp:img;
 
32915
          bool compressed = false;
 
32916
          if (compression) {
 
32917
#ifdef cimg_use_zlib
 
32918
            const unsigned long siz = sizeof(T)*ref.size();
 
32919
            unsigned long csiz = siz + siz/10 + 16;
 
32920
            Bytef *const cbuf = new Bytef[csiz];
 
32921
            if (compress(cbuf,&csiz,(Bytef*)ref.data,siz)) {
 
32922
              cimg::warn("CImgList<%s>::save_cimg() : File '%s', failed to save compressed data.\n Data will be saved uncompressed.",
 
32923
                       pixel_type());
 
32924
              compressed = false;
 
32925
            } else {
 
32926
              std::fprintf(nfile," #%lu\n",csiz);
 
32927
              cimg::fwrite(cbuf,csiz,nfile);
 
32928
              delete[] cbuf;
 
32929
              compressed = true;
 
32930
            }
 
32931
#else
 
32932
            cimg::warn("CImgList<%s>::save_cimg() : File '%s', cannot save compressed data unless zlib is used ('cimg_use_zlib' must be defined).\n Data will be saved uncompressed.",
 
32933
                       pixel_type(),filename?filename:"(FILE*)");
 
32934
            compressed = false;
 
32935
#endif
 
32936
          }
 
32937
          if (!compressed) {
 
32938
            std::fputc('\n',nfile);
 
32939
            cimg::fwrite(ref.data,ref.size(),nfile);
 
32940
          }
24031
32941
        }
24032
32942
      }
24033
32943
      if (!file) cimg::fclose(nfile);
24035
32945
    }
24036
32946
 
24037
32947
    //! Save an image list into a CImg file (RAW binary file + simple header)
24038
 
    const CImgList& save_cimg(const char *const filename) const {
24039
 
      return save_cimg(0,filename);
 
32948
    const CImgList<T>& save_cimg(std::FILE *file, const bool compress=false) const {
 
32949
      return _save_cimg(file,0,compress);
 
32950
    }
 
32951
 
 
32952
    //! Save an image list into a CImg file (RAW binary file + simple header)
 
32953
    const CImgList<T>& save_cimg(const char *const filename, const bool compress=false) const {
 
32954
      return _save_cimg(0,filename,compress);
24040
32955
    }
24041
32956
 
24042
32957
    // Insert the instance image into into an existing .cimg file, at specified coordinates.
24043
 
    const CImgList& save_cimg(std::FILE *const file, const char *const filename,
24044
 
                              const unsigned int n0,
24045
 
                              const unsigned int x0, const unsigned int y0,
24046
 
                              const unsigned int z0, const unsigned int v0) const {
24047
 
#define cimg_save_cimg_case(Ts,Tss) \
 
32958
    const CImgList<T>& _save_cimg(std::FILE *const file, const char *const filename,
 
32959
                                 const unsigned int n0,
 
32960
                                 const unsigned int x0, const unsigned int y0,
 
32961
                                 const unsigned int z0, const unsigned int v0) const {
 
32962
#define _cimg_save_cimg_case(Ts,Tss) \
24048
32963
      if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \
24049
32964
        for (unsigned int l=0; l<lmax; ++l) { \
24050
32965
          j = 0; while((i=std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j]='\0'; \
24056
32971
            if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
24057
32972
            else { \
24058
32973
              const CImg<T>& img = (*this)[l-n0]; \
24059
 
              const T *ptrs = img.ptr(); \
 
32974
              const T *ptrs = img.data; \
24060
32975
              const unsigned int \
24061
32976
                x1 = x0 + img.width - 1, \
24062
32977
                y1 = y0 + img.height - 1, \
24080
32995
                    if (skipxb) std::fseek(nfile,skipxb,SEEK_CUR); \
24081
32996
                    raw.assign(ptrs, raw.width); \
24082
32997
                    ptrs+=img.width; \
24083
 
                    if (endian) cimg::endian_swap(raw.data,raw.width); \
 
32998
                    if (endian) cimg::invert_endianness(raw.data,raw.width); \
24084
32999
                    cimg::fwrite(raw.data,raw.width,nfile); \
24085
33000
                    const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
24086
33001
                    if (skipxe) std::fseek(nfile,skipxe,SEEK_CUR); \
24107
33022
      typedef unsigned int uint;
24108
33023
      typedef unsigned long ulong;
24109
33024
      std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+");
24110
 
      bool saved = false, endian = cimg::endian();
 
33025
      bool saved = false, endian = cimg::endianness();
24111
33026
      char tmp[256], str_pixeltype[256], str_endian[256];
24112
33027
      unsigned int j, err, N, W, H, D, V;
24113
33028
      int i;
24121
33036
      if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
24122
33037
      else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
24123
33038
      const unsigned int lmax = cimg::min(N,n0+size);
24124
 
      cimg_save_cimg_case("bool",bool);
24125
 
      cimg_save_cimg_case("unsigned_char",uchar);
24126
 
      cimg_save_cimg_case("uchar",uchar);
24127
 
      cimg_save_cimg_case("char",char);
24128
 
      cimg_save_cimg_case("unsigned_short",ushort);
24129
 
      cimg_save_cimg_case("ushort",ushort);
24130
 
      cimg_save_cimg_case("short",short);
24131
 
      cimg_save_cimg_case("unsigned_int",uint);
24132
 
      cimg_save_cimg_case("uint",uint);
24133
 
      cimg_save_cimg_case("int",int);
24134
 
      cimg_save_cimg_case("unsigned_long",ulong);
24135
 
      cimg_save_cimg_case("ulong",ulong);
24136
 
      cimg_save_cimg_case("long",long);
24137
 
      cimg_save_cimg_case("float",float);
24138
 
      cimg_save_cimg_case("double",double);
 
33039
      _cimg_save_cimg_case("bool",bool);
 
33040
      _cimg_save_cimg_case("unsigned_char",uchar);
 
33041
      _cimg_save_cimg_case("uchar",uchar);
 
33042
      _cimg_save_cimg_case("char",char);
 
33043
      _cimg_save_cimg_case("unsigned_short",ushort);
 
33044
      _cimg_save_cimg_case("ushort",ushort);
 
33045
      _cimg_save_cimg_case("short",short);
 
33046
      _cimg_save_cimg_case("unsigned_int",uint);
 
33047
      _cimg_save_cimg_case("uint",uint);
 
33048
      _cimg_save_cimg_case("int",int);
 
33049
      _cimg_save_cimg_case("unsigned_long",ulong);
 
33050
      _cimg_save_cimg_case("ulong",ulong);
 
33051
      _cimg_save_cimg_case("long",long);
 
33052
      _cimg_save_cimg_case("float",float);
 
33053
      _cimg_save_cimg_case("double",double);
24139
33054
      if (!saved) {
24140
33055
        if (!file) cimg::fclose(nfile);
24141
33056
        throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', cannot save images of pixels coded as '%s'.",
24146
33061
    }
24147
33062
 
24148
33063
    //! Insert the instance image into into an existing .cimg file, at specified coordinates.
24149
 
    const CImgList& save_cimg(std::FILE *const file,
24150
 
                              const unsigned int n0,
24151
 
                              const unsigned int x0, const unsigned int y0,
24152
 
                              const unsigned int z0, const unsigned int v0) const {
24153
 
      return save_cimg(file,0,n0,x0,y0,z0,v0);
 
33064
    const CImgList<T>& save_cimg(const char *const filename,
 
33065
                                 const unsigned int n0,
 
33066
                                 const unsigned int x0, const unsigned int y0,
 
33067
                                 const unsigned int z0, const unsigned int v0) const {
 
33068
      return _save_cimg(0,filename,n0,x0,y0,z0,v0);
24154
33069
    }
24155
33070
 
24156
33071
    //! Insert the instance image into into an existing .cimg file, at specified coordinates.
24157
 
    const CImgList& save_cimg(const char *const filename,
24158
 
                              const unsigned int n0,
24159
 
                              const unsigned int x0, const unsigned int y0,
24160
 
                              const unsigned int z0, const unsigned int v0) const {
24161
 
      return save_cimg(0,filename,n0,x0,y0,z0,v0);
 
33072
    const CImgList<T>& save_cimg(std::FILE *const file,
 
33073
                                 const unsigned int n0,
 
33074
                                 const unsigned int x0, const unsigned int y0,
 
33075
                                 const unsigned int z0, const unsigned int v0) const {
 
33076
      return _save_cimg(file,0,n0,x0,y0,z0,v0);
24162
33077
    }
24163
33078
 
24164
 
    // Create an empty .cimg file with specified dimensions (inner routine)
24165
 
    static void save_empty_cimg(std::FILE *const file, const char *const filename,
 
33079
    // Create an empty .cimg file with specified dimensions (internal)
 
33080
    static void _save_empty_cimg(std::FILE *const file, const char *const filename,
24166
33081
                                const unsigned int nb,
24167
 
                                const unsigned int dx, const unsigned int dy=1,
24168
 
                                const unsigned int dz=1, const unsigned int dv=1) {
 
33082
                                const unsigned int dx, const unsigned int dy,
 
33083
                                const unsigned int dz, const unsigned int dv) {
24169
33084
      std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
24170
33085
      const unsigned int siz = dx*dy*dz*dv*sizeof(T);
24171
33086
      std::fprintf(nfile,"%u %s\n",nb,pixel_type());
24177
33092
    }
24178
33093
 
24179
33094
    //! Create an empty .cimg file with specified dimensions.
 
33095
    static void save_empty_cimg(const char *const filename,
 
33096
                                const unsigned int nb,
 
33097
                                const unsigned int dx, const unsigned int dy=1,
 
33098
                                const unsigned int dz=1, const unsigned int dv=1) {
 
33099
      return _save_empty_cimg(0,filename,nb,dx,dy,dz,dv);
 
33100
    }
 
33101
 
 
33102
    //! Create an empty .cimg file with specified dimensions.
24180
33103
    static void save_empty_cimg(std::FILE *const file,
24181
33104
                                const unsigned int nb,
24182
33105
                                const unsigned int dx, const unsigned int dy=1,
24183
33106
                                const unsigned int dz=1, const unsigned int dv=1) {
24184
 
      return save_empty_cimg(file,0,nb,dx,dy,dz,dv);
24185
 
    }
24186
 
 
24187
 
    //! Create an empty .cimg file with specified dimensions.
24188
 
    static void save_empty_cimg(const char *const filename,
24189
 
                                const unsigned int nb,
24190
 
                                const unsigned int dx, const unsigned int dy=1,
24191
 
                                const unsigned int dz=1, const unsigned int dv=1) {
24192
 
      return save_empty_cimg(0,filename,nb,dx,dy,dz,dv);
24193
 
    }
24194
 
 
24195
 
    //! Save an image list into a OFF file.
24196
 
    template<typename tf, typename tc>
24197
 
    const CImgList& save_off(std::FILE *const file, const char *const filename,
24198
 
                             const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
24199
 
      get_append('x','y').save_off(file,filename,primitives,colors,invert_faces);
24200
 
      return *this;
24201
 
    }
24202
 
 
24203
 
    //! Save an image list into a OFF file.
24204
 
    template<typename tf, typename tc>
24205
 
    const CImgList& save_off(const char *const filename,
24206
 
                             const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
24207
 
      return save_off(0,filename,primitives,colors,invert_faces);
24208
 
    }
24209
 
 
24210
 
    // Return a list where each image has been split along the specified axis
24211
 
    CImgList<T> get_split(const char axe='x') const {
24212
 
      CImgList res;
24213
 
      cimglist_for(*this,l) res.insert(data[l].get_split(axe));
24214
 
      return res;
24215
 
    }
24216
 
 
24217
 
    // In-place version of the previous function.
24218
 
    CImgList& split(const char axe='x') {
24219
 
      return get_split(axe).swap(*this);
24220
 
    }
24221
 
 
24222
 
    //! Return a single image which is the concatenation of all images of the current CImgList instance.
24223
 
    /**
24224
 
       \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'.
24225
 
       \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
24226
 
       \return A CImg<T> image corresponding to the concatenation is returned.
24227
 
    **/
24228
 
    CImg<T> get_append(const char axe='x', const char align='c') const {
24229
 
      if (is_empty()) return CImg<T>();
24230
 
      if (size==1) return (*this)[0];
24231
 
      unsigned int dx = 0, dy = 0, dz = 0, dv = 0, pos = 0;
24232
 
      CImg<T> res;
24233
 
      switch(cimg::uncase(axe)) {
24234
 
      case 'x': {
24235
 
        switch (cimg::uncase(align)) {
24236
 
        case 'x': { dy = dz = dv = 1; cimglist_for(*this,l) dx+=(*this)[l].size(); } break;
24237
 
        case 'y': { dx = size; dz = dv = 1; cimglist_for(*this,l) dy = cimg::max(dy,(unsigned int)(*this)[l].size()); } break;
24238
 
        case 'z': { dx = size; dy = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
24239
 
        case 'v': { dx = size; dy = dz = 1; cimglist_for(*this,l) dv = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
24240
 
        default:
24241
 
          cimglist_for(*this,l) {
24242
 
            const CImg<T>& img = (*this)[l];
24243
 
            dx += img.width;
24244
 
            dy = cimg::max(dy,img.height);
24245
 
            dz = cimg::max(dz,img.depth);
24246
 
            dv = cimg::max(dv,img.dim);
24247
 
          }
24248
 
        }
24249
 
        res.assign(dx,dy,dz,dv,0);
24250
 
        switch (cimg::uncase(align)) {
24251
 
        case 'x': {
24252
 
          cimglist_for(*this,l) { res.draw_image(CImg<T>((*this)[l],true).unroll('x'),pos,0,0,0); pos+=(*this)[l].size(); }
24253
 
        } break;
24254
 
        case 'y': {
24255
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('y'),pos++,0,0,0);
24256
 
        } break;
24257
 
        case 'z': {
24258
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('z'),pos++,0,0,0);
24259
 
        } break;
24260
 
        case 'v': {
24261
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('v'),pos++,0,0,0);
24262
 
        } break;
24263
 
        case 'p': {
24264
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],pos,0,0,0); pos+=(*this)[l].width; }
24265
 
        } break;
24266
 
        case 'n': {
24267
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],pos,dy-(*this)[l].height,dz-(*this)[l].depth,dv-(*this)[l].dim); pos+=(*this)[l].width; }
24268
 
        } break;
24269
 
        default : {
24270
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],pos,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2); pos+=(*this)[l].width; }
24271
 
        } break;
24272
 
        }
24273
 
      } break;
24274
 
 
24275
 
      case 'y': {
24276
 
        switch (cimg::uncase(align)) {
24277
 
        case 'x': { dy = size; dz = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
24278
 
        case 'y': { dx = dz = dv = 1; cimglist_for(*this,l) dy+=(*this)[l].size(); } break;
24279
 
        case 'z': { dy = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
24280
 
        case 'v': { dy = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
24281
 
        default:
24282
 
          cimglist_for(*this,l) {
24283
 
            const CImg<T>& img = (*this)[l];
24284
 
            dx = cimg::max(dx,img.width);
24285
 
            dy += img.height;
24286
 
            dz = cimg::max(dz,img.depth);
24287
 
            dv = cimg::max(dv,img.dim);
24288
 
          }
24289
 
        }
24290
 
        res.assign(dx,dy,dz,dv,0);
24291
 
        switch (cimg::uncase(align)) {
24292
 
        case 'x': {
24293
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('x'),0,pos++,0,0);
24294
 
        } break;
24295
 
        case 'y': {
24296
 
          cimglist_for(*this,l) { res.draw_image(CImg<T>((*this)[l],true).unroll('y'),0,pos,0,0); pos+=(*this)[l].size(); }
24297
 
        } break;
24298
 
        case 'z': {
24299
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('z'),0,pos++,0,0);
24300
 
        } break;
24301
 
        case 'v': {
24302
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('v'),0,pos++,0,0);
24303
 
        } break;
24304
 
        case 'p': {
24305
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],0,pos,0,0); pos+=(*this)[l].height; }
24306
 
        } break;
24307
 
        case 'n': {
24308
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],dx-(*this)[l].width,pos,dz-(*this)[l].depth,dv-(*this)[l].dim); pos+=(*this)[l].height; }
24309
 
        } break;
24310
 
        default : {
24311
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],(dx-(*this)[l].width)/2,pos,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2);
24312
 
          pos+=(*this)[l].height; }
24313
 
        } break;
24314
 
        }
24315
 
      } break;
24316
 
 
24317
 
      case 'z': {
24318
 
        switch (cimg::uncase(align)) {
24319
 
        case 'x': { dz = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
24320
 
        case 'y': { dz = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
24321
 
        case 'z': { dx = dy = dv = 1; cimglist_for(*this,l) dz+=(*this)[l].size(); } break;
24322
 
        case 'v': { dz = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
24323
 
        default :
24324
 
          cimglist_for(*this,l) {
24325
 
            const CImg<T>& img = (*this)[l];
24326
 
            dx = cimg::max(dx,img.width);
24327
 
            dy = cimg::max(dy,img.height);
24328
 
            dz += img.depth;
24329
 
            dv = cimg::max(dv,img.dim);
24330
 
          }
24331
 
        }
24332
 
        res.assign(dx,dy,dz,dv,0);
24333
 
        switch (cimg::uncase(align)) {
24334
 
        case 'x': {
24335
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('x'),0,0,pos++,0);
24336
 
        } break;
24337
 
        case 'y': {
24338
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('y'),0,0,pos++,0);
24339
 
        } break;
24340
 
        case 'z': {
24341
 
          cimglist_for(*this,l) { res.draw_image(CImg<T>((*this)[l],true).unroll('z'),0,0,pos,0); pos+=(*this)[l].size(); }
24342
 
        } break;
24343
 
        case 'v': {
24344
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('v'),0,0,pos++,0);
24345
 
        } break;
24346
 
        case 'p': {
24347
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],0,0,pos,0); pos+=(*this)[l].depth; }
24348
 
        } break;
24349
 
        case 'n': {
24350
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],dx-(*this)[l].width,dy-(*this)[l].height,pos,dv-(*this)[l].dim); pos+=(*this)[l].depth; }
24351
 
        } break;
24352
 
        case 'c': {
24353
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],(dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,pos,(dv-(*this)[l].dim)/2);
24354
 
          pos+=(*this)[l].depth; }
24355
 
        } break;
24356
 
        }
24357
 
      } break;
24358
 
 
24359
 
      case 'v': {
24360
 
        switch (cimg::uncase(align)) {
24361
 
        case 'x': { dv = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
24362
 
        case 'y': { dv = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
24363
 
        case 'z': { dv = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
24364
 
        case 'v': { dx = dy = dz = 1; cimglist_for(*this,l) dv+=(*this)[l].size(); } break;
24365
 
        default :
24366
 
          cimglist_for(*this,l) {
24367
 
            const CImg<T>& img = (*this)[l];
24368
 
            dx = cimg::max(dx,img.width);
24369
 
            dy = cimg::max(dy,img.height);
24370
 
            dz = cimg::max(dz,img.depth);
24371
 
            dv += img.dim;
24372
 
          }
24373
 
        }
24374
 
        res.assign(dx,dy,dz,dv,0);
24375
 
        switch (cimg::uncase(align)) {
24376
 
        case 'x': {
24377
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('x'),0,0,0,pos++);
24378
 
        } break;
24379
 
        case 'y': {
24380
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('y'),0,0,0,pos++);
24381
 
        } break;
24382
 
        case 'z': {
24383
 
          cimglist_for(*this,l) res.draw_image(CImg<T>((*this)[l],true).unroll('v'),0,0,0,pos++);
24384
 
        } break;
24385
 
        case 'v': {
24386
 
          cimglist_for(*this,l) { res.draw_image(CImg<T>((*this)[l],true).unroll('z'),0,0,0,pos); pos+=(*this)[l].size(); }
24387
 
        } break;
24388
 
        case 'p': {
24389
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],0,0,0,pos); pos+=(*this)[l].dim; }
24390
 
        } break;
24391
 
        case 'n': {
24392
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],dx-(*this)[l].width,dy-(*this)[l].height,dz-(*this)[l].depth,pos); pos+=(*this)[l].dim; }
24393
 
        } break;
24394
 
        case 'c': {
24395
 
          cimglist_for(*this,l) { res.draw_image((*this)[l],(dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,pos);
24396
 
          pos+=(*this)[l].dim; }
24397
 
        } break;
24398
 
        }
24399
 
      } break;
24400
 
      default: throw CImgArgumentException("CImgList<%s>::get_append() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe);
24401
 
      }
24402
 
      return res;
24403
 
    }
24404
 
 
24405
 
    // Create an auto-cropped font (along the X axis) from a input font \p font.
24406
 
    CImgList<T> get_crop_font() const {
24407
 
      CImgList<T> res;
 
33107
      return _save_empty_cimg(file,0,nb,dx,dy,dz,dv);
 
33108
    }
 
33109
 
 
33110
    //! Save a file in TIFF format.
 
33111
#ifdef cimg_use_tiff
 
33112
    const CImgList<T>& save_tiff(const char *const filename) const {
 
33113
      if (is_empty()) throw CImgInstanceException("CImgList<%s>::save_tiff() : File '%s', instance list (%u,%p) is empty.",
 
33114
                                                  pixel_type(),filename,size,data);
 
33115
      if (!filename) throw CImgArgumentException("CImgList<%s>::save_tiff() : Specified filename is (null) for instance list (%u,%p).",
 
33116
                                                 pixel_type(),size,data);
 
33117
      TIFF *tif = TIFFOpen(filename,"w");
 
33118
      if (tif) {
 
33119
        for (unsigned int dir=0, l=0; l<size; ++l) {
 
33120
          const CImg<T>& img = (*this)[l];
 
33121
          if (img) {
 
33122
            if (img.depth==1) img._save_tiff(tif,dir++);
 
33123
            else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++);
 
33124
          }
 
33125
        }
 
33126
        TIFFClose(tif);
 
33127
      } else throw CImgException("CImgList<%s>::save_tiff() : File '%s', error while opening stream for tiff file.",
 
33128
                                 pixel_type(),filename);
 
33129
      return *this;
 
33130
    }
 
33131
#endif
 
33132
 
 
33133
    //! Save an image list as a gzipped file, using external tool 'gzip'.
 
33134
    const CImgList<T>& save_gzip_external(const char *const filename) const {
 
33135
      if (!filename)
 
33136
        throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
 
33137
                              pixel_type());
 
33138
      char command[1024], filetmp[512], body[512];
 
33139
      const char
 
33140
        *ext = cimg::split_filename(filename,body),
 
33141
        *ext2 = cimg::split_filename(body,0);
 
33142
      std::FILE *file;
 
33143
      do {
 
33144
        if (!cimg::strcasecmp(ext,"gz")) {
 
33145
          if (*ext2) std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
33146
                                  cimg::filenamerand(),ext2);
 
33147
          else std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
33148
                            cimg::filenamerand());
 
33149
        } else {
 
33150
          if (*ext) std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
33151
                                 cimg::filenamerand(),ext);
 
33152
          else std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
 
33153
                                 cimg::filenamerand());
 
33154
        }
 
33155
        if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file);
 
33156
      } while (file);
 
33157
      save(filetmp);
 
33158
      std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
 
33159
      cimg::system(command);
 
33160
      file = std::fopen(filename,"rb");
 
33161
      if (!file)
 
33162
        throw CImgIOException("CImgList<%s>::save_gzip_external() : Failed to save image file '%s'.",
 
33163
                              pixel_type(),filename);
 
33164
      else cimg::fclose(file);
 
33165
      std::remove(filetmp);
 
33166
      return *this;
 
33167
    }
 
33168
 
 
33169
    //! Save an image list into a OFF file.
 
33170
    template<typename tf, typename tc>
 
33171
    const CImgList<T>& save_off(const char *const filename,
 
33172
                                const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 
33173
      get_append('x','y').save_off(filename,primitives,colors,invert_faces);
 
33174
      return *this;
 
33175
    }
 
33176
 
 
33177
    //! Save an image list into a OFF file.
 
33178
    template<typename tf, typename tc>
 
33179
    const CImgList<T>& save_off(std::FILE *const file,
 
33180
                                const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
 
33181
      get_append('x','y').save_off(file,primitives,colors,invert_faces);
 
33182
      return *this;
 
33183
    }
 
33184
 
 
33185
    //! Save an image sequence using the external tool 'ffmpeg'.
 
33186
    const CImgList<T>& save_ffmpeg_external(const char *const filename, const char *const codec="mpeg2video") const {
 
33187
      char command[1024], filetmp[512], filetmp2[512];
 
33188
      std::FILE *file = 0;
 
33189
 
 
33190
      cimglist_for(*this,ll) if (!data[ll].is_sameXYZ(data[0]))
 
33191
        throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : All images of the sequence must be of the same dimension (file '%s').",
 
33192
                                    pixel_type(),filename);
 
33193
 
 
33194
      do {
 
33195
        std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
 
33196
        std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
 
33197
        if ((file=std::fopen(filetmp2,"rb"))!=0) std::fclose(file);
 
33198
      } while (file);
24408
33199
      cimglist_for(*this,l) {
24409
 
        const CImg<T>& letter = (*this)[l];
24410
 
        int xmin = letter.width, xmax = 0;
24411
 
        cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
24412
 
        if (xmin>xmax) res.insert(CImg<T>(letter.width,letter.height,1,letter.dim,0));
24413
 
        else res.insert(letter.get_crop(xmin,0,xmax,letter.height-1));
24414
 
      }
24415
 
      res[' '].resize(res['f'].width);
24416
 
      res[' '+256].resize(res['f'].width);
24417
 
      return res;
24418
 
    }
24419
 
 
24420
 
    CImgList<T>& crop_font() {
24421
 
      return get_crop_font().swap(*this);
24422
 
    }
24423
 
 
24424
 
    static CImgList<T> get_font(const unsigned int *const font, const unsigned int w, const unsigned int h,
24425
 
                             const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true) {
24426
 
      CImgList<T> res = CImgList<T>(256,w,h,1,3).insert(CImgList<T>(256,w,h,1,1));
24427
 
      const unsigned int *ptr = font;
24428
 
      unsigned int m = 0, val = 0;
24429
 
      for (unsigned int y=0; y<h; ++y)
24430
 
        for (unsigned int x=0; x<256*w; ++x) {
24431
 
          m>>=1; if (!m) { m = 0x80000000; val = *(ptr++); }
24432
 
          CImg<T>& img = res[x/w], &mask = res[x/w+256];
24433
 
          unsigned int xm = x%w;
24434
 
          img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0);
24435
 
        }
24436
 
      if (variable_size) res.crop_font();
24437
 
      if (paddingx || paddingy) cimglist_for(res,l) res[l].resize(res[l].dimx()+paddingx, res[l].dimy()+paddingy,1,-100,0);
24438
 
      return res;
24439
 
    }
24440
 
 
24441
 
    //! Return a CImg pre-defined font with desired size
24442
 
    /**
24443
 
       \param font_height = height of the desired font (can be 11,13,24,38 or 57)
24444
 
       \param fixed_size = tell if the font has a fixed or variable width.
24445
 
    **/
24446
 
    static CImgList<T> get_font(const unsigned int font_width, const bool variable_size=true) {
24447
 
      if (font_width<=11) {
24448
 
        static CImgList<T> font7x11, nfont7x11;
24449
 
        if (!variable_size && !font7x11)  font7x11  = get_font(cimg::font7x11,7,11,1,0,false);
24450
 
        if (variable_size  && !nfont7x11) nfont7x11 = get_font(cimg::font7x11,7,11,1,0,true);
24451
 
        return variable_size?nfont7x11:font7x11;
24452
 
      }
24453
 
      if (font_width<=13) {
24454
 
        static CImgList<T> font10x13, nfont10x13;
24455
 
        if (!variable_size && !font10x13)  font10x13  = get_font(cimg::font10x13,10,13,1,0,false);
24456
 
        if (variable_size  && !nfont10x13) nfont10x13 = get_font(cimg::font10x13,10,13,1,0,true);
24457
 
        return variable_size?nfont10x13:font10x13;
24458
 
      }
24459
 
      if (font_width<=17) {
24460
 
        static CImgList<T> font8x17, nfont8x17;
24461
 
        if (!variable_size && !font8x17)  font8x17  = get_font(cimg::font8x17,8,17,1,0,false);
24462
 
        if (variable_size  && !nfont8x17) nfont8x17 = get_font(cimg::font8x17,8,17,1,0,true);
24463
 
        return variable_size?nfont8x17:font8x17;
24464
 
      }
24465
 
      if (font_width<=19) {
24466
 
        static CImgList<T> font10x19, nfont10x19;
24467
 
        if (!variable_size && !font10x19)  font10x19  = get_font(cimg::font10x19,10,19,2,0,false);
24468
 
        if (variable_size  && !nfont10x19) nfont10x19 = get_font(cimg::font10x19,10,19,2,0,true);
24469
 
        return variable_size?nfont10x19:font10x19;
24470
 
      }
24471
 
      if (font_width<=24) {
24472
 
        static CImgList<T> font12x24, nfont12x24;
24473
 
        if (!variable_size && !font12x24)  font12x24  = get_font(cimg::font12x24,12,24,2,0,false);
24474
 
        if (variable_size  && !nfont12x24) nfont12x24 = get_font(cimg::font12x24,12,24,2,0,true);
24475
 
        return variable_size?nfont12x24:font12x24;
24476
 
      }
24477
 
      if (font_width<=32) {
24478
 
        static CImgList<T> font16x32, nfont16x32;
24479
 
        if (!variable_size && !font16x32)  font16x32  = get_font(cimg::font16x32,16,32,2,0,false);
24480
 
        if (variable_size  && !nfont16x32) nfont16x32 = get_font(cimg::font16x32,16,32,2,0,true);
24481
 
        return variable_size?nfont16x32:font16x32;
24482
 
      }
24483
 
      if (font_width<=38) {
24484
 
        static CImgList<T> font19x38, nfont19x38;
24485
 
        if (!variable_size && !font19x38)  font19x38  = get_font(cimg::font19x38,19,38,3,0,false);
24486
 
        if (variable_size  && !nfont19x38) nfont19x38 = get_font(cimg::font19x38,19,38,3,0,true);
24487
 
        return variable_size?nfont19x38:font19x38;
24488
 
      }
24489
 
      static CImgList<T> font29x57, nfont29x57;
24490
 
      if (!variable_size && !font29x57)  font29x57  = get_font(cimg::font29x57,29,57,5,0,false);
24491
 
      if (variable_size  && !nfont29x57) nfont29x57 = get_font(cimg::font29x57,29,57,5,0,true);
24492
 
      return variable_size?nfont29x57:font29x57;
24493
 
    }
24494
 
 
24495
 
    //! Display the current CImgList instance in an existing CImgDisplay window (by reference).
24496
 
    /**
24497
 
       This function displays the list images of the current CImgList instance into an existing CImgDisplay window.
24498
 
       Images of the list are concatenated in a single temporarly image for visualization purposes.
24499
 
       The function returns immediately.
24500
 
       \param disp : reference to an existing CImgDisplay instance, where the current image list will be displayed.
24501
 
       \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'.
24502
 
       \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
24503
 
       \return A reference to the current CImgList instance is returned.
24504
 
    **/
24505
 
    const CImgList& display(CImgDisplay& disp, const char axe='x', const char align='c') const {
24506
 
      get_append(axe,align).display(disp);
24507
 
      return *this;
24508
 
    }
24509
 
 
24510
 
    //! Display the current CImgList instance in a new display window.
24511
 
    /**
24512
 
       This function opens a new window with a specific title and displays the list images of the current CImgList instance into it.
24513
 
       Images of the list are concatenated in a single temporarly image for visualization purposes.
24514
 
       The function returns when a key is pressed or the display window is closed by the user.
24515
 
       \param title : specify the title of the opening display window.
24516
 
       \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'.
24517
 
       \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
24518
 
       \param min_size : specify the minimum size of the opening display window. Images having dimensions below this
24519
 
       size will be upscaled.
24520
 
       \param max_size : specify the maximum size of the opening display window. Images having dimensions above this
24521
 
       size will be downscaled.
24522
 
       \return A reference to the current CImgList instance is returned.
24523
 
    **/
24524
 
    const CImgList& display(const char* title, const char axe='x', const char align='c',
24525
 
                            const int min_size=128, const int max_size=1024, const int print_flag=1) const {
24526
 
 
24527
 
      if (is_empty())
24528
 
        throw CImgInstanceException("CImgList<%s>::display() : Instance list (%u,%u) is empty.",
24529
 
                                    pixel_type(),size,data);
24530
 
      const CImg<T> visu = get_append(axe,align);
24531
 
      CImgDisplay disp;
24532
 
      unsigned int w = visu.width+(visu.depth>1?visu.depth:0), h = visu.height+(visu.depth>1?visu.depth:0), XYZ[3];
24533
 
      print(title,print_flag);
24534
 
      const unsigned int dmin = cimg::min(w,h), minsiz = min_size>=0?min_size:(-min_size)*dmin/100;
24535
 
      if (dmin<minsiz) { w=w*minsiz/dmin; w+=(w==0); h=h*minsiz/dmin; h+=(h==0); }
24536
 
      const unsigned int dmax = cimg::max(w,h), maxsiz = max_size>=0?max_size:(-max_size)*dmax/100;
24537
 
      if (dmax>maxsiz) { w=w*maxsiz/dmax; w+=(w==0); h=h*maxsiz/dmax; h+=(h==0); }
24538
 
      disp.assign(w,h,title,1,3);
24539
 
      XYZ[0] = visu.width/2; XYZ[1] = visu.height/2; XYZ[2] = visu.depth/2;
24540
 
      while (!disp.is_closed && !disp.key) visu.get_coordinates(1,disp,XYZ);
24541
 
      return *this;
24542
 
    }
24543
 
 
24544
 
    //! Display the current CImgList instance in a new display window.
24545
 
    /**
24546
 
       This function opens a new window and displays the list images of the current CImgList instance into it.
24547
 
       Images of the list are concatenated in a single temporarly image for visualization purposes.
24548
 
       The function returns when a key is pressed or the display window is closed by the user.
24549
 
       \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'.
24550
 
       \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
24551
 
       \param min_size : specify the minimum size of the opening display window. Images having dimensions below this
24552
 
       size will be upscaled.
24553
 
       \param max_size : specify the maximum size of the opening display window. Images having dimensions above this
24554
 
       size will be downscaled.
24555
 
       \return A reference to the current CImgList instance is returned.
24556
 
    **/
24557
 
    const CImgList& display(const char axe='x', const char align='c',
24558
 
                            const int min_size=128, const int max_size=1024, const int print_flag=1) const {
24559
 
      char title[256] = { 0 };
24560
 
      std::sprintf(title,"CImgList<%s>",pixel_type());
24561
 
      return display(title,axe,align,min_size,max_size,print_flag);
24562
 
    }
24563
 
 
24564
 
    // Swap fields of two CImgList instances.
24565
 
    CImgList& swap(CImgList& list) {
24566
 
      cimg::swap(size,list.size);
24567
 
      cimg::swap(allocsize,list.allocsize);
24568
 
      cimg::swap(data,list.data);
24569
 
      return list;
24570
 
    }
24571
 
 
24572
 
  };
 
33200
        std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,l+1);
 
33201
        if (data[l].depth>1 || data[l].dim!=3) data[l].get_resize(-100,-100,1,3).save_pnm(filetmp2);
 
33202
        else data[l].save_pnm(filetmp2);
 
33203
      }
 
33204
#if cimg_OS!=2
 
33205
      std::sprintf(command,"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\" >/dev/null 2>&1",filetmp,codec,filename);
 
33206
#else
 
33207
      std::sprintf(command,"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\"",filetmp,codec,filename);
 
33208
#endif
 
33209
      cimg::system(command);
 
33210
      file = std::fopen(filename,"rb");
 
33211
      if (!file) throw CImgIOException("CImg<%s>::save_ffmpeg_external() : Failed to save image sequence '%s'.\n\n",
 
33212
                                       pixel_type(),filename);
 
33213
      else cimg::fclose(file);
 
33214
      cimglist_for(*this,lll) { std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,lll+1); std::remove(filetmp2); }
 
33215
      return *this;
 
33216
    }
 
33217
 
 
33218
   };
24573
33219
 
24574
33220
  /*
24575
 
   #-----------------------------------------
24576
 
   #
24577
 
   #
24578
 
   #
24579
 
   # Complete previously defined functions
24580
 
   #
24581
 
   #
24582
 
   #
24583
 
   #------------------------------------------
 
33221
   #---------------------------------------------
 
33222
   #
 
33223
   # Completion of previously declared functions
 
33224
   #
 
33225
   #----------------------------------------------
24584
33226
  */
24585
33227
 
24586
33228
namespace cimg {
24610
33252
                    const char *button3_txt, const char *button4_txt,
24611
33253
                    const char *button5_txt, const char *button6_txt,
24612
33254
                    const CImg<t>& logo, const bool centering = false) {
24613
 
#if cimg_display_type!=0
 
33255
#if cimg_display!=0
24614
33256
    const unsigned char
24615
33257
      black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };
24616
33258
 
24688
33330
      cimglist_for(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(buttons[lll],xbuttons[lll],by); }
24689
33331
 
24690
33332
      // Open window and enter events loop
24691
 
      CImgDisplay disp(canvas,title?title:" ",0,3,false,centering?true:false);
 
33333
      CImgDisplay disp(canvas,title?title:" ",0,false,centering?true:false);
24692
33334
      if (centering) disp.move((CImgDisplay::screen_dimx()-disp.dimx())/2,
24693
33335
                               (CImgDisplay::screen_dimy()-disp.dimy())/2);
24694
33336
      bool stopflag = false, refresh = false;
25062
33704
    return 0;
25063
33705
  }
25064
33706
 
25065
 
  //! Polygonize an implicit 2D function by the marching squares algorithm
 
33707
  //! Polygonize an implicit 2D function by the marching squares algorithm.
25066
33708
  template<typename tfunc, typename tp, typename tf>
25067
33709
  inline void marching_squares(const tfunc& func, const float isovalue,
25068
33710
                               const float x0, const float y0,
25151
33793
#ifdef cimg_use_visualcpp6
25152
33794
#undef std
25153
33795
#endif
25154
 
#ifdef cimg_redefine_min
 
33796
#ifdef _cimg_redefine_min
25155
33797
#define min(a,b) (((a)<(b))?(a):(b))
25156
33798
#endif
25157
 
#ifdef cimg_redefine_max
 
33799
#ifdef _cimg_redefine_max
25158
33800
#define max(a,b) (((a)>(b))?(a):(b))
25159
33801
#endif
25160
33802